diff --git a/src/PepperDash.Core/Comm/CommunicationGather.cs b/src/PepperDash.Core/Comm/CommunicationGather.cs index 9ffe8262..27d42888 100644 --- a/src/PepperDash.Core/Comm/CommunicationGather.cs +++ b/src/PepperDash.Core/Comm/CommunicationGather.cs @@ -8,8 +8,8 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + /// /// Defines the string event handler for line events on the gather /// @@ -30,7 +30,7 @@ namespace PepperDash.Core /// /// The communication port that this gathers on /// - public ICommunicationReceiver Port { get; private set; } + public ICommunicationReceiver Port { get; private set; } /// /// Default false. If true, the delimiter will be included in the line output @@ -67,22 +67,22 @@ namespace PepperDash.Core /// /// /// - public CommunicationGather(ICommunicationReceiver port, string delimiter) - :this(port, new string[] { delimiter} ) + public CommunicationGather(ICommunicationReceiver port, string delimiter) + :this(port, new string[] { delimiter} ) { } - /// - /// Constructor for using an array of string delimiters - /// - /// - /// - public CommunicationGather(ICommunicationReceiver port, string[] delimiters) - { - Port = port; - StringDelimiters = delimiters; - port.TextReceived += Port_TextReceivedStringDelimiter; - } + /// + /// Constructor for using an array of string delimiters + /// + /// + /// + public CommunicationGather(ICommunicationReceiver port, string[] delimiters) + { + Port = port; + StringDelimiters = delimiters; + port.TextReceived += Port_TextReceivedStringDelimiter; + } /// /// Disconnects this gather from the Port's TextReceived event. This will not fire LineReceived @@ -136,35 +136,35 @@ namespace PepperDash.Core ReceiveBuffer.Append(args.Text); var str = ReceiveBuffer.ToString(); - // Case: Receiving DEVICE get version\x0d\0x0a+OK "value":"1234"\x0d\x0a + // Case: Receiving DEVICE get version\x0d\0x0a+OK "value":"1234"\x0d\x0a - // RX: DEV - // Split: (1) "DEV" - // RX: I - // Split: (1) "DEVI" - // RX: CE get version - // Split: (1) "DEVICE get version" - // RX: \x0d\x0a+OK "value":"1234"\x0d\x0a - // Split: (2) DEVICE get version, +OK "value":"1234" + // RX: DEV + // Split: (1) "DEV" + // RX: I + // Split: (1) "DEVI" + // RX: CE get version + // Split: (1) "DEVICE get version" + // RX: \x0d\x0a+OK "value":"1234"\x0d\x0a + // Split: (2) DEVICE get version, +OK "value":"1234" - // Iterate the delimiters and fire an event for any matching delimiter - foreach (var delimiter in StringDelimiters) + // Iterate the delimiters and fire an event for any matching delimiter + foreach (var delimiter in StringDelimiters) + { + var lines = Regex.Split(str, delimiter); + if (lines.Length == 1) + continue; + + for (int i = 0; i < lines.Length - 1; i++) { - var lines = Regex.Split(str, delimiter); - if (lines.Length == 1) - continue; - - for (int i = 0; i < lines.Length - 1; i++) - { - string strToSend = null; - if (IncludeDelimiter) - strToSend = lines[i] + delimiter; - else - strToSend = lines[i]; - handler(this, new GenericCommMethodReceiveTextArgs(strToSend, delimiter)); - } - ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]); + string strToSend = null; + if (IncludeDelimiter) + strToSend = lines[i] + delimiter; + else + strToSend = lines[i]; + handler(this, new GenericCommMethodReceiveTextArgs(strToSend, delimiter)); } + ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]); + } } } @@ -175,5 +175,4 @@ namespace PepperDash.Core { Stop(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs b/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs index 0a38d826..1b3cfb1f 100644 --- a/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs +++ b/src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs @@ -5,173 +5,172 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable +/// +public class CommunicationStreamDebugging { /// - /// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable + /// Device Key that this instance configures /// - public class CommunicationStreamDebugging + public string ParentDeviceKey { get; private set; } + + /// + /// Timer to disable automatically if not manually disabled + /// + private CTimer DebugExpiryPeriod; + + /// + /// The current debug setting + /// + public eStreamDebuggingSetting DebugSetting { get; private set; } + + private uint _DebugTimeoutInMs; + private const uint _DefaultDebugTimeoutMin = 30; + + /// + /// Timeout in Minutes + /// + public uint DebugTimeoutMinutes { - /// - /// Device Key that this instance configures - /// - public string ParentDeviceKey { get; private set; } - - /// - /// Timer to disable automatically if not manually disabled - /// - private CTimer DebugExpiryPeriod; - - /// - /// The current debug setting - /// - public eStreamDebuggingSetting DebugSetting { get; private set; } - - private uint _DebugTimeoutInMs; - private const uint _DefaultDebugTimeoutMin = 30; - - /// - /// Timeout in Minutes - /// - public uint DebugTimeoutMinutes + get { - get - { - return _DebugTimeoutInMs/60000; - } - } - - /// - /// Indicates that receive stream debugging is enabled - /// - public bool RxStreamDebuggingIsEnabled{ get; private set; } - - /// - /// Indicates that transmit stream debugging is enabled - /// - public bool TxStreamDebuggingIsEnabled { get; private set; } - - /// - /// Constructor - /// - /// - public CommunicationStreamDebugging(string parentDeviceKey) - { - ParentDeviceKey = parentDeviceKey; - } - - - /// - /// Sets the debugging setting and if not setting to off, assumes the default of 30 mintues - /// - /// - public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting) - { - if (setting == eStreamDebuggingSetting.Off) - { - DisableDebugging(); - return; - } - - SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin); - } - - /// - /// Sets the debugging setting for the specified number of minutes - /// - /// - /// - public void SetDebuggingWithSpecificTimeout(eStreamDebuggingSetting setting, uint minutes) - { - if (setting == eStreamDebuggingSetting.Off) - { - DisableDebugging(); - return; - } - - _DebugTimeoutInMs = minutes * 60000; - - StopDebugTimer(); - - DebugExpiryPeriod = new CTimer((o) => DisableDebugging(), _DebugTimeoutInMs); - - if ((setting & eStreamDebuggingSetting.Rx) == eStreamDebuggingSetting.Rx) - RxStreamDebuggingIsEnabled = true; - - if ((setting & eStreamDebuggingSetting.Tx) == eStreamDebuggingSetting.Tx) - TxStreamDebuggingIsEnabled = true; - - Debug.SetDeviceDebugSettings(ParentDeviceKey, setting); - - } - - /// - /// Disabled debugging - /// - private void DisableDebugging() - { - StopDebugTimer(); - - Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off); - } - - private void StopDebugTimer() - { - RxStreamDebuggingIsEnabled = false; - TxStreamDebuggingIsEnabled = false; - - if (DebugExpiryPeriod == null) - { - return; - } - - DebugExpiryPeriod.Stop(); - DebugExpiryPeriod.Dispose(); - DebugExpiryPeriod = null; + return _DebugTimeoutInMs/60000; } } /// - /// The available settings for stream debugging + /// Indicates that receive stream debugging is enabled /// - [Flags] - public enum eStreamDebuggingSetting + public bool RxStreamDebuggingIsEnabled{ get; private set; } + + /// + /// Indicates that transmit stream debugging is enabled + /// + public bool TxStreamDebuggingIsEnabled { get; private set; } + + /// + /// Constructor + /// + /// + public CommunicationStreamDebugging(string parentDeviceKey) { - /// - /// Debug off - /// - Off = 0, - /// - /// Debug received data - /// - Rx = 1, - /// - /// Debug transmitted data - /// - Tx = 2, - /// - /// Debug both received and transmitted data - /// - Both = Rx | Tx + ParentDeviceKey = parentDeviceKey; + } + + + /// + /// Sets the debugging setting and if not setting to off, assumes the default of 30 mintues + /// + /// + public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting) + { + if (setting == eStreamDebuggingSetting.Off) + { + DisableDebugging(); + return; + } + + SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin); } /// - /// The available settings for stream debugging response types + /// Sets the debugging setting for the specified number of minutes /// - [Flags] - public enum eStreamDebuggingDataTypeSettings + /// + /// + public void SetDebuggingWithSpecificTimeout(eStreamDebuggingSetting setting, uint minutes) { - /// - /// Debug data in byte format - /// - Bytes = 0, - /// - /// Debug data in text format - /// - Text = 1, - /// - /// Debug data in both byte and text formats - /// - Both = Bytes | Text, + if (setting == eStreamDebuggingSetting.Off) + { + DisableDebugging(); + return; + } + + _DebugTimeoutInMs = minutes * 60000; + + StopDebugTimer(); + + DebugExpiryPeriod = new CTimer((o) => DisableDebugging(), _DebugTimeoutInMs); + + if ((setting & eStreamDebuggingSetting.Rx) == eStreamDebuggingSetting.Rx) + RxStreamDebuggingIsEnabled = true; + + if ((setting & eStreamDebuggingSetting.Tx) == eStreamDebuggingSetting.Tx) + TxStreamDebuggingIsEnabled = true; + + Debug.SetDeviceDebugSettings(ParentDeviceKey, setting); + + } + + /// + /// Disabled debugging + /// + private void DisableDebugging() + { + StopDebugTimer(); + + Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off); + } + + private void StopDebugTimer() + { + RxStreamDebuggingIsEnabled = false; + TxStreamDebuggingIsEnabled = false; + + if (DebugExpiryPeriod == null) + { + return; + } + + DebugExpiryPeriod.Stop(); + DebugExpiryPeriod.Dispose(); + DebugExpiryPeriod = null; } } + +/// +/// The available settings for stream debugging +/// +[Flags] +public enum eStreamDebuggingSetting +{ + /// + /// Debug off + /// + Off = 0, + /// + /// Debug received data + /// + Rx = 1, + /// + /// Debug transmitted data + /// + Tx = 2, + /// + /// Debug both received and transmitted data + /// + Both = Rx | Tx +} + +/// +/// The available settings for stream debugging response types +/// +[Flags] +public enum eStreamDebuggingDataTypeSettings +{ + /// + /// Debug data in byte format + /// + Bytes = 0, + /// + /// Debug data in text format + /// + Text = 1, + /// + /// Debug data in both byte and text formats + /// + Both = Bytes | Text, +} diff --git a/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs b/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs index ff869f77..d0dd2b97 100644 --- a/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs +++ b/src/PepperDash.Core/Comm/ControlPropertiesConfig.cs @@ -3,91 +3,90 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Config properties that indicate how to communicate with a device for control +/// +public class ControlPropertiesConfig { /// - /// Config properties that indicate how to communicate with a device for control + /// The method of control /// - public class ControlPropertiesConfig - { - /// - /// The method of control - /// - [JsonProperty("method")] - [JsonConverter(typeof(StringEnumConverter))] - public eControlMethod Method { get; set; } + [JsonProperty("method")] + [JsonConverter(typeof(StringEnumConverter))] + public eControlMethod Method { get; set; } - /// - /// The key of the device that contains the control port - /// - [JsonProperty("controlPortDevKey", NullValueHandling = NullValueHandling.Ignore)] - public string ControlPortDevKey { get; set; } + /// + /// The key of the device that contains the control port + /// + [JsonProperty("controlPortDevKey", NullValueHandling = NullValueHandling.Ignore)] + public string ControlPortDevKey { get; set; } - /// - /// The number of the control port on the device specified by ControlPortDevKey - /// - [JsonProperty("controlPortNumber", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value - public uint? ControlPortNumber { get; set; } + /// + /// The number of the control port on the device specified by ControlPortDevKey + /// + [JsonProperty("controlPortNumber", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value + public uint? ControlPortNumber { get; set; } - /// - /// The name of the control port on the device specified by ControlPortDevKey - /// - [JsonProperty("controlPortName", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value - public string ControlPortName { get; set; } + /// + /// The name of the control port on the device specified by ControlPortDevKey + /// + [JsonProperty("controlPortName", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value + public string ControlPortName { get; set; } - /// - /// Properties for ethernet based communications - /// - [JsonProperty("tcpSshProperties", NullValueHandling = NullValueHandling.Ignore)] - public TcpSshPropertiesConfig TcpSshProperties { get; set; } + /// + /// Properties for ethernet based communications + /// + [JsonProperty("tcpSshProperties", NullValueHandling = NullValueHandling.Ignore)] + public TcpSshPropertiesConfig TcpSshProperties { get; set; } - /// - /// The filename and path for the IR file - /// - [JsonProperty("irFile", NullValueHandling = NullValueHandling.Ignore)] - public string IrFile { get; set; } + /// + /// The filename and path for the IR file + /// + [JsonProperty("irFile", NullValueHandling = NullValueHandling.Ignore)] + public string IrFile { get; set; } - /// - /// The IpId of a Crestron device - /// - [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] - public string IpId { get; set; } + /// + /// The IpId of a Crestron device + /// + [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] + public string IpId { get; set; } - /// - /// Readonly uint representation of the IpId - /// - [JsonIgnore] - public uint IpIdInt { get { return Convert.ToUInt32(IpId, 16); } } + /// + /// Readonly uint representation of the IpId + /// + [JsonIgnore] + public uint IpIdInt { get { return Convert.ToUInt32(IpId, 16); } } - /// - /// Char indicating end of line - /// - [JsonProperty("endOfLineChar", NullValueHandling = NullValueHandling.Ignore)] - public char EndOfLineChar { get; set; } + /// + /// Char indicating end of line + /// + [JsonProperty("endOfLineChar", NullValueHandling = NullValueHandling.Ignore)] + public char EndOfLineChar { get; set; } - /// - /// Defaults to Environment.NewLine; - /// - [JsonProperty("endOfLineString", NullValueHandling = NullValueHandling.Ignore)] - public string EndOfLineString { get; set; } + /// + /// Defaults to Environment.NewLine; + /// + [JsonProperty("endOfLineString", NullValueHandling = NullValueHandling.Ignore)] + public string EndOfLineString { get; set; } - /// - /// Indicates - /// - [JsonProperty("deviceReadyResponsePattern", NullValueHandling = NullValueHandling.Ignore)] - public string DeviceReadyResponsePattern { get; set; } + /// + /// Indicates + /// + [JsonProperty("deviceReadyResponsePattern", NullValueHandling = NullValueHandling.Ignore)] + public string DeviceReadyResponsePattern { get; set; } - /// - /// Used when communcating to programs running in VC-4 - /// - [JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)] - public string RoomId { get; set; } + /// + /// Used when communcating to programs running in VC-4 + /// + [JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)] + public string RoomId { get; set; } - /// - /// Constructor - /// - public ControlPropertiesConfig() - { - } + /// + /// Constructor + /// + public ControlPropertiesConfig() + { } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/EventArgs.cs b/src/PepperDash.Core/Comm/EventArgs.cs index cf76d6b3..f018d072 100644 --- a/src/PepperDash.Core/Comm/EventArgs.cs +++ b/src/PepperDash.Core/Comm/EventArgs.cs @@ -16,28 +16,28 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; -namespace PepperDash.Core -{ - /// - /// Delegate for notifying of socket status changes - /// - /// - public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client); +namespace PepperDash.Core; - /// - /// EventArgs class for socket status changes - /// +/// +/// Delegate for notifying of socket status changes +/// +/// +public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client); + +/// +/// EventArgs class for socket status changes +/// public class GenericSocketStatusChageEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ISocketStatus Client { get; private set; } - /// - /// - /// - /// + /// + /// + /// + /// public GenericSocketStatusChageEventArgs(ISocketStatus client) { Client = client; @@ -46,105 +46,105 @@ namespace PepperDash.Core /// S+ Constructor /// public GenericSocketStatusChageEventArgs() { } - } +} + +/// +/// Delegate for notifying of TCP Server state changes +/// +/// +public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state); + +/// +/// EventArgs class for TCP Server state changes +/// +public class GenericTcpServerStateChangedEventArgs : EventArgs +{ + /// + /// + /// + public ServerState State { get; private set; } /// - /// Delegate for notifying of TCP Server state changes + /// /// /// - public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state); - - /// - /// EventArgs class for TCP Server state changes - /// - public class GenericTcpServerStateChangedEventArgs : EventArgs + public GenericTcpServerStateChangedEventArgs(ServerState state) { - /// - /// - /// - public ServerState State { get; private set; } - - /// - /// - /// - /// - public GenericTcpServerStateChangedEventArgs(ServerState state) - { - State = state; - } + State = state; + } /// /// S+ Constructor /// public GenericTcpServerStateChangedEventArgs() { } +} + +/// +/// Delegate for TCP Server socket status changes +/// +/// +/// +/// +public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus); +/// +/// EventArgs for TCP server socket status changes +/// +public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs +{ + /// + /// + /// + public object Socket { get; private set; } + /// + /// + /// + public uint ReceivedFromClientIndex { get; private set; } + /// + /// + /// + public SocketStatus ClientStatus { get; set; } + + /// + /// + /// + /// + /// + public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus) + { + Socket = socket; + ClientStatus = clientStatus; } /// - /// Delegate for TCP Server socket status changes + /// /// /// /// /// - public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus); - /// - /// EventArgs for TCP server socket status changes - /// - public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs + public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus) { - /// - /// - /// - public object Socket { get; private set; } - /// - /// - /// - public uint ReceivedFromClientIndex { get; private set; } - /// - /// - /// - public SocketStatus ClientStatus { get; set; } - - /// - /// - /// - /// - /// - public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus) - { - Socket = socket; - ClientStatus = clientStatus; - } - - /// - /// - /// - /// - /// - /// - public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus) - { - Socket = socket; - ReceivedFromClientIndex = clientIndex; - ClientStatus = clientStatus; - } + Socket = socket; + ReceivedFromClientIndex = clientIndex; + ClientStatus = clientStatus; + } /// /// S+ Constructor /// public GenericTcpServerSocketStatusChangeEventArgs() { } - } +} + +/// +/// EventArgs for TCP server com method receive text +/// +public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs +{ + /// + /// + /// + public uint ReceivedFromClientIndex { get; private set; } /// - /// EventArgs for TCP server com method receive text + /// /// - public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs - { - /// - /// - /// - public uint ReceivedFromClientIndex { get; private set; } - - /// - /// - /// public ushort ReceivedFromClientIndexShort { get @@ -153,99 +153,96 @@ namespace PepperDash.Core } } - /// - /// - /// - public string Text { get; private set; } + /// + /// + /// + public string Text { get; private set; } - /// - /// - /// - /// - public GenericTcpServerCommMethodReceiveTextArgs(string text) - { - Text = text; - } + /// + /// + /// + /// + public GenericTcpServerCommMethodReceiveTextArgs(string text) + { + Text = text; + } - /// - /// - /// - /// - /// - public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex) - { - Text = text; - ReceivedFromClientIndex = clientIndex; - } + /// + /// + /// + /// + /// + public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex) + { + Text = text; + ReceivedFromClientIndex = clientIndex; + } /// /// S+ Constructor /// public GenericTcpServerCommMethodReceiveTextArgs() { } - } +} + +/// +/// EventArgs for TCP server client ready for communication +/// +public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs +{ + /// + /// + /// + public bool IsReady; /// - /// EventArgs for TCP server client ready for communication + /// /// - public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs + /// + public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady) { - /// - /// - /// - public bool IsReady; - - /// - /// - /// - /// - public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady) - { - IsReady = isReady; - } + IsReady = isReady; + } /// /// S+ Constructor /// public GenericTcpServerClientReadyForcommunicationsEventArgs() { } +} + +/// +/// EventArgs for UDP connected +/// +public class GenericUdpConnectedEventArgs : EventArgs +{ + /// + /// + /// + public ushort UConnected; + /// + /// + /// + public bool Connected; + + /// + /// Constructor + /// + public GenericUdpConnectedEventArgs() { } + + /// + /// + /// + /// + public GenericUdpConnectedEventArgs(ushort uconnected) + { + UConnected = uconnected; } /// - /// EventArgs for UDP connected + /// /// - public class GenericUdpConnectedEventArgs : EventArgs + /// + public GenericUdpConnectedEventArgs(bool connected) { - /// - /// - /// - public ushort UConnected; - /// - /// - /// - public bool Connected; - - /// - /// Constructor - /// - public GenericUdpConnectedEventArgs() { } - - /// - /// - /// - /// - public GenericUdpConnectedEventArgs(ushort uconnected) - { - UConnected = uconnected; - } - - /// - /// - /// - /// - public GenericUdpConnectedEventArgs(bool connected) - { - Connected = connected; - } - + Connected = connected; } - +} -} \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs index 5ad2e29d..f7867286 100644 --- a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs +++ b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs @@ -7,949 +7,947 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// A class to handle secure TCP/IP communications with a server +/// +public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect { + private const string SplusKey = "Uninitialized Secure Tcp _client"; /// - /// A class to handle secure TCP/IP communications with a server + /// Stream debugging /// - public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect + public CommunicationStreamDebugging StreamDebugging { get; private set; } + + /// + /// Fires when data is received from the server and returns it as a Byte array + /// + public event EventHandler BytesReceived; + + /// + /// Fires when data is received from the server and returns it as text + /// + public event EventHandler TextReceived; + + #region GenericSecureTcpIpClient Events & Delegates + + /// + /// + /// + //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; + public event EventHandler ConnectionChange; + + /// + /// Auto reconnect evant handler + /// + public event EventHandler AutoReconnectTriggered; + + /// + /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. + /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. + /// + public event EventHandler TextReceivedQueueInvoke; + + /// + /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require + /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. + /// + public event EventHandler ClientReadyForCommunications; + + #endregion + + + #region GenricTcpIpClient properties + + private string _hostname; + + /// + /// Address of server + /// + public string Hostname { - private const string SplusKey = "Uninitialized Secure Tcp _client"; - /// - /// Stream debugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } - - /// - /// Fires when data is received from the server and returns it as a Byte array - /// - public event EventHandler BytesReceived; - - /// - /// Fires when data is received from the server and returns it as text - /// - public event EventHandler TextReceived; - - #region GenericSecureTcpIpClient Events & Delegates - - /// - /// - /// - //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; - public event EventHandler ConnectionChange; - - /// - /// Auto reconnect evant handler - /// - public event EventHandler AutoReconnectTriggered; - - /// - /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. - /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. - /// - public event EventHandler TextReceivedQueueInvoke; - - /// - /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require - /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. - /// - public event EventHandler ClientReadyForCommunications; - - #endregion - - - #region GenricTcpIpClient properties - - private string _hostname; - - /// - /// Address of server - /// - public string Hostname - { - get { return _hostname; } - set - { - _hostname = value; - if (_client != null) - { - _client.AddressClientConnectedTo = _hostname; - } - } - } - - /// - /// Port on server - /// - public int Port { get; set; } - - /// - /// S+ helper - /// - public ushort UPort - { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } - } - - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } - - /// - /// Internal secure client - /// - private SecureTCPClient _client; - - /// - /// Bool showing if socket is connected - /// - public bool IsConnected - { - get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } - } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected - { - get { return (ushort)(IsConnected ? 1 : 0); } - } - - /// - /// _client socket status Read only - /// - public SocketStatus ClientStatus - { - get - { - return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; - } - } - - /// - /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event - /// and IsConnected would be true when this == 2. - /// - public ushort UStatus - { - get { return (ushort)ClientStatus; } - } - - /// - /// Status text shows the message associated with socket status - /// - public string ClientStatusText { get { return ClientStatus.ToString(); } } - - /// - /// Connection failure reason - /// - public string ConnectionFailure { get { return ClientStatus.ToString(); } } - - /// - /// bool to track if auto reconnect should be set on the socket - /// - public bool AutoReconnect { get; set; } - - /// - /// S+ helper for AutoReconnect - /// - public ushort UAutoReconnect - { - get { return (ushort)(AutoReconnect ? 1 : 0); } - set { AutoReconnect = value == 1; } - } - - /// - /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 - /// - public int AutoReconnectIntervalMs { get; set; } - - /// - /// Flag Set only when the disconnect method is called. - /// - bool DisconnectCalledByUser; - - /// - /// - /// - public bool Connected - { - get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } - } - - // private Timer for auto reconnect - private CTimer RetryTimer; - - #endregion - - #region GenericSecureTcpIpClient properties - - /// - /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class - /// - public bool SharedKeyRequired { get; set; } - - /// - /// S+ helper for requires shared key bool - /// - public ushort USharedKeyRequired - { - set - { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; - } - } - - /// - /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module - /// - public string SharedKey { get; set; } - - /// - /// flag to show the client is waiting for the server to send the shared key - /// - private bool WaitingForSharedKeyResponse { get; set; } - - /// - /// Semaphore on connect method - /// - bool IsTryingToConnect; - - /// - /// Bool showing if socket is ready for communication after shared key exchange - /// - public bool IsReadyForCommunication { get; set; } - - /// - /// S+ helper for IsReadyForCommunication - /// - public ushort UIsReadyForCommunication - { - get { return (ushort)(IsReadyForCommunication ? 1 : 0); } - } - - /// - /// Bool Heartbeat Enabled flag - /// - public bool HeartbeatEnabled { get; set; } - - /// - /// S+ helper for Heartbeat Enabled - /// - public ushort UHeartbeatEnabled - { - get { return (ushort)(HeartbeatEnabled ? 1 : 0); } - set { HeartbeatEnabled = value == 1; } - } - - /// - /// Heartbeat String - /// - public string HeartbeatString { get; set; } - //public int HeartbeatInterval = 50000; - - /// - /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ - /// - public int HeartbeatInterval { get; set; } - - /// - /// Simpl+ Heartbeat Analog value in seconds - /// - public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } - - CTimer HeartbeatSendTimer; - CTimer HeartbeatAckTimer; - - // Used to force disconnection on a dead connect attempt - CTimer ConnectFailTimer; - CTimer WaitForSharedKey; - private int ConnectionCount; - - bool ProgramIsStopping; - - /// - /// Queue lock - /// - CCriticalSection DequeueLock = new CCriticalSection(); - - /// - /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before - /// calling initialize. - /// - public int ReceiveQueueSize { get; set; } - - /// - /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before - /// calling initialize. - /// - private CrestronQueue MessageQueue; - - #endregion - - #region Constructors - - /// - /// Constructor - /// - /// - /// - /// - /// - public GenericSecureTcpIpClient(string key, string address, int port, int bufferSize) - : base(key) - { - StreamDebugging = new CommunicationStreamDebugging(key); - Hostname = address; - Port = port; - BufferSize = bufferSize; - AutoReconnectIntervalMs = 5000; - - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - } - - /// - /// Contstructor that sets all properties by calling the initialize method with a config object. - /// - /// - /// - public GenericSecureTcpIpClient(string key, TcpClientConfigObject clientConfigObject) - : base(key) - { - StreamDebugging = new CommunicationStreamDebugging(key); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; - - Initialize(clientConfigObject); - } - - /// - /// Default constructor for S+ - /// - public GenericSecureTcpIpClient() - : base(SplusKey) - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; - } - - /// - /// Just to help S+ set the key - /// - public void Initialize(string key) - { - Key = key; - } - - /// - /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. - /// - /// - public void Initialize(TcpClientConfigObject config) - { - if (config == null) - { - Debug.Console(0, this, "Could not initialize client with key: {0}", Key); - return; - } - try - { - Hostname = config.Control.TcpSshProperties.Address; - Port = config.Control.TcpSshProperties.Port > 0 && config.Control.TcpSshProperties.Port <= 65535 - ? config.Control.TcpSshProperties.Port - : 80; - - AutoReconnect = config.Control.TcpSshProperties.AutoReconnect; - AutoReconnectIntervalMs = config.Control.TcpSshProperties.AutoReconnectIntervalMs > 1000 - ? config.Control.TcpSshProperties.AutoReconnectIntervalMs - : 5000; - - SharedKey = config.SharedKey; - SharedKeyRequired = config.SharedKeyRequired; - - HeartbeatEnabled = config.HeartbeatRequired; - HeartbeatRequiredIntervalInSeconds = config.HeartbeatRequiredIntervalInSeconds > 0 - ? config.HeartbeatRequiredIntervalInSeconds - : (ushort)15; - - - HeartbeatString = string.IsNullOrEmpty(config.HeartbeatStringToMatch) - ? "heartbeat" - : config.HeartbeatStringToMatch; - - BufferSize = config.Control.TcpSshProperties.BufferSize > 2000 - ? config.Control.TcpSshProperties.BufferSize - : 2000; - - ReceiveQueueSize = config.ReceiveQueueSize > 20 - ? config.ReceiveQueueSize - : 20; - - MessageQueue = new CrestronQueue(ReceiveQueueSize); - } - catch (Exception ex) - { - Debug.Console(0, this, "Exception initializing client with key: {0}\rException: {1}", Key, ex); - } - } - - #endregion - - /// - /// Handles closing this up when the program shuts down - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing _client connection"); - ProgramIsStopping = true; - Disconnect(); - } - - } - - /// - /// Deactivate the client - /// - /// - public override bool Deactivate() + get { return _hostname; } + set { + _hostname = value; if (_client != null) { - _client.SocketStatusChange -= this.Client_SocketStatusChange; - DisconnectClient(); - } - return true; - } - - /// - /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. - /// - public void Connect() - { - ConnectionCount++; - Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); - - - if (IsConnected) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); - return; - } - if (IsTryingToConnect) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); - return; - } - try - { - IsTryingToConnect = true; - if (RetryTimer != null) - { - RetryTimer.Stop(); - RetryTimer = null; - } - if (string.IsNullOrEmpty(Hostname)) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); - return; - } - if (Port < 1 || Port > 65535) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); - return; - } - if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); - return; - } - - // clean up previous client - if (_client != null) - { - Disconnect(); - } - DisconnectCalledByUser = false; - - _client = new SecureTCPClient(Hostname, Port, BufferSize); - _client.SocketStatusChange += Client_SocketStatusChange; - if (HeartbeatEnabled) - _client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); - _client.AddressClientConnectedTo = Hostname; - _client.PortNumber = Port; - // SecureClient = c; - - //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); - - ConnectFailTimer = new CTimer(o => - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); - if (IsTryingToConnect) - { - IsTryingToConnect = false; - - //if (ConnectionHasHungCallback != null) - //{ - // ConnectionHasHungCallback(); - //} - //SecureClient.DisconnectFromServer(); - //CheckClosedAndTryReconnect(); - } - }, 30000); - - Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); - _client.ConnectToServerAsync(o => - { - Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); - - if (ConnectFailTimer != null) - { - ConnectFailTimer.Stop(); - } - IsTryingToConnect = false; - - if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - { - Debug.Console(2, this, "_client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); - o.ReceiveDataAsync(Receive); - - if (SharedKeyRequired) - { - WaitingForSharedKeyResponse = true; - WaitForSharedKey = new CTimer(timer => - { - - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); - // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); - // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup - o.DisconnectFromServer(); - //CheckClosedAndTryReconnect(); - //OnClientReadyForcommunications(false); // Should send false event - }, 15000); - } - else - { - //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key - //required this is called by the shared key being negotiated - if (IsReadyForCommunication == false) - { - OnClientReadyForcommunications(true); // Key not required - } - } - } - else - { - Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); - CheckClosedAndTryReconnect(); - } - }); - } - catch (Exception ex) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Error, "_client connection exception: {0}", ex.Message); - IsTryingToConnect = false; - CheckClosedAndTryReconnect(); + _client.AddressClientConnectedTo = _hostname; } } + } - /// - /// - /// - public void Disconnect() + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// S+ helper + /// + public ushort UPort + { + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Internal secure client + /// + private SecureTCPClient _client; + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + + /// + /// _client socket status Read only + /// + public SocketStatus ClientStatus + { + get { - this.LogVerbose("Disconnect Called"); + return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; + } + } - DisconnectCalledByUser = true; + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected would be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)ClientStatus; } + } - // stop trying reconnects, if we are + /// + /// Status text shows the message associated with socket status + /// + public string ClientStatusText { get { return ClientStatus.ToString(); } } + + /// + /// Connection failure reason + /// + public string ConnectionFailure { get { return ClientStatus.ToString(); } } + + /// + /// bool to track if auto reconnect should be set on the socket + /// + public bool AutoReconnect { get; set; } + + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } + + /// + /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 + /// + public int AutoReconnectIntervalMs { get; set; } + + /// + /// Flag Set only when the disconnect method is called. + /// + bool DisconnectCalledByUser; + + /// + /// + /// + public bool Connected + { + get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + // private Timer for auto reconnect + private CTimer RetryTimer; + + #endregion + + #region GenericSecureTcpIpClient properties + + /// + /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class + /// + public bool SharedKeyRequired { get; set; } + + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set + { + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + public string SharedKey { get; set; } + + /// + /// flag to show the client is waiting for the server to send the shared key + /// + private bool WaitingForSharedKeyResponse { get; set; } + + /// + /// Semaphore on connect method + /// + bool IsTryingToConnect; + + /// + /// Bool showing if socket is ready for communication after shared key exchange + /// + public bool IsReadyForCommunication { get; set; } + + /// + /// S+ helper for IsReadyForCommunication + /// + public ushort UIsReadyForCommunication + { + get { return (ushort)(IsReadyForCommunication ? 1 : 0); } + } + + /// + /// Bool Heartbeat Enabled flag + /// + public bool HeartbeatEnabled { get; set; } + + /// + /// S+ helper for Heartbeat Enabled + /// + public ushort UHeartbeatEnabled + { + get { return (ushort)(HeartbeatEnabled ? 1 : 0); } + set { HeartbeatEnabled = value == 1; } + } + + /// + /// Heartbeat String + /// + public string HeartbeatString { get; set; } + //public int HeartbeatInterval = 50000; + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatInterval { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } + + CTimer HeartbeatSendTimer; + CTimer HeartbeatAckTimer; + + // Used to force disconnection on a dead connect attempt + CTimer ConnectFailTimer; + CTimer WaitForSharedKey; + private int ConnectionCount; + + bool ProgramIsStopping; + + /// + /// Queue lock + /// + CCriticalSection DequeueLock = new CCriticalSection(); + + /// + /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before + /// calling initialize. + /// + public int ReceiveQueueSize { get; set; } + + /// + /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before + /// calling initialize. + /// + private CrestronQueue MessageQueue; + + #endregion + + #region Constructors + + /// + /// Constructor + /// + /// + /// + /// + /// + public GenericSecureTcpIpClient(string key, string address, int port, int bufferSize) + : base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); + Hostname = address; + Port = port; + BufferSize = bufferSize; + AutoReconnectIntervalMs = 5000; + + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + } + + /// + /// Contstructor that sets all properties by calling the initialize method with a config object. + /// + /// + /// + public GenericSecureTcpIpClient(string key, TcpClientConfigObject clientConfigObject) + : base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + BufferSize = 2000; + + Initialize(clientConfigObject); + } + + /// + /// Default constructor for S+ + /// + public GenericSecureTcpIpClient() + : base(SplusKey) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + BufferSize = 2000; + } + + /// + /// Just to help S+ set the key + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. + /// + /// + public void Initialize(TcpClientConfigObject config) + { + if (config == null) + { + Debug.Console(0, this, "Could not initialize client with key: {0}", Key); + return; + } + try + { + Hostname = config.Control.TcpSshProperties.Address; + Port = config.Control.TcpSshProperties.Port > 0 && config.Control.TcpSshProperties.Port <= 65535 + ? config.Control.TcpSshProperties.Port + : 80; + + AutoReconnect = config.Control.TcpSshProperties.AutoReconnect; + AutoReconnectIntervalMs = config.Control.TcpSshProperties.AutoReconnectIntervalMs > 1000 + ? config.Control.TcpSshProperties.AutoReconnectIntervalMs + : 5000; + + SharedKey = config.SharedKey; + SharedKeyRequired = config.SharedKeyRequired; + + HeartbeatEnabled = config.HeartbeatRequired; + HeartbeatRequiredIntervalInSeconds = config.HeartbeatRequiredIntervalInSeconds > 0 + ? config.HeartbeatRequiredIntervalInSeconds + : (ushort)15; + + + HeartbeatString = string.IsNullOrEmpty(config.HeartbeatStringToMatch) + ? "heartbeat" + : config.HeartbeatStringToMatch; + + BufferSize = config.Control.TcpSshProperties.BufferSize > 2000 + ? config.Control.TcpSshProperties.BufferSize + : 2000; + + ReceiveQueueSize = config.ReceiveQueueSize > 20 + ? config.ReceiveQueueSize + : 20; + + MessageQueue = new CrestronQueue(ReceiveQueueSize); + } + catch (Exception ex) + { + Debug.Console(0, this, "Exception initializing client with key: {0}\rException: {1}", Key, ex); + } + } + + #endregion + + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing _client connection"); + ProgramIsStopping = true; + Disconnect(); + } + + } + + /// + /// Deactivate the client + /// + /// + public override bool Deactivate() + { + if (_client != null) + { + _client.SocketStatusChange -= this.Client_SocketStatusChange; + DisconnectClient(); + } + return true; + } + + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + ConnectionCount++; + Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); + + + if (IsConnected) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); + return; + } + if (IsTryingToConnect) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); + return; + } + try + { + IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } - - if (_client != null) + if (string.IsNullOrEmpty(Hostname)) { - DisconnectClient(); - this.LogDebug("Disconnected"); + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); + return; + } + if (Port < 1 || Port > 65535) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); + return; } - } - /// - /// Does the actual disconnect business - /// - public void DisconnectClient() - { - if (_client == null) return; - - Debug.Console(1, this, "Disconnecting client"); - if (IsConnected) - _client.DisconnectFromServer(); - - // close up client. ALWAYS use this when disconnecting. - IsTryingToConnect = false; - - Debug.Console(2, this, "Disconnecting _client {0}", DisconnectCalledByUser ? ", Called by user" : ""); - _client.SocketStatusChange -= Client_SocketStatusChange; - _client.Dispose(); - _client = null; - - if (ConnectFailTimer == null) return; - ConnectFailTimer.Stop(); - ConnectFailTimer.Dispose(); - ConnectFailTimer = null; - } - - #region Methods - - /// - /// Called from Connect failure or Socket Status change if - /// auto reconnect and socket disconnected (Not disconnected by user) - /// - void CheckClosedAndTryReconnect() - { + // clean up previous client if (_client != null) { - Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Disconnect(); } - if (!DisconnectCalledByUser && AutoReconnect) + DisconnectCalledByUser = false; + + _client = new SecureTCPClient(Hostname, Port, BufferSize); + _client.SocketStatusChange += Client_SocketStatusChange; + if (HeartbeatEnabled) + _client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); + _client.AddressClientConnectedTo = Hostname; + _client.PortNumber = Port; + // SecureClient = c; + + //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); + + ConnectFailTimer = new CTimer(o => { - var halfInterval = AutoReconnectIntervalMs / 2; - var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; - Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); - if (RetryTimer != null) + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); + if (IsTryingToConnect) { - RetryTimer.Stop(); - RetryTimer = null; + IsTryingToConnect = false; + + //if (ConnectionHasHungCallback != null) + //{ + // ConnectionHasHungCallback(); + //} + //SecureClient.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); } - if (AutoReconnectTriggered != null) - AutoReconnectTriggered(this, new EventArgs()); - RetryTimer = new CTimer(o => Connect(), rndTime); - } - } + }, 30000); - /// - /// Receive callback - /// - /// - /// - void Receive(SecureTCPClient client, int numBytes) - { - if (numBytes > 0) + Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); + _client.ConnectToServerAsync(o => { - string str = string.Empty; - var handler = TextReceivedQueueInvoke; - try + Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); + + if (ConnectFailTimer != null) { - var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); - str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - Debug.Console(2, this, "_client Received:\r--------\r{0}\r--------", str); - if (!string.IsNullOrEmpty(checkHeartbeat(str))) + ConnectFailTimer.Stop(); + } + IsTryingToConnect = false; + + if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + Debug.Console(2, this, "_client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); + o.ReceiveDataAsync(Receive); + + if (SharedKeyRequired) { - - if (SharedKeyRequired && str == "SharedKey:") + WaitingForSharedKeyResponse = true; + WaitForSharedKey = new CTimer(timer => { - Debug.Console(2, this, "Server asking for shared key, sending"); - SendText(SharedKey + "\n"); - } - else if (SharedKeyRequired && str == "Shared Key Match") - { - StopWaitForSharedKeyTimer(); - - Debug.Console(2, this, "Shared key confirmed. Ready for communication"); - OnClientReadyForcommunications(true); // Successful key exchange - } - else + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); + // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); + // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup + o.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); + //OnClientReadyForcommunications(false); // Should send false event + }, 15000); + } + else + { + //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key + //required this is called by the shared key being negotiated + if (IsReadyForCommunication == false) { - //var bytesHandler = BytesReceived; - //if (bytesHandler != null) - // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - var textHandler = TextReceived; - if (textHandler != null) - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - if (handler != null) - { - MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); - } + OnClientReadyForcommunications(true); // Key not required } } } - catch (Exception ex) + else { - Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); + CheckClosedAndTryReconnect(); } - if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - client.ReceiveDataAsync(Receive); + }); + } + catch (Exception ex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "_client connection exception: {0}", ex.Message); + IsTryingToConnect = false; + CheckClosedAndTryReconnect(); + } + } - //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. - if (handler != null) - { - var gotLock = DequeueLock.TryEnter(); - if (gotLock) - CrestronInvoke.BeginInvoke((o) => DequeueEvent()); - } - } - else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync - { - client.DisconnectFromServer(); - } + /// + /// + /// + public void Disconnect() + { + this.LogVerbose("Disconnect Called"); + + DisconnectCalledByUser = true; + + // stop trying reconnects, if we are + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; } - /// - /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. - /// It will dequeue items as they are enqueued automatically. - /// - void DequeueEvent() + if (_client != null) { + DisconnectClient(); + this.LogDebug("Disconnected"); + } + } + + /// + /// Does the actual disconnect business + /// + public void DisconnectClient() + { + if (_client == null) return; + + Debug.Console(1, this, "Disconnecting client"); + if (IsConnected) + _client.DisconnectFromServer(); + + // close up client. ALWAYS use this when disconnecting. + IsTryingToConnect = false; + + Debug.Console(2, this, "Disconnecting _client {0}", DisconnectCalledByUser ? ", Called by user" : ""); + _client.SocketStatusChange -= Client_SocketStatusChange; + _client.Dispose(); + _client = null; + + if (ConnectFailTimer == null) return; + ConnectFailTimer.Stop(); + ConnectFailTimer.Dispose(); + ConnectFailTimer = null; + } + + #region Methods + + /// + /// Called from Connect failure or Socket Status change if + /// auto reconnect and socket disconnected (Not disconnected by user) + /// + void CheckClosedAndTryReconnect() + { + if (_client != null) + { + Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); + Disconnect(); + } + if (!DisconnectCalledByUser && AutoReconnect) + { + var halfInterval = AutoReconnectIntervalMs / 2; + var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; + Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; + } + if (AutoReconnectTriggered != null) + AutoReconnectTriggered(this, new EventArgs()); + RetryTimer = new CTimer(o => Connect(), rndTime); + } + } + + /// + /// Receive callback + /// + /// + /// + void Receive(SecureTCPClient client, int numBytes) + { + if (numBytes > 0) + { + string str = string.Empty; + var handler = TextReceivedQueueInvoke; try { - while (true) + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + Debug.Console(2, this, "_client Received:\r--------\r{0}\r--------", str); + if (!string.IsNullOrEmpty(checkHeartbeat(str))) { - // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. - var message = MessageQueue.Dequeue(); - var handler = TextReceivedQueueInvoke; - if (handler != null) + + if (SharedKeyRequired && str == "SharedKey:") { - handler(this, message); + Debug.Console(2, this, "Server asking for shared key, sending"); + SendText(SharedKey + "\n"); + } + else if (SharedKeyRequired && str == "Shared Key Match") + { + StopWaitForSharedKeyTimer(); + + + Debug.Console(2, this, "Shared key confirmed. Ready for communication"); + OnClientReadyForcommunications(true); // Successful key exchange + } + else + { + //var bytesHandler = BytesReceived; + //if (bytesHandler != null) + // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + if (handler != null) + { + MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); + } } } } - catch (Exception e) + catch (Exception ex) { - this.LogException(e, "DequeueEvent error"); + Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); } - // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. - if (DequeueLock != null) + if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + client.ReceiveDataAsync(Receive); + + //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. + if (handler != null) { - DequeueLock.Leave(); + var gotLock = DequeueLock.TryEnter(); + if (gotLock) + CrestronInvoke.BeginInvoke((o) => DequeueEvent()); + } + } + else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync + { + client.DisconnectFromServer(); + } + } + + /// + /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. + /// It will dequeue items as they are enqueued automatically. + /// + void DequeueEvent() + { + try + { + while (true) + { + // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. + var message = MessageQueue.Dequeue(); + var handler = TextReceivedQueueInvoke; + if (handler != null) + { + handler(this, message); + } + } + } + catch (Exception e) + { + this.LogException(e, "DequeueEvent error"); + } + // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. + if (DequeueLock != null) + { + DequeueLock.Leave(); + } + } + + void HeartbeatStart() + { + if (HeartbeatEnabled) + { + this.LogVerbose("Starting Heartbeat"); + if (HeartbeatSendTimer == null) + { + + HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); + } + if (HeartbeatAckTimer == null) + { + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } } - void HeartbeatStart() + } + void HeartbeatStop() + { + + if (HeartbeatSendTimer != null) + { + Debug.Console(2, this, "Stoping Heartbeat Send"); + HeartbeatSendTimer.Stop(); + HeartbeatSendTimer = null; + } + if (HeartbeatAckTimer != null) + { + Debug.Console(2, this, "Stoping Heartbeat Ack"); + HeartbeatAckTimer.Stop(); + HeartbeatAckTimer = null; + } + + } + void SendHeartbeat(object notused) + { + this.SendText(HeartbeatString); + Debug.Console(2, this, "Sending Heartbeat"); + + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(string received) + { + try { if (HeartbeatEnabled) { - this.LogVerbose("Starting Heartbeat"); - if (HeartbeatSendTimer == null) + if (!string.IsNullOrEmpty(HeartbeatString)) { - - HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); - } - if (HeartbeatAckTimer == null) - { - HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); - } - } - - } - void HeartbeatStop() - { - - if (HeartbeatSendTimer != null) - { - Debug.Console(2, this, "Stoping Heartbeat Send"); - HeartbeatSendTimer.Stop(); - HeartbeatSendTimer = null; - } - if (HeartbeatAckTimer != null) - { - Debug.Console(2, this, "Stoping Heartbeat Ack"); - HeartbeatAckTimer.Stop(); - HeartbeatAckTimer = null; - } - - } - void SendHeartbeat(object notused) - { - this.SendText(HeartbeatString); - Debug.Console(2, this, "Sending Heartbeat"); - - } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(string received) - { - try - { - if (HeartbeatEnabled) - { - if (!string.IsNullOrEmpty(HeartbeatString)) + var remainingText = received.Replace(HeartbeatString, ""); + var noDelimiter = received.Trim(new char[] { '\r', '\n' }); + if (noDelimiter.Contains(HeartbeatString)) { - var remainingText = received.Replace(HeartbeatString, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatString)) + if (HeartbeatAckTimer != null) { - if (HeartbeatAckTimer != null) - { - HeartbeatAckTimer.Reset(HeartbeatInterval * 2); - } - else - { - HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); - } - Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); - return remainingText; + HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } - } - } - } - catch (Exception ex) - { - Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); - } - return received; - } - - - - void HeartbeatAckTimerFail(object o) - { - try - { - - if (IsConnected) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); - SendText("Heartbeat not received by server, closing connection"); - CheckClosedAndTryReconnect(); - } - - } - catch (Exception ex) - { - ErrorLog.Error("Heartbeat timeout Error on _client: {0}, {1}", Key, ex); - } - } - - /// - /// - /// - void StopWaitForSharedKeyTimer() - { - if (WaitForSharedKey != null) - { - WaitForSharedKey.Stop(); - WaitForSharedKey = null; - } - } - - /// - /// General send method - /// - public void SendText(string text) - { - if (!string.IsNullOrEmpty(text)) - { - try - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - if (_client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - { - _client.SendDataAsync(bytes, bytes.Length, (c, n) => + else { - // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? - if (n <= 0) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); - } - }); + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); + } + Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); + return remainingText; } } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); - } } } - - /// - /// - /// - public void SendBytes(byte[] bytes) + catch (Exception ex) { - if (bytes.Length > 0) - { - try - { - if (_client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - _client.SendData(bytes, bytes.Length); - } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); - } - } + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } - - /// - /// SocketStatusChange Callback - /// - /// - /// - void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) - { - if (ProgramIsStopping) - { - ProgramIsStopping = false; - return; - } - try - { - Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); - - OnConnectionChange(); - // The client could be null or disposed by this time... - if (_client == null || _client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - { - HeartbeatStop(); - OnClientReadyForcommunications(false); // socket has gone low - CheckClosedAndTryReconnect(); - } - } - catch (Exception ex) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); - } - } - - /// - /// Helper for ConnectionChange event - /// - void OnConnectionChange() - { - var handler = ConnectionChange; - if (handler == null) return; - - handler(this, new GenericSocketStatusChageEventArgs(this)); - } - - /// - /// Helper to fire ClientReadyForCommunications event - /// - void OnClientReadyForcommunications(bool isReady) - { - IsReadyForCommunication = isReady; - if (IsReadyForCommunication) - HeartbeatStart(); - - var handler = ClientReadyForCommunications; - if (handler == null) return; - - handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); - } - #endregion + return received; } + + + void HeartbeatAckTimerFail(object o) + { + try + { + + if (IsConnected) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); + SendText("Heartbeat not received by server, closing connection"); + CheckClosedAndTryReconnect(); + } + + } + catch (Exception ex) + { + ErrorLog.Error("Heartbeat timeout Error on _client: {0}, {1}", Key, ex); + } + } + + /// + /// + /// + void StopWaitForSharedKeyTimer() + { + if (WaitForSharedKey != null) + { + WaitForSharedKey.Stop(); + WaitForSharedKey = null; + } + } + + /// + /// General send method + /// + public void SendText(string text) + { + if (!string.IsNullOrEmpty(text)) + { + try + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + if (_client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + _client.SendDataAsync(bytes, bytes.Length, (c, n) => + { + // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? + if (n <= 0) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); + } + }); + } + } + catch (Exception ex) + { + Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); + } + } + } + + /// + /// + /// + public void SendBytes(byte[] bytes) + { + if (bytes.Length > 0) + { + try + { + if (_client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + _client.SendData(bytes, bytes.Length); + } + catch (Exception ex) + { + Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); + } + } + } + + /// + /// SocketStatusChange Callback + /// + /// + /// + void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) + { + if (ProgramIsStopping) + { + ProgramIsStopping = false; + return; + } + try + { + Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); + + OnConnectionChange(); + // The client could be null or disposed by this time... + if (_client == null || _client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + HeartbeatStop(); + OnClientReadyForcommunications(false); // socket has gone low + CheckClosedAndTryReconnect(); + } + } + catch (Exception ex) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); + } + } + + /// + /// Helper for ConnectionChange event + /// + void OnConnectionChange() + { + var handler = ConnectionChange; + if (handler == null) return; + + handler(this, new GenericSocketStatusChageEventArgs(this)); + } + + /// + /// Helper to fire ClientReadyForCommunications event + /// + void OnClientReadyForcommunications(bool isReady) + { + IsReadyForCommunication = isReady; + if (IsReadyForCommunication) + HeartbeatStart(); + + var handler = ClientReadyForCommunications; + if (handler == null) return; + + handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); + } + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs index 93b195ca..297233b1 100644 --- a/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs +++ b/src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs @@ -19,891 +19,889 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic secure TCP/IP client for server +/// +public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect { /// - /// Generic secure TCP/IP client for server + /// Band aid delegate for choked server /// - public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect + internal delegate void ConnectionHasHungCallbackDelegate(); + + #region Events + + //public event EventHandler BytesReceived; + + /// + /// Notifies of text received + /// + public event EventHandler TextReceived; + + /// + /// Notifies of auto reconnect sequence triggered + /// + public event EventHandler AutoReconnectTriggered; + + /// + /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. + /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. + /// + public event EventHandler TextReceivedQueueInvoke; + + /// + /// Notifies of socket status change + /// + public event EventHandler ConnectionChange; + + + /// + /// This is something of a band-aid callback. If the client times out during the connection process, because the server + /// is stuck, this will fire. It is intended to be used by the Server class monitor client, to help + /// keep a watch on the server and reset it if necessary. + /// + internal ConnectionHasHungCallbackDelegate ConnectionHasHungCallback; + + /// + /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require + /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. + /// + public event EventHandler ClientReadyForCommunications; + + #endregion + + #region Properties & Variables + + /// + /// Address of server + /// + public string Hostname { get; set; } + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// S+ helper + /// + public ushort UPort { - /// - /// Band aid delegate for choked server - /// - internal delegate void ConnectionHasHungCallbackDelegate(); + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } - #region Events + /// + /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class + /// + public bool SharedKeyRequired { get; set; } - //public event EventHandler BytesReceived; - - /// - /// Notifies of text received - /// - public event EventHandler TextReceived; - - /// - /// Notifies of auto reconnect sequence triggered - /// - public event EventHandler AutoReconnectTriggered; - - /// - /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. - /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. - /// - public event EventHandler TextReceivedQueueInvoke; - - /// - /// Notifies of socket status change - /// - public event EventHandler ConnectionChange; - - - /// - /// This is something of a band-aid callback. If the client times out during the connection process, because the server - /// is stuck, this will fire. It is intended to be used by the Server class monitor client, to help - /// keep a watch on the server and reset it if necessary. - /// - internal ConnectionHasHungCallbackDelegate ConnectionHasHungCallback; - - /// - /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require - /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. - /// - public event EventHandler ClientReadyForCommunications; - - #endregion - - #region Properties & Variables - - /// - /// Address of server - /// - public string Hostname { get; set; } - - /// - /// Port on server - /// - public int Port { get; set; } - - /// - /// S+ helper - /// - public ushort UPort + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; } + } - /// - /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class - /// - public bool SharedKeyRequired { get; set; } + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + public string SharedKey { get; set; } - /// - /// S+ helper for requires shared key bool - /// - public ushort USharedKeyRequired + /// + /// flag to show the client is waiting for the server to send the shared key + /// + private bool WaitingForSharedKeyResponse { get; set; } + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Semaphore on connect method + /// + bool IsTryingToConnect; + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { - set + if (Client != null) + return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; + else + return false; + } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + + /// + /// Bool showing if socket is ready for communication after shared key exchange + /// + public bool IsReadyForCommunication { get; set; } + + /// + /// S+ helper for IsReadyForCommunication + /// + public ushort UIsReadyForCommunication + { + get { return (ushort)(IsReadyForCommunication ? 1 : 0); } + } + + /// + /// Client socket status Read only + /// + public SocketStatus ClientStatus + { + get + { + if (Client != null) + return Client.ClientStatus; + else + return SocketStatus.SOCKET_STATUS_NO_CONNECT; + } + } + + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected would be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)ClientStatus; } + } + + /// + /// Status text shows the message associated with socket status + /// + public string ClientStatusText { get { return ClientStatus.ToString(); } } + + /// + /// bool to track if auto reconnect should be set on the socket + /// + public bool AutoReconnect { get; set; } + + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } + /// + /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 + /// + public int AutoReconnectIntervalMs { get; set; } + + /// + /// Flag Set only when the disconnect method is called. + /// + bool DisconnectCalledByUser; + + /// + /// private Timer for auto reconnect + /// + CTimer RetryTimer; + + + /// + /// + /// + public bool HeartbeatEnabled { get; set; } + /// + /// + /// + public ushort UHeartbeatEnabled + { + get { return (ushort)(HeartbeatEnabled ? 1 : 0); } + set { HeartbeatEnabled = value == 1; } + } + + /// + /// + /// + public string HeartbeatString { get; set; } + //public int HeartbeatInterval = 50000; + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatInterval { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } + + CTimer HeartbeatSendTimer; + CTimer HeartbeatAckTimer; + /// + /// Used to force disconnection on a dead connect attempt + /// + CTimer ConnectFailTimer; + CTimer WaitForSharedKey; + private int ConnectionCount; + /// + /// Internal secure client + /// + SecureTCPClient Client; + + bool ProgramIsStopping; + + /// + /// Queue lock + /// + CCriticalSection DequeueLock = new CCriticalSection(); + + /// + /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before + /// calling initialize. + /// + public int ReceiveQueueSize { get; set; } + + /// + /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before + /// calling initialize. + /// + private CrestronQueue MessageQueue; + + + #endregion + + #region Constructors + + /// + /// Constructor + /// + /// + /// + /// + /// + public GenericSecureTcpIpClient_ForServer(string key, string address, int port, int bufferSize) + : base(key) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + Hostname = address; + Port = port; + BufferSize = bufferSize; + AutoReconnectIntervalMs = 5000; + + } + + /// + /// Constructor for S+ + /// + public GenericSecureTcpIpClient_ForServer() + : base("Uninitialized Secure Tcp Client For Server") + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + BufferSize = 2000; + } + + /// + /// Contstructor that sets all properties by calling the initialize method with a config object. + /// + /// + /// + public GenericSecureTcpIpClient_ForServer(string key, TcpClientConfigObject clientConfigObject) + : base(key) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + Initialize(clientConfigObject); + } + + #endregion + + #region Methods + + /// + /// Just to help S+ set the key + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. + /// + /// + public void Initialize(TcpClientConfigObject clientConfigObject) + { + try + { + if (clientConfigObject != null) { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; + var TcpSshProperties = clientConfigObject.Control.TcpSshProperties; + Hostname = TcpSshProperties.Address; + AutoReconnect = TcpSshProperties.AutoReconnect; + AutoReconnectIntervalMs = TcpSshProperties.AutoReconnectIntervalMs > 1000 ? + TcpSshProperties.AutoReconnectIntervalMs : 5000; + SharedKey = clientConfigObject.SharedKey; + SharedKeyRequired = clientConfigObject.SharedKeyRequired; + HeartbeatEnabled = clientConfigObject.HeartbeatRequired; + HeartbeatRequiredIntervalInSeconds = clientConfigObject.HeartbeatRequiredIntervalInSeconds > 0 ? + clientConfigObject.HeartbeatRequiredIntervalInSeconds : (ushort)15; + HeartbeatString = string.IsNullOrEmpty(clientConfigObject.HeartbeatStringToMatch) ? "heartbeat" : clientConfigObject.HeartbeatStringToMatch; + Port = TcpSshProperties.Port; + BufferSize = TcpSshProperties.BufferSize > 2000 ? TcpSshProperties.BufferSize : 2000; + ReceiveQueueSize = clientConfigObject.ReceiveQueueSize > 20 ? clientConfigObject.ReceiveQueueSize : 20; + MessageQueue = new CrestronQueue(ReceiveQueueSize); } - } - - /// - /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module - /// - public string SharedKey { get; set; } - - /// - /// flag to show the client is waiting for the server to send the shared key - /// - private bool WaitingForSharedKeyResponse { get; set; } - - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } - - /// - /// Semaphore on connect method - /// - bool IsTryingToConnect; - - /// - /// Bool showing if socket is connected - /// - public bool IsConnected - { - get - { - if (Client != null) - return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; - else - return false; - } - } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected - { - get { return (ushort)(IsConnected ? 1 : 0); } - } - - /// - /// Bool showing if socket is ready for communication after shared key exchange - /// - public bool IsReadyForCommunication { get; set; } - - /// - /// S+ helper for IsReadyForCommunication - /// - public ushort UIsReadyForCommunication - { - get { return (ushort)(IsReadyForCommunication ? 1 : 0); } - } - - /// - /// Client socket status Read only - /// - public SocketStatus ClientStatus - { - get - { - if (Client != null) - return Client.ClientStatus; - else - return SocketStatus.SOCKET_STATUS_NO_CONNECT; - } - } - - /// - /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event - /// and IsConnected would be true when this == 2. - /// - public ushort UStatus - { - get { return (ushort)ClientStatus; } - } - - /// - /// Status text shows the message associated with socket status - /// - public string ClientStatusText { get { return ClientStatus.ToString(); } } - - /// - /// bool to track if auto reconnect should be set on the socket - /// - public bool AutoReconnect { get; set; } - - /// - /// S+ helper for AutoReconnect - /// - public ushort UAutoReconnect - { - get { return (ushort)(AutoReconnect ? 1 : 0); } - set { AutoReconnect = value == 1; } - } - /// - /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 - /// - public int AutoReconnectIntervalMs { get; set; } - - /// - /// Flag Set only when the disconnect method is called. - /// - bool DisconnectCalledByUser; - - /// - /// private Timer for auto reconnect - /// - CTimer RetryTimer; - - - /// - /// - /// - public bool HeartbeatEnabled { get; set; } - /// - /// - /// - public ushort UHeartbeatEnabled - { - get { return (ushort)(HeartbeatEnabled ? 1 : 0); } - set { HeartbeatEnabled = value == 1; } - } - - /// - /// - /// - public string HeartbeatString { get; set; } - //public int HeartbeatInterval = 50000; - - /// - /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ - /// - public int HeartbeatInterval { get; set; } - - /// - /// Simpl+ Heartbeat Analog value in seconds - /// - public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } - - CTimer HeartbeatSendTimer; - CTimer HeartbeatAckTimer; - /// - /// Used to force disconnection on a dead connect attempt - /// - CTimer ConnectFailTimer; - CTimer WaitForSharedKey; - private int ConnectionCount; - /// - /// Internal secure client - /// - SecureTCPClient Client; - - bool ProgramIsStopping; - - /// - /// Queue lock - /// - CCriticalSection DequeueLock = new CCriticalSection(); - - /// - /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before - /// calling initialize. - /// - public int ReceiveQueueSize { get; set; } - - /// - /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before - /// calling initialize. - /// - private CrestronQueue MessageQueue; - - - #endregion - - #region Constructors - - /// - /// Constructor - /// - /// - /// - /// - /// - public GenericSecureTcpIpClient_ForServer(string key, string address, int port, int bufferSize) - : base(key) - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - Hostname = address; - Port = port; - BufferSize = bufferSize; - AutoReconnectIntervalMs = 5000; - - } - - /// - /// Constructor for S+ - /// - public GenericSecureTcpIpClient_ForServer() - : base("Uninitialized Secure Tcp Client For Server") - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; - } - - /// - /// Contstructor that sets all properties by calling the initialize method with a config object. - /// - /// - /// - public GenericSecureTcpIpClient_ForServer(string key, TcpClientConfigObject clientConfigObject) - : base(key) - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - Initialize(clientConfigObject); - } - - #endregion - - #region Methods - - /// - /// Just to help S+ set the key - /// - public void Initialize(string key) - { - Key = key; - } - - /// - /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. - /// - /// - public void Initialize(TcpClientConfigObject clientConfigObject) - { - try - { - if (clientConfigObject != null) - { - var TcpSshProperties = clientConfigObject.Control.TcpSshProperties; - Hostname = TcpSshProperties.Address; - AutoReconnect = TcpSshProperties.AutoReconnect; - AutoReconnectIntervalMs = TcpSshProperties.AutoReconnectIntervalMs > 1000 ? - TcpSshProperties.AutoReconnectIntervalMs : 5000; - SharedKey = clientConfigObject.SharedKey; - SharedKeyRequired = clientConfigObject.SharedKeyRequired; - HeartbeatEnabled = clientConfigObject.HeartbeatRequired; - HeartbeatRequiredIntervalInSeconds = clientConfigObject.HeartbeatRequiredIntervalInSeconds > 0 ? - clientConfigObject.HeartbeatRequiredIntervalInSeconds : (ushort)15; - HeartbeatString = string.IsNullOrEmpty(clientConfigObject.HeartbeatStringToMatch) ? "heartbeat" : clientConfigObject.HeartbeatStringToMatch; - Port = TcpSshProperties.Port; - BufferSize = TcpSshProperties.BufferSize > 2000 ? TcpSshProperties.BufferSize : 2000; - ReceiveQueueSize = clientConfigObject.ReceiveQueueSize > 20 ? clientConfigObject.ReceiveQueueSize : 20; - MessageQueue = new CrestronQueue(ReceiveQueueSize); - } - else - { - ErrorLog.Error("Could not initialize client with key: {0}", Key); - } - } - catch + else { ErrorLog.Error("Could not initialize client with key: {0}", Key); } } - - /// - /// Handles closing this up when the program shuts down - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + catch { - if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); - ProgramIsStopping = true; - Disconnect(); - } + ErrorLog.Error("Could not initialize client with key: {0}", Key); + } + } + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); + ProgramIsStopping = true; + Disconnect(); } - /// - /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. - /// - public void Connect() + } + + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + ConnectionCount++; + Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); + + + if (IsConnected) { - ConnectionCount++; - Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); - - - if (IsConnected) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); - return; - } - if (IsTryingToConnect) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); - return; - } - try - { - IsTryingToConnect = true; - if (RetryTimer != null) - { - RetryTimer.Stop(); - RetryTimer = null; - } - if (string.IsNullOrEmpty(Hostname)) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); - return; - } - if (Port < 1 || Port > 65535) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); - return; - } - if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); - return; - } - - // clean up previous client - if (Client != null) - { - Cleanup(); - } - DisconnectCalledByUser = false; - - Client = new SecureTCPClient(Hostname, Port, BufferSize); - Client.SocketStatusChange += Client_SocketStatusChange; - if (HeartbeatEnabled) - Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); - Client.AddressClientConnectedTo = Hostname; - Client.PortNumber = Port; - // SecureClient = c; - - //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); - - ConnectFailTimer = new CTimer(o => - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); - if (IsTryingToConnect) - { - IsTryingToConnect = false; - - //if (ConnectionHasHungCallback != null) - //{ - // ConnectionHasHungCallback(); - //} - //SecureClient.DisconnectFromServer(); - //CheckClosedAndTryReconnect(); - } - }, 30000); - - Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); - Client.ConnectToServerAsync(o => - { - Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); - - if (ConnectFailTimer != null) - { - ConnectFailTimer.Stop(); - } - IsTryingToConnect = false; - - if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - { - Debug.Console(2, this, "Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); - o.ReceiveDataAsync(Receive); - - if (SharedKeyRequired) - { - WaitingForSharedKeyResponse = true; - WaitForSharedKey = new CTimer(timer => - { - - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); - // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); - // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup - o.DisconnectFromServer(); - //CheckClosedAndTryReconnect(); - //OnClientReadyForcommunications(false); // Should send false event - }, 15000); - } - else - { - //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key - //required this is called by the shared key being negotiated - if (IsReadyForCommunication == false) - { - OnClientReadyForcommunications(true); // Key not required - } - } - } - else - { - Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); - CheckClosedAndTryReconnect(); - } - }); - } - catch (Exception ex) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Client connection exception: {0}", ex.Message); - IsTryingToConnect = false; - CheckClosedAndTryReconnect(); - } + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); + return; } - - /// - /// - /// - public void Disconnect() + if (IsTryingToConnect) { - this.LogVerbose("Disconnect Called"); - - DisconnectCalledByUser = true; - if (IsConnected) - { - Client.DisconnectFromServer(); - - } + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); + return; + } + try + { + IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } - Cleanup(); - } - - /// - /// Internal call to close up client. ALWAYS use this when disconnecting. - /// - void Cleanup() - { - IsTryingToConnect = false; + if (string.IsNullOrEmpty(Hostname)) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); + return; + } + if (Port < 1 || Port > 65535) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); + return; + } + // clean up previous client if (Client != null) { - //SecureClient.DisconnectFromServer(); - Debug.Console(2, this, "Disconnecting Client {0}", DisconnectCalledByUser ? ", Called by user" : ""); - Client.SocketStatusChange -= Client_SocketStatusChange; - Client.Dispose(); - Client = null; - } - if (ConnectFailTimer != null) - { - ConnectFailTimer.Stop(); - ConnectFailTimer.Dispose(); - ConnectFailTimer = null; - } - } - - - /// ff - /// Called from Connect failure or Socket Status change if - /// auto reconnect and socket disconnected (Not disconnected by user) - /// - void CheckClosedAndTryReconnect() - { - if (Client != null) - { - Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Cleanup(); } - if (!DisconnectCalledByUser && AutoReconnect) + DisconnectCalledByUser = false; + + Client = new SecureTCPClient(Hostname, Port, BufferSize); + Client.SocketStatusChange += Client_SocketStatusChange; + if (HeartbeatEnabled) + Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); + Client.AddressClientConnectedTo = Hostname; + Client.PortNumber = Port; + // SecureClient = c; + + //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); + + ConnectFailTimer = new CTimer(o => { - var halfInterval = AutoReconnectIntervalMs / 2; - var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; - Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); - if (RetryTimer != null) + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); + if (IsTryingToConnect) { - RetryTimer.Stop(); - RetryTimer = null; + IsTryingToConnect = false; + + //if (ConnectionHasHungCallback != null) + //{ + // ConnectionHasHungCallback(); + //} + //SecureClient.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); } - if(AutoReconnectTriggered != null) - AutoReconnectTriggered(this, new EventArgs()); - RetryTimer = new CTimer(o => Connect(), rndTime); - } - } + }, 30000); - /// - /// Receive callback - /// - /// - /// - void Receive(SecureTCPClient client, int numBytes) - { - if (numBytes > 0) + Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); + Client.ConnectToServerAsync(o => { - string str = string.Empty; - var handler = TextReceivedQueueInvoke; - try + Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); + + if (ConnectFailTimer != null) { - var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); - str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - Debug.Console(2, this, "Client Received:\r--------\r{0}\r--------", str); - if (!string.IsNullOrEmpty(checkHeartbeat(str))) + ConnectFailTimer.Stop(); + } + IsTryingToConnect = false; + + if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + Debug.Console(2, this, "Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); + o.ReceiveDataAsync(Receive); + + if (SharedKeyRequired) { - - if (SharedKeyRequired && str == "SharedKey:") + WaitingForSharedKeyResponse = true; + WaitForSharedKey = new CTimer(timer => { - Debug.Console(2, this, "Server asking for shared key, sending"); - SendText(SharedKey + "\n"); - } - else if (SharedKeyRequired && str == "Shared Key Match") - { - StopWaitForSharedKeyTimer(); - - Debug.Console(2, this, "Shared key confirmed. Ready for communication"); - OnClientReadyForcommunications(true); // Successful key exchange - } - else + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); + // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); + // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup + o.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); + //OnClientReadyForcommunications(false); // Should send false event + }, 15000); + } + else + { + //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key + //required this is called by the shared key being negotiated + if (IsReadyForCommunication == false) { - //var bytesHandler = BytesReceived; - //if (bytesHandler != null) - // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - var textHandler = TextReceived; - if (textHandler != null) - textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); - if (handler != null) - { - MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); - } + OnClientReadyForcommunications(true); // Key not required } } } - catch (Exception ex) + else { - Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); + CheckClosedAndTryReconnect(); } - if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - client.ReceiveDataAsync(Receive); - - //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. - if (handler != null) - { - var gotLock = DequeueLock.TryEnter(); - if (gotLock) - CrestronInvoke.BeginInvoke((o) => DequeueEvent()); - } - } - else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync - { - client.DisconnectFromServer(); - } + }); } - - /// - /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. - /// It will dequeue items as they are enqueued automatically. - /// - void DequeueEvent() + catch (Exception ex) { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Client connection exception: {0}", ex.Message); + IsTryingToConnect = false; + CheckClosedAndTryReconnect(); + } + } + + /// + /// + /// + public void Disconnect() + { + this.LogVerbose("Disconnect Called"); + + DisconnectCalledByUser = true; + if (IsConnected) + { + Client.DisconnectFromServer(); + + } + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; + } + Cleanup(); + } + + /// + /// Internal call to close up client. ALWAYS use this when disconnecting. + /// + void Cleanup() + { + IsTryingToConnect = false; + + if (Client != null) + { + //SecureClient.DisconnectFromServer(); + Debug.Console(2, this, "Disconnecting Client {0}", DisconnectCalledByUser ? ", Called by user" : ""); + Client.SocketStatusChange -= Client_SocketStatusChange; + Client.Dispose(); + Client = null; + } + if (ConnectFailTimer != null) + { + ConnectFailTimer.Stop(); + ConnectFailTimer.Dispose(); + ConnectFailTimer = null; + } + } + + + /// ff + /// Called from Connect failure or Socket Status change if + /// auto reconnect and socket disconnected (Not disconnected by user) + /// + void CheckClosedAndTryReconnect() + { + if (Client != null) + { + Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); + Cleanup(); + } + if (!DisconnectCalledByUser && AutoReconnect) + { + var halfInterval = AutoReconnectIntervalMs / 2; + var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; + Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; + } + if(AutoReconnectTriggered != null) + AutoReconnectTriggered(this, new EventArgs()); + RetryTimer = new CTimer(o => Connect(), rndTime); + } + } + + /// + /// Receive callback + /// + /// + /// + void Receive(SecureTCPClient client, int numBytes) + { + if (numBytes > 0) + { + string str = string.Empty; + var handler = TextReceivedQueueInvoke; try { - while (true) + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + Debug.Console(2, this, "Client Received:\r--------\r{0}\r--------", str); + if (!string.IsNullOrEmpty(checkHeartbeat(str))) { - // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. - var message = MessageQueue.Dequeue(); - var handler = TextReceivedQueueInvoke; - if (handler != null) + + if (SharedKeyRequired && str == "SharedKey:") { - handler(this, message); + Debug.Console(2, this, "Server asking for shared key, sending"); + SendText(SharedKey + "\n"); + } + else if (SharedKeyRequired && str == "Shared Key Match") + { + StopWaitForSharedKeyTimer(); + + + Debug.Console(2, this, "Shared key confirmed. Ready for communication"); + OnClientReadyForcommunications(true); // Successful key exchange + } + else + { + //var bytesHandler = BytesReceived; + //if (bytesHandler != null) + // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); + if (handler != null) + { + MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); + } } } } - catch (Exception e) + catch (Exception ex) { - this.LogException(e, "DequeueEvent error"); + Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); } - // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. - if (DequeueLock != null) + if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + client.ReceiveDataAsync(Receive); + + //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. + if (handler != null) { - DequeueLock.Leave(); + var gotLock = DequeueLock.TryEnter(); + if (gotLock) + CrestronInvoke.BeginInvoke((o) => DequeueEvent()); + } + } + else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync + { + client.DisconnectFromServer(); + } + } + + /// + /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. + /// It will dequeue items as they are enqueued automatically. + /// + void DequeueEvent() + { + try + { + while (true) + { + // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. + var message = MessageQueue.Dequeue(); + var handler = TextReceivedQueueInvoke; + if (handler != null) + { + handler(this, message); + } + } + } + catch (Exception e) + { + this.LogException(e, "DequeueEvent error"); + } + // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. + if (DequeueLock != null) + { + DequeueLock.Leave(); + } + } + + void HeartbeatStart() + { + if (HeartbeatEnabled) + { + Debug.Console(2, this, "Starting Heartbeat"); + if (HeartbeatSendTimer == null) + { + + HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); + } + if (HeartbeatAckTimer == null) + { + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } } - void HeartbeatStart() + } + void HeartbeatStop() + { + + if (HeartbeatSendTimer != null) + { + Debug.Console(2, this, "Stoping Heartbeat Send"); + HeartbeatSendTimer.Stop(); + HeartbeatSendTimer = null; + } + if (HeartbeatAckTimer != null) + { + Debug.Console(2, this, "Stoping Heartbeat Ack"); + HeartbeatAckTimer.Stop(); + HeartbeatAckTimer = null; + } + + } + void SendHeartbeat(object notused) + { + this.SendText(HeartbeatString); + Debug.Console(2, this, "Sending Heartbeat"); + + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(string received) + { + try { if (HeartbeatEnabled) { - Debug.Console(2, this, "Starting Heartbeat"); - if (HeartbeatSendTimer == null) + if (!string.IsNullOrEmpty(HeartbeatString)) { - - HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); - } - if (HeartbeatAckTimer == null) - { - HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); - } - } - - } - void HeartbeatStop() - { - - if (HeartbeatSendTimer != null) - { - Debug.Console(2, this, "Stoping Heartbeat Send"); - HeartbeatSendTimer.Stop(); - HeartbeatSendTimer = null; - } - if (HeartbeatAckTimer != null) - { - Debug.Console(2, this, "Stoping Heartbeat Ack"); - HeartbeatAckTimer.Stop(); - HeartbeatAckTimer = null; - } - - } - void SendHeartbeat(object notused) - { - this.SendText(HeartbeatString); - Debug.Console(2, this, "Sending Heartbeat"); - - } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(string received) - { - try - { - if (HeartbeatEnabled) - { - if (!string.IsNullOrEmpty(HeartbeatString)) + var remainingText = received.Replace(HeartbeatString, ""); + var noDelimiter = received.Trim(new char[] { '\r', '\n' }); + if (noDelimiter.Contains(HeartbeatString)) { - var remainingText = received.Replace(HeartbeatString, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatString)) + if (HeartbeatAckTimer != null) { - if (HeartbeatAckTimer != null) - { - HeartbeatAckTimer.Reset(HeartbeatInterval * 2); - } - else - { - HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); - } - Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); - return remainingText; + HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } - } - } - } - catch (Exception ex) - { - Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); - } - return received; - } - - - - void HeartbeatAckTimerFail(object o) - { - try - { - - if (IsConnected) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); - SendText("Heartbeat not received by server, closing connection"); - CheckClosedAndTryReconnect(); - } - - } - catch (Exception ex) - { - ErrorLog.Error("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); - } - } - - /// - /// - /// - void StopWaitForSharedKeyTimer() - { - if (WaitForSharedKey != null) - { - WaitForSharedKey.Stop(); - WaitForSharedKey = null; - } - } - - /// - /// General send method - /// - public void SendText(string text) - { - if (!string.IsNullOrEmpty(text)) - { - try - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - { - Client.SendDataAsync(bytes, bytes.Length, (c, n) => + else { - // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? - if (n <= 0) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); - } - }); + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); + } + Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); + return remainingText; } } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); - } } } - - /// - /// - /// - public void SendBytes(byte[] bytes) + catch (Exception ex) { - if (bytes.Length > 0) - { - try - { - if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - Client.SendData(bytes, bytes.Length); - } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); - } - } + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } - - /// - /// SocketStatusChange Callback - /// - /// - /// - void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) - { - if (ProgramIsStopping) - { - ProgramIsStopping = false; - return; - } - try - { - Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); - - OnConnectionChange(); - // The client could be null or disposed by this time... - if (Client == null || Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - { - HeartbeatStop(); - OnClientReadyForcommunications(false); // socket has gone low - CheckClosedAndTryReconnect(); - } - } - catch (Exception ex) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); - } - } - - /// - /// Helper for ConnectionChange event - /// - void OnConnectionChange() - { - var handler = ConnectionChange; - if (handler != null) - ConnectionChange(this, new GenericTcpServerSocketStatusChangeEventArgs(this, Client.ClientStatus)); - } - - /// - /// Helper to fire ClientReadyForCommunications event - /// - void OnClientReadyForcommunications(bool isReady) - { - IsReadyForCommunication = isReady; - if (this.IsReadyForCommunication) { HeartbeatStart(); } - var handler = ClientReadyForCommunications; - if (handler != null) - handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); - } - #endregion + return received; } + + + void HeartbeatAckTimerFail(object o) + { + try + { + + if (IsConnected) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); + SendText("Heartbeat not received by server, closing connection"); + CheckClosedAndTryReconnect(); + } + + } + catch (Exception ex) + { + ErrorLog.Error("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); + } + } + + /// + /// + /// + void StopWaitForSharedKeyTimer() + { + if (WaitForSharedKey != null) + { + WaitForSharedKey.Stop(); + WaitForSharedKey = null; + } + } + + /// + /// General send method + /// + public void SendText(string text) + { + if (!string.IsNullOrEmpty(text)) + { + try + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + Client.SendDataAsync(bytes, bytes.Length, (c, n) => + { + // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? + if (n <= 0) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); + } + }); + } + } + catch (Exception ex) + { + Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); + } + } + } + + /// + /// + /// + public void SendBytes(byte[] bytes) + { + if (bytes.Length > 0) + { + try + { + if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + Client.SendData(bytes, bytes.Length); + } + catch (Exception ex) + { + Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); + } + } + } + + /// + /// SocketStatusChange Callback + /// + /// + /// + void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) + { + if (ProgramIsStopping) + { + ProgramIsStopping = false; + return; + } + try + { + Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); + + OnConnectionChange(); + // The client could be null or disposed by this time... + if (Client == null || Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + HeartbeatStop(); + OnClientReadyForcommunications(false); // socket has gone low + CheckClosedAndTryReconnect(); + } + } + catch (Exception ex) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); + } + } + + /// + /// Helper for ConnectionChange event + /// + void OnConnectionChange() + { + var handler = ConnectionChange; + if (handler != null) + ConnectionChange(this, new GenericTcpServerSocketStatusChangeEventArgs(this, Client.ClientStatus)); + } + + /// + /// Helper to fire ClientReadyForCommunications event + /// + void OnClientReadyForcommunications(bool isReady) + { + IsReadyForCommunication = isReady; + if (this.IsReadyForCommunication) { HeartbeatStart(); } + var handler = ClientReadyForCommunications; + if (handler != null) + handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); + } + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs b/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs index e0da068f..7804369c 100644 --- a/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs +++ b/src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs @@ -17,403 +17,403 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic secure TCP/IP server +/// +public class GenericSecureTcpIpServer : Device { + #region Events /// - /// Generic secure TCP/IP server + /// Event for Receiving text /// - public class GenericSecureTcpIpServer : Device + public event EventHandler TextReceived; + + /// + /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. + /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. + /// + public event EventHandler TextReceivedQueueInvoke; + + /// + /// Event for client connection socket status change + /// + public event EventHandler ClientConnectionChange; + + /// + /// Event for Server State Change + /// + public event EventHandler ServerStateChange; + + /// + /// For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire + /// after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. + /// + public event EventHandler ServerClientReadyForCommunications; + + /// + /// A band aid event to notify user that the server has choked. + /// + public ServerHasChokedCallbackDelegate ServerHasChoked { get; set; } + + /// + /// + /// + public delegate void ServerHasChokedCallbackDelegate(); + + #endregion + + #region Properties/Variables + + /// + /// Server listen lock + /// + CCriticalSection ServerCCSection = new CCriticalSection(); + + /// + /// Queue lock + /// + CCriticalSection DequeueLock = new CCriticalSection(); + + /// + /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before + /// calling initialize. + /// + public int ReceiveQueueSize { get; set; } + + /// + /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before + /// calling initialize. + /// + private CrestronQueue MessageQueue; + + /// + /// A bandaid client that monitors whether the server is reachable + /// + GenericSecureTcpIpClient_ForServer MonitorClient; + + /// + /// Timer to operate the bandaid monitor client in a loop. + /// + CTimer MonitorClientTimer; + + /// + /// + /// + int MonitorClientFailureCount; + + /// + /// 3 by default + /// + public int MonitorClientMaxFailureCount { get; set; } + + /// + /// Text representation of the Socket Status enum values for the server + /// + public string Status { - #region Events - /// - /// Event for Receiving text - /// - public event EventHandler TextReceived; - - /// - /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. - /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. - /// - public event EventHandler TextReceivedQueueInvoke; - - /// - /// Event for client connection socket status change - /// - public event EventHandler ClientConnectionChange; - - /// - /// Event for Server State Change - /// - public event EventHandler ServerStateChange; - - /// - /// For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire - /// after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. - /// - public event EventHandler ServerClientReadyForCommunications; - - /// - /// A band aid event to notify user that the server has choked. - /// - public ServerHasChokedCallbackDelegate ServerHasChoked { get; set; } - - /// - /// - /// - public delegate void ServerHasChokedCallbackDelegate(); - - #endregion - - #region Properties/Variables - - /// - /// Server listen lock - /// - CCriticalSection ServerCCSection = new CCriticalSection(); - - /// - /// Queue lock - /// - CCriticalSection DequeueLock = new CCriticalSection(); - - /// - /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before - /// calling initialize. - /// - public int ReceiveQueueSize { get; set; } - - /// - /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before - /// calling initialize. - /// - private CrestronQueue MessageQueue; - - /// - /// A bandaid client that monitors whether the server is reachable - /// - GenericSecureTcpIpClient_ForServer MonitorClient; - - /// - /// Timer to operate the bandaid monitor client in a loop. - /// - CTimer MonitorClientTimer; - - /// - /// - /// - int MonitorClientFailureCount; - - /// - /// 3 by default - /// - public int MonitorClientMaxFailureCount { get; set; } - - /// - /// Text representation of the Socket Status enum values for the server - /// - public string Status + get { - get - { - if (SecureServer != null) - return SecureServer.State.ToString(); - return ServerState.SERVER_NOT_LISTENING.ToString(); - - } + if (SecureServer != null) + return SecureServer.State.ToString(); + return ServerState.SERVER_NOT_LISTENING.ToString(); } - /// - /// Bool showing if socket is connected - /// - public bool IsConnected + } + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { - get - { - if (SecureServer != null) - return (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; + if (SecureServer != null) + return (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; + return false; + + //return (Secure ? SecureServer != null : UnsecureServer != null) && + //(Secure ? (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED : + // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); + } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + + /// + /// Bool showing if socket is connected + /// + public bool IsListening + { + get + { + if (SecureServer != null) + return (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING; + else return false; - - //return (Secure ? SecureServer != null : UnsecureServer != null) && - //(Secure ? (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED : - // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); - } + //return (Secure ? SecureServer != null : UnsecureServer != null) && + //(Secure ? (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING : + // (UnsecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING); } + } - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected + /// + /// S+ helper for IsConnected + /// + public ushort UIsListening + { + get { return (ushort)(IsListening ? 1 : 0); } + } + /// + /// Max number of clients this server will allow for connection. Crestron max is 64. This number should be less than 65 + /// + public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable + /// + /// Number of clients currently connected. + /// + public ushort NumberOfClientsConnected + { + get { - get { return (ushort)(IsConnected ? 1 : 0); } + if (SecureServer != null) + return (ushort)SecureServer.NumberOfClientsConnected; + return 0; } + } - /// - /// Bool showing if socket is connected - /// - public bool IsListening + /// + /// Port Server should listen on + /// + public int Port { get; set; } + + /// + /// S+ helper for Port + /// + public ushort UPort + { + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } + + /// + /// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client + /// + public bool SharedKeyRequired { get; set; } + + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set { - get + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. + /// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called + /// + public string SharedKey { get; set; } + + /// + /// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received + /// + public bool HeartbeatRequired { get; set; } + + /// + /// S+ Helper for Heartbeat Required + /// + public ushort UHeartbeatRequired + { + set + { + if (value == 1) + HeartbeatRequired = true; + else + HeartbeatRequired = false; + } + } + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatRequiredIntervalMs { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } + + /// + /// String to Match for heartbeat. If null or empty any string will reset heartbeat timer + /// + public string HeartbeatStringToMatch { get; set; } + + //private timers for Heartbeats per client + Dictionary HeartbeatTimerDictionary = new Dictionary(); + + //flags to show the secure server is waiting for client at index to send the shared key + List WaitingForSharedKey = new List(); + + List ClientReadyAfterKeyExchange = new List(); + + /// + /// The connected client indexes + /// + public List ConnectedClientsIndexes = new List(); + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Private flag to note that the server has stopped intentionally + /// + private bool ServerStopped { get; set; } + + //Servers + SecureTCPServer SecureServer; + + /// + /// + /// + bool ProgramIsStopping; + + #endregion + + #region Constructors + /// + /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. + /// + public GenericSecureTcpIpServer() + : base("Uninitialized Secure TCP Server") + { + HeartbeatRequiredIntervalInSeconds = 15; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + BufferSize = 2000; + MonitorClientMaxFailureCount = 3; + } + + /// + /// constructor with debug key set at instantiation. Make sure to set all properties before listening. + /// + /// + public GenericSecureTcpIpServer(string key) + : base("Uninitialized Secure TCP Server") + { + HeartbeatRequiredIntervalInSeconds = 15; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + BufferSize = 2000; + MonitorClientMaxFailureCount = 3; + Key = key; + } + + /// + /// Contstructor that sets all properties by calling the initialize method with a config object. This does set Queue size. + /// + /// + public GenericSecureTcpIpServer(TcpServerConfigObject serverConfigObject) + : base("Uninitialized Secure TCP Server") + { + HeartbeatRequiredIntervalInSeconds = 15; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + BufferSize = 2000; + MonitorClientMaxFailureCount = 3; + Initialize(serverConfigObject); + } + #endregion + + #region Methods - Server Actions + /// + /// Disconnects all clients and stops the server + /// + public void KillServer() + { + ServerStopped = true; + if (MonitorClient != null) + { + MonitorClient.Disconnect(); + } + DisconnectAllClientsForShutdown(); + StopListening(); + } + + /// + /// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ + /// + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Initialze the server + /// + /// + public void Initialize(TcpServerConfigObject serverConfigObject) + { + try + { + if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) { - if (SecureServer != null) - return (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING; - else - return false; - //return (Secure ? SecureServer != null : UnsecureServer != null) && - //(Secure ? (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING : - // (UnsecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING); + Key = serverConfigObject.Key; + MaxClients = serverConfigObject.MaxClients; + Port = serverConfigObject.Port; + SharedKeyRequired = serverConfigObject.SharedKeyRequired; + SharedKey = serverConfigObject.SharedKey; + HeartbeatRequired = serverConfigObject.HeartbeatRequired; + HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; + HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; + BufferSize = serverConfigObject.BufferSize; + ReceiveQueueSize = serverConfigObject.ReceiveQueueSize > 20 ? serverConfigObject.ReceiveQueueSize : 20; + MessageQueue = new CrestronQueue(ReceiveQueueSize); } - } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsListening - { - get { return (ushort)(IsListening ? 1 : 0); } - } - /// - /// Max number of clients this server will allow for connection. Crestron max is 64. This number should be less than 65 - /// - public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable - /// - /// Number of clients currently connected. - /// - public ushort NumberOfClientsConnected - { - get - { - if (SecureServer != null) - return (ushort)SecureServer.NumberOfClientsConnected; - return 0; - } - } - - /// - /// Port Server should listen on - /// - public int Port { get; set; } - - /// - /// S+ helper for Port - /// - public ushort UPort - { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } - } - - /// - /// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client - /// - public bool SharedKeyRequired { get; set; } - - /// - /// S+ helper for requires shared key bool - /// - public ushort USharedKeyRequired - { - set - { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; - } - } - - /// - /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. - /// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called - /// - public string SharedKey { get; set; } - - /// - /// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received - /// - public bool HeartbeatRequired { get; set; } - - /// - /// S+ Helper for Heartbeat Required - /// - public ushort UHeartbeatRequired - { - set - { - if (value == 1) - HeartbeatRequired = true; - else - HeartbeatRequired = false; - } - } - - /// - /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ - /// - public int HeartbeatRequiredIntervalMs { get; set; } - - /// - /// Simpl+ Heartbeat Analog value in seconds - /// - public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } - - /// - /// String to Match for heartbeat. If null or empty any string will reset heartbeat timer - /// - public string HeartbeatStringToMatch { get; set; } - - //private timers for Heartbeats per client - Dictionary HeartbeatTimerDictionary = new Dictionary(); - - //flags to show the secure server is waiting for client at index to send the shared key - List WaitingForSharedKey = new List(); - - List ClientReadyAfterKeyExchange = new List(); - - /// - /// The connected client indexes - /// - public List ConnectedClientsIndexes = new List(); - - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } - - /// - /// Private flag to note that the server has stopped intentionally - /// - private bool ServerStopped { get; set; } - - //Servers - SecureTCPServer SecureServer; - - /// - /// - /// - bool ProgramIsStopping; - - #endregion - - #region Constructors - /// - /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. - /// - public GenericSecureTcpIpServer() - : base("Uninitialized Secure TCP Server") - { - HeartbeatRequiredIntervalInSeconds = 15; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - BufferSize = 2000; - MonitorClientMaxFailureCount = 3; - } - - /// - /// constructor with debug key set at instantiation. Make sure to set all properties before listening. - /// - /// - public GenericSecureTcpIpServer(string key) - : base("Uninitialized Secure TCP Server") - { - HeartbeatRequiredIntervalInSeconds = 15; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - BufferSize = 2000; - MonitorClientMaxFailureCount = 3; - Key = key; - } - - /// - /// Contstructor that sets all properties by calling the initialize method with a config object. This does set Queue size. - /// - /// - public GenericSecureTcpIpServer(TcpServerConfigObject serverConfigObject) - : base("Uninitialized Secure TCP Server") - { - HeartbeatRequiredIntervalInSeconds = 15; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - BufferSize = 2000; - MonitorClientMaxFailureCount = 3; - Initialize(serverConfigObject); - } - #endregion - - #region Methods - Server Actions - /// - /// Disconnects all clients and stops the server - /// - public void KillServer() - { - ServerStopped = true; - if (MonitorClient != null) - { - MonitorClient.Disconnect(); - } - DisconnectAllClientsForShutdown(); - StopListening(); - } - - /// - /// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ - /// - /// - public void Initialize(string key) - { - Key = key; - } - - /// - /// Initialze the server - /// - /// - public void Initialize(TcpServerConfigObject serverConfigObject) - { - try - { - if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) - { - Key = serverConfigObject.Key; - MaxClients = serverConfigObject.MaxClients; - Port = serverConfigObject.Port; - SharedKeyRequired = serverConfigObject.SharedKeyRequired; - SharedKey = serverConfigObject.SharedKey; - HeartbeatRequired = serverConfigObject.HeartbeatRequired; - HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; - HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; - BufferSize = serverConfigObject.BufferSize; - ReceiveQueueSize = serverConfigObject.ReceiveQueueSize > 20 ? serverConfigObject.ReceiveQueueSize : 20; - MessageQueue = new CrestronQueue(ReceiveQueueSize); - } - else - { - ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); - } - } - catch + else { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } - - /// - /// Start listening on the specified port - /// - public void Listen() + catch { - ServerCCSection.Enter(); - try + ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); + } + } + + /// + /// Start listening on the specified port + /// + public void Listen() + { + ServerCCSection.Enter(); + try + { + if (Port < 1 || Port > 65535) { - if (Port < 1 || Port > 65535) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': Invalid port", Key); - ErrorLog.Warn(string.Format("Server '{0}': Invalid port", Key)); - return; - } - if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': No Shared Key set", Key); - ErrorLog.Warn(string.Format("Server '{0}': No Shared Key set", Key)); - return; - } + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': Invalid port", Key); + ErrorLog.Warn(string.Format("Server '{0}': Invalid port", Key)); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': No Shared Key set", Key); + ErrorLog.Warn(string.Format("Server '{0}': No Shared Key set", Key)); + return; + } if (SecureServer == null) @@ -444,19 +444,19 @@ namespace PepperDash.Core Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Secure Server Status: {0}, Socket Status: {1}", SecureServer.State, SecureServer.ServerSocketStatus); ServerCCSection.Leave(); - } - catch (Exception ex) - { - ServerCCSection.Leave(); - ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); - } } - - /// - /// Stop Listeneing - /// - public void StopListening() + catch (Exception ex) { + ServerCCSection.Leave(); + ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); + } + } + + /// + /// Stop Listeneing + /// + public void StopListening() + { try { Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); @@ -472,144 +472,129 @@ namespace PepperDash.Core { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error stopping server. Error: {0}", ex); } - } + } - /// - /// Disconnects Client - /// - /// - public void DisconnectClient(uint client) + /// + /// Disconnects Client + /// + /// + public void DisconnectClient(uint client) + { + try { - try - { - SecureServer.Disconnect(client); - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); - } + SecureServer.Disconnect(client); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); } - /// - /// Disconnect All Clients - /// - public void DisconnectAllClientsForShutdown() + catch (Exception ex) { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); - if (SecureServer != null) + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); + } + } + /// + /// Disconnect All Clients + /// + public void DisconnectAllClientsForShutdown() + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); + if (SecureServer != null) + { + SecureServer.SocketStatusChange -= SecureServer_SocketStatusChange; + foreach (var index in ConnectedClientsIndexes.ToList()) // copy it here so that it iterates properly { - SecureServer.SocketStatusChange -= SecureServer_SocketStatusChange; - foreach (var index in ConnectedClientsIndexes.ToList()) // copy it here so that it iterates properly + var i = index; + if (!SecureServer.ClientConnected(index)) + continue; + try { - var i = index; - if (!SecureServer.ClientConnected(index)) - continue; - try - { - SecureServer.Disconnect(i); - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); - } + SecureServer.Disconnect(i); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); } - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", SecureServer.ServerSocketStatus); - } - - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); - ConnectedClientsIndexes.Clear(); - - if (!ProgramIsStopping) - { - OnConnectionChange(); - OnServerStateChange(SecureServer.State); //State shows both listening and connected - } - - // var o = new { }; - } - - /// - /// Broadcast text from server to all connected clients - /// - /// - public void BroadcastText(string text) - { - CCriticalSection CCBroadcast = new CCriticalSection(); - CCBroadcast.Enter(); - try - { - if (ConnectedClientsIndexes.Count > 0) + catch (Exception ex) { - byte[] b = Encoding.GetEncoding(28591).GetBytes(text); - foreach (uint i in ConnectedClientsIndexes) - { - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(i))) - { - SocketErrorCodes error = SecureServer.SendDataAsync(i, b, b.Length, (x, y, z) => { }); - if (error != SocketErrorCodes.SOCKET_OK && error != SocketErrorCodes.SOCKET_OPERATION_PENDING) - this.LogVerbose("{error}", error); - } - } + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); } - CCBroadcast.Leave(); - } - catch (Exception ex) - { - CCBroadcast.Leave(); - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); } + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", SecureServer.ServerSocketStatus); } - /// - /// Not sure this is useful in library, maybe Pro?? - /// - /// - /// - public void SendTextToClient(string text, uint clientIndex) + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); + ConnectedClientsIndexes.Clear(); + + if (!ProgramIsStopping) { - try + OnConnectionChange(); + OnServerStateChange(SecureServer.State); //State shows both listening and connected + } + + // var o = new { }; + } + + /// + /// Broadcast text from server to all connected clients + /// + /// + public void BroadcastText(string text) + { + CCriticalSection CCBroadcast = new CCriticalSection(); + CCBroadcast.Enter(); + try + { + if (ConnectedClientsIndexes.Count > 0) { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); - if (SecureServer != null && SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) + foreach (uint i in ConnectedClientsIndexes) { - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) - SecureServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(i))) + { + SocketErrorCodes error = SecureServer.SendDataAsync(i, b, b.Length, (x, y, z) => { }); + if (error != SocketErrorCodes.SOCKET_OK && error != SocketErrorCodes.SOCKET_OPERATION_PENDING) + this.LogVerbose("{error}", error); + } } } - catch (Exception ex) + CCBroadcast.Leave(); + } + catch (Exception ex) + { + CCBroadcast.Leave(); + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); + } + } + + /// + /// Not sure this is useful in library, maybe Pro?? + /// + /// + /// + public void SendTextToClient(string text, uint clientIndex) + { + try + { + byte[] b = Encoding.GetEncoding(28591).GetBytes(text); + if (SecureServer != null && SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) { - Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) + SecureServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); } } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(uint clientIndex, string received) + catch (Exception ex) { - try + Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); + } + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(uint clientIndex, string received) + { + try + { + if (HeartbeatRequired) { - if (HeartbeatRequired) + if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) { - if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) - { - var remainingText = received.Replace(HeartbeatStringToMatch, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatStringToMatch)) - { - if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) - HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); - else - { - CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); - HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); - } - Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); - // Return Heartbeat - SendTextToClient(HeartbeatStringToMatch, clientIndex); - return remainingText; - } - } - else + var remainingText = received.Replace(HeartbeatStringToMatch, ""); + var noDelimiter = received.Trim(new char[] { '\r', '\n' }); + if (noDelimiter.Contains(HeartbeatStringToMatch)) { if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); @@ -618,179 +603,194 @@ namespace PepperDash.Core CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); } - Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", received, clientIndex); + Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); + // Return Heartbeat + SendTextToClient(HeartbeatStringToMatch, clientIndex); + return remainingText; } } - } - catch (Exception ex) - { - Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); - } - return received; - } - - /// - /// Get the IP Address for the client at the specifed index - /// - /// - /// - public string GetClientIPAddress(uint clientIndex) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress Index: {0}", clientIndex); - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) - { - var ipa = this.SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress IPAddreess: {0}", ipa); - return ipa; - - } - else - { - return ""; + else + { + if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) + HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); + else + { + CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); + HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); + } + Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", received, clientIndex); + } } } - - #endregion - - #region Methods - HeartbeatTimer Callback - - void HeartbeatTimer_CallbackFunction(object o) + catch (Exception ex) { - uint clientIndex = 99999; - string address = string.Empty; - try + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); + } + return received; + } + + /// + /// Get the IP Address for the client at the specifed index + /// + /// + /// + public string GetClientIPAddress(uint clientIndex) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress Index: {0}", clientIndex); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) + { + var ipa = this.SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress IPAddreess: {0}", ipa); + return ipa; + + } + else + { + return ""; + } + } + + #endregion + + #region Methods - HeartbeatTimer Callback + + void HeartbeatTimer_CallbackFunction(object o) + { + uint clientIndex = 99999; + string address = string.Empty; + try + { + clientIndex = (uint)o; + address = SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); + + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Heartbeat not received for Client index {2} IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE {1}", + address, string.IsNullOrEmpty(HeartbeatStringToMatch) ? "" : ("HeartbeatStringToMatch: " + HeartbeatStringToMatch), clientIndex); + + if (SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) + SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); + + var discoResult = SecureServer.Disconnect(clientIndex); + //Debug.Console(1, this, "{0}", discoResult); + + if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) { - clientIndex = (uint)o; - address = SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); + HeartbeatTimerDictionary[clientIndex].Stop(); + HeartbeatTimerDictionary[clientIndex].Dispose(); + HeartbeatTimerDictionary.Remove(clientIndex); + } + } + catch (Exception ex) + { + ErrorLog.Error("{3}: Heartbeat timeout Error on Client Index: {0}, at address: {1}, error: {2}", clientIndex, address, ex.Message, Key); + } + } - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Heartbeat not received for Client index {2} IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE {1}", - address, string.IsNullOrEmpty(HeartbeatStringToMatch) ? "" : ("HeartbeatStringToMatch: " + HeartbeatStringToMatch), clientIndex); + #endregion - if (SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) - SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); + #region Methods - Socket Status Changed Callbacks + /// + /// Secure Server Socket Status Changed Callback + /// + /// + /// + /// + void SecureServer_SocketStatusChange(SecureTCPServer server, uint clientIndex, SocketStatus serverSocketStatus) + { + try + { + - var discoResult = SecureServer.Disconnect(clientIndex); - //Debug.Console(1, this, "{0}", discoResult); - - if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) + // Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange Index:{0} status:{1} Port:{2} IP:{3}", clientIndex, serverSocketStatus, this.SecureServer.GetPortNumberServerAcceptedConnectionFromForSpecificClient(clientIndex), this.SecureServer.GetLocalAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); + if (serverSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange ConnectedCLients: {0} ServerState: {1} Port: {2}", SecureServer.NumberOfClientsConnected, SecureServer.State, SecureServer.PortNumber); + + if (ConnectedClientsIndexes.Contains(clientIndex)) + ConnectedClientsIndexes.Remove(clientIndex); + if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary[clientIndex].Stop(); HeartbeatTimerDictionary[clientIndex].Dispose(); HeartbeatTimerDictionary.Remove(clientIndex); } - } - catch (Exception ex) - { - ErrorLog.Error("{3}: Heartbeat timeout Error on Client Index: {0}, at address: {1}, error: {2}", clientIndex, address, ex.Message, Key); - } - } - - #endregion - - #region Methods - Socket Status Changed Callbacks - /// - /// Secure Server Socket Status Changed Callback - /// - /// - /// - /// - void SecureServer_SocketStatusChange(SecureTCPServer server, uint clientIndex, SocketStatus serverSocketStatus) - { - try - { - - - // Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange Index:{0} status:{1} Port:{2} IP:{3}", clientIndex, serverSocketStatus, this.SecureServer.GetPortNumberServerAcceptedConnectionFromForSpecificClient(clientIndex), this.SecureServer.GetLocalAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); - if (serverSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange ConnectedCLients: {0} ServerState: {1} Port: {2}", SecureServer.NumberOfClientsConnected, SecureServer.State, SecureServer.PortNumber); - - if (ConnectedClientsIndexes.Contains(clientIndex)) - ConnectedClientsIndexes.Remove(clientIndex); - if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex)) - { - HeartbeatTimerDictionary[clientIndex].Stop(); - HeartbeatTimerDictionary[clientIndex].Dispose(); - HeartbeatTimerDictionary.Remove(clientIndex); - } - if (ClientReadyAfterKeyExchange.Contains(clientIndex)) - ClientReadyAfterKeyExchange.Remove(clientIndex); + if (ClientReadyAfterKeyExchange.Contains(clientIndex)) + ClientReadyAfterKeyExchange.Remove(clientIndex); if (WaitingForSharedKey.Contains(clientIndex)) WaitingForSharedKey.Remove(clientIndex); if (SecureServer.MaxNumberOfClientSupported > SecureServer.NumberOfClientsConnected) { Listen(); } - } } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); - } - //Use a thread for this event so that the server state updates to listening while this event is processed. Listening must be added to the server state - //after every client connection so that the server can check and see if it is at max clients. Due to this the event fires and server listening enum bit flag - //is not set. Putting in a thread allows the state to update before this event processes so that the subscribers to this event get accurate isListening in the event. - CrestronInvoke.BeginInvoke(o => onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)), null); } - - #endregion - - #region Methods Connected Callbacks - /// - /// Secure TCP Client Connected to Secure Server Callback - /// - /// - /// - void SecureConnectCallback(SecureTCPServer server, uint clientIndex) + catch (Exception ex) { - try + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); + } + //Use a thread for this event so that the server state updates to listening while this event is processed. Listening must be added to the server state + //after every client connection so that the server can check and see if it is at max clients. Due to this the event fires and server listening enum bit flag + //is not set. Putting in a thread allows the state to update before this event processes so that the subscribers to this event get accurate isListening in the event. + CrestronInvoke.BeginInvoke(o => onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)), null); + } + + #endregion + + #region Methods Connected Callbacks + /// + /// Secure TCP Client Connected to Secure Server Callback + /// + /// + /// + void SecureConnectCallback(SecureTCPServer server, uint clientIndex) + { + try + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectCallback: IPAddress: {0}. Index: {1}. Status: {2}", + server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), + clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); + if (clientIndex != 0) { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectCallback: IPAddress: {0}. Index: {1}. Status: {2}", - server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), - clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); - if (clientIndex != 0) + if (server.ClientConnected(clientIndex)) { - if (server.ClientConnected(clientIndex)) + + if (!ConnectedClientsIndexes.Contains(clientIndex)) { - - if (!ConnectedClientsIndexes.Contains(clientIndex)) - { - ConnectedClientsIndexes.Add(clientIndex); - } - if (SharedKeyRequired) - { - if (!WaitingForSharedKey.Contains(clientIndex)) - { - WaitingForSharedKey.Add(clientIndex); - } - byte[] b = Encoding.GetEncoding(28591).GetBytes("SharedKey:"); - server.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Sent Shared Key Request to client at {0}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); - } - else - { - OnServerClientReadyForCommunications(clientIndex); - } - if (HeartbeatRequired) - { - if (!HeartbeatTimerDictionary.ContainsKey(clientIndex)) - { - HeartbeatTimerDictionary.Add(clientIndex, new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs)); - } - } - - server.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback); + ConnectedClientsIndexes.Add(clientIndex); } - } - else - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); + if (SharedKeyRequired) + { + if (!WaitingForSharedKey.Contains(clientIndex)) + { + WaitingForSharedKey.Add(clientIndex); + } + byte[] b = Encoding.GetEncoding(28591).GetBytes("SharedKey:"); + server.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Sent Shared Key Request to client at {0}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); + } + else + { + OnServerClientReadyForCommunications(clientIndex); + } + if (HeartbeatRequired) + { + if (!HeartbeatTimerDictionary.ContainsKey(clientIndex)) + { + HeartbeatTimerDictionary.Add(clientIndex, new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs)); + } + } + + server.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback); } } - catch (Exception ex) + else { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); } + } + catch (Exception ex) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); + } // Rearm the listner SocketErrorCodes status = server.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback); @@ -806,279 +806,278 @@ namespace PepperDash.Core } } - #endregion + #endregion - #region Methods - Send/Receive Callbacks - /// - /// Secure Received Data Async Callback - /// - /// - /// - /// - void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived) + #region Methods - Send/Receive Callbacks + /// + /// Secure Received Data Async Callback + /// + /// + /// + /// + void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived) + { + if (numberOfBytesReceived > 0) { - if (numberOfBytesReceived > 0) - { - string received = "Nothing"; - var handler = TextReceivedQueueInvoke; - try + string received = "Nothing"; + var handler = TextReceivedQueueInvoke; + try + { + byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex); + received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived); + if (WaitingForSharedKey.Contains(clientIndex)) { - byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex); - received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived); - if (WaitingForSharedKey.Contains(clientIndex)) + received = received.Replace("\r", ""); + received = received.Replace("\n", ""); + if (received != SharedKey) { - received = received.Replace("\r", ""); - received = received.Replace("\n", ""); - if (received != SharedKey) - { - byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting"); - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Client at index {0} Shared key did not match the server, disconnecting client. Key: {1}", clientIndex, received); - mySecureTCPServer.SendData(clientIndex, b, b.Length); - mySecureTCPServer.Disconnect(clientIndex); - - return; - } + byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting"); + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Client at index {0} Shared key did not match the server, disconnecting client. Key: {1}", clientIndex, received); + mySecureTCPServer.SendData(clientIndex, b, b.Length); + mySecureTCPServer.Disconnect(clientIndex); + + return; + } - WaitingForSharedKey.Remove(clientIndex); - byte[] success = Encoding.GetEncoding(28591).GetBytes("Shared Key Match"); - mySecureTCPServer.SendDataAsync(clientIndex, success, success.Length, null); - OnServerClientReadyForCommunications(clientIndex); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Client with index {0} provided the shared key and successfully connected to the server", clientIndex); - } - else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) - { - onTextReceived(received, clientIndex); - if (handler != null) - { - MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(received, clientIndex)); - } - } + WaitingForSharedKey.Remove(clientIndex); + byte[] success = Encoding.GetEncoding(28591).GetBytes("Shared Key Match"); + mySecureTCPServer.SendDataAsync(clientIndex, success, success.Length, null); + OnServerClientReadyForCommunications(clientIndex); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Client with index {0} provided the shared key and successfully connected to the server", clientIndex); } - catch (Exception ex) + else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Receiving data: {0}. Error: {1}", received, ex); + onTextReceived(received, clientIndex); + if (handler != null) + { + MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(received, clientIndex)); + } } + } + catch (Exception ex) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Receiving data: {0}. Error: {1}", received, ex); + } if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback); - //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. - if (handler != null) - { - var gotLock = DequeueLock.TryEnter(); - if (gotLock) - CrestronInvoke.BeginInvoke((o) => DequeueEvent()); - } + //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. + if (handler != null) + { + var gotLock = DequeueLock.TryEnter(); + if (gotLock) + CrestronInvoke.BeginInvoke((o) => DequeueEvent()); } + } else { mySecureTCPServer.Disconnect(clientIndex); - } } + } - /// - /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. - /// It will dequeue items as they are enqueued automatically. - /// - void DequeueEvent() + /// + /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. + /// It will dequeue items as they are enqueued automatically. + /// + void DequeueEvent() + { + try { - try + while (true) { - while (true) - { - // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. - var message = MessageQueue.Dequeue(); - var handler = TextReceivedQueueInvoke; - if (handler != null) - { - handler(this, message); - } - } - } - catch (Exception e) - { - this.LogException(e, "DequeueEvent error"); - } - // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. - if (DequeueLock != null) - { - DequeueLock.Leave(); - } - } - - #endregion - - #region Methods - EventHelpers/Callbacks - - //Private Helper method to call the Connection Change Event - void onConnectionChange(uint clientIndex, SocketStatus clientStatus) - { - if (clientIndex != 0) //0 is error not valid client change - { - var handler = ClientConnectionChange; + // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. + var message = MessageQueue.Dequeue(); + var handler = TextReceivedQueueInvoke; if (handler != null) { - handler(this, new GenericTcpServerSocketStatusChangeEventArgs(SecureServer, clientIndex, clientStatus)); + handler(this, message); } } } - - //Private Helper method to call the Connection Change Event - void OnConnectionChange() + catch (Exception e) + { + this.LogException(e, "DequeueEvent error"); + } + // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. + if (DequeueLock != null) + { + DequeueLock.Leave(); + } + } + + #endregion + + #region Methods - EventHelpers/Callbacks + + //Private Helper method to call the Connection Change Event + void onConnectionChange(uint clientIndex, SocketStatus clientStatus) + { + if (clientIndex != 0) //0 is error not valid client change { - if (ProgramIsStopping) - { - return; - } var handler = ClientConnectionChange; if (handler != null) { - handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); + handler(this, new GenericTcpServerSocketStatusChangeEventArgs(SecureServer, clientIndex, clientStatus)); } } + } - //Private Helper Method to call the Text Received Event - void onTextReceived(string text, uint clientIndex) + //Private Helper method to call the Connection Change Event + void OnConnectionChange() + { + if (ProgramIsStopping) { - var handler = TextReceived; - if (handler != null) - handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); + return; } - - //Private Helper Method to call the Server State Change Event - void OnServerStateChange(ServerState state) + var handler = ClientConnectionChange; + if (handler != null) { - if (ProgramIsStopping) - { - return; - } - var handler = ServerStateChange; - if (handler != null) - { - handler(this, new GenericTcpServerStateChangedEventArgs(state)); - } + handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); } + } - /// - /// Private Event Handler method to handle the closing of connections when the program stops - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + //Private Helper Method to call the Text Received Event + void onTextReceived(string text, uint clientIndex) + { + var handler = TextReceived; + if (handler != null) + handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); + } + + //Private Helper Method to call the Server State Change Event + void OnServerStateChange(ServerState state) + { + if (ProgramIsStopping) { - if (programEventType == eProgramStatusEventType.Stopping) - { - ProgramIsStopping = true; - // kill bandaid things - if (MonitorClientTimer != null) - MonitorClientTimer.Stop(); - if (MonitorClient != null) - MonitorClient.Disconnect(); - - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing server"); - KillServer(); - } + return; } - - //Private event handler method to raise the event that the server is ready to send data after a successful client shared key negotiation - void OnServerClientReadyForCommunications(uint clientIndex) + var handler = ServerStateChange; + if (handler != null) { - ClientReadyAfterKeyExchange.Add(clientIndex); - var handler = ServerClientReadyForCommunications; - if (handler != null) - handler(this, new GenericTcpServerSocketStatusChangeEventArgs( - this, clientIndex, SecureServer.GetServerSocketStatusForSpecificClient(clientIndex))); + handler(this, new GenericTcpServerStateChangedEventArgs(state)); } - #endregion + } - #region Monitor Client - /// - /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient - /// - void StartMonitorClient() + /// + /// Private Event Handler method to handle the closing of connections when the program stops + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) { + ProgramIsStopping = true; + // kill bandaid things if (MonitorClientTimer != null) - { - return; - } - MonitorClientTimer = new CTimer(o => RunMonitorClient(), 60000); - } - - /// - /// - /// - void RunMonitorClient() - { - MonitorClient = new GenericSecureTcpIpClient_ForServer(Key + "-MONITOR", "127.0.0.1", Port, 2000); - MonitorClient.SharedKeyRequired = this.SharedKeyRequired; - MonitorClient.SharedKey = this.SharedKey; - MonitorClient.ConnectionHasHungCallback = MonitorClientHasHungCallback; - //MonitorClient.ConnectionChange += MonitorClient_ConnectionChange; - MonitorClient.ClientReadyForCommunications += MonitorClient_IsReadyForComm; - - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Starting monitor check"); - - MonitorClient.Connect(); - // From here MonitorCLient either connects or hangs, MonitorClient will call back - - } - - /// - /// - /// - void StopMonitorClient() - { - if (MonitorClient == null) - return; - - MonitorClient.ClientReadyForCommunications -= MonitorClient_IsReadyForComm; - MonitorClient.Disconnect(); - MonitorClient = null; - } - - /// - /// On monitor connect, restart the operation - /// - void MonitorClient_IsReadyForComm(object sender, GenericTcpServerClientReadyForcommunicationsEventArgs args) - { - if (args.IsReady) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Monitor client connection success. Disconnecting in 2s"); MonitorClientTimer.Stop(); - MonitorClientTimer = null; - MonitorClientFailureCount = 0; - CrestronEnvironment.Sleep(2000); - StopMonitorClient(); - StartMonitorClient(); - } - } + if (MonitorClient != null) + MonitorClient.Disconnect(); - /// - /// If the client hangs, add to counter and maybe fire the choke event - /// - void MonitorClientHasHungCallback() + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing server"); + KillServer(); + } + } + + //Private event handler method to raise the event that the server is ready to send data after a successful client shared key negotiation + void OnServerClientReadyForCommunications(uint clientIndex) + { + ClientReadyAfterKeyExchange.Add(clientIndex); + var handler = ServerClientReadyForCommunications; + if (handler != null) + handler(this, new GenericTcpServerSocketStatusChangeEventArgs( + this, clientIndex, SecureServer.GetServerSocketStatusForSpecificClient(clientIndex))); + } + #endregion + + #region Monitor Client + /// + /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient + /// + void StartMonitorClient() + { + if (MonitorClientTimer != null) { - MonitorClientFailureCount++; + return; + } + MonitorClientTimer = new CTimer(o => RunMonitorClient(), 60000); + } + + /// + /// + /// + void RunMonitorClient() + { + MonitorClient = new GenericSecureTcpIpClient_ForServer(Key + "-MONITOR", "127.0.0.1", Port, 2000); + MonitorClient.SharedKeyRequired = this.SharedKeyRequired; + MonitorClient.SharedKey = this.SharedKey; + MonitorClient.ConnectionHasHungCallback = MonitorClientHasHungCallback; + //MonitorClient.ConnectionChange += MonitorClient_ConnectionChange; + MonitorClient.ClientReadyForCommunications += MonitorClient_IsReadyForComm; + + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Starting monitor check"); + + MonitorClient.Connect(); + // From here MonitorCLient either connects or hangs, MonitorClient will call back + + } + + /// + /// + /// + void StopMonitorClient() + { + if (MonitorClient == null) + return; + + MonitorClient.ClientReadyForCommunications -= MonitorClient_IsReadyForComm; + MonitorClient.Disconnect(); + MonitorClient = null; + } + + /// + /// On monitor connect, restart the operation + /// + void MonitorClient_IsReadyForComm(object sender, GenericTcpServerClientReadyForcommunicationsEventArgs args) + { + if (args.IsReady) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Monitor client connection success. Disconnecting in 2s"); MonitorClientTimer.Stop(); MonitorClientTimer = null; + MonitorClientFailureCount = 0; + CrestronEnvironment.Sleep(2000); StopMonitorClient(); - if (MonitorClientFailureCount < MonitorClientMaxFailureCount) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Warning, "Monitor client connection has hung {0} time{1}, maximum {2}", - MonitorClientFailureCount, MonitorClientFailureCount > 1 ? "s" : "", MonitorClientMaxFailureCount); - StartMonitorClient(); - } - else - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, - "\r***************************\rMonitor client connection has hung a maximum of {0} times. \r***************************", - MonitorClientMaxFailureCount); - - var handler = ServerHasChoked; - if (handler != null) - handler(); - // Some external thing is in charge here. Expected reset of program - } + StartMonitorClient(); } - #endregion } + + /// + /// If the client hangs, add to counter and maybe fire the choke event + /// + void MonitorClientHasHungCallback() + { + MonitorClientFailureCount++; + MonitorClientTimer.Stop(); + MonitorClientTimer = null; + StopMonitorClient(); + if (MonitorClientFailureCount < MonitorClientMaxFailureCount) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Warning, "Monitor client connection has hung {0} time{1}, maximum {2}", + MonitorClientFailureCount, MonitorClientFailureCount > 1 ? "s" : "", MonitorClientMaxFailureCount); + StartMonitorClient(); + } + else + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, + "\r***************************\rMonitor client connection has hung a maximum of {0} times. \r***************************", + MonitorClientMaxFailureCount); + + var handler = ServerHasChoked; + if (handler != null) + handler(); + // Some external thing is in charge here. Expected reset of program + } + } + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericSshClient.cs b/src/PepperDash.Core/Comm/GenericSshClient.cs index fa5b95bb..2030c5f9 100644 --- a/src/PepperDash.Core/Comm/GenericSshClient.cs +++ b/src/PepperDash.Core/Comm/GenericSshClient.cs @@ -8,145 +8,145 @@ using PepperDash.Core.Logging; using Renci.SshNet; using Renci.SshNet.Common; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// +/// +public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect { + private const string SPlusKey = "Uninitialized SshClient"; + /// + /// Object to enable stream debugging + /// + public CommunicationStreamDebugging StreamDebugging { get; private set; } + + /// + /// Event that fires when data is received. Delivers args with byte array + /// + public event EventHandler BytesReceived; + + /// + /// Event that fires when data is received. Delivered as text. + /// + public event EventHandler TextReceived; + + /// + /// Event when the connection status changes. + /// + public event EventHandler ConnectionChange; + + ///// + ///// + ///// + //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; + + /// + /// Address of server + /// + public string Hostname { get; set; } + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// Username for server + /// + public string Username { get; set; } + + /// + /// And... Password for server. That was worth documenting! + /// + public string Password { get; set; } + + /// + /// True when the server is connected - when status == 2. + /// + public bool IsConnected + { + // returns false if no client or not connected + get { return Client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + /// /// /// - public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect + public SocketStatus ClientStatus { - private const string SPlusKey = "Uninitialized SshClient"; - /// - /// Object to enable stream debugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } - - /// - /// Event that fires when data is received. Delivers args with byte array - /// - public event EventHandler BytesReceived; - - /// - /// Event that fires when data is received. Delivered as text. - /// - public event EventHandler TextReceived; - - /// - /// Event when the connection status changes. - /// - public event EventHandler ConnectionChange; - - ///// - ///// - ///// - //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; - - /// - /// Address of server - /// - public string Hostname { get; set; } - - /// - /// Port on server - /// - public int Port { get; set; } - - /// - /// Username for server - /// - public string Username { get; set; } - - /// - /// And... Password for server. That was worth documenting! - /// - public string Password { get; set; } - - /// - /// True when the server is connected - when status == 2. - /// - public bool IsConnected + get { return _ClientStatus; } + private set { - // returns false if no client or not connected - get { return Client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + if (_ClientStatus == value) + return; + _ClientStatus = value; + OnConnectionChange(); } + } + SocketStatus _ClientStatus; - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected - { - get { return (ushort)(IsConnected ? 1 : 0); } - } + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected with be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)_ClientStatus; } + } - /// - /// - /// - public SocketStatus ClientStatus - { - get { return _ClientStatus; } - private set - { - if (_ClientStatus == value) - return; - _ClientStatus = value; - OnConnectionChange(); - } - } - SocketStatus _ClientStatus; + /// + /// Determines whether client will attempt reconnection on failure. Default is true + /// + public bool AutoReconnect { get; set; } - /// - /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event - /// and IsConnected with be true when this == 2. - /// - public ushort UStatus - { - get { return (ushort)_ClientStatus; } - } + /// + /// Will be set and unset by connect and disconnect only + /// + public bool ConnectEnabled { get; private set; } - /// - /// Determines whether client will attempt reconnection on failure. Default is true - /// - public bool AutoReconnect { get; set; } + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } - /// - /// Will be set and unset by connect and disconnect only - /// - public bool ConnectEnabled { get; private set; } + /// + /// Millisecond value, determines the timeout period in between reconnect attempts. + /// Set to 5000 by default + /// + public int AutoReconnectIntervalMs { get; set; } - /// - /// S+ helper for AutoReconnect - /// - public ushort UAutoReconnect - { - get { return (ushort)(AutoReconnect ? 1 : 0); } - set { AutoReconnect = value == 1; } - } + SshClient Client; - /// - /// Millisecond value, determines the timeout period in between reconnect attempts. - /// Set to 5000 by default - /// - public int AutoReconnectIntervalMs { get; set; } + ShellStream TheStream; - SshClient Client; + CTimer ReconnectTimer; - ShellStream TheStream; + //Lock object to prevent simulatneous connect/disconnect operations + //private CCriticalSection connectLock = new CCriticalSection(); + private SemaphoreSlim connectLock = new SemaphoreSlim(1); - CTimer ReconnectTimer; + private bool DisconnectLogged = false; - //Lock object to prevent simulatneous connect/disconnect operations - //private CCriticalSection connectLock = new CCriticalSection(); - private SemaphoreSlim connectLock = new SemaphoreSlim(1); - - private bool DisconnectLogged = false; - - /// - /// Typical constructor. - /// - public GenericSshClient(string key, string hostname, int port, string username, string password) : - base(key) - { - StreamDebugging = new CommunicationStreamDebugging(key); + /// + /// Typical constructor. + /// + public GenericSshClient(string key, string hostname, int port, string username, string password) : + base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); Key = key; Hostname = hostname; @@ -155,12 +155,12 @@ namespace PepperDash.Core Password = password; AutoReconnectIntervalMs = 5000; - ReconnectTimer = new CTimer(o => + ReconnectTimer = new CTimer(o => { - if (ConnectEnabled) - { - Connect(); - } + if (ConnectEnabled) + { + Connect(); + } }, System.Threading.Timeout.Infinite); } @@ -173,13 +173,13 @@ namespace PepperDash.Core CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; - ReconnectTimer = new CTimer(o => + ReconnectTimer = new CTimer(o => + { + if (ConnectEnabled) { - if (ConnectEnabled) - { - Connect(); - } - }, System.Threading.Timeout.Infinite); + Connect(); + } + }, System.Threading.Timeout.Infinite); } /// @@ -192,137 +192,137 @@ namespace PepperDash.Core if (Client != null) { this.LogDebug("Program stopping. Closing connection"); - Disconnect(); - } + Disconnect(); } } + } - /// - /// Connect to the server, using the provided properties. - /// - public void Connect() + /// + /// Connect to the server, using the provided properties. + /// + public void Connect() + { + // Don't go unless everything is here + if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535 + || Username == null || Password == null) { - // Don't go unless everything is here - if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535 - || Username == null || Password == null) + this.LogError("Connect failed. Check hostname, port, username and password are set or not null"); + return; + } + + ConnectEnabled = true; + + try + { + connectLock.Wait(); + if (IsConnected) { - this.LogError("Connect failed. Check hostname, port, username and password are set or not null"); - return; + this.LogDebug("Connection already connected. Exiting Connect"); } - - ConnectEnabled = true; - - try + else { - connectLock.Wait(); - if (IsConnected) - { - this.LogDebug("Connection already connected. Exiting Connect"); - } - else - { - this.LogDebug("Attempting connect"); + this.LogDebug("Attempting connect"); - // Cancel reconnect if running. + // Cancel reconnect if running. if (ReconnectTimer != null) { ReconnectTimer.Stop(); } - // Cleanup the old client if it already exists - if (Client != null) + // Cleanup the old client if it already exists + if (Client != null) + { + this.LogDebug("Cleaning up disconnected client"); + KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); + } + + // This handles both password and keyboard-interactive (like on OS-X, 'nixes) + KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(Username); + kauth.AuthenticationPrompt += new EventHandler(kauth_AuthenticationPrompt); + PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password); + + this.LogDebug("Creating new SshClient"); + ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); + Client = new SshClient(connectionInfo); + Client.ErrorOccurred += Client_ErrorOccurred; + + //Attempt to connect + ClientStatus = SocketStatus.SOCKET_STATUS_WAITING; + try + { + Client.Connect(); + TheStream = Client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534); + if (TheStream.DataAvailable) { - this.LogDebug("Cleaning up disconnected client"); - KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); + // empty the buffer if there is data + string str = TheStream.Read(); + } + TheStream.DataReceived += Stream_DataReceived; + this.LogInformation("Connected"); + ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; + DisconnectLogged = false; + } + catch (SshConnectionException e) + { + var ie = e.InnerException; // The details are inside!! + var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; + + if (ie is SocketException) + { + this.LogException(ie, "CONNECTION failure: Cannot reach host"); } - // This handles both password and keyboard-interactive (like on OS-X, 'nixes) - KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(Username); - kauth.AuthenticationPrompt += new EventHandler(kauth_AuthenticationPrompt); - PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password); - - this.LogDebug("Creating new SshClient"); - ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); - Client = new SshClient(connectionInfo); - Client.ErrorOccurred += Client_ErrorOccurred; - - //Attempt to connect - ClientStatus = SocketStatus.SOCKET_STATUS_WAITING; - try + if (ie is System.Net.Sockets.SocketException socketException) { - Client.Connect(); - TheStream = Client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534); - if (TheStream.DataAvailable) - { - // empty the buffer if there is data - string str = TheStream.Read(); - } - TheStream.DataReceived += Stream_DataReceived; - this.LogInformation("Connected"); - ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; - DisconnectLogged = false; + this.LogException(ie, "Connection failure: Cannot reach {host} on {port}", + Hostname, Port); } - catch (SshConnectionException e) + if (ie is SshAuthenticationException) { - var ie = e.InnerException; // The details are inside!! - var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; - - if (ie is SocketException) - { - this.LogException(ie, "CONNECTION failure: Cannot reach host"); - } - - if (ie is System.Net.Sockets.SocketException socketException) - { - this.LogException(ie, "Connection failure: Cannot reach {host} on {port}", - Hostname, Port); - } - if (ie is SshAuthenticationException) - { - this.LogException(ie, "Authentication failure for username {userName}", Username); - } - else - this.LogException(ie, "Error on connect"); - - DisconnectLogged = true; - KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect) - { - this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs); - ReconnectTimer.Reset(AutoReconnectIntervalMs); - } + this.LogException(ie, "Authentication failure for username {userName}", Username); } - catch(SshOperationTimeoutException ex) - { - this.LogWarning("Connection attempt timed out: {message}", ex.Message); + else + this.LogException(ie, "Error on connect"); - DisconnectLogged = true; - KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect) - { - this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); - ReconnectTimer.Reset(AutoReconnectIntervalMs); - } - } - catch (Exception e) + DisconnectLogged = true; + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + if (AutoReconnect) { - var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; - this.LogException(e, "Unhandled exception on connect"); - DisconnectLogged = true; - KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect) - { - this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); - ReconnectTimer.Reset(AutoReconnectIntervalMs); - } + this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } + } + catch(SshOperationTimeoutException ex) + { + this.LogWarning("Connection attempt timed out: {message}", ex.Message); + + DisconnectLogged = true; + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + if (AutoReconnect) + { + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } + } + catch (Exception e) + { + var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; + this.LogException(e, "Unhandled exception on connect"); + DisconnectLogged = true; + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + if (AutoReconnect) + { + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); } } } - finally - { - connectLock.Release(); - } } + finally + { + connectLock.Release(); + } + } /// /// Disconnect the clients and put away it's resources. @@ -337,54 +337,54 @@ namespace PepperDash.Core // ReconnectTimer = null; } - KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); - } + KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); + } - /// - /// Kills the stream, cleans up the client and sets it to null - /// - private void KillClient(SocketStatus status) + /// + /// Kills the stream, cleans up the client and sets it to null + /// + private void KillClient(SocketStatus status) + { + KillStream(); + + try { - KillStream(); - - try + if (Client != null) { - if (Client != null) - { - Client.ErrorOccurred -= Client_ErrorOccurred; - Client.Disconnect(); - Client.Dispose(); - Client = null; - ClientStatus = status; - this.LogDebug("Disconnected"); - } - } - catch (Exception ex) - { - this.LogException(ex,"Exception in Kill Client"); + Client.ErrorOccurred -= Client_ErrorOccurred; + Client.Disconnect(); + Client.Dispose(); + Client = null; + ClientStatus = status; + this.LogDebug("Disconnected"); } } + catch (Exception ex) + { + this.LogException(ex,"Exception in Kill Client"); + } + } - /// - /// Kills the stream - /// + /// + /// Kills the stream + /// void KillStream() { - try + try + { + if (TheStream != null) { - if (TheStream != null) - { - TheStream.DataReceived -= Stream_DataReceived; - TheStream.Close(); - TheStream.Dispose(); - TheStream = null; - this.LogDebug("Disconnected stream"); - } - } - catch (Exception ex) - { - this.LogException(ex, "Exception in Kill Stream:{0}"); + TheStream.DataReceived -= Stream_DataReceived; + TheStream.Close(); + TheStream.Dispose(); + TheStream = null; + this.LogDebug("Disconnected stream"); } + } + catch (Exception ex) + { + this.LogException(ex, "Exception in Kill Stream:{0}"); + } } /// @@ -402,32 +402,32 @@ namespace PepperDash.Core /// void Stream_DataReceived(object sender, ShellDataEventArgs e) { - if (((ShellStream)sender).Length <= 0L) - { - return; - } - var response = ((ShellStream)sender).Read(); - + if (((ShellStream)sender).Length <= 0L) + { + return; + } + var response = ((ShellStream)sender).Read(); + var bytesHandler = BytesReceived; - + if (bytesHandler != null) { - var bytes = Encoding.UTF8.GetBytes(response); + var bytes = Encoding.UTF8.GetBytes(response); if (StreamDebugging.RxStreamDebuggingIsEnabled) { this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); } - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response)); + if (StreamDebugging.RxStreamDebuggingIsEnabled) + this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response)); - textHandler(this, new GenericCommMethodReceiveTextArgs(response)); - } + textHandler(this, new GenericCommMethodReceiveTextArgs(response)); + } } @@ -438,39 +438,39 @@ namespace PepperDash.Core /// void Client_ErrorOccurred(object sender, ExceptionEventArgs e) { - CrestronInvoke.BeginInvoke(o => - { - if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException) - this.LogError("Disconnected by remote"); - else - this.LogException(e.Exception, "Unhandled SSH client error"); - try - { - connectLock.Wait(); - KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY); - } - finally - { - connectLock.Release(); - } - if (AutoReconnect && ConnectEnabled) - { - this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); - ReconnectTimer.Reset(AutoReconnectIntervalMs); - } - }); - } - - /// - /// Helper for ConnectionChange event - /// - void OnConnectionChange() + CrestronInvoke.BeginInvoke(o => { - if (ConnectionChange != null) - ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); - } + if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException) + this.LogError("Disconnected by remote"); + else + this.LogException(e.Exception, "Unhandled SSH client error"); + try + { + connectLock.Wait(); + KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY); + } + finally + { + connectLock.Release(); + } + if (AutoReconnect && ConnectEnabled) + { + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } + }); + } - #region IBasicCommunication Members + /// + /// Helper for ConnectionChange event + /// + void OnConnectionChange() + { + if (ConnectionChange != null) + ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); + } + + #region IBasicCommunication Members /// /// Sends text to the server @@ -497,52 +497,52 @@ namespace PepperDash.Core } } catch (ObjectDisposedException) - { - this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim()); + { + this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim()); - KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - ReconnectTimer.Reset(); + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + ReconnectTimer.Reset(); } catch (Exception ex) { - this.LogException(ex, "Exception sending text: '{message}'", text); + this.LogException(ex, "Exception sending text: '{message}'", text); } } - /// - /// Sends Bytes to the server - /// - /// + /// + /// Sends Bytes to the server + /// + /// public void SendBytes(byte[] bytes) { - try + try + { + if (Client != null && TheStream != null && IsConnected) { - if (Client != null && TheStream != null && IsConnected) - { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + if (StreamDebugging.TxStreamDebuggingIsEnabled) + this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); - TheStream.Write(bytes, 0, bytes.Length); - TheStream.Flush(); - } - else - { - this.LogDebug("Client is null or disconnected. Cannot Send Bytes"); - } + TheStream.Write(bytes, 0, bytes.Length); + TheStream.Flush(); } - catch (ObjectDisposedException ex) + else { - this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes)); + this.LogDebug("Client is null or disconnected. Cannot Send Bytes"); + } + } + catch (ObjectDisposedException ex) + { + this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes)); - KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - ReconnectTimer.Reset(); - } - catch (Exception ex) - { - this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes)); - } + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + ReconnectTimer.Reset(); + } + catch (Exception ex) + { + this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes)); + } } - #endregion +#endregion } @@ -553,40 +553,39 @@ namespace PepperDash.Core /// public class SshConnectionChangeEventArgs : EventArgs { - /// - /// Connection State - /// + /// + /// Connection State + /// public bool IsConnected { get; private set; } - /// - /// Connection Status represented as a ushort - /// + /// + /// Connection Status represented as a ushort + /// public ushort UIsConnected { get { return (ushort)(Client.IsConnected ? 1 : 0); } } - /// - /// The client - /// + /// + /// The client + /// public GenericSshClient Client { get; private set; } - /// - /// Socket Status as represented by - /// + /// + /// Socket Status as represented by + /// public ushort Status { get { return Client.UStatus; } } - /// - /// S+ Constructor - /// - public SshConnectionChangeEventArgs() { } + /// + /// S+ Constructor + /// + public SshConnectionChangeEventArgs() { } - /// - /// EventArgs class - /// - /// Connection State - /// The Client + /// + /// EventArgs class + /// + /// Connection State + /// The Client public SshConnectionChangeEventArgs(bool isConnected, GenericSshClient client) - { - IsConnected = isConnected; - Client = client; - } + { + IsConnected = isConnected; + Client = client; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericTcpIpClient.cs b/src/PepperDash.Core/Comm/GenericTcpIpClient.cs index 9529aa29..ee0df8de 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpClient.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpClient.cs @@ -6,18 +6,18 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using Newtonsoft.Json; -namespace PepperDash.Core -{ - /// - /// A class to handle basic TCP/IP communications with a server - /// +namespace PepperDash.Core; + +/// +/// A class to handle basic TCP/IP communications with a server +/// public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect - { - private const string SplusKey = "Uninitialized TcpIpClient"; - /// - /// Object to enable stream debugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } +{ + private const string SplusKey = "Uninitialized TcpIpClient"; + /// + /// Object to enable stream debugging + /// + public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Fires when data is received from the server and returns it as a Byte array @@ -38,11 +38,11 @@ namespace PepperDash.Core private string _hostname; - /// - /// Address of server - /// - public string Hostname - { + /// + /// Address of server + /// + public string Hostname + { get { return _hostname; @@ -58,25 +58,25 @@ namespace PepperDash.Core } } - /// - /// Port on server - /// - public int Port { get; set; } + /// + /// Port on server + /// + public int Port { get; set; } - /// - /// Another damn S+ helper because S+ seems to treat large port nums as signed ints - /// which screws up things - /// - public ushort UPort - { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } - } + /// + /// Another damn S+ helper because S+ seems to treat large port nums as signed ints + /// which screws up things + /// + public ushort UPort + { + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } /// /// The actual client class @@ -87,47 +87,47 @@ namespace PepperDash.Core /// Bool showing if socket is connected /// public bool IsConnected - { - get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } - } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected - { - get { return (ushort)(IsConnected ? 1 : 0); } - } + { + get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } /// /// _client socket status Read only /// public SocketStatus ClientStatus - { - get - { - return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; - } - } - - /// - /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event - /// and IsConnected would be true when this == 2. - /// - public ushort UStatus + { + get { - get { return (ushort)ClientStatus; } - } + return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; + } + } + + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected would be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)ClientStatus; } + } /// - /// Status text shows the message associated with socket status + /// Status text shows the message associated with socket status /// public string ClientStatusText { get { return ClientStatus.ToString(); } } /// /// Ushort representation of client status /// - [Obsolete] + [Obsolete] public ushort UClientStatus { get { return (ushort)ClientStatus; } } /// @@ -140,14 +140,14 @@ namespace PepperDash.Core /// public bool AutoReconnect { get; set; } - /// - /// S+ helper for AutoReconnect - /// - public ushort UAutoReconnect - { - get { return (ushort)(AutoReconnect ? 1 : 0); } - set { AutoReconnect = value == 1; } - } + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } /// /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 @@ -167,283 +167,283 @@ namespace PepperDash.Core get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } - //Lock object to prevent simulatneous connect/disconnect operations - private CCriticalSection connectLock = new CCriticalSection(); + //Lock object to prevent simulatneous connect/disconnect operations + private CCriticalSection connectLock = new CCriticalSection(); - // private Timer for auto reconnect + // private Timer for auto reconnect private CTimer RetryTimer; - /// - /// Constructor - /// - /// unique string to differentiate between instances - /// - /// - /// + /// + /// Constructor + /// + /// unique string to differentiate between instances + /// + /// + /// public GenericTcpIpClient(string key, string address, int port, int bufferSize) : base(key) { - StreamDebugging = new CommunicationStreamDebugging(key); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - Hostname = address; - Port = port; - BufferSize = bufferSize; + StreamDebugging = new CommunicationStreamDebugging(key); + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + Hostname = address; + Port = port; + BufferSize = bufferSize; - RetryTimer = new CTimer(o => - { - Reconnect(); - }, Timeout.Infinite); - } - - /// - /// Constructor - /// - /// - public GenericTcpIpClient(string key) - : base(key) + RetryTimer = new CTimer(o => { - StreamDebugging = new CommunicationStreamDebugging(key); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; + Reconnect(); + }, Timeout.Infinite); + } - RetryTimer = new CTimer(o => - { - Reconnect(); - }, Timeout.Infinite); - } + /// + /// Constructor + /// + /// + public GenericTcpIpClient(string key) + : base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + BufferSize = 2000; - /// - /// Default constructor for S+ - /// - public GenericTcpIpClient() + RetryTimer = new CTimer(o => + { + Reconnect(); + }, Timeout.Infinite); + } + + /// + /// Default constructor for S+ + /// + public GenericTcpIpClient() : base(SplusKey) - { - StreamDebugging = new CommunicationStreamDebugging(SplusKey); + { + StreamDebugging = new CommunicationStreamDebugging(SplusKey); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; - BufferSize = 2000; + BufferSize = 2000; - RetryTimer = new CTimer(o => - { - Reconnect(); - }, Timeout.Infinite); + RetryTimer = new CTimer(o => + { + Reconnect(); + }, Timeout.Infinite); } - /// - /// Just to help S+ set the key - /// - public void Initialize(string key) - { - Key = key; - } + /// + /// Just to help S+ set the key + /// + public void Initialize(string key) + { + Key = key; + } - /// - /// Handles closing this up when the program shuts down - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) { - if (programEventType == eProgramStatusEventType.Stopping) - { - Debug.Console(1, this, "Program stopping. Closing connection"); - Deactivate(); - } + Debug.Console(1, this, "Program stopping. Closing connection"); + Deactivate(); } + } - /// - /// - /// - /// + /// + /// + /// + /// public override bool Deactivate() { - RetryTimer.Stop(); - RetryTimer.Dispose(); - if (_client != null) - { - _client.SocketStatusChange -= this.Client_SocketStatusChange; - DisconnectClient(); - } + RetryTimer.Stop(); + RetryTimer.Dispose(); + if (_client != null) + { + _client.SocketStatusChange -= this.Client_SocketStatusChange; + DisconnectClient(); + } return true; } - /// - /// Attempts to connect to the server - /// + /// + /// Attempts to connect to the server + /// public void Connect() { - if (string.IsNullOrEmpty(Hostname)) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key); - return; - } - if (Port < 1 || Port > 65535) - { - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': Invalid port", Key); - return; - } - } - - try - { - connectLock.Enter(); - if (IsConnected) - { - Debug.Console(1, this, "Connection already connected. Exiting Connect()"); - } - else - { - //Stop retry timer if running - RetryTimer.Stop(); - _client = new TCPClient(Hostname, Port, BufferSize); - _client.SocketStatusChange -= Client_SocketStatusChange; - _client.SocketStatusChange += Client_SocketStatusChange; - DisconnectCalledByUser = false; - _client.ConnectToServerAsync(ConnectToServerCallback); - } - } - finally - { - connectLock.Leave(); - } - } - - private void Reconnect() + if (string.IsNullOrEmpty(Hostname)) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key); + return; + } + if (Port < 1 || Port > 65535) { - if (_client == null) { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': Invalid port", Key); return; } - try - { - connectLock.Enter(); - if (IsConnected || DisconnectCalledByUser == true) - { - Debug.Console(1, this, "Reconnect no longer needed. Exiting Reconnect()"); - } - else - { - Debug.Console(1, this, "Attempting reconnect now"); - _client.ConnectToServerAsync(ConnectToServerCallback); - } - } - finally - { - connectLock.Leave(); - } } - /// - /// Attempts to disconnect the client - /// - public void Disconnect() - { - try - { - connectLock.Enter(); - DisconnectCalledByUser = true; - - // Stop trying reconnects, if we are - RetryTimer.Stop(); - DisconnectClient(); - } - finally - { - connectLock.Leave(); - } - } - - /// - /// Does the actual disconnect business - /// - public void DisconnectClient() + try { - if (_client != null) + connectLock.Enter(); + if (IsConnected) { - Debug.Console(1, this, "Disconnecting client"); - if (IsConnected) - _client.DisconnectFromServer(); - } - } - - /// - /// Callback method for connection attempt - /// - /// - void ConnectToServerCallback(TCPClient c) - { - if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - { - Debug.Console(0, this, "Server connection result: {0}", c.ClientStatus); - WaitAndTryReconnect(); + Debug.Console(1, this, "Connection already connected. Exiting Connect()"); } else { - Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus); + //Stop retry timer if running + RetryTimer.Stop(); + _client = new TCPClient(Hostname, Port, BufferSize); + _client.SocketStatusChange -= Client_SocketStatusChange; + _client.SocketStatusChange += Client_SocketStatusChange; + DisconnectCalledByUser = false; + _client.ConnectToServerAsync(ConnectToServerCallback); } + } + finally + { + connectLock.Leave(); + } } - /// - /// Disconnects, waits and attemtps to connect again - /// + private void Reconnect() + { + if (_client == null) + { + return; + } + try + { + connectLock.Enter(); + if (IsConnected || DisconnectCalledByUser == true) + { + Debug.Console(1, this, "Reconnect no longer needed. Exiting Reconnect()"); + } + else + { + Debug.Console(1, this, "Attempting reconnect now"); + _client.ConnectToServerAsync(ConnectToServerCallback); + } + } + finally + { + connectLock.Leave(); + } + } + + /// + /// Attempts to disconnect the client + /// + public void Disconnect() + { + try + { + connectLock.Enter(); + DisconnectCalledByUser = true; + + // Stop trying reconnects, if we are + RetryTimer.Stop(); + DisconnectClient(); + } + finally + { + connectLock.Leave(); + } + } + + /// + /// Does the actual disconnect business + /// + public void DisconnectClient() + { + if (_client != null) + { + Debug.Console(1, this, "Disconnecting client"); + if (IsConnected) + _client.DisconnectFromServer(); + } + } + + /// + /// Callback method for connection attempt + /// + /// + void ConnectToServerCallback(TCPClient c) + { + if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + Debug.Console(0, this, "Server connection result: {0}", c.ClientStatus); + WaitAndTryReconnect(); + } + else + { + Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus); + } + } + + /// + /// Disconnects, waits and attemtps to connect again + /// void WaitAndTryReconnect() { - CrestronInvoke.BeginInvoke(o => + CrestronInvoke.BeginInvoke(o => + { + try { - try + connectLock.Enter(); + if (!IsConnected && AutoReconnect && !DisconnectCalledByUser && _client != null) { - connectLock.Enter(); - if (!IsConnected && AutoReconnect && !DisconnectCalledByUser && _client != null) - { - DisconnectClient(); - Debug.Console(1, this, "Attempting reconnect, status={0}", _client.ClientStatus); - RetryTimer.Reset(AutoReconnectIntervalMs); - } + DisconnectClient(); + Debug.Console(1, this, "Attempting reconnect, status={0}", _client.ClientStatus); + RetryTimer.Reset(AutoReconnectIntervalMs); } - finally - { - connectLock.Leave(); - } - }); + } + finally + { + connectLock.Leave(); + } + }); } - /// - /// Recieves incoming data - /// - /// - /// + /// + /// Recieves incoming data + /// + /// + /// void Receive(TCPClient client, int numBytes) { - if (client != null) + if (client != null) + { + if (numBytes > 0) { - if (numBytes > 0) + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + var bytesHandler = BytesReceived; + if (bytesHandler != null) { - var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); - var bytesHandler = BytesReceived; - if (bytesHandler != null) + if (StreamDebugging.RxStreamDebuggingIsEnabled) { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); - } - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); } - var textHandler = TextReceived; - if (textHandler != null) - { - var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); - } - - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } - client.ReceiveDataAsync(Receive); + var textHandler = TextReceived; + if (textHandler != null) + { + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); + } + + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } } + client.ReceiveDataAsync(Receive); + } } /// @@ -453,9 +453,9 @@ namespace PepperDash.Core { var bytes = Encoding.GetEncoding(28591).GetBytes(text); // Check debug level before processing byte array - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); - if (_client != null) + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + if (_client != null) _client.SendData(bytes, bytes.Length); } @@ -472,35 +472,35 @@ namespace PepperDash.Core SendText(unescapedText); } - /// - /// Sends Bytes to the server - /// - /// + /// + /// Sends Bytes to the server + /// + /// public void SendBytes(byte[] bytes) { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); - if (_client != null) + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + if (_client != null) _client.SendData(bytes, bytes.Length); } - /// - /// Socket Status Change Handler - /// - /// - /// + /// + /// Socket Status Change Handler + /// + /// + /// void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) { - if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - { - Debug.Console(0, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); - WaitAndTryReconnect(); - } - else - { - Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); + if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + Debug.Console(0, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); + WaitAndTryReconnect(); + } + else + { + Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); _client.ReceiveDataAsync(Receive); - } + } var handler = ConnectionChange; if (handler != null) @@ -508,30 +508,30 @@ namespace PepperDash.Core } } - /// - /// Configuration properties for TCP/SSH Connections - /// +/// +/// Configuration properties for TCP/SSH Connections +/// public class TcpSshPropertiesConfig { - /// - /// Address to connect to - /// + /// + /// Address to connect to + /// [JsonProperty(Required = Required.Always)] public string Address { get; set; } - /// - /// Port to connect to - /// + /// + /// Port to connect to + /// [JsonProperty(Required = Required.Always)] public int Port { get; set; } - /// - /// Username credential - /// + /// + /// Username credential + /// public string Username { get; set; } - /// - /// Passord credential - /// + /// + /// Passord credential + /// public string Password { get; set; } /// @@ -549,18 +549,16 @@ namespace PepperDash.Core /// public int AutoReconnectIntervalMs { get; set; } - /// - /// Default constructor - /// + /// + /// Default constructor + /// public TcpSshPropertiesConfig() { BufferSize = 32768; AutoReconnect = true; AutoReconnectIntervalMs = 5000; - Username = ""; - Password = ""; + Username = ""; + Password = ""; } } - -} diff --git a/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs b/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs index 03a27827..a1a0887f 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs @@ -19,757 +19,755 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic TCP/IP client for server +/// +public class GenericTcpIpClient_ForServer : Device, IAutoReconnect { /// - /// Generic TCP/IP client for server + /// Band aid delegate for choked server /// - public class GenericTcpIpClient_ForServer : Device, IAutoReconnect + internal delegate void ConnectionHasHungCallbackDelegate(); + + #region Events + + //public event EventHandler BytesReceived; + + /// + /// Notifies of text received + /// + public event EventHandler TextReceived; + + /// + /// Notifies of socket status change + /// + public event EventHandler ConnectionChange; + + + /// + /// This is something of a band-aid callback. If the client times out during the connection process, because the server + /// is stuck, this will fire. It is intended to be used by the Server class monitor client, to help + /// keep a watch on the server and reset it if necessary. + /// + internal ConnectionHasHungCallbackDelegate ConnectionHasHungCallback; + + /// + /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require + /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. + /// + public event EventHandler ClientReadyForCommunications; + + #endregion + + #region Properties & Variables + + /// + /// Address of server + /// + public string Hostname { get; set; } + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// S+ helper + /// + public ushort UPort { - /// - /// Band aid delegate for choked server - /// - internal delegate void ConnectionHasHungCallbackDelegate(); + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } - #region Events + /// + /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class + /// + public bool SharedKeyRequired { get; set; } - //public event EventHandler BytesReceived; - - /// - /// Notifies of text received - /// - public event EventHandler TextReceived; - - /// - /// Notifies of socket status change - /// - public event EventHandler ConnectionChange; - - - /// - /// This is something of a band-aid callback. If the client times out during the connection process, because the server - /// is stuck, this will fire. It is intended to be used by the Server class monitor client, to help - /// keep a watch on the server and reset it if necessary. - /// - internal ConnectionHasHungCallbackDelegate ConnectionHasHungCallback; - - /// - /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require - /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. - /// - public event EventHandler ClientReadyForCommunications; - - #endregion - - #region Properties & Variables - - /// - /// Address of server - /// - public string Hostname { get; set; } - - /// - /// Port on server - /// - public int Port { get; set; } - - /// - /// S+ helper - /// - public ushort UPort + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module + /// + public string SharedKey { get; set; } + + /// + /// flag to show the client is waiting for the server to send the shared key + /// + private bool WaitingForSharedKeyResponse { get; set; } + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Semaphore on connect method + /// + bool IsTryingToConnect; + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get + { + if (Client != null) + return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; + else + return false; + } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + + /// + /// Bool showing if socket is ready for communication after shared key exchange + /// + public bool IsReadyForCommunication { get; set; } + + /// + /// S+ helper for IsReadyForCommunication + /// + public ushort UIsReadyForCommunication + { + get { return (ushort)(IsReadyForCommunication ? 1 : 0); } + } + + /// + /// Client socket status Read only + /// + public SocketStatus ClientStatus + { + get + { + if (Client != null) + return Client.ClientStatus; + else + return SocketStatus.SOCKET_STATUS_NO_CONNECT; + } + } + + /// + /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event + /// and IsConnected would be true when this == 2. + /// + public ushort UStatus + { + get { return (ushort)ClientStatus; } + } + + /// + /// Status text shows the message associated with socket status + /// + public string ClientStatusText { get { return ClientStatus.ToString(); } } + + /// + /// bool to track if auto reconnect should be set on the socket + /// + public bool AutoReconnect { get; set; } + + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } + /// + /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 + /// + public int AutoReconnectIntervalMs { get; set; } + + /// + /// Flag Set only when the disconnect method is called. + /// + bool DisconnectCalledByUser; + + /// + /// private Timer for auto reconnect + /// + CTimer RetryTimer; + + + /// + /// + /// + public bool HeartbeatEnabled { get; set; } + + /// + /// + /// + public ushort UHeartbeatEnabled + { + get { return (ushort)(HeartbeatEnabled ? 1 : 0); } + set { HeartbeatEnabled = value == 1; } + } + + /// + /// + /// + public string HeartbeatString = "heartbeat"; + + /// + /// + /// + public int HeartbeatInterval = 50000; + + CTimer HeartbeatSendTimer; + CTimer HeartbeatAckTimer; + /// + /// Used to force disconnection on a dead connect attempt + /// + CTimer ConnectFailTimer; + CTimer WaitForSharedKey; + private int ConnectionCount; + /// + /// Internal secure client + /// + TCPClient Client; + + bool ProgramIsStopping; + + #endregion + + #region Constructors + + /// + /// Constructor + /// + /// + /// + /// + /// + public GenericTcpIpClient_ForServer(string key, string address, int port, int bufferSize) + : base(key) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + Hostname = address; + Port = port; + BufferSize = bufferSize; + AutoReconnectIntervalMs = 5000; + + } + + /// + /// Constructor for S+ + /// + public GenericTcpIpClient_ForServer() + : base("Uninitialized DynamicTcpClient") + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + BufferSize = 2000; + } + #endregion + + #region Methods + + /// + /// Just to help S+ set the key + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); + ProgramIsStopping = true; + Disconnect(); } - /// - /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class - /// - public bool SharedKeyRequired { get; set; } + } - /// - /// S+ helper for requires shared key bool - /// - public ushort USharedKeyRequired + /// + /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. + /// + public void Connect() + { + ConnectionCount++; + Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); + + + if (IsConnected) { - set - { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; - } + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); + return; } - - /// - /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module - /// - public string SharedKey { get; set; } - - /// - /// flag to show the client is waiting for the server to send the shared key - /// - private bool WaitingForSharedKeyResponse { get; set; } - - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } - - /// - /// Semaphore on connect method - /// - bool IsTryingToConnect; - - /// - /// Bool showing if socket is connected - /// - public bool IsConnected + if (IsTryingToConnect) { - get - { - if (Client != null) - return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; - else - return false; - } + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); + return; } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected + try { - get { return (ushort)(IsConnected ? 1 : 0); } - } - - /// - /// Bool showing if socket is ready for communication after shared key exchange - /// - public bool IsReadyForCommunication { get; set; } - - /// - /// S+ helper for IsReadyForCommunication - /// - public ushort UIsReadyForCommunication - { - get { return (ushort)(IsReadyForCommunication ? 1 : 0); } - } - - /// - /// Client socket status Read only - /// - public SocketStatus ClientStatus - { - get - { - if (Client != null) - return Client.ClientStatus; - else - return SocketStatus.SOCKET_STATUS_NO_CONNECT; - } - } - - /// - /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event - /// and IsConnected would be true when this == 2. - /// - public ushort UStatus - { - get { return (ushort)ClientStatus; } - } - - /// - /// Status text shows the message associated with socket status - /// - public string ClientStatusText { get { return ClientStatus.ToString(); } } - - /// - /// bool to track if auto reconnect should be set on the socket - /// - public bool AutoReconnect { get; set; } - - /// - /// S+ helper for AutoReconnect - /// - public ushort UAutoReconnect - { - get { return (ushort)(AutoReconnect ? 1 : 0); } - set { AutoReconnect = value == 1; } - } - /// - /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 - /// - public int AutoReconnectIntervalMs { get; set; } - - /// - /// Flag Set only when the disconnect method is called. - /// - bool DisconnectCalledByUser; - - /// - /// private Timer for auto reconnect - /// - CTimer RetryTimer; - - - /// - /// - /// - public bool HeartbeatEnabled { get; set; } - - /// - /// - /// - public ushort UHeartbeatEnabled - { - get { return (ushort)(HeartbeatEnabled ? 1 : 0); } - set { HeartbeatEnabled = value == 1; } - } - - /// - /// - /// - public string HeartbeatString = "heartbeat"; - - /// - /// - /// - public int HeartbeatInterval = 50000; - - CTimer HeartbeatSendTimer; - CTimer HeartbeatAckTimer; - /// - /// Used to force disconnection on a dead connect attempt - /// - CTimer ConnectFailTimer; - CTimer WaitForSharedKey; - private int ConnectionCount; - /// - /// Internal secure client - /// - TCPClient Client; - - bool ProgramIsStopping; - - #endregion - - #region Constructors - - /// - /// Constructor - /// - /// - /// - /// - /// - public GenericTcpIpClient_ForServer(string key, string address, int port, int bufferSize) - : base(key) - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - Hostname = address; - Port = port; - BufferSize = bufferSize; - AutoReconnectIntervalMs = 5000; - - } - - /// - /// Constructor for S+ - /// - public GenericTcpIpClient_ForServer() - : base("Uninitialized DynamicTcpClient") - { - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - AutoReconnectIntervalMs = 5000; - BufferSize = 2000; - } - #endregion - - #region Methods - - /// - /// Just to help S+ set the key - /// - public void Initialize(string key) - { - Key = key; - } - - /// - /// Handles closing this up when the program shuts down - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); - ProgramIsStopping = true; - Disconnect(); - } - - } - - /// - /// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name. - /// - public void Connect() - { - ConnectionCount++; - Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); - - - if (IsConnected) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); - return; - } - if (IsTryingToConnect) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); - return; - } - try - { - IsTryingToConnect = true; - if (RetryTimer != null) - { - RetryTimer.Stop(); - RetryTimer = null; - } - if (string.IsNullOrEmpty(Hostname)) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); - return; - } - if (Port < 1 || Port > 65535) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); - return; - } - if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); - return; - } - - // clean up previous client - if (Client != null) - { - Cleanup(); - } - DisconnectCalledByUser = false; - - Client = new TCPClient(Hostname, Port, BufferSize); - Client.SocketStatusChange += Client_SocketStatusChange; - if(HeartbeatEnabled) - Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); - Client.AddressClientConnectedTo = Hostname; - Client.PortNumber = Port; - // SecureClient = c; - - //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); - - ConnectFailTimer = new CTimer(o => - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); - if (IsTryingToConnect) - { - IsTryingToConnect = false; - - //if (ConnectionHasHungCallback != null) - //{ - // ConnectionHasHungCallback(); - //} - //SecureClient.DisconnectFromServer(); - //CheckClosedAndTryReconnect(); - } - }, 30000); - - Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); - Client.ConnectToServerAsync(o => - { - Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); - - if (ConnectFailTimer != null) - { - ConnectFailTimer.Stop(); - } - IsTryingToConnect = false; - - if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - { - Debug.Console(2, this, "Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); - o.ReceiveDataAsync(Receive); - - if (SharedKeyRequired) - { - WaitingForSharedKeyResponse = true; - WaitForSharedKey = new CTimer(timer => - { - - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); - // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); - // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup - o.DisconnectFromServer(); - //CheckClosedAndTryReconnect(); - //OnClientReadyForcommunications(false); // Should send false event - }, 15000); - } - else - { - //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key - //required this is called by the shared key being negotiated - if (IsReadyForCommunication == false) - { - OnClientReadyForcommunications(true); // Key not required - } - } - } - else - { - Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); - CheckClosedAndTryReconnect(); - } - }); - } - catch (Exception ex) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Client connection exception: {0}", ex.Message); - IsTryingToConnect = false; - CheckClosedAndTryReconnect(); - } - } - - /// - /// - /// - public void Disconnect() - { - this.LogVerbose("Disconnect Called"); - - DisconnectCalledByUser = true; - if (IsConnected) - { - Client.DisconnectFromServer(); - - } + IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } - Cleanup(); - } - - /// - /// Internal call to close up client. ALWAYS use this when disconnecting. - /// - void Cleanup() - { - IsTryingToConnect = false; + if (string.IsNullOrEmpty(Hostname)) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); + return; + } + if (Port < 1 || Port > 65535) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); + return; + } + // clean up previous client if (Client != null) { - //SecureClient.DisconnectFromServer(); - Debug.Console(2, this, "Disconnecting Client {0}", DisconnectCalledByUser ? ", Called by user" : ""); - Client.SocketStatusChange -= Client_SocketStatusChange; - Client.Dispose(); - Client = null; - } - if (ConnectFailTimer != null) - { - ConnectFailTimer.Stop(); - ConnectFailTimer.Dispose(); - ConnectFailTimer = null; - } - } - - - /// ff - /// Called from Connect failure or Socket Status change if - /// auto reconnect and socket disconnected (Not disconnected by user) - /// - void CheckClosedAndTryReconnect() - { - if (Client != null) - { - Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Cleanup(); } - if (!DisconnectCalledByUser && AutoReconnect) + DisconnectCalledByUser = false; + + Client = new TCPClient(Hostname, Port, BufferSize); + Client.SocketStatusChange += Client_SocketStatusChange; + if(HeartbeatEnabled) + Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); + Client.AddressClientConnectedTo = Hostname; + Client.PortNumber = Port; + // SecureClient = c; + + //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); + + ConnectFailTimer = new CTimer(o => { - var halfInterval = AutoReconnectIntervalMs / 2; - var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; - Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); - if (RetryTimer != null) + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); + if (IsTryingToConnect) { - RetryTimer.Stop(); - RetryTimer = null; + IsTryingToConnect = false; + + //if (ConnectionHasHungCallback != null) + //{ + // ConnectionHasHungCallback(); + //} + //SecureClient.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); } - RetryTimer = new CTimer(o => Connect(), rndTime); - } - } + }, 30000); - /// - /// Receive callback - /// - /// - /// - void Receive(TCPClient client, int numBytes) - { - if (numBytes > 0) + Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); + Client.ConnectToServerAsync(o => { - string str = string.Empty; + Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); - try + if (ConnectFailTimer != null) { - var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); - str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - Debug.Console(2, this, "Client Received:\r--------\r{0}\r--------", str); - if (!string.IsNullOrEmpty(checkHeartbeat(str))) + ConnectFailTimer.Stop(); + } + IsTryingToConnect = false; + + if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + { + Debug.Console(2, this, "Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); + o.ReceiveDataAsync(Receive); + + if (SharedKeyRequired) { - if (SharedKeyRequired && str == "SharedKey:") + WaitingForSharedKeyResponse = true; + WaitForSharedKey = new CTimer(timer => { - Debug.Console(2, this, "Server asking for shared key, sending"); - SendText(SharedKey + "\n"); - } - else if (SharedKeyRequired && str == "Shared Key Match") + + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); + // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); + // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup + o.DisconnectFromServer(); + //CheckClosedAndTryReconnect(); + //OnClientReadyForcommunications(false); // Should send false event + }, 15000); + } + else + { + //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key + //required this is called by the shared key being negotiated + if (IsReadyForCommunication == false) { - StopWaitForSharedKeyTimer(); - Debug.Console(2, this, "Shared key confirmed. Ready for communication"); - OnClientReadyForcommunications(true); // Successful key exchange - } - else - { - //var bytesHandler = BytesReceived; - //if (bytesHandler != null) - // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - var textHandler = TextReceived; - if (textHandler != null) - textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); + OnClientReadyForcommunications(true); // Key not required } } } - catch (Exception ex) + else { - Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); + CheckClosedAndTryReconnect(); + } + }); + } + catch (Exception ex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Client connection exception: {0}", ex.Message); + IsTryingToConnect = false; + CheckClosedAndTryReconnect(); + } + } + + /// + /// + /// + public void Disconnect() + { + this.LogVerbose("Disconnect Called"); + + DisconnectCalledByUser = true; + if (IsConnected) + { + Client.DisconnectFromServer(); + + } + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; + } + Cleanup(); + } + + /// + /// Internal call to close up client. ALWAYS use this when disconnecting. + /// + void Cleanup() + { + IsTryingToConnect = false; + + if (Client != null) + { + //SecureClient.DisconnectFromServer(); + Debug.Console(2, this, "Disconnecting Client {0}", DisconnectCalledByUser ? ", Called by user" : ""); + Client.SocketStatusChange -= Client_SocketStatusChange; + Client.Dispose(); + Client = null; + } + if (ConnectFailTimer != null) + { + ConnectFailTimer.Stop(); + ConnectFailTimer.Dispose(); + ConnectFailTimer = null; + } + } + + + /// ff + /// Called from Connect failure or Socket Status change if + /// auto reconnect and socket disconnected (Not disconnected by user) + /// + void CheckClosedAndTryReconnect() + { + if (Client != null) + { + Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); + Cleanup(); + } + if (!DisconnectCalledByUser && AutoReconnect) + { + var halfInterval = AutoReconnectIntervalMs / 2; + var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; + Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); + if (RetryTimer != null) + { + RetryTimer.Stop(); + RetryTimer = null; + } + RetryTimer = new CTimer(o => Connect(), rndTime); + } + } + + /// + /// Receive callback + /// + /// + /// + void Receive(TCPClient client, int numBytes) + { + if (numBytes > 0) + { + string str = string.Empty; + + try + { + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + Debug.Console(2, this, "Client Received:\r--------\r{0}\r--------", str); + if (!string.IsNullOrEmpty(checkHeartbeat(str))) + { + if (SharedKeyRequired && str == "SharedKey:") + { + Debug.Console(2, this, "Server asking for shared key, sending"); + SendText(SharedKey + "\n"); + } + else if (SharedKeyRequired && str == "Shared Key Match") + { + StopWaitForSharedKeyTimer(); + Debug.Console(2, this, "Shared key confirmed. Ready for communication"); + OnClientReadyForcommunications(true); // Successful key exchange + } + else + { + //var bytesHandler = BytesReceived; + //if (bytesHandler != null) + // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); + } } } - if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - client.ReceiveDataAsync(Receive); + catch (Exception ex) + { + Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); + } + } + if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + client.ReceiveDataAsync(Receive); + } + + void HeartbeatStart() + { + if (HeartbeatEnabled) + { + Debug.Console(2, this, "Starting Heartbeat"); + if (HeartbeatSendTimer == null) + { + + HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); + } + if (HeartbeatAckTimer == null) + { + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); + } } - void HeartbeatStart() + } + void HeartbeatStop() + { + + if (HeartbeatSendTimer != null) + { + Debug.Console(2, this, "Stoping Heartbeat Send"); + HeartbeatSendTimer.Stop(); + HeartbeatSendTimer = null; + } + if (HeartbeatAckTimer != null) + { + Debug.Console(2, this, "Stoping Heartbeat Ack"); + HeartbeatAckTimer.Stop(); + HeartbeatAckTimer = null; + } + + } + void SendHeartbeat(object notused) + { + this.SendText(HeartbeatString); + Debug.Console(2, this, "Sending Heartbeat"); + + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(string received) + { + try { if (HeartbeatEnabled) { - Debug.Console(2, this, "Starting Heartbeat"); - if (HeartbeatSendTimer == null) + if (!string.IsNullOrEmpty(HeartbeatString)) { - - HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); - } - if (HeartbeatAckTimer == null) - { - HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); - } - } - - } - void HeartbeatStop() - { - - if (HeartbeatSendTimer != null) - { - Debug.Console(2, this, "Stoping Heartbeat Send"); - HeartbeatSendTimer.Stop(); - HeartbeatSendTimer = null; - } - if (HeartbeatAckTimer != null) - { - Debug.Console(2, this, "Stoping Heartbeat Ack"); - HeartbeatAckTimer.Stop(); - HeartbeatAckTimer = null; - } - - } - void SendHeartbeat(object notused) - { - this.SendText(HeartbeatString); - Debug.Console(2, this, "Sending Heartbeat"); - - } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(string received) - { - try - { - if (HeartbeatEnabled) - { - if (!string.IsNullOrEmpty(HeartbeatString)) + var remainingText = received.Replace(HeartbeatString, ""); + var noDelimiter = received.Trim(new char[] { '\r', '\n' }); + if (noDelimiter.Contains(HeartbeatString)) { - var remainingText = received.Replace(HeartbeatString, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatString)) + if (HeartbeatAckTimer != null) { - if (HeartbeatAckTimer != null) - { - HeartbeatAckTimer.Reset(HeartbeatInterval * 2); - } - else - { - HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); - } - Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); - return remainingText; + HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } - } - } - } - catch (Exception ex) - { - Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); - } - return received; - } - - - - void HeartbeatAckTimerFail(object o) - { - try - { - - if (IsConnected) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); - SendText("Heartbeat not received by server, closing connection"); - CheckClosedAndTryReconnect(); - } - - } - catch (Exception ex) - { - ErrorLog.Error("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); - } - } - - /// - /// - /// - void StopWaitForSharedKeyTimer() - { - if (WaitForSharedKey != null) - { - WaitForSharedKey.Stop(); - WaitForSharedKey = null; - } - } - - /// - /// General send method - /// - public void SendText(string text) - { - if (!string.IsNullOrEmpty(text)) - { - try - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - { - Client.SendDataAsync(bytes, bytes.Length, (c, n) => + else { - // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? - if (n <= 0) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); - } - }); + HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); + } + Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); + return remainingText; } - } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); - } + } } } - - /// - /// - /// - public void SendBytes(byte[] bytes) + catch (Exception ex) { - if (bytes.Length > 0) - { - try - { - if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) - Client.SendData(bytes, bytes.Length); - } - catch (Exception ex) - { - Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); - } - } + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } + return received; + } - /// - /// SocketStatusChange Callback - /// - /// - /// - void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) + + + void HeartbeatAckTimerFail(object o) + { + try { - if (ProgramIsStopping) + + if (IsConnected) { - ProgramIsStopping = false; - return; + Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); + SendText("Heartbeat not received by server, closing connection"); + CheckClosedAndTryReconnect(); } + + } + catch (Exception ex) + { + ErrorLog.Error("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); + } + } + + /// + /// + /// + void StopWaitForSharedKeyTimer() + { + if (WaitForSharedKey != null) + { + WaitForSharedKey.Stop(); + WaitForSharedKey = null; + } + } + + /// + /// General send method + /// + public void SendText(string text) + { + if (!string.IsNullOrEmpty(text)) + { try { - Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); - - OnConnectionChange(); - - // The client could be null or disposed by this time... - if (Client == null || Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { - HeartbeatStop(); - OnClientReadyForcommunications(false); // socket has gone low - CheckClosedAndTryReconnect(); + Client.SendDataAsync(bytes, bytes.Length, (c, n) => + { + // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? + if (n <= 0) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); + } + }); } } catch (Exception ex) { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); + Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); } } - - /// - /// Helper for ConnectionChange event - /// - void OnConnectionChange() - { - var handler = ConnectionChange; - if (handler != null) - ConnectionChange(this, new GenericTcpServerSocketStatusChangeEventArgs(this, Client.ClientStatus)); - } - - /// - /// Helper to fire ClientReadyForCommunications event - /// - void OnClientReadyForcommunications(bool isReady) - { - IsReadyForCommunication = isReady; - if (this.IsReadyForCommunication) { HeartbeatStart(); } - var handler = ClientReadyForCommunications; - if (handler != null) - handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); - } - #endregion } - -} \ No newline at end of file + + /// + /// + /// + public void SendBytes(byte[] bytes) + { + if (bytes.Length > 0) + { + try + { + if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) + Client.SendData(bytes, bytes.Length); + } + catch (Exception ex) + { + Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); + } + } + } + + /// + /// SocketStatusChange Callback + /// + /// + /// + void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) + { + if (ProgramIsStopping) + { + ProgramIsStopping = false; + return; + } + try + { + Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); + + OnConnectionChange(); + + // The client could be null or disposed by this time... + if (Client == null || Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + HeartbeatStop(); + OnClientReadyForcommunications(false); // socket has gone low + CheckClosedAndTryReconnect(); + } + } + catch (Exception ex) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); + } + } + + /// + /// Helper for ConnectionChange event + /// + void OnConnectionChange() + { + var handler = ConnectionChange; + if (handler != null) + ConnectionChange(this, new GenericTcpServerSocketStatusChangeEventArgs(this, Client.ClientStatus)); + } + + /// + /// Helper to fire ClientReadyForCommunications event + /// + void OnClientReadyForcommunications(bool isReady) + { + IsReadyForCommunication = isReady; + if (this.IsReadyForCommunication) { HeartbeatStart(); } + var handler = ClientReadyForCommunications; + if (handler != null) + handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); + } + #endregion +} diff --git a/src/PepperDash.Core/Comm/GenericTcpIpServer.cs b/src/PepperDash.Core/Comm/GenericTcpIpServer.cs index 6aa5e6b5..3dce8895 100644 --- a/src/PepperDash.Core/Comm/GenericTcpIpServer.cs +++ b/src/PepperDash.Core/Comm/GenericTcpIpServer.cs @@ -17,578 +17,563 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic TCP/IP server device +/// +public class GenericTcpIpServer : Device { + #region Events /// - /// Generic TCP/IP server device + /// Event for Receiving text /// - public class GenericTcpIpServer : Device + public event EventHandler TextReceived; + + /// + /// Event for client connection socket status change + /// + public event EventHandler ClientConnectionChange; + + /// + /// Event for Server State Change + /// + public event EventHandler ServerStateChange; + + /// + /// For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire + /// after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. + /// + public event EventHandler ServerClientReadyForCommunications; + + /// + /// A band aid event to notify user that the server has choked. + /// + public ServerHasChokedCallbackDelegate ServerHasChoked { get; set; } + + /// + /// + /// + public delegate void ServerHasChokedCallbackDelegate(); + + #endregion + + #region Properties/Variables + + /// + /// + /// + CCriticalSection ServerCCSection = new CCriticalSection(); + + + /// + /// A bandaid client that monitors whether the server is reachable + /// + GenericTcpIpClient_ForServer MonitorClient; + + /// + /// Timer to operate the bandaid monitor client in a loop. + /// + CTimer MonitorClientTimer; + + /// + /// + /// + int MonitorClientFailureCount; + + /// + /// 3 by default + /// + public int MonitorClientMaxFailureCount { get; set; } + + /// + /// Text representation of the Socket Status enum values for the server + /// + public string Status { - #region Events - /// - /// Event for Receiving text - /// - public event EventHandler TextReceived; - - /// - /// Event for client connection socket status change - /// - public event EventHandler ClientConnectionChange; - - /// - /// Event for Server State Change - /// - public event EventHandler ServerStateChange; - - /// - /// For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire - /// after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. - /// - public event EventHandler ServerClientReadyForCommunications; - - /// - /// A band aid event to notify user that the server has choked. - /// - public ServerHasChokedCallbackDelegate ServerHasChoked { get; set; } - - /// - /// - /// - public delegate void ServerHasChokedCallbackDelegate(); - - #endregion - - #region Properties/Variables - - /// - /// - /// - CCriticalSection ServerCCSection = new CCriticalSection(); - - - /// - /// A bandaid client that monitors whether the server is reachable - /// - GenericTcpIpClient_ForServer MonitorClient; - - /// - /// Timer to operate the bandaid monitor client in a loop. - /// - CTimer MonitorClientTimer; - - /// - /// - /// - int MonitorClientFailureCount; - - /// - /// 3 by default - /// - public int MonitorClientMaxFailureCount { get; set; } - - /// - /// Text representation of the Socket Status enum values for the server - /// - public string Status + get { - get - { - if (myTcpServer != null) - return myTcpServer.State.ToString(); - return ServerState.SERVER_NOT_LISTENING.ToString(); - - } + if (myTcpServer != null) + return myTcpServer.State.ToString(); + return ServerState.SERVER_NOT_LISTENING.ToString(); } - /// - /// Bool showing if socket is connected - /// - public bool IsConnected + } + + /// + /// Bool showing if socket is connected + /// + public bool IsConnected + { + get { - get - { - if (myTcpServer != null) - return (myTcpServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; + if (myTcpServer != null) + return (myTcpServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; + return false; + + //return (Secure ? SecureServer != null : UnsecureServer != null) && + //(Secure ? (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED : + // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); + } + } + + /// + /// S+ helper for IsConnected + /// + public ushort UIsConnected + { + get { return (ushort)(IsConnected ? 1 : 0); } + } + + /// + /// Bool showing if socket is connected + /// + public bool IsListening + { + get + { + if (myTcpServer != null) + return (myTcpServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING; + else return false; - - //return (Secure ? SecureServer != null : UnsecureServer != null) && - //(Secure ? (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED : - // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); - } + //return (Secure ? SecureServer != null : UnsecureServer != null) && + //(Secure ? (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING : + // (UnsecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING); } + } - /// - /// S+ helper for IsConnected - /// - public ushort UIsConnected + /// + /// S+ helper for IsConnected + /// + public ushort UIsListening + { + get { return (ushort)(IsListening ? 1 : 0); } + } + + /// + /// The maximum number of clients. + /// Should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable + /// + public ushort MaxClients { get; set; } + + /// + /// Number of clients currently connected. + /// + public ushort NumberOfClientsConnected + { + get { - get { return (ushort)(IsConnected ? 1 : 0); } + if (myTcpServer != null) + return (ushort)myTcpServer.NumberOfClientsConnected; + return 0; } + } - /// - /// Bool showing if socket is connected - /// - public bool IsListening + /// + /// Port Server should listen on + /// + public int Port { get; set; } + + /// + /// S+ helper for Port + /// + public ushort UPort + { + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } + + /// + /// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client + /// + public bool SharedKeyRequired { get; set; } + + /// + /// S+ helper for requires shared key bool + /// + public ushort USharedKeyRequired + { + set { - get + if (value == 1) + SharedKeyRequired = true; + else + SharedKeyRequired = false; + } + } + + /// + /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. + /// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called + /// + public string SharedKey { get; set; } + + /// + /// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received + /// + public bool HeartbeatRequired { get; set; } + + /// + /// S+ Helper for Heartbeat Required + /// + public ushort UHeartbeatRequired + { + set + { + if (value == 1) + HeartbeatRequired = true; + else + HeartbeatRequired = false; + } + } + + /// + /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ + /// + public int HeartbeatRequiredIntervalMs { get; set; } + + /// + /// Simpl+ Heartbeat Analog value in seconds + /// + public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } + + /// + /// String to Match for heartbeat. If null or empty any string will reset heartbeat timer + /// + public string HeartbeatStringToMatch { get; set; } + + //private timers for Heartbeats per client + Dictionary HeartbeatTimerDictionary = new Dictionary(); + + //flags to show the secure server is waiting for client at index to send the shared key + List WaitingForSharedKey = new List(); + + List ClientReadyAfterKeyExchange = new List(); + + /// + /// The connected client indexes + /// + public List ConnectedClientsIndexes = new List(); + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// Private flag to note that the server has stopped intentionally + /// + private bool ServerStopped { get; set; } + + //Servers + TCPServer myTcpServer; + + /// + /// + /// + bool ProgramIsStopping; + + #endregion + + #region Constructors + /// + /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. + /// + public GenericTcpIpServer() + : base("Uninitialized Dynamic TCP Server") + { + HeartbeatRequiredIntervalInSeconds = 15; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + BufferSize = 2000; + MonitorClientMaxFailureCount = 3; + } + + /// + /// constructor with debug key set at instantiation. Make sure to set all properties before listening. + /// + /// + public GenericTcpIpServer(string key) + : base("Uninitialized Dynamic TCP Server") + { + HeartbeatRequiredIntervalInSeconds = 15; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + BufferSize = 2000; + MonitorClientMaxFailureCount = 3; + Key = key; + } + + /// + /// Contstructor that sets all properties by calling the initialize method with a config object. + /// + /// + public GenericTcpIpServer(TcpServerConfigObject serverConfigObject) + : base("Uninitialized Dynamic TCP Server") + { + HeartbeatRequiredIntervalInSeconds = 15; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + BufferSize = 2000; + MonitorClientMaxFailureCount = 3; + Initialize(serverConfigObject); + } + #endregion + + #region Methods - Server Actions + /// + /// Disconnects all clients and stops the server + /// + public void KillServer() + { + ServerStopped = true; + if (MonitorClient != null) + { + MonitorClient.Disconnect(); + } + DisconnectAllClientsForShutdown(); + StopListening(); + } + + /// + /// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ + /// + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Initialze with server configuration object + /// + /// + public void Initialize(TcpServerConfigObject serverConfigObject) + { + try + { + if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) { - if (myTcpServer != null) - return (myTcpServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING; - else - return false; - //return (Secure ? SecureServer != null : UnsecureServer != null) && - //(Secure ? (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING : - // (UnsecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING); + Key = serverConfigObject.Key; + MaxClients = serverConfigObject.MaxClients; + Port = serverConfigObject.Port; + SharedKeyRequired = serverConfigObject.SharedKeyRequired; + SharedKey = serverConfigObject.SharedKey; + HeartbeatRequired = serverConfigObject.HeartbeatRequired; + HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; + HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; + BufferSize = serverConfigObject.BufferSize; + } - } - - /// - /// S+ helper for IsConnected - /// - public ushort UIsListening - { - get { return (ushort)(IsListening ? 1 : 0); } - } - - /// - /// The maximum number of clients. - /// Should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable - /// - public ushort MaxClients { get; set; } - - /// - /// Number of clients currently connected. - /// - public ushort NumberOfClientsConnected - { - get - { - if (myTcpServer != null) - return (ushort)myTcpServer.NumberOfClientsConnected; - return 0; - } - } - - /// - /// Port Server should listen on - /// - public int Port { get; set; } - - /// - /// S+ helper for Port - /// - public ushort UPort - { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } - } - - /// - /// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client - /// - public bool SharedKeyRequired { get; set; } - - /// - /// S+ helper for requires shared key bool - /// - public ushort USharedKeyRequired - { - set - { - if (value == 1) - SharedKeyRequired = true; - else - SharedKeyRequired = false; - } - } - - /// - /// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module. - /// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called - /// - public string SharedKey { get; set; } - - /// - /// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received - /// - public bool HeartbeatRequired { get; set; } - - /// - /// S+ Helper for Heartbeat Required - /// - public ushort UHeartbeatRequired - { - set - { - if (value == 1) - HeartbeatRequired = true; - else - HeartbeatRequired = false; - } - } - - /// - /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ - /// - public int HeartbeatRequiredIntervalMs { get; set; } - - /// - /// Simpl+ Heartbeat Analog value in seconds - /// - public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } - - /// - /// String to Match for heartbeat. If null or empty any string will reset heartbeat timer - /// - public string HeartbeatStringToMatch { get; set; } - - //private timers for Heartbeats per client - Dictionary HeartbeatTimerDictionary = new Dictionary(); - - //flags to show the secure server is waiting for client at index to send the shared key - List WaitingForSharedKey = new List(); - - List ClientReadyAfterKeyExchange = new List(); - - /// - /// The connected client indexes - /// - public List ConnectedClientsIndexes = new List(); - - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } - - /// - /// Private flag to note that the server has stopped intentionally - /// - private bool ServerStopped { get; set; } - - //Servers - TCPServer myTcpServer; - - /// - /// - /// - bool ProgramIsStopping; - - #endregion - - #region Constructors - /// - /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. - /// - public GenericTcpIpServer() - : base("Uninitialized Dynamic TCP Server") - { - HeartbeatRequiredIntervalInSeconds = 15; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - BufferSize = 2000; - MonitorClientMaxFailureCount = 3; - } - - /// - /// constructor with debug key set at instantiation. Make sure to set all properties before listening. - /// - /// - public GenericTcpIpServer(string key) - : base("Uninitialized Dynamic TCP Server") - { - HeartbeatRequiredIntervalInSeconds = 15; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - BufferSize = 2000; - MonitorClientMaxFailureCount = 3; - Key = key; - } - - /// - /// Contstructor that sets all properties by calling the initialize method with a config object. - /// - /// - public GenericTcpIpServer(TcpServerConfigObject serverConfigObject) - : base("Uninitialized Dynamic TCP Server") - { - HeartbeatRequiredIntervalInSeconds = 15; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - BufferSize = 2000; - MonitorClientMaxFailureCount = 3; - Initialize(serverConfigObject); - } - #endregion - - #region Methods - Server Actions - /// - /// Disconnects all clients and stops the server - /// - public void KillServer() - { - ServerStopped = true; - if (MonitorClient != null) - { - MonitorClient.Disconnect(); - } - DisconnectAllClientsForShutdown(); - StopListening(); - } - - /// - /// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ - /// - /// - public void Initialize(string key) - { - Key = key; - } - - /// - /// Initialze with server configuration object - /// - /// - public void Initialize(TcpServerConfigObject serverConfigObject) - { - try - { - if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) - { - Key = serverConfigObject.Key; - MaxClients = serverConfigObject.MaxClients; - Port = serverConfigObject.Port; - SharedKeyRequired = serverConfigObject.SharedKeyRequired; - SharedKey = serverConfigObject.SharedKey; - HeartbeatRequired = serverConfigObject.HeartbeatRequired; - HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; - HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; - BufferSize = serverConfigObject.BufferSize; - - } - else - { - ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); - } - } - catch + else { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } - - /// - /// Start listening on the specified port - /// - public void Listen() + catch { - ServerCCSection.Enter(); - try - { - if (Port < 1 || Port > 65535) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': Invalid port", Key); - ErrorLog.Warn(string.Format("Server '{0}': Invalid port", Key)); - return; - } - if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': No Shared Key set", Key); - ErrorLog.Warn(string.Format("Server '{0}': No Shared Key set", Key)); - return; - } - if (IsListening) - return; + ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); + } + } - if (myTcpServer == null) - { - myTcpServer = new TCPServer(Port, MaxClients); - if(HeartbeatRequired) - myTcpServer.SocketSendOrReceiveTimeOutInMs = (this.HeartbeatRequiredIntervalMs * 5); - + /// + /// Start listening on the specified port + /// + public void Listen() + { + ServerCCSection.Enter(); + try + { + if (Port < 1 || Port > 65535) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': Invalid port", Key); + ErrorLog.Warn(string.Format("Server '{0}': Invalid port", Key)); + return; + } + if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': No Shared Key set", Key); + ErrorLog.Warn(string.Format("Server '{0}': No Shared Key set", Key)); + return; + } + if (IsListening) + return; + + if (myTcpServer == null) + { + myTcpServer = new TCPServer(Port, MaxClients); + if(HeartbeatRequired) + myTcpServer.SocketSendOrReceiveTimeOutInMs = (this.HeartbeatRequiredIntervalMs * 5); + // myTcpServer.HandshakeTimeout = 30; - } - else - { - KillServer(); - myTcpServer.PortNumber = Port; - } - - myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange; - myTcpServer.SocketStatusChange += TcpServer_SocketStatusChange; - - ServerStopped = false; - myTcpServer.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); - OnServerStateChange(myTcpServer.State); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "TCP Server Status: {0}, Socket Status: {1}", myTcpServer.State, myTcpServer.ServerSocketStatus); - - // StartMonitorClient(); - - - ServerCCSection.Leave(); } - catch (Exception ex) + else { - ServerCCSection.Leave(); - ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); + KillServer(); + myTcpServer.PortNumber = Port; } + + myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange; + myTcpServer.SocketStatusChange += TcpServer_SocketStatusChange; + + ServerStopped = false; + myTcpServer.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); + OnServerStateChange(myTcpServer.State); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "TCP Server Status: {0}, Socket Status: {1}", myTcpServer.State, myTcpServer.ServerSocketStatus); + + // StartMonitorClient(); + + + ServerCCSection.Leave(); } - - /// - /// Stop Listening - /// - public void StopListening() + catch (Exception ex) { - try - { - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); - if (myTcpServer != null) - { - myTcpServer.Stop(); - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server State: {0}", myTcpServer.State); - OnServerStateChange(myTcpServer.State); - } - ServerStopped = true; - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error stopping server. Error: {0}", ex); - } + ServerCCSection.Leave(); + ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); } + } - /// - /// Disconnects Client - /// - /// - public void DisconnectClient(uint client) + /// + /// Stop Listening + /// + public void StopListening() + { + try { - try - { - myTcpServer.Disconnect(client); - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); - } - } - /// - /// Disconnect All Clients - /// - public void DisconnectAllClientsForShutdown() - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); if (myTcpServer != null) { - myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange; - foreach (var index in ConnectedClientsIndexes.ToList()) // copy it here so that it iterates properly - { - var i = index; - if (!myTcpServer.ClientConnected(index)) - continue; - try - { - myTcpServer.Disconnect(i); - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); - } - } - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", myTcpServer.ServerSocketStatus); + myTcpServer.Stop(); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server State: {0}", myTcpServer.State); + OnServerStateChange(myTcpServer.State); } + ServerStopped = true; + } + catch (Exception ex) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error stopping server. Error: {0}", ex); + } + } - Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); - ConnectedClientsIndexes.Clear(); - - if (!ProgramIsStopping) + /// + /// Disconnects Client + /// + /// + public void DisconnectClient(uint client) + { + try + { + myTcpServer.Disconnect(client); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); + } + catch (Exception ex) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); + } + } + /// + /// Disconnect All Clients + /// + public void DisconnectAllClientsForShutdown() + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); + if (myTcpServer != null) + { + myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange; + foreach (var index in ConnectedClientsIndexes.ToList()) // copy it here so that it iterates properly { - OnConnectionChange(); - OnServerStateChange(myTcpServer.State); //State shows both listening and connected + var i = index; + if (!myTcpServer.ClientConnected(index)) + continue; + try + { + myTcpServer.Disconnect(i); + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); + } + catch (Exception ex) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); + } } - - // var o = new { }; + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", myTcpServer.ServerSocketStatus); } - /// - /// Broadcast text from server to all connected clients - /// - /// - public void BroadcastText(string text) + Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); + ConnectedClientsIndexes.Clear(); + + if (!ProgramIsStopping) { - CCriticalSection CCBroadcast = new CCriticalSection(); - CCBroadcast.Enter(); - try - { - if (ConnectedClientsIndexes.Count > 0) - { - byte[] b = Encoding.GetEncoding(28591).GetBytes(text); - foreach (uint i in ConnectedClientsIndexes) - { - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(i))) - { - SocketErrorCodes error = myTcpServer.SendDataAsync(i, b, b.Length, (x, y, z) => { }); - if (error != SocketErrorCodes.SOCKET_OK && error != SocketErrorCodes.SOCKET_OPERATION_PENDING) - this.LogError("{error}",error.ToString()); - } - } - } - CCBroadcast.Leave(); - } - catch (Exception ex) - { - CCBroadcast.Leave(); - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); - } + OnConnectionChange(); + OnServerStateChange(myTcpServer.State); //State shows both listening and connected } - /// - /// Not sure this is useful in library, maybe Pro?? - /// - /// - /// - public void SendTextToClient(string text, uint clientIndex) + // var o = new { }; + } + + /// + /// Broadcast text from server to all connected clients + /// + /// + public void BroadcastText(string text) + { + CCriticalSection CCBroadcast = new CCriticalSection(); + CCBroadcast.Enter(); + try { - try + if (ConnectedClientsIndexes.Count > 0) { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); - if (myTcpServer != null && myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) + foreach (uint i in ConnectedClientsIndexes) { - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) - myTcpServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(i))) + { + SocketErrorCodes error = myTcpServer.SendDataAsync(i, b, b.Length, (x, y, z) => { }); + if (error != SocketErrorCodes.SOCKET_OK && error != SocketErrorCodes.SOCKET_OPERATION_PENDING) + this.LogError("{error}",error.ToString()); + } } } - catch (Exception ex) + CCBroadcast.Leave(); + } + catch (Exception ex) + { + CCBroadcast.Leave(); + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); + } + } + + /// + /// Not sure this is useful in library, maybe Pro?? + /// + /// + /// + public void SendTextToClient(string text, uint clientIndex) + { + try + { + byte[] b = Encoding.GetEncoding(28591).GetBytes(text); + if (myTcpServer != null && myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) { - Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) + myTcpServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); } } - - //private method to check heartbeat requirements and start or reset timer - string checkHeartbeat(uint clientIndex, string received) + catch (Exception ex) { - try + Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); + } + } + + //private method to check heartbeat requirements and start or reset timer + string checkHeartbeat(uint clientIndex, string received) + { + try + { + if (HeartbeatRequired) { - if (HeartbeatRequired) + if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) { - if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) - { - var remainingText = received.Replace(HeartbeatStringToMatch, ""); - var noDelimiter = received.Trim(new char[] { '\r', '\n' }); - if (noDelimiter.Contains(HeartbeatStringToMatch)) - { - if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) - HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); - else - { - CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); - HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); - } - Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); - // Return Heartbeat - SendTextToClient(HeartbeatStringToMatch, clientIndex); - return remainingText; - } - } - else + var remainingText = received.Replace(HeartbeatStringToMatch, ""); + var noDelimiter = received.Trim(new char[] { '\r', '\n' }); + if (noDelimiter.Contains(HeartbeatStringToMatch)) { if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); @@ -597,197 +582,212 @@ namespace PepperDash.Core CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); } - Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", received, clientIndex); + Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); + // Return Heartbeat + SendTextToClient(HeartbeatStringToMatch, clientIndex); + return remainingText; } } - } - catch (Exception ex) - { - Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); - } - return received; - } - - /// - /// Gets the IP address based on the client index - /// - /// - /// IP address of the client - public string GetClientIPAddress(uint clientIndex) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress Index: {0}", clientIndex); - if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) - { - var ipa = this.myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress IPAddreess: {0}", ipa); - return ipa; - - } - else - { - return ""; + else + { + if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) + HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); + else + { + CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); + HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); + } + Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", received, clientIndex); + } } } - - #endregion - - #region Methods - HeartbeatTimer Callback - - void HeartbeatTimer_CallbackFunction(object o) + catch (Exception ex) { - uint clientIndex = 99999; - string address = string.Empty; - try + Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); + } + return received; + } + + /// + /// Gets the IP address based on the client index + /// + /// + /// IP address of the client + public string GetClientIPAddress(uint clientIndex) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress Index: {0}", clientIndex); + if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) + { + var ipa = this.myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress IPAddreess: {0}", ipa); + return ipa; + + } + else + { + return ""; + } + } + + #endregion + + #region Methods - HeartbeatTimer Callback + + void HeartbeatTimer_CallbackFunction(object o) + { + uint clientIndex = 99999; + string address = string.Empty; + try + { + clientIndex = (uint)o; + address = myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); + + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Heartbeat not received for Client index {2} IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE {1}", + address, string.IsNullOrEmpty(HeartbeatStringToMatch) ? "" : ("HeartbeatStringToMatch: " + HeartbeatStringToMatch), clientIndex); + + if (myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) + SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); + + var discoResult = myTcpServer.Disconnect(clientIndex); + //Debug.Console(1, this, "{0}", discoResult); + + if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) { - clientIndex = (uint)o; - address = myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); + HeartbeatTimerDictionary[clientIndex].Stop(); + HeartbeatTimerDictionary[clientIndex].Dispose(); + HeartbeatTimerDictionary.Remove(clientIndex); + } + } + catch (Exception ex) + { + ErrorLog.Error("{3}: Heartbeat timeout Error on Client Index: {0}, at address: {1}, error: {2}", clientIndex, address, ex.Message, Key); + } + } - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Heartbeat not received for Client index {2} IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE {1}", - address, string.IsNullOrEmpty(HeartbeatStringToMatch) ? "" : ("HeartbeatStringToMatch: " + HeartbeatStringToMatch), clientIndex); + #endregion - if (myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) - SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); + #region Methods - Socket Status Changed Callbacks + /// + /// Secure Server Socket Status Changed Callback + /// + /// + /// + /// + void TcpServer_SocketStatusChange(TCPServer server, uint clientIndex, SocketStatus serverSocketStatus) + { + try + { - var discoResult = myTcpServer.Disconnect(clientIndex); - //Debug.Console(1, this, "{0}", discoResult); - - if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange Index:{0} status:{1} Port:{2} IP:{3}", clientIndex, serverSocketStatus, this.myTcpServer.GetPortNumberServerAcceptedConnectionFromForSpecificClient(clientIndex), this.myTcpServer.GetLocalAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); + if (serverSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + { + if (ConnectedClientsIndexes.Contains(clientIndex)) + ConnectedClientsIndexes.Remove(clientIndex); + if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary[clientIndex].Stop(); HeartbeatTimerDictionary[clientIndex].Dispose(); HeartbeatTimerDictionary.Remove(clientIndex); } - } - catch (Exception ex) - { - ErrorLog.Error("{3}: Heartbeat timeout Error on Client Index: {0}, at address: {1}, error: {2}", clientIndex, address, ex.Message, Key); - } - } - - #endregion - - #region Methods - Socket Status Changed Callbacks - /// - /// Secure Server Socket Status Changed Callback - /// - /// - /// - /// - void TcpServer_SocketStatusChange(TCPServer server, uint clientIndex, SocketStatus serverSocketStatus) - { - try - { - - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange Index:{0} status:{1} Port:{2} IP:{3}", clientIndex, serverSocketStatus, this.myTcpServer.GetPortNumberServerAcceptedConnectionFromForSpecificClient(clientIndex), this.myTcpServer.GetLocalAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); - if (serverSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - { - if (ConnectedClientsIndexes.Contains(clientIndex)) - ConnectedClientsIndexes.Remove(clientIndex); - if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex)) - { - HeartbeatTimerDictionary[clientIndex].Stop(); - HeartbeatTimerDictionary[clientIndex].Dispose(); - HeartbeatTimerDictionary.Remove(clientIndex); - } - if (ClientReadyAfterKeyExchange.Contains(clientIndex)) - ClientReadyAfterKeyExchange.Remove(clientIndex); + if (ClientReadyAfterKeyExchange.Contains(clientIndex)) + ClientReadyAfterKeyExchange.Remove(clientIndex); if (WaitingForSharedKey.Contains(clientIndex)) WaitingForSharedKey.Remove(clientIndex); - } - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); - } - onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); - } - - #endregion - - #region Methods Connected Callbacks - /// - /// Secure TCP Client Connected to Secure Server Callback - /// - /// - /// - void TcpConnectCallback(TCPServer server, uint clientIndex) - { - try - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectCallback: IPAddress: {0}. Index: {1}. Status: {2}", - server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), - clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); - if (clientIndex != 0) - { - if (server.ClientConnected(clientIndex)) - { - - if (!ConnectedClientsIndexes.Contains(clientIndex)) - { - ConnectedClientsIndexes.Add(clientIndex); - } - if (SharedKeyRequired) - { - if (!WaitingForSharedKey.Contains(clientIndex)) - { - WaitingForSharedKey.Add(clientIndex); - } - byte[] b = Encoding.GetEncoding(28591).GetBytes("SharedKey:"); - server.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Sent Shared Key Request to client at {0}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); - } - else - { - OnServerClientReadyForCommunications(clientIndex); - } - if (HeartbeatRequired) - { - if (!HeartbeatTimerDictionary.ContainsKey(clientIndex)) - { - HeartbeatTimerDictionary.Add(clientIndex, new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs)); - } - } - - server.ReceiveDataAsync(clientIndex, TcpServerReceivedDataAsyncCallback); - } - } - else - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); - if (!ServerStopped) - { - server.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); - return; - } - } - } - catch (Exception ex) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); - } - //Debug.Console(1, this, Debug.ErrorLogLevel, "((((((Server State bitfield={0}; maxclient={1}; ServerStopped={2}))))))", - // server.State, - // MaxClients, - // ServerStopped); - if ((server.State & ServerState.SERVER_LISTENING) != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Waiting for next connection"); - server.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); - } } - - #endregion - - #region Methods - Send/Receive Callbacks - /// - /// Secure Received Data Async Callback - /// - /// - /// - /// - void TcpServerReceivedDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesReceived) + catch (Exception ex) { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); + } + onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); + } + + #endregion + + #region Methods Connected Callbacks + /// + /// Secure TCP Client Connected to Secure Server Callback + /// + /// + /// + void TcpConnectCallback(TCPServer server, uint clientIndex) + { + try + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectCallback: IPAddress: {0}. Index: {1}. Status: {2}", + server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), + clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); + if (clientIndex != 0) + { + if (server.ClientConnected(clientIndex)) + { + + if (!ConnectedClientsIndexes.Contains(clientIndex)) + { + ConnectedClientsIndexes.Add(clientIndex); + } + if (SharedKeyRequired) + { + if (!WaitingForSharedKey.Contains(clientIndex)) + { + WaitingForSharedKey.Add(clientIndex); + } + byte[] b = Encoding.GetEncoding(28591).GetBytes("SharedKey:"); + server.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Sent Shared Key Request to client at {0}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); + } + else + { + OnServerClientReadyForCommunications(clientIndex); + } + if (HeartbeatRequired) + { + if (!HeartbeatTimerDictionary.ContainsKey(clientIndex)) + { + HeartbeatTimerDictionary.Add(clientIndex, new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs)); + } + } + + server.ReceiveDataAsync(clientIndex, TcpServerReceivedDataAsyncCallback); + } + } + else + { + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); + if (!ServerStopped) + { + server.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); + return; + } + } + } + catch (Exception ex) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); + } + //Debug.Console(1, this, Debug.ErrorLogLevel, "((((((Server State bitfield={0}; maxclient={1}; ServerStopped={2}))))))", + // server.State, + // MaxClients, + // ServerStopped); + if ((server.State & ServerState.SERVER_LISTENING) != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Waiting for next connection"); + server.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); + + } + } + + #endregion + + #region Methods - Send/Receive Callbacks + /// + /// Secure Received Data Async Callback + /// + /// + /// + /// + void TcpServerReceivedDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesReceived) + { if (numberOfBytesReceived > 0) { string received = "Nothing"; @@ -831,181 +831,180 @@ namespace PepperDash.Core myTCPServer.Disconnect(); } - } + } - #endregion + #endregion - #region Methods - EventHelpers/Callbacks + #region Methods - EventHelpers/Callbacks - //Private Helper method to call the Connection Change Event - void onConnectionChange(uint clientIndex, SocketStatus clientStatus) + //Private Helper method to call the Connection Change Event + void onConnectionChange(uint clientIndex, SocketStatus clientStatus) + { + if (clientIndex != 0) //0 is error not valid client change { - if (clientIndex != 0) //0 is error not valid client change - { - var handler = ClientConnectionChange; - if (handler != null) - { - handler(this, new GenericTcpServerSocketStatusChangeEventArgs(myTcpServer, clientIndex, clientStatus)); - } - } - } - - //Private Helper method to call the Connection Change Event - void OnConnectionChange() - { - if (ProgramIsStopping) - { - return; - } var handler = ClientConnectionChange; if (handler != null) { - handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); + handler(this, new GenericTcpServerSocketStatusChangeEventArgs(myTcpServer, clientIndex, clientStatus)); } } + } - //Private Helper Method to call the Text Received Event - void onTextReceived(string text, uint clientIndex) + //Private Helper method to call the Connection Change Event + void OnConnectionChange() + { + if (ProgramIsStopping) { - var handler = TextReceived; - if (handler != null) - handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); + return; } - - //Private Helper Method to call the Server State Change Event - void OnServerStateChange(ServerState state) + var handler = ClientConnectionChange; + if (handler != null) { - if (ProgramIsStopping) - { - return; - } - var handler = ServerStateChange; - if (handler != null) - { - handler(this, new GenericTcpServerStateChangedEventArgs(state)); - } + handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); } + } - /// - /// Private Event Handler method to handle the closing of connections when the program stops - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + //Private Helper Method to call the Text Received Event + void onTextReceived(string text, uint clientIndex) + { + var handler = TextReceived; + if (handler != null) + handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); + } + + //Private Helper Method to call the Server State Change Event + void OnServerStateChange(ServerState state) + { + if (ProgramIsStopping) { - if (programEventType == eProgramStatusEventType.Stopping) - { - ProgramIsStopping = true; - // kill bandaid things - if (MonitorClientTimer != null) - MonitorClientTimer.Stop(); - if (MonitorClient != null) - MonitorClient.Disconnect(); - - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing server"); - KillServer(); - } + return; } - - //Private event handler method to raise the event that the server is ready to send data after a successful client shared key negotiation - void OnServerClientReadyForCommunications(uint clientIndex) + var handler = ServerStateChange; + if (handler != null) { - ClientReadyAfterKeyExchange.Add(clientIndex); - var handler = ServerClientReadyForCommunications; - if (handler != null) - handler(this, new GenericTcpServerSocketStatusChangeEventArgs( - this, clientIndex, myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex))); + handler(this, new GenericTcpServerStateChangedEventArgs(state)); } - #endregion + } - #region Monitor Client - /// - /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient - /// - void StartMonitorClient() + /// + /// Private Event Handler method to handle the closing of connections when the program stops + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) { + ProgramIsStopping = true; + // kill bandaid things if (MonitorClientTimer != null) - { - return; - } - MonitorClientTimer = new CTimer(o => RunMonitorClient(), 60000); - } - - /// - /// - /// - void RunMonitorClient() - { - MonitorClient = new GenericTcpIpClient_ForServer(Key + "-MONITOR", "127.0.0.1", Port, 2000); - MonitorClient.SharedKeyRequired = this.SharedKeyRequired; - MonitorClient.SharedKey = this.SharedKey; - MonitorClient.ConnectionHasHungCallback = MonitorClientHasHungCallback; - //MonitorClient.ConnectionChange += MonitorClient_ConnectionChange; - MonitorClient.ClientReadyForCommunications += MonitorClient_IsReadyForComm; - - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Starting monitor check"); - - MonitorClient.Connect(); - // From here MonitorCLient either connects or hangs, MonitorClient will call back - - } - - /// - /// - /// - void StopMonitorClient() - { - if (MonitorClient == null) - return; - - MonitorClient.ClientReadyForCommunications -= MonitorClient_IsReadyForComm; - MonitorClient.Disconnect(); - MonitorClient = null; - } - - /// - /// On monitor connect, restart the operation - /// - void MonitorClient_IsReadyForComm(object sender, GenericTcpServerClientReadyForcommunicationsEventArgs args) - { - if (args.IsReady) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Monitor client connection success. Disconnecting in 2s"); MonitorClientTimer.Stop(); - MonitorClientTimer = null; - MonitorClientFailureCount = 0; - CrestronEnvironment.Sleep(2000); - StopMonitorClient(); - StartMonitorClient(); - } - } + if (MonitorClient != null) + MonitorClient.Disconnect(); - /// - /// If the client hangs, add to counter and maybe fire the choke event - /// - void MonitorClientHasHungCallback() + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing server"); + KillServer(); + } + } + + //Private event handler method to raise the event that the server is ready to send data after a successful client shared key negotiation + void OnServerClientReadyForCommunications(uint clientIndex) + { + ClientReadyAfterKeyExchange.Add(clientIndex); + var handler = ServerClientReadyForCommunications; + if (handler != null) + handler(this, new GenericTcpServerSocketStatusChangeEventArgs( + this, clientIndex, myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex))); + } + #endregion + + #region Monitor Client + /// + /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient + /// + void StartMonitorClient() + { + if (MonitorClientTimer != null) { - MonitorClientFailureCount++; + return; + } + MonitorClientTimer = new CTimer(o => RunMonitorClient(), 60000); + } + + /// + /// + /// + void RunMonitorClient() + { + MonitorClient = new GenericTcpIpClient_ForServer(Key + "-MONITOR", "127.0.0.1", Port, 2000); + MonitorClient.SharedKeyRequired = this.SharedKeyRequired; + MonitorClient.SharedKey = this.SharedKey; + MonitorClient.ConnectionHasHungCallback = MonitorClientHasHungCallback; + //MonitorClient.ConnectionChange += MonitorClient_ConnectionChange; + MonitorClient.ClientReadyForCommunications += MonitorClient_IsReadyForComm; + + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Starting monitor check"); + + MonitorClient.Connect(); + // From here MonitorCLient either connects or hangs, MonitorClient will call back + + } + + /// + /// + /// + void StopMonitorClient() + { + if (MonitorClient == null) + return; + + MonitorClient.ClientReadyForCommunications -= MonitorClient_IsReadyForComm; + MonitorClient.Disconnect(); + MonitorClient = null; + } + + /// + /// On monitor connect, restart the operation + /// + void MonitorClient_IsReadyForComm(object sender, GenericTcpServerClientReadyForcommunicationsEventArgs args) + { + if (args.IsReady) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Monitor client connection success. Disconnecting in 2s"); MonitorClientTimer.Stop(); MonitorClientTimer = null; + MonitorClientFailureCount = 0; + CrestronEnvironment.Sleep(2000); StopMonitorClient(); - if (MonitorClientFailureCount < MonitorClientMaxFailureCount) - { - Debug.Console(2, this, Debug.ErrorLogLevel.Warning, "Monitor client connection has hung {0} time{1}, maximum {2}", - MonitorClientFailureCount, MonitorClientFailureCount > 1 ? "s" : "", MonitorClientMaxFailureCount); - StartMonitorClient(); - } - else - { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, - "\r***************************\rMonitor client connection has hung a maximum of {0} times.\r***************************", - MonitorClientMaxFailureCount); - - var handler = ServerHasChoked; - if (handler != null) - handler(); - // Some external thing is in charge here. Expected reset of program - } + StartMonitorClient(); } - #endregion } + + /// + /// If the client hangs, add to counter and maybe fire the choke event + /// + void MonitorClientHasHungCallback() + { + MonitorClientFailureCount++; + MonitorClientTimer.Stop(); + MonitorClientTimer = null; + StopMonitorClient(); + if (MonitorClientFailureCount < MonitorClientMaxFailureCount) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Warning, "Monitor client connection has hung {0} time{1}, maximum {2}", + MonitorClientFailureCount, MonitorClientFailureCount > 1 ? "s" : "", MonitorClientMaxFailureCount); + StartMonitorClient(); + } + else + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, + "\r***************************\rMonitor client connection has hung a maximum of {0} times.\r***************************", + MonitorClientMaxFailureCount); + + var handler = ServerHasChoked; + if (handler != null) + handler(); + // Some external thing is in charge here. Expected reset of program + } + } + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/GenericUdpServer.cs b/src/PepperDash.Core/Comm/GenericUdpServer.cs index a5a68c45..377b9cbe 100644 --- a/src/PepperDash.Core/Comm/GenericUdpServer.cs +++ b/src/PepperDash.Core/Comm/GenericUdpServer.cs @@ -8,347 +8,347 @@ using Crestron.SimplSharp.CrestronSockets; using Newtonsoft.Json; using PepperDash.Core.Logging; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Generic UDP Server device +/// +public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging { + private const string SplusKey = "Uninitialized Udp Server"; /// - /// Generic UDP Server device + /// Object to enable stream debugging /// - public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging - { - private const string SplusKey = "Uninitialized Udp Server"; - /// - /// Object to enable stream debugging - /// - public CommunicationStreamDebugging StreamDebugging { get; private set; } - /// - /// - /// - public event EventHandler BytesReceived; + public CommunicationStreamDebugging StreamDebugging { get; private set; } + /// + /// + /// + public event EventHandler BytesReceived; - /// - /// - /// - public event EventHandler TextReceived; + /// + /// + /// + public event EventHandler TextReceived; - /// - /// This event will fire when a message is dequeued that includes the source IP and Port info if needed to determine the source of the received data. - /// + /// + /// This event will fire when a message is dequeued that includes the source IP and Port info if needed to determine the source of the received data. + /// public event EventHandler DataRecievedExtra; - /// - /// - /// - public event EventHandler ConnectionChange; + /// + /// + /// + public event EventHandler ConnectionChange; - /// - /// - /// - public event EventHandler UpdateConnectionStatus; + /// + /// + /// + public event EventHandler UpdateConnectionStatus; - /// - /// - /// - public SocketStatus ClientStatus + /// + /// + /// + public SocketStatus ClientStatus + { + get { - get - { - return Server.ServerStatus; - } + return Server.ServerStatus; } - - /// - /// - /// - public ushort UStatus - { - get { return (ushort)Server.ServerStatus; } - } - - /// - /// Address of server - /// - public string Hostname { get; set; } - - - /// - /// Port on server - /// - public int Port { get; set; } - - /// - /// Another damn S+ helper because S+ seems to treat large port nums as signed ints - /// which screws up things - /// - public ushort UPort - { - get { return Convert.ToUInt16(Port); } - set { Port = Convert.ToInt32(value); } - } - - /// - /// Indicates that the UDP Server is enabled - /// - public bool IsConnected - { - get; - private set; - } - - /// - /// Numeric value indicating - /// - public ushort UIsConnected - { - get { return IsConnected ? (ushort)1 : (ushort)0; } - } - - /// - /// Defaults to 2000 - /// - public int BufferSize { get; set; } - - /// - /// The server - /// - public UDPServer Server { get; private set; } - - /// - /// Constructor for S+. Make sure to set key, address, port, and buffersize using init method - /// - public GenericUdpServer() - : base(SplusKey) - { - StreamDebugging = new CommunicationStreamDebugging(SplusKey); - BufferSize = 5000; - - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); - } - - /// - /// - /// - /// - /// - /// - /// - public GenericUdpServer(string key, string address, int port, int buffefSize) - : base(key) - { - StreamDebugging = new CommunicationStreamDebugging(key); - Hostname = address; - Port = port; - BufferSize = buffefSize; - - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); - } - - /// - /// Call from S+ to initialize values - /// - /// - /// - /// - public void Initialize(string key, string address, ushort port) - { - Key = key; - Hostname = address; - UPort = port; - } - - /// - /// - /// - /// - void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) - { - // Re-enable the server if the link comes back up and the status should be connected - if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp - && IsConnected) - { - Connect(); - } - } - - /// - /// - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType != eProgramStatusEventType.Stopping) - return; - - Debug.Console(1, this, "Program stopping. Disabling Server"); - Disconnect(); - } - - /// - /// Enables the UDP Server - /// - public void Connect() - { - if (Server == null) - { - Server = new UDPServer(); - } - - if (string.IsNullOrEmpty(Hostname)) - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key); - return; - } - if (Port < 1 || Port > 65535) - { - { - Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key); - return; - } - } - - var status = Server.EnableUDPServer(Hostname, Port); - - Debug.Console(2, this, "SocketErrorCode: {0}", status); - if (status == SocketErrorCodes.SOCKET_OK) - IsConnected = true; - - var handler = UpdateConnectionStatus; - if (handler != null) - handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); - - // Start receiving data - Server.ReceiveDataAsync(Receive); - } - - /// - /// Disabled the UDP Server - /// - public void Disconnect() - { - if(Server != null) - Server.DisableUDPServer(); - - IsConnected = false; - - var handler = UpdateConnectionStatus; - if (handler != null) - handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); - } - - - /// - /// Recursive method to receive data - /// - /// - /// - void Receive(UDPServer server, int numBytes) - { - Debug.Console(2, this, "Received {0} bytes", numBytes); - - try - { - if (numBytes <= 0) - return; - - var sourceIp = Server.IPAddressLastMessageReceivedFrom; - var sourcePort = Server.IPPortLastMessageReceivedFrom; - var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray(); - var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - - var dataRecivedExtra = DataRecievedExtra; - if (dataRecivedExtra != null) - dataRecivedExtra(this, new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes)); - - Debug.Console(2, this, "Bytes: {0}", bytes.ToString()); - var bytesHandler = BytesReceived; - if (bytesHandler != null) - { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); - } - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - } - var textHandler = TextReceived; - if (textHandler != null) - { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } - } - catch (Exception ex) - { - this.LogException(ex, "GenericUdpServer Receive error"); - } - finally - { - server.ReceiveDataAsync(Receive); - } - } - - /// - /// General send method - /// - /// - public void SendText(string text) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - - if (IsConnected && Server != null) - { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); - - Server.SendData(bytes, bytes.Length); - } - } - - /// - /// - /// - /// - public void SendBytes(byte[] bytes) - { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); - - if (IsConnected && Server != null) - Server.SendData(bytes, bytes.Length); - } - } /// /// /// + public ushort UStatus + { + get { return (ushort)Server.ServerStatus; } + } + + /// + /// Address of server + /// + public string Hostname { get; set; } + + + /// + /// Port on server + /// + public int Port { get; set; } + + /// + /// Another damn S+ helper because S+ seems to treat large port nums as signed ints + /// which screws up things + /// + public ushort UPort + { + get { return Convert.ToUInt16(Port); } + set { Port = Convert.ToInt32(value); } + } + + /// + /// Indicates that the UDP Server is enabled + /// + public bool IsConnected + { + get; + private set; + } + + /// + /// Numeric value indicating + /// + public ushort UIsConnected + { + get { return IsConnected ? (ushort)1 : (ushort)0; } + } + + /// + /// Defaults to 2000 + /// + public int BufferSize { get; set; } + + /// + /// The server + /// + public UDPServer Server { get; private set; } + + /// + /// Constructor for S+. Make sure to set key, address, port, and buffersize using init method + /// + public GenericUdpServer() + : base(SplusKey) + { + StreamDebugging = new CommunicationStreamDebugging(SplusKey); + BufferSize = 5000; + + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + } + + /// + /// + /// + /// + /// + /// + /// + public GenericUdpServer(string key, string address, int port, int buffefSize) + : base(key) + { + StreamDebugging = new CommunicationStreamDebugging(key); + Hostname = address; + Port = port; + BufferSize = buffefSize; + + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + } + + /// + /// Call from S+ to initialize values + /// + /// + /// + /// + public void Initialize(string key, string address, ushort port) + { + Key = key; + Hostname = address; + UPort = port; + } + + /// + /// + /// + /// + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + { + // Re-enable the server if the link comes back up and the status should be connected + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp + && IsConnected) + { + Connect(); + } + } + + /// + /// + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType != eProgramStatusEventType.Stopping) + return; + + Debug.Console(1, this, "Program stopping. Disabling Server"); + Disconnect(); + } + + /// + /// Enables the UDP Server + /// + public void Connect() + { + if (Server == null) + { + Server = new UDPServer(); + } + + if (string.IsNullOrEmpty(Hostname)) + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key); + return; + } + if (Port < 1 || Port > 65535) + { + { + Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key); + return; + } + } + + var status = Server.EnableUDPServer(Hostname, Port); + + Debug.Console(2, this, "SocketErrorCode: {0}", status); + if (status == SocketErrorCodes.SOCKET_OK) + IsConnected = true; + + var handler = UpdateConnectionStatus; + if (handler != null) + handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); + + // Start receiving data + Server.ReceiveDataAsync(Receive); + } + + /// + /// Disabled the UDP Server + /// + public void Disconnect() + { + if(Server != null) + Server.DisableUDPServer(); + + IsConnected = false; + + var handler = UpdateConnectionStatus; + if (handler != null) + handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); + } + + + /// + /// Recursive method to receive data + /// + /// + /// + void Receive(UDPServer server, int numBytes) + { + Debug.Console(2, this, "Received {0} bytes", numBytes); + + try + { + if (numBytes <= 0) + return; + + var sourceIp = Server.IPAddressLastMessageReceivedFrom; + var sourcePort = Server.IPPortLastMessageReceivedFrom; + var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray(); + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + + var dataRecivedExtra = DataRecievedExtra; + if (dataRecivedExtra != null) + dataRecivedExtra(this, new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes)); + + Debug.Console(2, this, "Bytes: {0}", bytes.ToString()); + var bytesHandler = BytesReceived; + if (bytesHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); + } + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + var textHandler = TextReceived; + if (textHandler != null) + { + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length); + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + catch (Exception ex) + { + this.LogException(ex, "GenericUdpServer Receive error"); + } + finally + { + server.ReceiveDataAsync(Receive); + } + } + + /// + /// General send method + /// + /// + public void SendText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + + if (IsConnected && Server != null) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + + Server.SendData(bytes, bytes.Length); + } + } + + /// + /// + /// + /// + public void SendBytes(byte[] bytes) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + + if (IsConnected && Server != null) + Server.SendData(bytes, bytes.Length); + } + +} + +/// +/// +/// public class GenericUdpReceiveTextExtraArgs : EventArgs { - /// - /// - /// + /// + /// + /// public string Text { get; private set; } - /// - /// - /// + /// + /// + /// public string IpAddress { get; private set; } - /// - /// - /// + /// + /// + /// public int Port { get; private set; } - /// - /// - /// + /// + /// + /// public byte[] Bytes { get; private set; } - /// - /// - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// + /// + /// public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes) { Text = text; @@ -363,34 +363,33 @@ namespace PepperDash.Core public GenericUdpReceiveTextExtraArgs() { } } +/// +/// +/// +public class UdpServerPropertiesConfig +{ /// /// /// - public class UdpServerPropertiesConfig + [JsonProperty(Required = Required.Always)] + public string Address { get; set; } + + /// + /// + /// + [JsonProperty(Required = Required.Always)] + public int Port { get; set; } + + /// + /// Defaults to 32768 + /// + public int BufferSize { get; set; } + + /// + /// + /// + public UdpServerPropertiesConfig() { - /// - /// - /// - [JsonProperty(Required = Required.Always)] - public string Address { get; set; } - - /// - /// - /// - [JsonProperty(Required = Required.Always)] - public int Port { get; set; } - - /// - /// Defaults to 32768 - /// - public int BufferSize { get; set; } - - /// - /// - /// - public UdpServerPropertiesConfig() - { - BufferSize = 32768; - } + BufferSize = 32768; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/TcpClientConfigObject.cs b/src/PepperDash.Core/Comm/TcpClientConfigObject.cs index c3b3bcec..a4382938 100644 --- a/src/PepperDash.Core/Comm/TcpClientConfigObject.cs +++ b/src/PepperDash.Core/Comm/TcpClientConfigObject.cs @@ -1,59 +1,58 @@ using Newtonsoft.Json; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat +/// +public class TcpClientConfigObject { /// - /// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat + /// TcpSsh Properties /// - public class TcpClientConfigObject - { - /// - /// TcpSsh Properties - /// - [JsonProperty("control")] - public ControlPropertiesConfig Control { get; set; } + [JsonProperty("control")] + public ControlPropertiesConfig Control { get; set; } - /// - /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic - /// - [JsonProperty("secure")] - public bool Secure { get; set; } + /// + /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic + /// + [JsonProperty("secure")] + public bool Secure { get; set; } - /// - /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client - /// - [JsonProperty("sharedKeyRequired")] - public bool SharedKeyRequired { get; set; } + /// + /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client + /// + [JsonProperty("sharedKeyRequired")] + public bool SharedKeyRequired { get; set; } - /// - /// The shared key that must match on the server and client - /// - [JsonProperty("sharedKey")] - public string SharedKey { get; set; } + /// + /// The shared key that must match on the server and client + /// + [JsonProperty("sharedKey")] + public string SharedKey { get; set; } - /// - /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. - /// heartbeats do not raise received events. - /// - [JsonProperty("heartbeatRequired")] - public bool HeartbeatRequired { get; set; } + /// + /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. + /// heartbeats do not raise received events. + /// + [JsonProperty("heartbeatRequired")] + public bool HeartbeatRequired { get; set; } - /// - /// The interval in seconds for the heartbeat from the client. If not received client is disconnected - /// - [JsonProperty("heartbeatRequiredIntervalInSeconds")] - public ushort HeartbeatRequiredIntervalInSeconds { get; set; } + /// + /// The interval in seconds for the heartbeat from the client. If not received client is disconnected + /// + [JsonProperty("heartbeatRequiredIntervalInSeconds")] + public ushort HeartbeatRequiredIntervalInSeconds { get; set; } - /// - /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. - /// - [JsonProperty("heartbeatStringToMatch")] - public string HeartbeatStringToMatch { get; set; } + /// + /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. + /// + [JsonProperty("heartbeatStringToMatch")] + public string HeartbeatStringToMatch { get; set; } - /// - /// Receive Queue size must be greater than 20 or defaults to 20 - /// - [JsonProperty("receiveQueueSize")] - public int ReceiveQueueSize { get; set; } - } + /// + /// Receive Queue size must be greater than 20 or defaults to 20 + /// + [JsonProperty("receiveQueueSize")] + public int ReceiveQueueSize { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/TcpServerConfigObject.cs b/src/PepperDash.Core/Comm/TcpServerConfigObject.cs index 043cf58d..b60f486f 100644 --- a/src/PepperDash.Core/Comm/TcpServerConfigObject.cs +++ b/src/PepperDash.Core/Comm/TcpServerConfigObject.cs @@ -4,57 +4,56 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities +/// +public class TcpServerConfigObject { /// - /// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities + /// Uique key /// - public class TcpServerConfigObject - { - /// - /// Uique key - /// - public string Key { get; set; } - /// - /// Max Clients that the server will allow to connect. - /// - public ushort MaxClients { get; set; } - /// - /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic - /// - public bool Secure { get; set; } - /// - /// Port for the server to listen on - /// - public int Port { get; set; } - /// - /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client - /// - public bool SharedKeyRequired { get; set; } - /// - /// The shared key that must match on the server and client - /// - public string SharedKey { get; set; } - /// - /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. - /// heartbeats do not raise received events. - /// - public bool HeartbeatRequired { get; set; } - /// - /// The interval in seconds for the heartbeat from the client. If not received client is disconnected - /// - public ushort HeartbeatRequiredIntervalInSeconds { get; set; } - /// - /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. - /// - public string HeartbeatStringToMatch { get; set; } - /// - /// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000 - /// - public int BufferSize { get; set; } - /// - /// Receive Queue size must be greater than 20 or defaults to 20 - /// - public int ReceiveQueueSize { get; set; } - } + public string Key { get; set; } + /// + /// Max Clients that the server will allow to connect. + /// + public ushort MaxClients { get; set; } + /// + /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic + /// + public bool Secure { get; set; } + /// + /// Port for the server to listen on + /// + public int Port { get; set; } + /// + /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client + /// + public bool SharedKeyRequired { get; set; } + /// + /// The shared key that must match on the server and client + /// + public string SharedKey { get; set; } + /// + /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. + /// heartbeats do not raise received events. + /// + public bool HeartbeatRequired { get; set; } + /// + /// The interval in seconds for the heartbeat from the client. If not received client is disconnected + /// + public ushort HeartbeatRequiredIntervalInSeconds { get; set; } + /// + /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. + /// + public string HeartbeatStringToMatch { get; set; } + /// + /// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000 + /// + public int BufferSize { get; set; } + /// + /// Receive Queue size must be greater than 20 or defaults to 20 + /// + public int ReceiveQueueSize { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Comm/eControlMethods.cs b/src/PepperDash.Core/Comm/eControlMethods.cs index 28a95b12..bdf6d79e 100644 --- a/src/PepperDash.Core/Comm/eControlMethods.cs +++ b/src/PepperDash.Core/Comm/eControlMethods.cs @@ -4,76 +4,75 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Crestron Control Methods for a comm object +/// +public enum eControlMethod { /// - /// Crestron Control Methods for a comm object + /// /// - public enum eControlMethod - { - /// - /// - /// - None = 0, - /// - /// RS232/422/485 - /// - Com, - /// - /// Crestron IpId (most Crestron ethernet devices) - /// - IpId, - /// - /// Crestron IpIdTcp (HD-MD series, etc.) - /// - IpidTcp, - /// - /// Crestron IR control - /// - IR, - /// - /// SSH client - /// - Ssh, - /// - /// TCP/IP client - /// - Tcpip, - /// - /// Telnet - /// - Telnet, - /// - /// Crestnet device - /// - Cresnet, - /// - /// CEC Control, via a DM HDMI port - /// - Cec, - /// - /// UDP Server - /// - Udp, - /// - /// HTTP client - /// - Http, - /// - /// HTTPS client - /// - Https, - /// - /// Websocket client - /// - Ws, - /// - /// Secure Websocket client - /// - Wss, - /// - /// Secure TCP/IP - /// - SecureTcpIp - } + None = 0, + /// + /// RS232/422/485 + /// + Com, + /// + /// Crestron IpId (most Crestron ethernet devices) + /// + IpId, + /// + /// Crestron IpIdTcp (HD-MD series, etc.) + /// + IpidTcp, + /// + /// Crestron IR control + /// + IR, + /// + /// SSH client + /// + Ssh, + /// + /// TCP/IP client + /// + Tcpip, + /// + /// Telnet + /// + Telnet, + /// + /// Crestnet device + /// + Cresnet, + /// + /// CEC Control, via a DM HDMI port + /// + Cec, + /// + /// UDP Server + /// + Udp, + /// + /// HTTP client + /// + Http, + /// + /// HTTPS client + /// + Https, + /// + /// Websocket client + /// + Ws, + /// + /// Secure Websocket client + /// + Wss, + /// + /// Secure TCP/IP + /// + SecureTcpIp } \ No newline at end of file diff --git a/src/PepperDash.Core/CommunicationExtras.cs b/src/PepperDash.Core/CommunicationExtras.cs index 81fd76c5..f17e1da0 100644 --- a/src/PepperDash.Core/CommunicationExtras.cs +++ b/src/PepperDash.Core/CommunicationExtras.cs @@ -7,74 +7,74 @@ using Crestron.SimplSharp.CrestronSockets; using System.Text.RegularExpressions; using Newtonsoft.Json; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// An incoming communication stream +/// +public interface ICommunicationReceiver : IKeyed { /// - /// An incoming communication stream + /// Notifies of bytes received /// - public interface ICommunicationReceiver : IKeyed - { - /// - /// Notifies of bytes received - /// - event EventHandler BytesReceived; - /// - /// Notifies of text received - /// - event EventHandler TextReceived; + event EventHandler BytesReceived; + /// + /// Notifies of text received + /// + event EventHandler TextReceived; - /// - /// Indicates connection status - /// - [JsonProperty("isConnected")] - bool IsConnected { get; } - /// - /// Connect to the device - /// - void Connect(); - /// - /// Disconnect from the device - /// - void Disconnect(); - } + /// + /// Indicates connection status + /// + [JsonProperty("isConnected")] + bool IsConnected { get; } + /// + /// Connect to the device + /// + void Connect(); + /// + /// Disconnect from the device + /// + void Disconnect(); +} /// /// Represents a device that uses basic connection /// - public interface IBasicCommunication : ICommunicationReceiver +public interface IBasicCommunication : ICommunicationReceiver { - /// - /// Send text to the device - /// - /// + /// + /// Send text to the device + /// + /// void SendText(string text); - /// - /// Send bytes to the device - /// - /// + /// + /// Send bytes to the device + /// + /// void SendBytes(byte[] bytes); } - /// - /// Represents a device that implements IBasicCommunication and IStreamDebugging - /// - public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging - { +/// +/// Represents a device that implements IBasicCommunication and IStreamDebugging +/// +public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging +{ - } +} +/// +/// Represents a device with stream debugging capablities +/// +public interface IStreamDebugging +{ /// - /// Represents a device with stream debugging capablities + /// Object to enable stream debugging /// - public interface IStreamDebugging - { - /// - /// Object to enable stream debugging - /// - [JsonProperty("streamDebugging")] - CommunicationStreamDebugging StreamDebugging { get; } - } + [JsonProperty("streamDebugging")] + CommunicationStreamDebugging StreamDebugging { get; } +} /// /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, @@ -82,41 +82,41 @@ namespace PepperDash.Core /// public interface ISocketStatus : IBasicCommunication { - /// - /// Notifies of socket status changes - /// + /// + /// Notifies of socket status changes + /// event EventHandler ConnectionChange; - /// - /// The current socket status of the client - /// - [JsonProperty("clientStatus")] - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - SocketStatus ClientStatus { get; } + /// + /// The current socket status of the client + /// + [JsonProperty("clientStatus")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + SocketStatus ClientStatus { get; } } - /// - /// Describes a device that implements ISocketStatus and IStreamDebugging - /// - public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging - { +/// +/// Describes a device that implements ISocketStatus and IStreamDebugging +/// +public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging +{ - } +} - /// - /// Describes a device that can automatically attempt to reconnect - /// +/// +/// Describes a device that can automatically attempt to reconnect +/// public interface IAutoReconnect { - /// - /// Enable automatic recconnect - /// - [JsonProperty("autoReconnect")] + /// + /// Enable automatic recconnect + /// + [JsonProperty("autoReconnect")] bool AutoReconnect { get; set; } - /// - /// Interval in ms to attempt automatic recconnections - /// - [JsonProperty("autoReconnectIntervalMs")] + /// + /// Interval in ms to attempt automatic recconnections + /// + [JsonProperty("autoReconnectIntervalMs")] int AutoReconnectIntervalMs { get; set; } } @@ -125,14 +125,14 @@ namespace PepperDash.Core /// public enum eGenericCommMethodStatusChangeType { - /// - /// Connected - /// + /// + /// Connected + /// Connected, - /// - /// Disconnected - /// - Disconnected + /// + /// Disconnected + /// + Disconnected } /// @@ -147,15 +147,15 @@ namespace PepperDash.Core /// public class GenericCommMethodReceiveBytesArgs : EventArgs { - /// - /// - /// + /// + /// + /// public byte[] Bytes { get; private set; } - /// - /// - /// - /// + /// + /// + /// + /// public GenericCommMethodReceiveBytesArgs(byte[] bytes) { Bytes = bytes; @@ -172,33 +172,33 @@ namespace PepperDash.Core /// public class GenericCommMethodReceiveTextArgs : EventArgs { - /// - /// - /// + /// + /// + /// public string Text { get; private set; } - /// - /// - /// - public string Delimiter { get; private set; } - /// - /// - /// - /// + /// + /// + /// + public string Delimiter { get; private set; } + /// + /// + /// + /// public GenericCommMethodReceiveTextArgs(string text) { Text = text; } - /// - /// - /// - /// - /// - public GenericCommMethodReceiveTextArgs(string text, string delimiter) - :this(text) - { - Delimiter = delimiter; - } + /// + /// + /// + /// + /// + public GenericCommMethodReceiveTextArgs(string text, string delimiter) + :this(text) + { + Delimiter = delimiter; + } /// /// S+ Constructor @@ -213,35 +213,34 @@ namespace PepperDash.Core /// public class ComTextHelper { - /// - /// Gets escaped text for a byte array - /// - /// - /// + /// + /// Gets escaped text for a byte array + /// + /// + /// public static string GetEscapedText(byte[] bytes) { return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); } - /// - /// Gets escaped text for a string - /// - /// - /// + /// + /// Gets escaped text for a string + /// + /// + /// public static string GetEscapedText(string text) { var bytes = Encoding.GetEncoding(28591).GetBytes(text); return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); } - /// - /// Gets debug text for a string - /// - /// - /// - public static string GetDebugText(string text) - { - return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); - } - } -} \ No newline at end of file + /// + /// Gets debug text for a string + /// + /// + /// + public static string GetDebugText(string text) + { + return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); + } + } \ No newline at end of file diff --git a/src/PepperDash.Core/Config/PortalConfigReader.cs b/src/PepperDash.Core/Config/PortalConfigReader.cs index 43e9ea1e..3094e5df 100644 --- a/src/PepperDash.Core/Config/PortalConfigReader.cs +++ b/src/PepperDash.Core/Config/PortalConfigReader.cs @@ -7,11 +7,11 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Core.Config -{ - /// - /// Reads a Portal formatted config file - /// +namespace PepperDash.Core.Config; + +/// +/// Reads a Portal formatted config file +/// public class PortalConfigReader { /// @@ -100,31 +100,31 @@ namespace PepperDash.Core.Config Merge(template["destinationLists"], system["destinationLists"], "destinationLists")); - if (system["cameraLists"] == null) - merged.Add("cameraLists", template["cameraLists"]); - else - merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists")); + if (system["cameraLists"] == null) + merged.Add("cameraLists", template["cameraLists"]); + else + merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists")); - if (system["audioControlPointLists"] == null) - merged.Add("audioControlPointLists", template["audioControlPointLists"]); - else - merged.Add("audioControlPointLists", - Merge(template["audioControlPointLists"], system["audioControlPointLists"], "audioControlPointLists")); + if (system["audioControlPointLists"] == null) + merged.Add("audioControlPointLists", template["audioControlPointLists"]); + else + merged.Add("audioControlPointLists", + Merge(template["audioControlPointLists"], system["audioControlPointLists"], "audioControlPointLists")); - // Template tie lines take precedence. Config tool doesn't do them at system - // level anyway... - if (template["tieLines"] != null) + // Template tie lines take precedence. Config tool doesn't do them at system + // level anyway... + if (template["tieLines"] != null) merged.Add("tieLines", template["tieLines"]); else if (system["tieLines"] != null) merged.Add("tieLines", system["tieLines"]); else merged.Add("tieLines", new JArray()); - if (template["joinMaps"] != null) - merged.Add("joinMaps", template["joinMaps"]); - else - merged.Add("joinMaps", new JObject()); + if (template["joinMaps"] != null) + merged.Add("joinMaps", template["joinMaps"]); + else + merged.Add("joinMaps", new JObject()); if (system["global"] != null) merged.Add("global", Merge(template["global"], system["global"], "global")); @@ -147,26 +147,26 @@ namespace PepperDash.Core.Config return a1; else if (a1 != null) { - if (a2[0]["key"] == null) // If the first item in the system array has no key, overwrite the template array - { // with the system array - return a2; - } - else // The arrays are keyed, merge them by key + if (a2[0]["key"] == null) // If the first item in the system array has no key, overwrite the template array + { // with the system array + return a2; + } + else // The arrays are keyed, merge them by key + { + for (int i = 0; i < a1.Count(); i++) { - for (int i = 0; i < a1.Count(); i++) + var a1Dev = a1[i]; + // Try to get a system device and if found, merge it onto template + var a2Match = a2.FirstOrDefault(t => t[propertyName].Equals(a1Dev[propertyName]));// t.Value("uid") == tmplDev.Value("uid")); + if (a2Match != null) { - var a1Dev = a1[i]; - // Try to get a system device and if found, merge it onto template - var a2Match = a2.FirstOrDefault(t => t[propertyName].Equals(a1Dev[propertyName]));// t.Value("uid") == tmplDev.Value("uid")); - if (a2Match != null) - { - var mergedItem = Merge(a1Dev, a2Match, string.Format("{0}[{1}].", path, i));// Merge(JObject.FromObject(a1Dev), JObject.FromObject(a2Match)); - result.Add(mergedItem); - } - else - result.Add(a1Dev); + var mergedItem = Merge(a1Dev, a2Match, string.Format("{0}[{1}].", path, i));// Merge(JObject.FromObject(a1Dev), JObject.FromObject(a2Match)); + result.Add(mergedItem); } + else + result.Add(a1Dev); } + } } return result; } @@ -183,9 +183,9 @@ namespace PepperDash.Core.Config /// /// Merge o2 onto o1 /// - /// - /// - /// + /// + /// + /// static JObject Merge(JObject o1, JObject o2, string path) { foreach (var o2Prop in o2) @@ -231,5 +231,4 @@ namespace PepperDash.Core.Config } return o1; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Conversion/Convert.cs b/src/PepperDash.Core/Conversion/Convert.cs index 2bafdcb0..13ef7263 100644 --- a/src/PepperDash.Core/Conversion/Convert.cs +++ b/src/PepperDash.Core/Conversion/Convert.cs @@ -4,19 +4,18 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core +namespace PepperDash.Core; + +public class EncodingHelper { - public class EncodingHelper + public static string ConvertUtf8ToAscii(string utf8String) { - public static string ConvertUtf8ToAscii(string utf8String) - { - return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); - } - - public static string ConvertUtf8ToUtf16(string utf8String) - { - return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); - } - + return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); } + + public static string ConvertUtf8ToUtf16(string utf8String) + { + return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); + } + } \ No newline at end of file diff --git a/src/PepperDash.Core/CoreInterfaces.cs b/src/PepperDash.Core/CoreInterfaces.cs index b142c69a..b66890c8 100644 --- a/src/PepperDash.Core/CoreInterfaces.cs +++ b/src/PepperDash.Core/CoreInterfaces.cs @@ -6,30 +6,28 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using Serilog; -namespace PepperDash.Core -{ - /// - /// Unique key interface to require a unique key for the class - /// +namespace PepperDash.Core; + +/// +/// Unique key interface to require a unique key for the class +/// public interface IKeyed { - /// - /// Gets the unique key associated with the object. - /// - [JsonProperty("key")] - string Key { get; } - } - - /// - /// Named Keyed device interface. Forces the device to have a Unique Key and a name. + /// + /// Gets the unique key associated with the object. /// - public interface IKeyName : IKeyed - { - /// - /// Gets the name associated with the current object. - /// - [JsonProperty("name")] - string Name { get; } - } + [JsonProperty("key")] + string Key { get; } +} +/// +/// Named Keyed device interface. Forces the device to have a Unique Key and a name. +/// + public interface IKeyName : IKeyed +{ + /// + /// Gets the name associated with the current object. + /// + [JsonProperty("name")] + string Name { get; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Device.cs b/src/PepperDash.Core/Device.cs index ef9f6111..8ea63265 100644 --- a/src/PepperDash.Core/Device.cs +++ b/src/PepperDash.Core/Device.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using Serilog.Events; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + //********************************************************************************************************* /// /// The core event and status-bearing class that most if not all device and connectors can derive from. @@ -178,15 +178,14 @@ namespace PepperDash.Core if (o is bool && !(bool)o) a(); } - /// - /// Returns a string representation of the object, including its key and name. - /// - /// The returned string is formatted as "{Key} - {Name}". If the Name property is - /// null or empty, "---" is used in place of the name. - /// A string that represents the object, containing the key and name in the format "{Key} - {Name}". + /// + /// Returns a string representation of the object, including its key and name. + /// + /// The returned string is formatted as "{Key} - {Name}". If the Name property is + /// null or empty, "---" is used in place of the name. + /// A string that represents the object, containing the key and name in the format "{Key} - {Name}". public override string ToString() { return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/EthernetHelper.cs b/src/PepperDash.Core/EthernetHelper.cs index 88429886..67c337bd 100644 --- a/src/PepperDash.Core/EthernetHelper.cs +++ b/src/PepperDash.Core/EthernetHelper.cs @@ -2,11 +2,11 @@ using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Core -{ - /// - /// Class to help with accessing values from the CrestronEthernetHelper class - /// +namespace PepperDash.Core; + +/// +/// Class to help with accessing values from the CrestronEthernetHelper class +/// public class EthernetHelper { /// @@ -113,5 +113,4 @@ namespace PepperDash.Core CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/EventArgs.cs b/src/PepperDash.Core/EventArgs.cs index 29ef13a8..adbfb5c8 100644 --- a/src/PepperDash.Core/EventArgs.cs +++ b/src/PepperDash.Core/EventArgs.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + /// /// Bool change event args /// @@ -168,5 +168,4 @@ namespace PepperDash.Core Type = type; Index = index; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs b/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs index 1b78c33f..d8a09e4e 100644 --- a/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs +++ b/src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs @@ -4,13 +4,13 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.GenericRESTfulCommunications -{ +namespace PepperDash.Core.GenericRESTfulCommunications; + /// /// Constants /// - public class GenericRESTfulConstants - { +public class GenericRESTfulConstants +{ /// /// Generic boolean change /// @@ -35,5 +35,4 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// Error string change /// public const ushort ErrorStringChange = 203; - } } \ No newline at end of file diff --git a/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs b/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs index bd33e13c..16a2ee04 100644 --- a/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs +++ b/src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Https; -namespace PepperDash.Core.GenericRESTfulCommunications -{ +namespace PepperDash.Core.GenericRESTfulCommunications; + /// /// Generic RESTful communication class /// @@ -42,7 +42,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// /// /// - /// + /// public void SubmitRequest(string url, ushort port, ushort requestType, string contentType, string username, string password) { if (url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) @@ -65,7 +65,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// /// /// - /// + /// /// /// private void SubmitRequestHttp(string url, ushort port, ushort requestType, string contentType, string username, string password) @@ -123,7 +123,7 @@ namespace PepperDash.Core.GenericRESTfulCommunications /// /// /// - /// + /// /// /// private void SubmitRequestHttps(string url, ushort port, ushort requestType, string contentType, string username, string password) @@ -252,5 +252,4 @@ namespace PepperDash.Core.GenericRESTfulCommunications StringChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs b/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs index ed02ccb0..a41345dc 100644 --- a/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs +++ b/src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.JsonStandardObjects -{ +namespace PepperDash.Core.JsonStandardObjects; + /// /// Constants for simpl modules /// @@ -73,5 +73,4 @@ namespace PepperDash.Core.JsonStandardObjects Type = type; Index = index; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs index 3abfd36a..591cbd5c 100644 --- a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs +++ b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharp; using PepperDash.Core.JsonToSimpl; using Serilog.Events; -namespace PepperDash.Core.JsonStandardObjects -{ +namespace PepperDash.Core.JsonStandardObjects; + /// /// Device class /// @@ -179,5 +179,4 @@ namespace PepperDash.Core.JsonStandardObjects } #endregion EventHandler Helpers - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs index fa23d87e..6f1f74c4 100644 --- a/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs +++ b/src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.JsonStandardObjects -{ +namespace PepperDash.Core.JsonStandardObjects; + /* Convert JSON snippt to C#: http://json2csharp.com/# @@ -52,55 +52,55 @@ namespace PepperDash.Core.JsonStandardObjects /// public class ComParamsConfig { - /// - /// - /// + /// + /// + /// public int baudRate { get; set; } - /// - /// - /// + /// + /// + /// public int dataBits { get; set; } - /// - /// - /// + /// + /// + /// public int stopBits { get; set; } - /// - /// - /// + /// + /// + /// public string parity { get; set; } - /// - /// - /// + /// + /// + /// public string protocol { get; set; } - /// - /// - /// + /// + /// + /// public string hardwareHandshake { get; set; } - /// - /// - /// + /// + /// + /// public string softwareHandshake { get; set; } - /// - /// - /// + /// + /// + /// public int pacing { get; set; } // convert properties for simpl - /// - /// - /// + /// + /// + /// public ushort simplBaudRate { get { return Convert.ToUInt16(baudRate); } } - /// - /// - /// + /// + /// + /// public ushort simplDataBits { get { return Convert.ToUInt16(dataBits); } } - /// - /// - /// + /// + /// + /// public ushort simplStopBits { get { return Convert.ToUInt16(stopBits); } } - /// - /// - /// + /// + /// + /// public ushort simplPacing { get { return Convert.ToUInt16(pacing); } } /// @@ -117,43 +117,43 @@ namespace PepperDash.Core.JsonStandardObjects /// public class TcpSshPropertiesConfig { - /// - /// - /// + /// + /// + /// public string address { get; set; } - /// - /// - /// + /// + /// + /// public int port { get; set; } - /// - /// - /// + /// + /// + /// public string username { get; set; } - /// - /// - /// + /// + /// + /// public string password { get; set; } - /// - /// - /// + /// + /// + /// public bool autoReconnect { get; set; } - /// - /// - /// + /// + /// + /// public int autoReconnectIntervalMs { get; set; } // convert properties for simpl - /// - /// - /// + /// + /// + /// public ushort simplPort { get { return Convert.ToUInt16(port); } } - /// - /// - /// + /// + /// + /// public ushort simplAutoReconnect { get { return (ushort)(autoReconnect ? 1 : 0); } } - /// - /// - /// + /// + /// + /// public ushort simplAutoReconnectIntervalMs { get { return Convert.ToUInt16(autoReconnectIntervalMs); } } /// @@ -170,31 +170,31 @@ namespace PepperDash.Core.JsonStandardObjects /// public class ControlConfig { - /// - /// - /// + /// + /// + /// public string method { get; set; } - /// - /// - /// + /// + /// + /// public string controlPortDevKey { get; set; } - /// - /// - /// + /// + /// + /// public int controlPortNumber { get; set; } - /// - /// - /// + /// + /// + /// public ComParamsConfig comParams { get; set; } - /// - /// - /// + /// + /// + /// public TcpSshPropertiesConfig tcpSshProperties { get; set; } // convert properties for simpl - /// - /// - /// + /// + /// + /// public ushort simplControlPortNumber { get { return Convert.ToUInt16(controlPortNumber); } } /// @@ -212,27 +212,27 @@ namespace PepperDash.Core.JsonStandardObjects /// public class PropertiesConfig { - /// - /// - /// + /// + /// + /// public int deviceId { get; set; } - /// - /// - /// + /// + /// + /// public bool enabled { get; set; } - /// - /// - /// + /// + /// + /// public ControlConfig control { get; set; } // convert properties for simpl - /// - /// - /// + /// + /// + /// public ushort simplDeviceId { get { return Convert.ToUInt16(deviceId); } } - /// - /// - /// + /// + /// + /// public ushort simplEnabled { get { return (ushort)(enabled ? 1 : 0); } } /// @@ -249,9 +249,8 @@ namespace PepperDash.Core.JsonStandardObjects /// public class RootObject { - /// - /// The collection of devices - /// + /// + /// The collection of devices + /// public List devices { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/Constants.cs b/src/PepperDash.Core/JsonToSimpl/Constants.cs index d87b50c2..9b8d08ff 100644 --- a/src/PepperDash.Core/JsonToSimpl/Constants.cs +++ b/src/PepperDash.Core/JsonToSimpl/Constants.cs @@ -4,78 +4,78 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.JsonToSimpl -{ +namespace PepperDash.Core.JsonToSimpl; + /// /// Constants for Simpl modules /// public class JsonToSimplConstants { - /// - /// - /// + /// + /// + /// public const ushort BoolValueChange = 1; - /// - /// - /// + /// + /// + /// public const ushort JsonIsValidBoolChange = 2; - /// - /// Reports the if the device is 3-series compatible - /// - public const ushort ProgramCompatibility3SeriesChange = 3; + /// + /// Reports the if the device is 3-series compatible + /// + public const ushort ProgramCompatibility3SeriesChange = 3; - /// - /// Reports the if the device is 4-series compatible - /// - public const ushort ProgramCompatibility4SeriesChange = 4; + /// + /// Reports the if the device is 4-series compatible + /// + public const ushort ProgramCompatibility4SeriesChange = 4; - /// - /// Reports the device platform enum value - /// - public const ushort DevicePlatformValueChange = 5; + /// + /// Reports the device platform enum value + /// + public const ushort DevicePlatformValueChange = 5; - /// - /// - /// + /// + /// + /// public const ushort UshortValueChange = 101; - /// - /// - /// + /// + /// + /// public const ushort StringValueChange = 201; - /// - /// - /// + /// + /// + /// public const ushort FullPathToArrayChange = 202; - /// - /// - /// + /// + /// + /// public const ushort ActualFilePathChange = 203; - /// - /// - /// + /// + /// + /// public const ushort FilenameResolvedChange = 204; - /// - /// - /// + /// + /// + /// public const ushort FilePathResolvedChange = 205; - /// - /// Reports the root directory change - /// - public const ushort RootDirectoryChange = 206; + /// + /// Reports the root directory change + /// + public const ushort RootDirectoryChange = 206; - /// - /// Reports the room ID change - /// - public const ushort RoomIdChange = 207; + /// + /// Reports the room ID change + /// + public const ushort RoomIdChange = 207; - /// - /// Reports the room name change - /// - public const ushort RoomNameChange = 208; + /// + /// Reports the room name change + /// + public const ushort RoomNameChange = 208; } /// @@ -88,33 +88,33 @@ namespace PepperDash.Core.JsonToSimpl /// public class SPlusValueWrapper { - /// - /// - /// + /// + /// + /// public SPlusType ValueType { get; private set; } - /// - /// - /// + /// + /// + /// public ushort Index { get; private set; } - /// - /// - /// + /// + /// + /// public ushort BoolUShortValue { get; set; } - /// - /// - /// + /// + /// + /// public string StringValue { get; set; } - /// - /// - /// + /// + /// + /// public SPlusValueWrapper() {} - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// public SPlusValueWrapper(SPlusType type, ushort index) { ValueType = type; @@ -127,17 +127,16 @@ namespace PepperDash.Core.JsonToSimpl /// public enum SPlusType { - /// - /// Digital - /// + /// + /// Digital + /// Digital, - /// - /// Analog - /// - Analog, - /// - /// String - /// - String - } -} \ No newline at end of file + /// + /// Analog + /// + Analog, + /// + /// String + /// + String + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/Global.cs b/src/PepperDash.Core/JsonToSimpl/Global.cs index 8392fa61..9a30853e 100644 --- a/src/PepperDash.Core/JsonToSimpl/Global.cs +++ b/src/PepperDash.Core/JsonToSimpl/Global.cs @@ -7,11 +7,11 @@ using Serilog.Events; //using PepperDash.Core; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// The global class to manage all the instances of JsonToSimplMaster - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// The global class to manage all the instances of JsonToSimplMaster +/// public class J2SGlobal { static List Masters = new List(); @@ -22,7 +22,7 @@ namespace PepperDash.Core.JsonToSimpl /// master, this will fail /// /// New master to add - /// + /// public static void AddMaster(JsonToSimplMaster master) { if (master == null) @@ -56,5 +56,4 @@ namespace PepperDash.Core.JsonToSimpl { return Masters.FirstOrDefault(m => m.UniqueID.Equals(file, StringComparison.OrdinalIgnoreCase)); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs index c94dad29..bd5ad8ae 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs @@ -3,20 +3,20 @@ using System.Linq; using Newtonsoft.Json.Linq; using Serilog.Events; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Used to interact with an array of values with the S+ modules - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Used to interact with an array of values with the S+ modules +/// public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase { - /// - /// - /// + /// + /// + /// public string SearchPropertyName { get; set; } - /// - /// - /// + /// + /// + /// public string SearchPropertyValue { get; set; } int ArrayIndex; @@ -76,9 +76,9 @@ namespace PepperDash.Core.JsonToSimpl PathSuffix == null ? "" : PathSuffix); } - /// - /// Process all values - /// + /// + /// Process all values + /// public override void ProcessAll() { if (FindInArray()) @@ -158,5 +158,4 @@ namespace PepperDash.Core.JsonToSimpl return false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs index 5aa67c96..7ebb6f27 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs @@ -3,29 +3,29 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Base class for JSON objects - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Base class for JSON objects +/// public abstract class JsonToSimplChildObjectBase : IKeyed { - /// - /// Notifies of bool change - /// + /// + /// Notifies of bool change + /// public event EventHandler BoolChange; - /// - /// Notifies of ushort change - /// + /// + /// Notifies of ushort change + /// public event EventHandler UShortChange; - /// - /// Notifies of string change - /// + /// + /// Notifies of string change + /// public event EventHandler StringChange; - /// - /// Delegate to get all values - /// + /// + /// Delegate to get all values + /// public SPlusValuesDelegate GetAllValuesDelegate { get; set; } /// @@ -33,9 +33,9 @@ namespace PepperDash.Core.JsonToSimpl /// public SPlusValuesDelegate SetAllPathsDelegate { get; set; } - /// - /// Unique identifier for instance - /// + /// + /// Unique identifier for instance + /// public string Key { get; protected set; } /// @@ -49,33 +49,33 @@ namespace PepperDash.Core.JsonToSimpl /// public string PathSuffix { get; protected set; } - /// - /// Indicates if the instance is linked to an object - /// + /// + /// Indicates if the instance is linked to an object + /// public bool LinkedToObject { get; protected set; } - /// - /// Reference to Master instance - /// + /// + /// Reference to Master instance + /// protected JsonToSimplMaster Master; - /// - /// Paths to boolean values in JSON structure - /// - protected Dictionary BoolPaths = new Dictionary(); - /// - /// Paths to numeric values in JSON structure - /// + /// + /// Paths to boolean values in JSON structure + /// + protected Dictionary BoolPaths = new Dictionary(); + /// + /// Paths to numeric values in JSON structure + /// protected Dictionary UshortPaths = new Dictionary(); - /// - /// Paths to string values in JSON structure - /// + /// + /// Paths to string values in JSON structure + /// protected Dictionary StringPaths = new Dictionary(); /// /// Call this before doing anything else /// - /// + /// /// /// /// @@ -92,10 +92,10 @@ namespace PepperDash.Core.JsonToSimpl Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId); } - /// - /// Sets the path prefix for the object - /// - /// + /// + /// Sets the path prefix for the object + /// + /// public void SetPathPrefix(string pathPrefix) { PathPrefix = pathPrefix; @@ -170,18 +170,18 @@ namespace PepperDash.Core.JsonToSimpl } // Processes the path to a ushort, converting to ushort if able, twos complement if necessary, firing off UshrtChange event - void ProcessUshortPath(ushort index) { - string response; - if (Process(UshortPaths[index], out response)) { - ushort val; - try { val = Convert.ToInt32(response) < 0 ? (ushort)(Convert.ToInt16(response) + 65536) : Convert.ToUInt16(response); } - catch { val = 0; } + void ProcessUshortPath(ushort index) { + string response; + if (Process(UshortPaths[index], out response)) { + ushort val; + try { val = Convert.ToInt32(response) < 0 ? (ushort)(Convert.ToInt16(response) + 65536) : Convert.ToUInt16(response); } + catch { val = 0; } - OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange); - } - else { } - // OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange); + OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange); } + else { } + // OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange); + } // Processes the path to a string property and fires of a StringChange event. void ProcessStringPath(ushort index) @@ -272,54 +272,54 @@ namespace PepperDash.Core.JsonToSimpl GetAllValuesDelegate(); } - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// public void USetBoolValue(ushort key, ushort theValue) { SetBoolValue(key, theValue == 1); } - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// public void SetBoolValue(ushort key, bool theValue) { if (BoolPaths.ContainsKey(key)) SetValueOnMaster(BoolPaths[key], new JValue(theValue)); } - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// public void SetUShortValue(ushort key, ushort theValue) { if (UshortPaths.ContainsKey(key)) SetValueOnMaster(UshortPaths[key], new JValue(theValue)); } - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// public void SetStringValue(ushort key, string theValue) { if (StringPaths.ContainsKey(key)) SetValueOnMaster(StringPaths[key], new JValue(theValue)); } - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// public void SetValueOnMaster(string keyPath, JValue valueToSave) { var path = GetFullPath(keyPath); @@ -349,12 +349,12 @@ namespace PepperDash.Core.JsonToSimpl // Helpers for events //****************************************************************************************** - /// - /// Event helper - /// - /// - /// - /// + /// + /// Event helper + /// + /// + /// + /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; @@ -367,12 +367,12 @@ namespace PepperDash.Core.JsonToSimpl } //****************************************************************************************** - /// - /// Event helper - /// - /// - /// - /// + /// + /// Event helper + /// + /// + /// + /// protected void OnUShortChange(ushort state, ushort index, ushort type) { var handler = UShortChange; @@ -384,12 +384,12 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Event helper - /// - /// - /// - /// + /// + /// Event helper + /// + /// + /// + /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; @@ -400,5 +400,4 @@ namespace PepperDash.Core.JsonToSimpl StringChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs index 411fbdc5..83c92e80 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs @@ -7,281 +7,280 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json.Linq; -namespace PepperDash.Core.JsonToSimpl +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Represents a JSON file that can be read and written to +/// +public class JsonToSimplFileMaster : JsonToSimplMaster { /// - /// Represents a JSON file that can be read and written to + /// Sets the filepath as well as registers this with the Global.Masters list /// - public class JsonToSimplFileMaster : JsonToSimplMaster + public string Filepath { get; private set; } + + /// + /// Filepath to the actual file that will be read (Portal or local) + /// + public string ActualFilePath { get; private set; } + + /// + /// + /// + public string Filename { get; private set; } + /// + /// + /// + public string FilePathName { get; private set; } + + /*****************************************************************************************/ + /** Privates **/ + + + // The JSON file in JObject form + // For gathering the incoming data + object StringBuilderLock = new object(); + // To prevent multiple same-file access + static object FileLock = new object(); + + /*****************************************************************************************/ + + /// + /// SIMPL+ default constructor. + /// + public JsonToSimplFileMaster() { - /// - /// Sets the filepath as well as registers this with the Global.Masters list - /// - public string Filepath { get; private set; } + } - /// - /// Filepath to the actual file that will be read (Portal or local) - /// - public string ActualFilePath { get; private set; } - - /// - /// - /// - public string Filename { get; private set; } - /// - /// - /// - public string FilePathName { get; private set; } - - /*****************************************************************************************/ - /** Privates **/ - - - // The JSON file in JObject form - // For gathering the incoming data - object StringBuilderLock = new object(); - // To prevent multiple same-file access - static object FileLock = new object(); - - /*****************************************************************************************/ - - /// - /// SIMPL+ default constructor. - /// - public JsonToSimplFileMaster() + /// + /// Read, evaluate and udpate status + /// + public void EvaluateFile(string filepath) + { + try { - } + OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); - /// - /// Read, evaluate and udpate status - /// - public void EvaluateFile(string filepath) - { - try + var dirSeparator = Path.DirectorySeparatorChar; + var dirSeparatorAlt = Path.AltDirectorySeparatorChar; + + var series = CrestronEnvironment.ProgramCompatibility; + + var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3)); + OnBoolChange(is3Series, 0, + JsonToSimplConstants.ProgramCompatibility3SeriesChange); + + var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4)); + OnBoolChange(is4Series, 0, + JsonToSimplConstants.ProgramCompatibility4SeriesChange); + + var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; + OnBoolChange(isServer, 0, + JsonToSimplConstants.DevicePlatformValueChange); + + // get the roomID + var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId; + if (!string.IsNullOrEmpty(roomId)) { - OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); + OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange); + } - var dirSeparator = Path.DirectorySeparatorChar; - var dirSeparatorAlt = Path.AltDirectorySeparatorChar; + // get the roomName + var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName; + if (!string.IsNullOrEmpty(roomName)) + { + OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange); + } - var series = CrestronEnvironment.ProgramCompatibility; + var rootDirectory = Directory.GetApplicationRootDirectory(); + OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange); + + var splusPath = string.Empty; + if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase)) + { + if (is4Series) + splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase); + else if (isServer) + splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase); + else + splusPath = filepath; + } - var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3)); - OnBoolChange(is3Series, 0, - JsonToSimplConstants.ProgramCompatibility3SeriesChange); + filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator); + + Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory, + filepath.TrimStart(dirSeparator, dirSeparatorAlt)); + + OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange); - var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4)); - OnBoolChange(is4Series, 0, - JsonToSimplConstants.ProgramCompatibility4SeriesChange); + if (string.IsNullOrEmpty(Filepath)) + { + OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange); + CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set"); + return; + } - var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; - OnBoolChange(isServer, 0, - JsonToSimplConstants.DevicePlatformValueChange); + // get file directory and name to search + var fileDirectory = Path.GetDirectoryName(Filepath); + var fileName = Path.GetFileName(Filepath); - // get the roomID - var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId; - if (!string.IsNullOrEmpty(roomId)) + OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange); + Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName); + + if (Directory.Exists(fileDirectory)) + { + // get the directory info + var directoryInfo = new DirectoryInfo(fileDirectory); + + // get the file to be read + var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault(); + if (actualFile == null) { - OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange); - } - - // get the roomName - var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName; - if (!string.IsNullOrEmpty(roomName)) - { - OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange); - } - - var rootDirectory = Directory.GetApplicationRootDirectory(); - OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange); - - var splusPath = string.Empty; - if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase)) - { - if (is4Series) - splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase); - else if (isServer) - splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase); - else - splusPath = filepath; - } - - filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator); - - Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory, - filepath.TrimStart(dirSeparator, dirSeparatorAlt)); - - OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange); - - if (string.IsNullOrEmpty(Filepath)) - { - OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange); - CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set"); + var msg = string.Format("JSON file not found: {0}", Filepath); + OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); + CrestronConsole.PrintLine(msg); + ErrorLog.Error(msg); return; } - // get file directory and name to search - var fileDirectory = Path.GetDirectoryName(Filepath); - var fileName = Path.GetFileName(Filepath); + // \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json + // \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json + ActualFilePath = actualFile.FullName; + OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); + OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange); + Debug.Console(1, "Actual JSON file is {0}", ActualFilePath); - OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange); - Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName); - - if (Directory.Exists(fileDirectory)) - { - // get the directory info - var directoryInfo = new DirectoryInfo(fileDirectory); - - // get the file to be read - var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault(); - if (actualFile == null) - { - var msg = string.Format("JSON file not found: {0}", Filepath); - OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); - CrestronConsole.PrintLine(msg); - ErrorLog.Error(msg); - return; - } - - // \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json - // \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json - ActualFilePath = actualFile.FullName; - OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); - OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange); - Debug.Console(1, "Actual JSON file is {0}", ActualFilePath); - - Filename = actualFile.Name; - OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange); - OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange); - Debug.Console(1, "JSON Filename is {0}", Filename); + Filename = actualFile.Name; + OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange); + OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange); + Debug.Console(1, "JSON Filename is {0}", Filename); - FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator); - OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange); - OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange); - Debug.Console(1, "JSON File Path is {0}", FilePathName); + FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator); + OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange); + OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange); + Debug.Console(1, "JSON File Path is {0}", FilePathName); - var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); + var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); - JsonObject = JObject.Parse(json); - foreach (var child in Children) - child.ProcessAll(); + JsonObject = JObject.Parse(json); + foreach (var child in Children) + child.ProcessAll(); - OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); - } - else - { - OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange); - Debug.Console(1, "'{0}' not found", fileDirectory); - } + OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); } - catch (Exception e) + else { - var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message); - OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); - CrestronConsole.PrintLine(msg); - ErrorLog.Error(msg); - - var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace); - OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange); - CrestronConsole.PrintLine(stackTrace); - ErrorLog.Error(stackTrace); + OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange); + Debug.Console(1, "'{0}' not found", fileDirectory); } } - - - /// - /// Sets the debug level - /// - /// - public void setDebugLevel(uint level) + catch (Exception e) { - Debug.SetDebugLevel(level); + var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message); + OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); + CrestronConsole.PrintLine(msg); + ErrorLog.Error(msg); + + var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace); + OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange); + CrestronConsole.PrintLine(stackTrace); + ErrorLog.Error(stackTrace); + } + } + + + /// + /// Sets the debug level + /// + /// + public void setDebugLevel(uint level) + { + Debug.SetDebugLevel(level); + } + + /// + /// Saves the values to the file + /// + public override void Save() + { + // this code is duplicated in the other masters!!!!!!!!!!!!! + UnsavedValues = new Dictionary(); + // Make each child update their values into master object + foreach (var child in Children) + { + Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); + child.UpdateInputsForMaster(); } - /// - /// Saves the values to the file - /// - public override void Save() + if (UnsavedValues == null || UnsavedValues.Count == 0) { - // this code is duplicated in the other masters!!!!!!!!!!!!! - UnsavedValues = new Dictionary(); - // Make each child update their values into master object - foreach (var child in Children) + Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); + return; + } + lock (FileLock) + { + Debug.Console(1, "Saving"); + foreach (var path in UnsavedValues.Keys) { - Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); - child.UpdateInputsForMaster(); - } - - if (UnsavedValues == null || UnsavedValues.Count == 0) - { - Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); - return; - } - lock (FileLock) - { - Debug.Console(1, "Saving"); - foreach (var path in UnsavedValues.Keys) - { - var tokenToReplace = JsonObject.SelectToken(path); - if (tokenToReplace != null) - {// It's found - tokenToReplace.Replace(UnsavedValues[path]); - Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); - } - else // No token. Let's make one - { - //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net - Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); - - // JContainer jpart = JsonObject; - // // walk down the path and find where it goes - //#warning Does not handle arrays. - // foreach (var part in path.Split('.')) - // { - - // var openPos = part.IndexOf('['); - // if (openPos > -1) - // { - // openPos++; // move to number - // var closePos = part.IndexOf(']'); - // var arrayName = part.Substring(0, openPos - 1); // get the name - // var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos)); - - // // Check if the array itself exists and add the item if so - // if (jpart[arrayName] != null) - // { - // var arrayObj = jpart[arrayName] as JArray; - // var item = arrayObj[index]; - // if (item == null) - // arrayObj.Add(new JObject()); - // } - - // Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW"); - // continue; - // } - // // Build the - // if (jpart[part] == null) - // jpart.Add(new JProperty(part, new JObject())); - // jpart = jpart[part] as JContainer; - // } - // jpart.Replace(UnsavedValues[path]); - } + var tokenToReplace = JsonObject.SelectToken(path); + if (tokenToReplace != null) + {// It's found + tokenToReplace.Replace(UnsavedValues[path]); + Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); } - using (StreamWriter sw = new StreamWriter(ActualFilePath)) + else // No token. Let's make one { - try - { - sw.Write(JsonObject.ToString()); - sw.Flush(); - } - catch (Exception e) - { - string err = string.Format("Error writing JSON file:\r{0}", e); - Debug.Console(0, err); - ErrorLog.Warn(err); - return; - } + //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net + Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); + + // JContainer jpart = JsonObject; + // // walk down the path and find where it goes + //#warning Does not handle arrays. + // foreach (var part in path.Split('.')) + // { + + // var openPos = part.IndexOf('['); + // if (openPos > -1) + // { + // openPos++; // move to number + // var closePos = part.IndexOf(']'); + // var arrayName = part.Substring(0, openPos - 1); // get the name + // var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos)); + + // // Check if the array itself exists and add the item if so + // if (jpart[arrayName] != null) + // { + // var arrayObj = jpart[arrayName] as JArray; + // var item = arrayObj[index]; + // if (item == null) + // arrayObj.Add(new JObject()); + // } + + // Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW"); + // continue; + // } + // // Build the + // if (jpart[part] == null) + // jpart.Add(new JProperty(part, new JObject())); + // jpart = jpart[part] as JContainer; + // } + // jpart.Replace(UnsavedValues[path]); + } + } + using (StreamWriter sw = new StreamWriter(ActualFilePath)) + { + try + { + sw.Write(JsonObject.ToString()); + sw.Flush(); + } + catch (Exception e) + { + string err = string.Format("Error writing JSON file:\r{0}", e); + Debug.Console(0, err); + ErrorLog.Warn(err); + return; } } } diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs index 3e69ed9d..6338e309 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs @@ -1,18 +1,17 @@  -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// +/// public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase { - /// - /// Constructor - /// + /// + /// Constructor + /// public JsonToSimplFixedPathObject() { this.LinkedToObject = true; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs index e0f42f8e..3399e079 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs @@ -3,35 +3,35 @@ using System.Collections.Generic; using Crestron.SimplSharp; using Newtonsoft.Json.Linq; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Generic Master - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Generic Master +/// public class JsonToSimplGenericMaster : JsonToSimplMaster - { +{ /*****************************************************************************************/ /** Privates **/ - + // The JSON file in JObject form // For gathering the incoming data object StringBuilderLock = new object(); // To prevent multiple same-file access static object WriteLock = new object(); - /// - /// Callback action for saving - /// + /// + /// Callback action for saving + /// public Action SaveCallback { get; set; } /*****************************************************************************************/ /// - /// SIMPL+ default constructor. - /// + /// SIMPL+ default constructor. + /// public JsonToSimplGenericMaster() - { + { } /// @@ -78,7 +78,7 @@ namespace PepperDash.Core.JsonToSimpl public override void Save() { // this code is duplicated in the other masters!!!!!!!!!!!!! - UnsavedValues = new Dictionary(); + UnsavedValues = new Dictionary(); // Make each child update their values into master object foreach (var child in Children) { @@ -114,5 +114,4 @@ namespace PepperDash.Core.JsonToSimpl else Debug.Console(0, this, "WARNING: No save callback defined."); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs index a4979d24..928d4e77 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs @@ -5,29 +5,29 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace PepperDash.Core.JsonToSimpl -{ - /// - /// Abstract base class for JsonToSimpl interactions - /// +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Abstract base class for JsonToSimpl interactions +/// public abstract class JsonToSimplMaster : IKeyed { - /// - /// Notifies of bool change - /// + /// + /// Notifies of bool change + /// public event EventHandler BoolChange; - /// - /// Notifies of ushort change - /// + /// + /// Notifies of ushort change + /// public event EventHandler UshrtChange; - /// - /// Notifies of string change - /// + /// + /// Notifies of string change + /// public event EventHandler StringChange; - /// - /// A collection of associated child modules - /// + /// + /// A collection of associated child modules + /// protected List Children = new List(); /*****************************************************************************************/ @@ -37,9 +37,9 @@ namespace PepperDash.Core.JsonToSimpl /// public string Key { get { return UniqueID; } } - /// - /// A unique ID - /// + /// + /// A unique ID + /// public string UniqueID { get; protected set; } /// @@ -82,9 +82,9 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// - /// + /// + /// + /// public JObject JsonObject { get; protected set; } /*****************************************************************************************/ @@ -141,9 +141,9 @@ namespace PepperDash.Core.JsonToSimpl //Debug.Console(0, "Master[{0}] Unsaved size={1}", UniqueID, UnsavedValues.Count); } - /// - /// Saves the file - /// + /// + /// Saves the file + /// public abstract void Save(); @@ -152,14 +152,14 @@ namespace PepperDash.Core.JsonToSimpl /// public static class JsonFixes { - /// - /// Deserializes a string into a JObject - /// - /// - /// + /// + /// Deserializes a string into a JObject + /// + /// + /// public static JObject ParseObject(string json) { - using (var reader = new JsonTextReader(new StringReader(json))) + using (var reader = new JsonTextReader(new StringReader(json))) { var startDepth = reader.Depth; var obj = JObject.Load(reader); @@ -169,15 +169,15 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Deserializes a string into a JArray - /// - /// - /// + /// + /// Deserializes a string into a JArray + /// + /// + /// public static JArray ParseArray(string json) { - using (var reader = new JsonTextReader(new StringReader(json))) + using (var reader = new JsonTextReader(new StringReader(json))) { var startDepth = reader.Depth; var obj = JArray.Load(reader); @@ -220,12 +220,12 @@ namespace PepperDash.Core.JsonToSimpl } } - /// - /// Helper event - /// - /// - /// - /// + /// + /// Helper event + /// + /// + /// + /// protected void OnStringChange(string value, ushort index, ushort type) { if (StringChange != null) @@ -236,4 +236,3 @@ namespace PepperDash.Core.JsonToSimpl } } } -} diff --git a/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs b/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs index c170a9a1..30c66dd2 100644 --- a/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs +++ b/src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs @@ -6,22 +6,22 @@ using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json.Linq; using PepperDash.Core.Config; -namespace PepperDash.Core.JsonToSimpl +namespace PepperDash.Core.JsonToSimpl; + +/// +/// Portal File Master +/// +public class JsonToSimplPortalFileMaster : JsonToSimplMaster { - /// - /// Portal File Master - /// - public class JsonToSimplPortalFileMaster : JsonToSimplMaster - { /// /// Sets the filepath as well as registers this with the Global.Masters list /// public string PortalFilepath { get; private set; } - /// - /// File path of the actual file being read (Portal or local) - /// - public string ActualFilePath { get; private set; } + /// + /// File path of the actual file being read (Portal or local) + /// + public string ActualFilePath { get; private set; } /*****************************************************************************************/ /** Privates **/ @@ -33,10 +33,10 @@ namespace PepperDash.Core.JsonToSimpl /*****************************************************************************************/ /// - /// SIMPL+ default constructor. - /// + /// SIMPL+ default constructor. + /// public JsonToSimplPortalFileMaster() - { + { } /// @@ -64,7 +64,7 @@ namespace PepperDash.Core.JsonToSimpl if (actualLocalFile != null) { ActualFilePath = actualLocalFile.FullName; - OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); + OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); } // If the local file does not exist, then read the portal file xyz.json // and create the local. @@ -78,7 +78,7 @@ namespace PepperDash.Core.JsonToSimpl // got the portal file, hand off to the merge / save method PortalConfigReader.ReadAndMergeFileIfNecessary(actualPortalFile.FullName, newLocalPath); ActualFilePath = newLocalPath; - OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); + OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); } else { @@ -188,4 +188,3 @@ namespace PepperDash.Core.JsonToSimpl } } } -} diff --git a/src/PepperDash.Core/Logging/CrestronEnricher.cs b/src/PepperDash.Core/Logging/CrestronEnricher.cs index 902ce8d5..1f879925 100644 --- a/src/PepperDash.Core/Logging/CrestronEnricher.cs +++ b/src/PepperDash.Core/Logging/CrestronEnricher.cs @@ -7,31 +7,30 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public class CrestronEnricher : ILogEventEnricher { - public class CrestronEnricher : ILogEventEnricher + static readonly string _appName; + + static CrestronEnricher() { - static readonly string _appName; - - static CrestronEnricher() + switch (CrestronEnvironment.DevicePlatform) { - switch (CrestronEnvironment.DevicePlatform) - { - case eDevicePlatform.Appliance: - _appName = $"App {InitialParametersClass.ApplicationNumber}"; - break; - case eDevicePlatform.Server: - _appName = $"{InitialParametersClass.RoomId}"; - break; - } - } - - - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - { - var property = propertyFactory.CreateProperty("App", _appName); - - logEvent.AddOrUpdateProperty(property); + case eDevicePlatform.Appliance: + _appName = $"App {InitialParametersClass.ApplicationNumber}"; + break; + case eDevicePlatform.Server: + _appName = $"{InitialParametersClass.RoomId}"; + break; } } + + + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + var property = propertyFactory.CreateProperty("App", _appName); + + logEvent.AddOrUpdateProperty(property); + } } diff --git a/src/PepperDash.Core/Logging/Debug.cs b/src/PepperDash.Core/Logging/Debug.cs index 38dfa034..219af2d5 100644 --- a/src/PepperDash.Core/Logging/Debug.cs +++ b/src/PepperDash.Core/Logging/Debug.cs @@ -16,8 +16,8 @@ using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + /// /// Contains debug commands for use in various situations /// @@ -1023,6 +1023,5 @@ namespace PepperDash.Core /// None /// None, - } } } \ No newline at end of file diff --git a/src/PepperDash.Core/Logging/DebugConsoleSink.cs b/src/PepperDash.Core/Logging/DebugConsoleSink.cs index a6c7f893..5e32a8a5 100644 --- a/src/PepperDash.Core/Logging/DebugConsoleSink.cs +++ b/src/PepperDash.Core/Logging/DebugConsoleSink.cs @@ -9,47 +9,45 @@ using System.IO; using System.Text; -namespace PepperDash.Core +namespace PepperDash.Core; + +public class DebugConsoleSink : ILogEventSink { - public class DebugConsoleSink : ILogEventSink + private readonly ITextFormatter _textFormatter; + + public void Emit(LogEvent logEvent) { - private readonly ITextFormatter _textFormatter; + if (!Debug.IsRunningOnAppliance) return; - public void Emit(LogEvent logEvent) + /*string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; + + if(logEvent.Properties.TryGetValue("Key",out var value) && value is ScalarValue sv && sv.Value is string rawValue) { - if (!Debug.IsRunningOnAppliance) return; + message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}"; + }*/ - /*string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; + var buffer = new StringWriter(new StringBuilder(256)); - if(logEvent.Properties.TryGetValue("Key",out var value) && value is ScalarValue sv && sv.Value is string rawValue) - { - message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}"; - }*/ + _textFormatter.Format(logEvent, buffer); - var buffer = new StringWriter(new StringBuilder(256)); - - _textFormatter.Format(logEvent, buffer); - - var message = buffer.ToString(); - - CrestronConsole.PrintLine(message); - } - - public DebugConsoleSink(ITextFormatter formatProvider ) - { - _textFormatter = formatProvider ?? new JsonFormatter(); - } + var message = buffer.ToString(); + CrestronConsole.PrintLine(message); } - public static class DebugConsoleSinkExtensions + public DebugConsoleSink(ITextFormatter formatProvider ) { - public static LoggerConfiguration DebugConsoleSink( - this LoggerSinkConfiguration loggerConfiguration, - ITextFormatter formatProvider = null) - { - return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider)); - } + _textFormatter = formatProvider ?? new JsonFormatter(); } } + +public static class DebugConsoleSinkExtensions +{ + public static LoggerConfiguration DebugConsoleSink( + this LoggerSinkConfiguration loggerConfiguration, + ITextFormatter formatProvider = null) + { + return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider)); + } +} diff --git a/src/PepperDash.Core/Logging/DebugContext.cs b/src/PepperDash.Core/Logging/DebugContext.cs index 54c87414..8b8d5f2c 100644 --- a/src/PepperDash.Core/Logging/DebugContext.cs +++ b/src/PepperDash.Core/Logging/DebugContext.cs @@ -6,276 +6,275 @@ using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Represents a debugging context +/// +public class DebugContext { /// - /// Represents a debugging context + /// Describes the folder location where a given program stores it's debug level memory. By default, the + /// file written will be named appNdebug where N is 1-10. /// - public class DebugContext + public string Key { get; private set; } + + ///// + ///// The name of the file containing the current debug settings. + ///// + //string FileName = string.Format(@"\nvram\debug\app{0}Debug.json", InitialParametersClass.ApplicationNumber); + + DebugContextSaveData SaveData; + + int SaveTimeoutMs = 30000; + + CTimer SaveTimer; + + + static List Contexts = new List(); + + /// + /// Creates or gets a debug context + /// + /// + /// + public static DebugContext GetDebugContext(string key) { - /// - /// Describes the folder location where a given program stores it's debug level memory. By default, the - /// file written will be named appNdebug where N is 1-10. - /// - public string Key { get; private set; } - - ///// - ///// The name of the file containing the current debug settings. - ///// - //string FileName = string.Format(@"\nvram\debug\app{0}Debug.json", InitialParametersClass.ApplicationNumber); - - DebugContextSaveData SaveData; - - int SaveTimeoutMs = 30000; - - CTimer SaveTimer; - - - static List Contexts = new List(); - - /// - /// Creates or gets a debug context - /// - /// - /// - public static DebugContext GetDebugContext(string key) + var context = Contexts.FirstOrDefault(c => c.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); + if (context == null) { - var context = Contexts.FirstOrDefault(c => c.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - if (context == null) - { - context = new DebugContext(key); - Contexts.Add(context); - } - return context; + context = new DebugContext(key); + Contexts.Add(context); + } + return context; + } + + /// + /// Do not use. For S+ access. + /// + public DebugContext() { } + + DebugContext(string key) + { + Key = key; + if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro) + { + // Add command to console + CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug", + "appdebug:P [0-2]: Sets the application's console debug message level", + ConsoleAccessLevelEnum.AccessOperator); } - /// - /// Do not use. For S+ access. - /// - public DebugContext() { } + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - DebugContext(string key) + LoadMemory(); + } + + /// + /// Used to save memory when shutting down + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) { - Key = key; - if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro) + if (SaveTimer != null) { - // Add command to console - CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug", - "appdebug:P [0-2]: Sets the application's console debug message level", - ConsoleAccessLevelEnum.AccessOperator); + SaveTimer.Stop(); + SaveTimer = null; + } + Console(0, "Saving debug settings"); + SaveMemory(); + } + } + + /// + /// Callback for console command + /// + /// + public void SetDebugFromConsole(string levelString) + { + try + { + if (string.IsNullOrEmpty(levelString.Trim())) + { + CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level); + return; } - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - - LoadMemory(); + SetDebugLevel(Convert.ToInt32(levelString)); } - - /// - /// Used to save memory when shutting down - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + catch { - if (programEventType == eProgramStatusEventType.Stopping) - { - if (SaveTimer != null) - { - SaveTimer.Stop(); - SaveTimer = null; - } - Console(0, "Saving debug settings"); - SaveMemory(); - } + CrestronConsole.PrintLine("Usage: appdebug:P [0-2]"); } + } - /// - /// Callback for console command - /// - /// - public void SetDebugFromConsole(string levelString) + /// + /// Sets the debug level + /// + /// Valid values 0 (no debug), 1 (critical), 2 (all messages) + public void SetDebugLevel(int level) + { + if (level <= 2) { - try - { - if (string.IsNullOrEmpty(levelString.Trim())) - { - CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level); - return; - } + SaveData.Level = level; + SaveMemoryOnTimeout(); - SetDebugLevel(Convert.ToInt32(levelString)); - } - catch - { - CrestronConsole.PrintLine("Usage: appdebug:P [0-2]"); - } + CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}", + InitialParametersClass.ApplicationNumber, SaveData.Level); } + } - /// - /// Sets the debug level - /// - /// Valid values 0 (no debug), 1 (critical), 2 (all messages) - public void SetDebugLevel(int level) + /// + /// Prints message to console if current debug level is equal to or higher than the level of this message. + /// Uses CrestronConsole.PrintLine. + /// + /// + /// Console format string + /// Object parameters + public void Console(uint level, string format, params object[] items) + { + if (SaveData.Level >= level) + CrestronConsole.PrintLine("App {0}:{1}", InitialParametersClass.ApplicationNumber, + string.Format(format, items)); + } + + /// + /// Appends a device Key to the beginning of a message + /// + public void Console(uint level, IKeyed dev, string format, params object[] items) + { + if (SaveData.Level >= level) + Console(level, "[{0}] {1}", dev.Key, string.Format(format, items)); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public void Console(uint level, IKeyed dev, Debug.ErrorLogLevel errorLogLevel, + string format, params object[] items) + { + if (SaveData.Level >= level) { - if (level <= 2) - { - SaveData.Level = level; - SaveMemoryOnTimeout(); - - CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}", - InitialParametersClass.ApplicationNumber, SaveData.Level); - } - } - - /// - /// Prints message to console if current debug level is equal to or higher than the level of this message. - /// Uses CrestronConsole.PrintLine. - /// - /// - /// Console format string - /// Object parameters - public void Console(uint level, string format, params object[] items) - { - if (SaveData.Level >= level) - CrestronConsole.PrintLine("App {0}:{1}", InitialParametersClass.ApplicationNumber, - string.Format(format, items)); - } - - /// - /// Appends a device Key to the beginning of a message - /// - public void Console(uint level, IKeyed dev, string format, params object[] items) - { - if (SaveData.Level >= level) - Console(level, "[{0}] {1}", dev.Key, string.Format(format, items)); - } - - /// - /// - /// - /// - /// - /// - /// - /// - public void Console(uint level, IKeyed dev, Debug.ErrorLogLevel errorLogLevel, - string format, params object[] items) - { - if (SaveData.Level >= level) - { - var str = string.Format("[{0}] {1}", dev.Key, string.Format(format, items)); - Console(level, str); - LogError(errorLogLevel, str); - } - } - - /// - /// - /// - /// - /// - /// - /// - public void Console(uint level, Debug.ErrorLogLevel errorLogLevel, - string format, params object[] items) - { - if (SaveData.Level >= level) - { - var str = string.Format(format, items); - Console(level, str); - LogError(errorLogLevel, str); - } - } - - /// - /// - /// - /// - /// - public void LogError(Debug.ErrorLogLevel errorLogLevel, string str) - { - string msg = string.Format("App {0}:{1}", InitialParametersClass.ApplicationNumber, str); - switch (errorLogLevel) - { - case Debug.ErrorLogLevel.Error: - ErrorLog.Error(msg); - break; - case Debug.ErrorLogLevel.Warning: - ErrorLog.Warn(msg); - break; - case Debug.ErrorLogLevel.Notice: - ErrorLog.Notice(msg); - break; - } - } - - /// - /// Writes the memory object after timeout - /// - void SaveMemoryOnTimeout() - { - if (SaveTimer == null) - SaveTimer = new CTimer(o => - { - SaveTimer = null; - SaveMemory(); - }, SaveTimeoutMs); - else - SaveTimer.Reset(SaveTimeoutMs); - } - - /// - /// Writes the memory - use SaveMemoryOnTimeout - /// - void SaveMemory() - { - using (StreamWriter sw = new StreamWriter(GetMemoryFileName())) - { - var json = JsonConvert.SerializeObject(SaveData); - sw.Write(json); - sw.Flush(); - } - } - - /// - /// - /// - void LoadMemory() - { - var file = GetMemoryFileName(); - if (File.Exists(file)) - { - using (StreamReader sr = new StreamReader(file)) - { - var data = JsonConvert.DeserializeObject(sr.ReadToEnd()); - if (data != null) - { - SaveData = data; - Debug.Console(1, "Debug memory restored from file"); - return; - } - else - SaveData = new DebugContextSaveData(); - } - } - } - - /// - /// Helper to get the file path for this app's debug memory - /// - string GetMemoryFileName() - { - return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key); + var str = string.Format("[{0}] {1}", dev.Key, string.Format(format, items)); + Console(level, str); + LogError(errorLogLevel, str); } } /// /// /// - public class DebugContextSaveData + /// + /// + /// + /// + public void Console(uint level, Debug.ErrorLogLevel errorLogLevel, + string format, params object[] items) { - /// - /// - /// - public int Level { get; set; } + if (SaveData.Level >= level) + { + var str = string.Format(format, items); + Console(level, str); + LogError(errorLogLevel, str); + } } + + /// + /// + /// + /// + /// + public void LogError(Debug.ErrorLogLevel errorLogLevel, string str) + { + string msg = string.Format("App {0}:{1}", InitialParametersClass.ApplicationNumber, str); + switch (errorLogLevel) + { + case Debug.ErrorLogLevel.Error: + ErrorLog.Error(msg); + break; + case Debug.ErrorLogLevel.Warning: + ErrorLog.Warn(msg); + break; + case Debug.ErrorLogLevel.Notice: + ErrorLog.Notice(msg); + break; + } + } + + /// + /// Writes the memory object after timeout + /// + void SaveMemoryOnTimeout() + { + if (SaveTimer == null) + SaveTimer = new CTimer(o => + { + SaveTimer = null; + SaveMemory(); + }, SaveTimeoutMs); + else + SaveTimer.Reset(SaveTimeoutMs); + } + + /// + /// Writes the memory - use SaveMemoryOnTimeout + /// + void SaveMemory() + { + using (StreamWriter sw = new StreamWriter(GetMemoryFileName())) + { + var json = JsonConvert.SerializeObject(SaveData); + sw.Write(json); + sw.Flush(); + } + } + + /// + /// + /// + void LoadMemory() + { + var file = GetMemoryFileName(); + if (File.Exists(file)) + { + using (StreamReader sr = new StreamReader(file)) + { + var data = JsonConvert.DeserializeObject(sr.ReadToEnd()); + if (data != null) + { + SaveData = data; + Debug.Console(1, "Debug memory restored from file"); + return; + } + else + SaveData = new DebugContextSaveData(); + } + } + } + + /// + /// Helper to get the file path for this app's debug memory + /// + string GetMemoryFileName() + { + return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key); + } +} + +/// +/// +/// +public class DebugContextSaveData +{ + /// + /// + /// + public int Level { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs b/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs index 0814453b..a2e82ec8 100644 --- a/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs +++ b/src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs @@ -3,27 +3,26 @@ using Crestron.SimplSharp.CrestronLogger; using Serilog.Core; using Serilog.Events; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public class DebugCrestronLoggerSink : ILogEventSink { - public class DebugCrestronLoggerSink : ILogEventSink + public void Emit(LogEvent logEvent) { - public void Emit(LogEvent logEvent) + if (!Debug.IsRunningOnAppliance) return; + + string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; + + if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue) { - if (!Debug.IsRunningOnAppliance) return; - - string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; - - if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue) - { - message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}"; - } - - CrestronLogger.WriteToLog(message, (uint)logEvent.Level); + message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}"; } - public DebugCrestronLoggerSink() - { - CrestronLogger.Initialize(1, LoggerModeEnum.RM); - } + CrestronLogger.WriteToLog(message, (uint)logEvent.Level); + } + + public DebugCrestronLoggerSink() + { + CrestronLogger.Initialize(1, LoggerModeEnum.RM); } } diff --git a/src/PepperDash.Core/Logging/DebugErrorLogSink.cs b/src/PepperDash.Core/Logging/DebugErrorLogSink.cs index 3885982b..3c2e6761 100644 --- a/src/PepperDash.Core/Logging/DebugErrorLogSink.cs +++ b/src/PepperDash.Core/Logging/DebugErrorLogSink.cs @@ -9,57 +9,56 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public class DebugErrorLogSink : ILogEventSink { - public class DebugErrorLogSink : ILogEventSink + private ITextFormatter _formatter; + + private Dictionary> _errorLogMap = new Dictionary> { - private ITextFormatter _formatter; + { LogEventLevel.Verbose, (msg) => ErrorLog.Notice(msg) }, + {LogEventLevel.Debug, (msg) => ErrorLog.Notice(msg) }, + {LogEventLevel.Information, (msg) => ErrorLog.Notice(msg) }, + {LogEventLevel.Warning, (msg) => ErrorLog.Warn(msg) }, + {LogEventLevel.Error, (msg) => ErrorLog.Error(msg) }, + {LogEventLevel.Fatal, (msg) => ErrorLog.Error(msg) } + }; + public void Emit(LogEvent logEvent) + { + string message; - private Dictionary> _errorLogMap = new Dictionary> + if (_formatter == null) { - { LogEventLevel.Verbose, (msg) => ErrorLog.Notice(msg) }, - {LogEventLevel.Debug, (msg) => ErrorLog.Notice(msg) }, - {LogEventLevel.Information, (msg) => ErrorLog.Notice(msg) }, - {LogEventLevel.Warning, (msg) => ErrorLog.Warn(msg) }, - {LogEventLevel.Error, (msg) => ErrorLog.Error(msg) }, - {LogEventLevel.Fatal, (msg) => ErrorLog.Error(msg) } - }; - public void Emit(LogEvent logEvent) + var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance + ? $"App {InitialParametersClass.ApplicationNumber}" + : $"Room {InitialParametersClass.RoomId}"; + + message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}]{logEvent.RenderMessage()}"; + + if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue) + { + message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}][{rawValue}]: {logEvent.RenderMessage()}"; + } + } else { - string message; + var buffer = new StringWriter(new StringBuilder(256)); - if (_formatter == null) - { - var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance - ? $"App {InitialParametersClass.ApplicationNumber}" - : $"Room {InitialParametersClass.RoomId}"; + _formatter.Format(logEvent, buffer); - message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}]{logEvent.RenderMessage()}"; - - if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue) - { - message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}][{rawValue}]: {logEvent.RenderMessage()}"; - } - } else - { - var buffer = new StringWriter(new StringBuilder(256)); - - _formatter.Format(logEvent, buffer); - - message = buffer.ToString(); - } - - if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler)) - { - return; - } - - handler(message); + message = buffer.ToString(); } - public DebugErrorLogSink(ITextFormatter formatter = null) + if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler)) { - _formatter = formatter; + return; } + + handler(message); + } + + public DebugErrorLogSink(ITextFormatter formatter = null) + { + _formatter = formatter; } } diff --git a/src/PepperDash.Core/Logging/DebugExtensions.cs b/src/PepperDash.Core/Logging/DebugExtensions.cs index a8b7bd55..05d36276 100644 --- a/src/PepperDash.Core/Logging/DebugExtensions.cs +++ b/src/PepperDash.Core/Logging/DebugExtensions.cs @@ -2,73 +2,72 @@ using System; using Log = PepperDash.Core.Debug; -namespace PepperDash.Core.Logging +namespace PepperDash.Core.Logging; + +public static class DebugExtensions { - public static class DebugExtensions + public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) { - public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(ex, message, device, args); - } + Log.LogMessage(ex, message, device, args); + } - public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Verbose, ex, message, device, args); - } + public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Verbose, ex, message, device, args); + } - public static void LogVerbose(this IKeyed device, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Verbose, device, message, args); - } + public static void LogVerbose(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Verbose, device, message, args); + } - public static void LogDebug(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Debug, ex, message, device, args); - } + public static void LogDebug(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Debug, ex, message, device, args); + } - public static void LogDebug(this IKeyed device, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Debug, device, message, args); - } + public static void LogDebug(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Debug, device, message, args); + } - public static void LogInformation(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Information, ex, message, device, args); - } + public static void LogInformation(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Information, ex, message, device, args); + } - public static void LogInformation(this IKeyed device, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Information, device, message, args); - } + public static void LogInformation(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Information, device, message, args); + } - public static void LogWarning(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Warning, ex, message, device, args); - } + public static void LogWarning(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Warning, ex, message, device, args); + } - public static void LogWarning(this IKeyed device, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Warning, device, message, args); - } + public static void LogWarning(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Warning, device, message, args); + } - public static void LogError(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Error, ex, message, device, args); - } + public static void LogError(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Error, ex, message, device, args); + } - public static void LogError(this IKeyed device, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Error, device, message, args); - } + public static void LogError(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Error, device, message, args); + } - public static void LogFatal(this IKeyed device, Exception ex, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Fatal, ex, message, device, args); - } + public static void LogFatal(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Fatal, ex, message, device, args); + } - public static void LogFatal(this IKeyed device, string message, params object[] args) - { - Log.LogMessage(LogEventLevel.Fatal, device, message, args); - } + public static void LogFatal(this IKeyed device, string message, params object[] args) + { + Log.LogMessage(LogEventLevel.Fatal, device, message, args); } } diff --git a/src/PepperDash.Core/Logging/DebugMemory.cs b/src/PepperDash.Core/Logging/DebugMemory.cs index a5737af9..7eb58693 100644 --- a/src/PepperDash.Core/Logging/DebugMemory.cs +++ b/src/PepperDash.Core/Logging/DebugMemory.cs @@ -2,25 +2,25 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Core.Logging -{ - /// - /// Class to persist current Debug settings across program restarts - /// +namespace PepperDash.Core.Logging; + +/// +/// Class to persist current Debug settings across program restarts +/// public class DebugContextCollection { - /// - /// To prevent threading issues with the DeviceDebugSettings collection - /// - private readonly CCriticalSection _deviceDebugSettingsLock; + /// + /// To prevent threading issues with the DeviceDebugSettings collection + /// + private readonly CCriticalSection _deviceDebugSettingsLock; [JsonProperty("items")] private readonly Dictionary _items; - /// - /// Collection of the debug settings for each device where the dictionary key is the device key - /// - [JsonProperty("deviceDebugSettings")] - private Dictionary DeviceDebugSettings { get; set; } + /// + /// Collection of the debug settings for each device where the dictionary key is the device key + /// + [JsonProperty("deviceDebugSettings")] + private Dictionary DeviceDebugSettings { get; set; } /// @@ -28,8 +28,8 @@ namespace PepperDash.Core.Logging /// public DebugContextCollection() { - _deviceDebugSettingsLock = new CCriticalSection(); - DeviceDebugSettings = new Dictionary(); + _deviceDebugSettingsLock = new CCriticalSection(); + DeviceDebugSettings = new Dictionary(); _items = new Dictionary(); } @@ -59,40 +59,40 @@ namespace PepperDash.Core.Logging } - /// - /// sets the settings for a device or creates a new entry - /// - /// - /// - /// - public void SetDebugSettingsForKey(string deviceKey, object settings) + /// + /// sets the settings for a device or creates a new entry + /// + /// + /// + /// + public void SetDebugSettingsForKey(string deviceKey, object settings) + { + try { - try - { - _deviceDebugSettingsLock.Enter(); + _deviceDebugSettingsLock.Enter(); - if (DeviceDebugSettings.ContainsKey(deviceKey)) - { - DeviceDebugSettings[deviceKey] = settings; - } - else - DeviceDebugSettings.Add(deviceKey, settings); - } - finally + if (DeviceDebugSettings.ContainsKey(deviceKey)) { - _deviceDebugSettingsLock.Leave(); + DeviceDebugSettings[deviceKey] = settings; } + else + DeviceDebugSettings.Add(deviceKey, settings); } - - /// - /// Gets the device settings for a device by key or returns null - /// - /// - /// - public object GetDebugSettingsForKey(string deviceKey) + finally { - return DeviceDebugSettings[deviceKey]; + _deviceDebugSettingsLock.Leave(); } + } + + /// + /// Gets the device settings for a device by key or returns null + /// + /// + /// + public object GetDebugSettingsForKey(string deviceKey) + { + return DeviceDebugSettings[deviceKey]; + } } /// @@ -100,16 +100,15 @@ namespace PepperDash.Core.Logging /// public class DebugContextItem { - /// - /// The level of debug messages to print - /// + /// + /// The level of debug messages to print + /// [JsonProperty("level")] public int Level { get; set; } - /// - /// Property to tell the program not to intitialize when it boots, if desired - /// - [JsonProperty("doNotLoadOnNextBoot")] - public bool DoNotLoadOnNextBoot { get; set; } - } -} \ No newline at end of file + /// + /// Property to tell the program not to intitialize when it boots, if desired + /// + [JsonProperty("doNotLoadOnNextBoot")] + public bool DoNotLoadOnNextBoot { get; set; } + } \ No newline at end of file diff --git a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs index f9b14028..af479cfa 100644 --- a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs +++ b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs @@ -13,11 +13,11 @@ using WebSocketSharp; using WebSocketSharp.Server; using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; -namespace PepperDash.Core -{ - /// - /// Provides a WebSocket-based logging sink for debugging purposes, allowing log events to be broadcast to connected - /// WebSocket clients. +namespace PepperDash.Core; + + /// + /// Provides a WebSocket-based logging sink for debugging purposes, allowing log events to be broadcast to connected + /// WebSocket clients. /// /// This class implements the interface and is designed to send /// formatted log events to WebSocket clients connected to a secure WebSocket server. The server is hosted locally @@ -30,8 +30,8 @@ namespace PepperDash.Core private const string _certificateName = "selfCres"; private const string _certificatePassword = "cres12345"; - /// - /// Gets the port number on which the HTTPS server is currently running. + /// + /// Gets the port number on which the HTTPS server is currently running. /// public int Port { get @@ -42,8 +42,8 @@ namespace PepperDash.Core } } - /// - /// Gets the WebSocket URL for the current server instance. + /// + /// Gets the WebSocket URL for the current server instance. /// /// The URL is dynamically constructed based on the server's current IP address, port, /// and WebSocket path. @@ -56,8 +56,8 @@ namespace PepperDash.Core } } - /// - /// Gets a value indicating whether the HTTPS server is currently listening for incoming connections. + /// + /// Gets a value indicating whether the HTTPS server is currently listening for incoming connections. /// public bool IsRunning { get => _httpsServer?.IsListening ?? false; } @@ -66,13 +66,13 @@ namespace PepperDash.Core private readonly ITextFormatter _textFormatter; - /// - /// Initializes a new instance of the class with the specified text formatter. - /// - /// This constructor initializes the WebSocket sink and ensures that a certificate is - /// available for secure communication. If the required certificate does not exist, it will be created - /// automatically. Additionally, the sink is configured to stop the server when the program is - /// stopping. + /// + /// Initializes a new instance of the class with the specified text formatter. + /// + /// This constructor initializes the WebSocket sink and ensures that a certificate is + /// available for secure communication. If the required certificate does not exist, it will be created + /// automatically. Additionally, the sink is configured to stop the server when the program is + /// stopping. /// The text formatter used to format log messages. If null, a default JSON formatter is used. public DebugWebsocketSink(ITextFormatter formatProvider) { @@ -117,12 +117,12 @@ namespace PepperDash.Core } } - /// - /// Sends a log event to all connected WebSocket clients. - /// - /// The log event is formatted using the configured text formatter and then broadcasted - /// to all clients connected to the WebSocket server. If the WebSocket server is not initialized or not - /// listening, the method exits without performing any action. + /// + /// Sends a log event to all connected WebSocket clients. + /// + /// The log event is formatted using the configured text formatter and then broadcasted + /// to all clients connected to the WebSocket server. If the WebSocket server is not initialized or not + /// listening, the method exits without performing any action. /// The log event to be formatted and broadcasted. Cannot be null. public void Emit(LogEvent logEvent) { @@ -134,12 +134,12 @@ namespace PepperDash.Core _httpsServer.WebSocketServices[_path].Sessions.Broadcast(sw.ToString()); } - /// - /// Starts the WebSocket server on the specified port and configures it with the appropriate certificate. - /// - /// This method initializes the WebSocket server and binds it to the specified port. It - /// also applies the server's certificate for secure communication. Ensure that the port is not already in use - /// and that the certificate file is accessible. + /// + /// Starts the WebSocket server on the specified port and configures it with the appropriate certificate. + /// + /// This method initializes the WebSocket server and binds it to the specified port. It + /// also applies the server's certificate for secure communication. Ensure that the port is not already in use + /// and that the certificate file is accessible. /// The port number on which the WebSocket server will listen. Must be a valid, non-negative port number. public void StartServerAndSetPort(int port) { @@ -160,15 +160,15 @@ namespace PepperDash.Core Debug.Console(0, "Assigning SSL Configuration"); _httpsServer.SslConfiguration.ServerCertificate = new X509Certificate2(certPath, certPassword); - _httpsServer.SslConfiguration.ClientCertificateRequired = false; - _httpsServer.SslConfiguration.CheckCertificateRevocation = false; - _httpsServer.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; - //this is just to test, you might want to actually validate + _httpsServer.SslConfiguration.ClientCertificateRequired = false; + _httpsServer.SslConfiguration.CheckCertificateRevocation = false; + _httpsServer.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; + //this is just to test, you might want to actually validate _httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered"); return true; - }; + }; } Debug.Console(0, "Adding Debug Client Service"); _httpsServer.AddWebSocketService(_path); @@ -216,8 +216,8 @@ namespace PepperDash.Core } } - /// - /// Stops the WebSocket server if it is currently running. + /// + /// Stops the WebSocket server if it is currently running. /// /// This method halts the WebSocket server and releases any associated resources. After /// calling this method, the server will no longer accept or process incoming connections. @@ -230,20 +230,20 @@ namespace PepperDash.Core } } - /// - /// Configures the logger to write log events to a debug WebSocket sink. + /// + /// Configures the logger to write log events to a debug WebSocket sink. /// /// This extension method allows you to direct log events to a WebSocket sink for debugging /// purposes. public static class DebugWebsocketSinkExtensions { - /// - /// Configures a logger to write log events to a debug WebSocket sink. - /// - /// This method adds a sink that writes log events to a WebSocket for debugging purposes. - /// It is typically used during development to stream log events in real-time. - /// The logger sink configuration to apply the WebSocket sink to. - /// An optional text formatter to format the log events. If not provided, a default formatter will be used. + /// + /// Configures a logger to write log events to a debug WebSocket sink. + /// + /// This method adds a sink that writes log events to a WebSocket for debugging purposes. + /// It is typically used during development to stream log events in real-time. + /// The logger sink configuration to apply the WebSocket sink to. + /// An optional text formatter to format the log events. If not provided, a default formatter will be used. /// A object that can be used to further configure the logger. public static LoggerConfiguration DebugWebsocketSink( this LoggerSinkConfiguration loggerConfiguration, @@ -253,9 +253,9 @@ namespace PepperDash.Core } } - /// - /// Represents a WebSocket client for debugging purposes, providing connection lifecycle management and message - /// handling functionality. + /// + /// Represents a WebSocket client for debugging purposes, providing connection lifecycle management and message + /// handling functionality. /// /// The class extends to handle /// WebSocket connections, including events for opening, closing, receiving messages, and errors. It tracks the @@ -264,8 +264,8 @@ namespace PepperDash.Core { private DateTime _connectionTime; - /// - /// Gets the duration of time the WebSocket connection has been active. + /// + /// Gets the duration of time the WebSocket connection has been active. /// public TimeSpan ConnectedDuration { @@ -282,8 +282,8 @@ namespace PepperDash.Core } } - /// - /// Initializes a new instance of the class. + /// + /// Initializes a new instance of the class. /// /// This constructor creates a new instance and logs its /// creation using the method with a debug level of 0. @@ -326,6 +326,5 @@ namespace PepperDash.Core base.OnError(e); Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message); - } } } diff --git a/src/PepperDash.Core/Network/DiscoveryThings.cs b/src/PepperDash.Core/Network/DiscoveryThings.cs index 973c03a4..c01613b7 100644 --- a/src/PepperDash.Core/Network/DiscoveryThings.cs +++ b/src/PepperDash.Core/Network/DiscoveryThings.cs @@ -4,19 +4,17 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core -{ +namespace PepperDash.Core; + +/// +/// Not in use +/// + public static class NetworkComm + { /// /// Not in use /// - public static class NetworkComm - { - /// - /// Not in use - /// static NetworkComm() { } - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/Config.cs b/src/PepperDash.Core/PasswordManagement/Config.cs index 22aa4881..a5f071a4 100644 --- a/src/PepperDash.Core/PasswordManagement/Config.cs +++ b/src/PepperDash.Core/PasswordManagement/Config.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.PasswordManagement -{ +namespace PepperDash.Core.PasswordManagement; + /// /// JSON password configuration /// @@ -22,5 +22,4 @@ namespace PepperDash.Core.PasswordManagement { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/Constants.cs b/src/PepperDash.Core/PasswordManagement/Constants.cs index 65a1bf45..d4cf1e0b 100644 --- a/src/PepperDash.Core/PasswordManagement/Constants.cs +++ b/src/PepperDash.Core/PasswordManagement/Constants.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.PasswordManagement -{ +namespace PepperDash.Core.PasswordManagement; + /// /// Constants /// @@ -53,5 +53,4 @@ namespace PepperDash.Core.PasswordManagement /// Generic string value change constant /// public const ushort StringValueChange = 201; - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/PasswordClient.cs b/src/PepperDash.Core/PasswordManagement/PasswordClient.cs index 225a563c..27d71e95 100644 --- a/src/PepperDash.Core/PasswordManagement/PasswordClient.cs +++ b/src/PepperDash.Core/PasswordManagement/PasswordClient.cs @@ -1,10 +1,10 @@ using System; -namespace PepperDash.Core.PasswordManagement -{ - /// - /// A class to allow user interaction with the PasswordManager - /// +namespace PepperDash.Core.PasswordManagement; + +/// +/// A class to allow user interaction with the PasswordManager +/// public class PasswordClient { /// @@ -183,5 +183,4 @@ namespace PepperDash.Core.PasswordManagement GetPasswordByIndex(args.Index); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/PasswordManagement/PasswordManager.cs b/src/PepperDash.Core/PasswordManagement/PasswordManager.cs index d15ac1e1..da44e059 100644 --- a/src/PepperDash.Core/PasswordManagement/PasswordManager.cs +++ b/src/PepperDash.Core/PasswordManagement/PasswordManager.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using Crestron.SimplSharp; -namespace PepperDash.Core.PasswordManagement -{ - /// - /// Allows passwords to be stored and managed - /// +namespace PepperDash.Core.PasswordManagement; + +/// +/// Allows passwords to be stored and managed +/// public class PasswordManager { /// @@ -190,7 +190,7 @@ namespace PepperDash.Core.PasswordManagement /// /// Protected ushort change event handler /// - /// + /// /// /// protected void OnUshrtChange(ushort value, ushort index, ushort type) @@ -237,5 +237,4 @@ namespace PepperDash.Core.PasswordManagement PasswordChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs b/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs index cc71e303..46d99072 100644 --- a/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs +++ b/src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs @@ -4,68 +4,68 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.SystemInfo -{ +namespace PepperDash.Core.SystemInfo; + /// /// Constants /// public class SystemInfoConstants { - /// - /// - /// + /// + /// + /// public const ushort BoolValueChange = 1; /// /// /// - public const ushort CompleteBoolChange = 2; + public const ushort CompleteBoolChange = 2; /// /// /// - public const ushort BusyBoolChange = 3; - - /// - /// - /// + public const ushort BusyBoolChange = 3; + + /// + /// + /// public const ushort UshortValueChange = 101; - /// - /// - /// + /// + /// + /// public const ushort StringValueChange = 201; /// /// /// - public const ushort ConsoleResponseChange = 202; + public const ushort ConsoleResponseChange = 202; /// /// /// - public const ushort ProcessorUptimeChange = 203; + public const ushort ProcessorUptimeChange = 203; /// /// /// - public const ushort ProgramUptimeChange = 204; + public const ushort ProgramUptimeChange = 204; - /// - /// - /// + /// + /// + /// public const ushort ObjectChange = 301; /// /// /// - public const ushort ProcessorConfigChange = 302; + public const ushort ProcessorConfigChange = 302; /// /// /// - public const ushort EthernetConfigChange = 303; + public const ushort EthernetConfigChange = 303; /// /// /// - public const ushort ControlSubnetConfigChange = 304; + public const ushort ControlSubnetConfigChange = 304; /// /// /// - public const ushort ProgramConfigChange = 305; + public const ushort ProgramConfigChange = 305; } /// @@ -73,18 +73,18 @@ namespace PepperDash.Core.SystemInfo /// public class ProcessorChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ProcessorInfo Processor { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -119,18 +119,18 @@ namespace PepperDash.Core.SystemInfo /// public class EthernetChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public EthernetInfo Adapter { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -143,7 +143,7 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type) { @@ -154,9 +154,9 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// - /// + /// public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type, ushort index) { Adapter = ethernet; @@ -170,18 +170,18 @@ namespace PepperDash.Core.SystemInfo /// public class ControlSubnetChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ControlSubnetInfo Adapter { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -216,18 +216,18 @@ namespace PepperDash.Core.SystemInfo /// public class ProgramChangeEventArgs : EventArgs { - /// - /// - /// + /// + /// + /// public ProgramInfo Program { get; set; } /// /// /// - public ushort Type { get; set; } + public ushort Type { get; set; } /// /// /// - public ushort Index { get; set; } + public ushort Index { get; set; } /// /// Constructor @@ -240,7 +240,7 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// public ProgramChangeEventArgs(ProgramInfo program, ushort type) { @@ -251,14 +251,13 @@ namespace PepperDash.Core.SystemInfo /// /// Constructor overload /// - /// + /// /// - /// + /// public ProgramChangeEventArgs(ProgramInfo program, ushort type, ushort index) { Program = program; Type = type; Index = index; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs b/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs index 8dc3acaf..950abecb 100644 --- a/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs +++ b/src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs @@ -4,52 +4,52 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.SystemInfo -{ +namespace PepperDash.Core.SystemInfo; + /// /// Processor info class /// public class ProcessorInfo { - /// - /// - /// + /// + /// + /// public string Model { get; set; } - /// - /// - /// + /// + /// + /// public string SerialNumber { get; set; } - /// - /// - /// + /// + /// + /// public string Firmware { get; set; } - /// - /// - /// + /// + /// + /// public string FirmwareDate { get; set; } - /// - /// - /// + /// + /// + /// public string OsVersion { get; set; } - /// - /// - /// + /// + /// + /// public string RuntimeEnvironment { get; set; } - /// - /// - /// + /// + /// + /// public string DevicePlatform { get; set; } - /// - /// - /// + /// + /// + /// public string ModuleDirectory { get; set; } - /// - /// - /// + /// + /// + /// public string LocalTimeZone { get; set; } - /// - /// - /// + /// + /// + /// public string ProgramIdTag { get; set; } /// @@ -66,45 +66,45 @@ namespace PepperDash.Core.SystemInfo /// public class EthernetInfo { - /// - /// - /// + /// + /// + /// public ushort DhcpIsOn { get; set; } - /// - /// - /// + /// + /// + /// public string Hostname { get; set; } - /// - /// - /// + /// + /// + /// public string MacAddress { get; set; } - /// - /// - /// + /// + /// + /// public string IpAddress { get; set; } - /// - /// - /// + /// + /// + /// public string Subnet { get; set; } - /// - /// - /// + /// + /// + /// public string Gateway { get; set; } - /// - /// - /// + /// + /// + /// public string Dns1 { get; set; } - /// - /// - /// + /// + /// + /// public string Dns2 { get; set; } - /// - /// - /// + /// + /// + /// public string Dns3 { get; set; } - /// - /// - /// + /// + /// + /// public string Domain { get; set; } /// @@ -121,29 +121,29 @@ namespace PepperDash.Core.SystemInfo /// public class ControlSubnetInfo { - /// - /// - /// + /// + /// + /// public ushort Enabled { get; set; } - /// - /// - /// + /// + /// + /// public ushort IsInAutomaticMode { get; set; } - /// - /// - /// + /// + /// + /// public string MacAddress { get; set; } - /// - /// - /// + /// + /// + /// public string IpAddress { get; set; } - /// - /// - /// + /// + /// + /// public string Subnet { get; set; } - /// - /// - /// + /// + /// + /// public string RouterPrefix { get; set; } /// @@ -160,37 +160,37 @@ namespace PepperDash.Core.SystemInfo /// public class ProgramInfo { - /// - /// - /// + /// + /// + /// public string Name { get; set; } - /// - /// - /// + /// + /// + /// public string Header { get; set; } - /// - /// - /// + /// + /// + /// public string System { get; set; } - /// - /// - /// + /// + /// + /// public string ProgramIdTag { get; set; } - /// - /// - /// + /// + /// + /// public string CompileTime { get; set; } - /// - /// - /// + /// + /// + /// public string Database { get; set; } - /// - /// - /// + /// + /// + /// public string Environment { get; set; } - /// - /// - /// + /// + /// + /// public string Programmer { get; set; } /// @@ -200,5 +200,4 @@ namespace PepperDash.Core.SystemInfo { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs b/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs index 6677b9ef..be24be57 100644 --- a/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs +++ b/src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs @@ -4,37 +4,37 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.SystemInfo -{ +namespace PepperDash.Core.SystemInfo; + /// /// System Info class /// public class SystemInfoToSimpl { - /// - /// Notifies of bool change - /// + /// + /// Notifies of bool change + /// public event EventHandler BoolChange; - /// - /// Notifies of string change - /// + /// + /// Notifies of string change + /// public event EventHandler StringChange; - /// - /// Notifies of processor change - /// + /// + /// Notifies of processor change + /// public event EventHandler ProcessorChange; - /// - /// Notifies of ethernet change - /// + /// + /// Notifies of ethernet change + /// public event EventHandler EthernetChange; - /// - /// Notifies of control subnet change - /// + /// + /// Notifies of control subnet change + /// public event EventHandler ControlSubnetChange; - /// - /// Notifies of program change - /// + /// + /// Notifies of program change + /// public event EventHandler ProgramChange; /// @@ -327,10 +327,10 @@ namespace PepperDash.Core.SystemInfo /// /// private method to parse console messages /// - /// + /// /// - /// - /// + /// + /// /// private string ParseConsoleResponse(string data, string line, string dataStart, string dataEnd) { @@ -458,5 +458,4 @@ namespace PepperDash.Core.SystemInfo ProgramChange(this, args); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/BouncyCertificate.cs b/src/PepperDash.Core/Web/BouncyCertificate.cs index bf8b0f4c..148b6eb1 100644 --- a/src/PepperDash.Core/Web/BouncyCertificate.cs +++ b/src/PepperDash.Core/Web/BouncyCertificate.cs @@ -20,337 +20,336 @@ using Org.BouncyCastle.Crypto.Operators; using BigInteger = Org.BouncyCastle.Math.BigInteger; using X509Certificate = Org.BouncyCastle.X509.X509Certificate; -namespace PepperDash.Core +namespace PepperDash.Core; + +/// +/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/ +/// +internal class BouncyCertificate { - /// - /// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/ - /// - internal class BouncyCertificate + public string CertificatePassword { get; set; } = "password"; + public X509Certificate2 LoadCertificate(string issuerFileName, string password) { - public string CertificatePassword { get; set; } = "password"; - public X509Certificate2 LoadCertificate(string issuerFileName, string password) + // We need to pass 'Exportable', otherwise we can't get the private key. + var issuerCertificate = new X509Certificate2(issuerFileName, password, X509KeyStorageFlags.Exportable); + return issuerCertificate; + } + + public X509Certificate2 IssueCertificate(string subjectName, X509Certificate2 issuerCertificate, string[] subjectAlternativeNames, KeyPurposeID[] usages) + { + // It's self-signed, so these are the same. + var issuerName = issuerCertificate.Subject; + + var random = GetSecureRandom(); + var subjectKeyPair = GenerateKeyPair(random, 2048); + + var issuerKeyPair = DotNetUtilities.GetKeyPair(issuerCertificate.PrivateKey); + + var serialNumber = GenerateSerialNumber(random); + var issuerSerialNumber = new BigInteger(issuerCertificate.GetSerialNumber()); + + const bool isCertificateAuthority = false; + var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, + subjectAlternativeNames, issuerName, issuerKeyPair, + issuerSerialNumber, isCertificateAuthority, + usages); + return ConvertCertificate(certificate, subjectKeyPair, random); + } + + public X509Certificate2 CreateCertificateAuthorityCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) + { + // It's self-signed, so these are the same. + var issuerName = subjectName; + + var random = GetSecureRandom(); + var subjectKeyPair = GenerateKeyPair(random, 2048); + + // It's self-signed, so these are the same. + var issuerKeyPair = subjectKeyPair; + + var serialNumber = GenerateSerialNumber(random); + var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number. + + const bool isCertificateAuthority = true; + var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, + subjectAlternativeNames, issuerName, issuerKeyPair, + issuerSerialNumber, isCertificateAuthority, + usages); + return ConvertCertificate(certificate, subjectKeyPair, random); + } + + public X509Certificate2 CreateSelfSignedCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) + { + // It's self-signed, so these are the same. + var issuerName = subjectName; + + var random = GetSecureRandom(); + var subjectKeyPair = GenerateKeyPair(random, 2048); + + // It's self-signed, so these are the same. + var issuerKeyPair = subjectKeyPair; + + var serialNumber = GenerateSerialNumber(random); + var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number. + + const bool isCertificateAuthority = false; + var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, + subjectAlternativeNames, issuerName, issuerKeyPair, + issuerSerialNumber, isCertificateAuthority, + usages); + return ConvertCertificate(certificate, subjectKeyPair, random); + } + + private SecureRandom GetSecureRandom() + { + // Since we're on Windows, we'll use the CryptoAPI one (on the assumption + // that it might have access to better sources of entropy than the built-in + // Bouncy Castle ones): + var randomGenerator = new CryptoApiRandomGenerator(); + var random = new SecureRandom(randomGenerator); + return random; + } + + private X509Certificate GenerateCertificate(SecureRandom random, + string subjectName, + AsymmetricCipherKeyPair subjectKeyPair, + BigInteger subjectSerialNumber, + string[] subjectAlternativeNames, + string issuerName, + AsymmetricCipherKeyPair issuerKeyPair, + BigInteger issuerSerialNumber, + bool isCertificateAuthority, + KeyPurposeID[] usages) + { + var certificateGenerator = new X509V3CertificateGenerator(); + + certificateGenerator.SetSerialNumber(subjectSerialNumber); + + var issuerDN = new X509Name(issuerName); + certificateGenerator.SetIssuerDN(issuerDN); + + // Note: The subject can be omitted if you specify a subject alternative name (SAN). + var subjectDN = new X509Name(subjectName); + certificateGenerator.SetSubjectDN(subjectDN); + + // Our certificate needs valid from/to values. + var notBefore = DateTime.UtcNow.Date; + var notAfter = notBefore.AddYears(2); + + certificateGenerator.SetNotBefore(notBefore); + certificateGenerator.SetNotAfter(notAfter); + + // The subject's public key goes in the certificate. + certificateGenerator.SetPublicKey(subjectKeyPair.Public); + + AddAuthorityKeyIdentifier(certificateGenerator, issuerDN, issuerKeyPair, issuerSerialNumber); + AddSubjectKeyIdentifier(certificateGenerator, subjectKeyPair); + //AddBasicConstraints(certificateGenerator, isCertificateAuthority); + + if (usages != null && usages.Any()) + AddExtendedKeyUsage(certificateGenerator, usages); + + if (subjectAlternativeNames != null && subjectAlternativeNames.Any()) + AddSubjectAlternativeNames(certificateGenerator, subjectAlternativeNames); + + // Set the signature algorithm. This is used to generate the thumbprint which is then signed + // with the issuer's private key. We'll use SHA-256, which is (currently) considered fairly strong. + const string signatureAlgorithm = "SHA256WithRSA"; + + // The certificate is signed with the issuer's private key. + ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private, random); + var certificate = certificateGenerator.Generate(signatureFactory); + return certificate; + } + + /// + /// The certificate needs a serial number. This is used for revocation, + /// and usually should be an incrementing index (which makes it easier to revoke a range of certificates). + /// Since we don't have anywhere to store the incrementing index, we can just use a random number. + /// + /// + /// + private BigInteger GenerateSerialNumber(SecureRandom random) + { + var serialNumber = + BigIntegers.CreateRandomInRange( + BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); + return serialNumber; + } + + /// + /// Generate a key pair. + /// + /// The random number generator. + /// The key length in bits. For RSA, 2048 bits should be considered the minimum acceptable these days. + /// + private AsymmetricCipherKeyPair GenerateKeyPair(SecureRandom random, int strength) + { + var keyGenerationParameters = new KeyGenerationParameters(random, strength); + + var keyPairGenerator = new RsaKeyPairGenerator(); + keyPairGenerator.Init(keyGenerationParameters); + var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); + return subjectKeyPair; + } + + /// + /// Add the Authority Key Identifier. According to http://www.alvestrand.no/objectid/2.5.29.35.html, this + /// identifies the public key to be used to verify the signature on this certificate. + /// In a certificate chain, this corresponds to the "Subject Key Identifier" on the *issuer* certificate. + /// The Bouncy Castle documentation, at http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation, + /// shows how to create this from the issuing certificate. Since we're creating a self-signed certificate, we have to do this slightly differently. + /// + /// + /// + /// + /// + private void AddAuthorityKeyIdentifier(X509V3CertificateGenerator certificateGenerator, + X509Name issuerDN, + AsymmetricCipherKeyPair issuerKeyPair, + BigInteger issuerSerialNumber) + { + var authorityKeyIdentifierExtension = + new AuthorityKeyIdentifier( + SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKeyPair.Public), + new GeneralNames(new GeneralName(issuerDN)), + issuerSerialNumber); + certificateGenerator.AddExtension( + X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifierExtension); + } + + /// + /// Add the "Subject Alternative Names" extension. Note that you have to repeat + /// the value from the "Subject Name" property. + /// + /// + /// + private void AddSubjectAlternativeNames(X509V3CertificateGenerator certificateGenerator, + IEnumerable subjectAlternativeNames) + { + var subjectAlternativeNamesExtension = + new DerSequence( + subjectAlternativeNames.Select(name => new GeneralName(GeneralName.DnsName, name)) + .ToArray()); + certificateGenerator.AddExtension( + X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension); + } + + /// + /// Add the "Extended Key Usage" extension, specifying (for example) "server authentication". + /// + /// + /// + private void AddExtendedKeyUsage(X509V3CertificateGenerator certificateGenerator, KeyPurposeID[] usages) + { + certificateGenerator.AddExtension( + X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(usages)); + } + + /// + /// Add the "Basic Constraints" extension. + /// + /// + /// + private void AddBasicConstraints(X509V3CertificateGenerator certificateGenerator, + bool isCertificateAuthority) + { + certificateGenerator.AddExtension( + X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCertificateAuthority)); + } + + /// + /// Add the Subject Key Identifier. + /// + /// + /// + private void AddSubjectKeyIdentifier(X509V3CertificateGenerator certificateGenerator, + AsymmetricCipherKeyPair subjectKeyPair) + { + var subjectKeyIdentifierExtension = + new SubjectKeyIdentifier( + SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public)); + certificateGenerator.AddExtension( + X509Extensions.SubjectKeyIdentifier.Id, false, subjectKeyIdentifierExtension); + } + + private X509Certificate2 ConvertCertificate(X509Certificate certificate, + AsymmetricCipherKeyPair subjectKeyPair, + SecureRandom random) + { + // Now to convert the Bouncy Castle certificate to a .NET certificate. + // See http://web.archive.org/web/20100504192226/http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx + // ...but, basically, we create a PKCS12 store (a .PFX file) in memory, and add the public and private key to that. + var store = new Pkcs12StoreBuilder().Build(); + + // What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name". + string friendlyName = certificate.SubjectDN.ToString(); + + // Add the certificate. + var certificateEntry = new X509CertificateEntry(certificate); + store.SetCertificateEntry(friendlyName, certificateEntry); + + // Add the private key. + store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry }); + + // Convert it to an X509Certificate2 object by saving/loading it from a MemoryStream. + // It needs a password. Since we'll remove this later, it doesn't particularly matter what we use. + + var stream = new MemoryStream(); + store.Save(stream, CertificatePassword.ToCharArray(), random); + + var convertedCertificate = + new X509Certificate2(stream.ToArray(), + CertificatePassword, + X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + return convertedCertificate; + } + + public void WriteCertificate(X509Certificate2 certificate, string outputDirectory, string certName) + { + // This password is the one attached to the PFX file. Use 'null' for no password. + // Create PFX (PKCS #12) with private key + try { - // We need to pass 'Exportable', otherwise we can't get the private key. - var issuerCertificate = new X509Certificate2(issuerFileName, password, X509KeyStorageFlags.Exportable); - return issuerCertificate; + var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword); + File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx); } - - public X509Certificate2 IssueCertificate(string subjectName, X509Certificate2 issuerCertificate, string[] subjectAlternativeNames, KeyPurposeID[] usages) + catch (Exception ex) { - // It's self-signed, so these are the same. - var issuerName = issuerCertificate.Subject; - - var random = GetSecureRandom(); - var subjectKeyPair = GenerateKeyPair(random, 2048); - - var issuerKeyPair = DotNetUtilities.GetKeyPair(issuerCertificate.PrivateKey); - - var serialNumber = GenerateSerialNumber(random); - var issuerSerialNumber = new BigInteger(issuerCertificate.GetSerialNumber()); - - const bool isCertificateAuthority = false; - var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, - subjectAlternativeNames, issuerName, issuerKeyPair, - issuerSerialNumber, isCertificateAuthority, - usages); - return ConvertCertificate(certificate, subjectKeyPair, random); + CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message)); } - - public X509Certificate2 CreateCertificateAuthorityCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) + // Create Base 64 encoded CER (public key only) + using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false)) { - // It's self-signed, so these are the same. - var issuerName = subjectName; - - var random = GetSecureRandom(); - var subjectKeyPair = GenerateKeyPair(random, 2048); - - // It's self-signed, so these are the same. - var issuerKeyPair = subjectKeyPair; - - var serialNumber = GenerateSerialNumber(random); - var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number. - - const bool isCertificateAuthority = true; - var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, - subjectAlternativeNames, issuerName, issuerKeyPair, - issuerSerialNumber, isCertificateAuthority, - usages); - return ConvertCertificate(certificate, subjectKeyPair, random); - } - - public X509Certificate2 CreateSelfSignedCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) - { - // It's self-signed, so these are the same. - var issuerName = subjectName; - - var random = GetSecureRandom(); - var subjectKeyPair = GenerateKeyPair(random, 2048); - - // It's self-signed, so these are the same. - var issuerKeyPair = subjectKeyPair; - - var serialNumber = GenerateSerialNumber(random); - var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number. - - const bool isCertificateAuthority = false; - var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, - subjectAlternativeNames, issuerName, issuerKeyPair, - issuerSerialNumber, isCertificateAuthority, - usages); - return ConvertCertificate(certificate, subjectKeyPair, random); - } - - private SecureRandom GetSecureRandom() - { - // Since we're on Windows, we'll use the CryptoAPI one (on the assumption - // that it might have access to better sources of entropy than the built-in - // Bouncy Castle ones): - var randomGenerator = new CryptoApiRandomGenerator(); - var random = new SecureRandom(randomGenerator); - return random; - } - - private X509Certificate GenerateCertificate(SecureRandom random, - string subjectName, - AsymmetricCipherKeyPair subjectKeyPair, - BigInteger subjectSerialNumber, - string[] subjectAlternativeNames, - string issuerName, - AsymmetricCipherKeyPair issuerKeyPair, - BigInteger issuerSerialNumber, - bool isCertificateAuthority, - KeyPurposeID[] usages) - { - var certificateGenerator = new X509V3CertificateGenerator(); - - certificateGenerator.SetSerialNumber(subjectSerialNumber); - - var issuerDN = new X509Name(issuerName); - certificateGenerator.SetIssuerDN(issuerDN); - - // Note: The subject can be omitted if you specify a subject alternative name (SAN). - var subjectDN = new X509Name(subjectName); - certificateGenerator.SetSubjectDN(subjectDN); - - // Our certificate needs valid from/to values. - var notBefore = DateTime.UtcNow.Date; - var notAfter = notBefore.AddYears(2); - - certificateGenerator.SetNotBefore(notBefore); - certificateGenerator.SetNotAfter(notAfter); - - // The subject's public key goes in the certificate. - certificateGenerator.SetPublicKey(subjectKeyPair.Public); - - AddAuthorityKeyIdentifier(certificateGenerator, issuerDN, issuerKeyPair, issuerSerialNumber); - AddSubjectKeyIdentifier(certificateGenerator, subjectKeyPair); - //AddBasicConstraints(certificateGenerator, isCertificateAuthority); - - if (usages != null && usages.Any()) - AddExtendedKeyUsage(certificateGenerator, usages); - - if (subjectAlternativeNames != null && subjectAlternativeNames.Any()) - AddSubjectAlternativeNames(certificateGenerator, subjectAlternativeNames); - - // Set the signature algorithm. This is used to generate the thumbprint which is then signed - // with the issuer's private key. We'll use SHA-256, which is (currently) considered fairly strong. - const string signatureAlgorithm = "SHA256WithRSA"; - - // The certificate is signed with the issuer's private key. - ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private, random); - var certificate = certificateGenerator.Generate(signatureFactory); - return certificate; - } - - /// - /// The certificate needs a serial number. This is used for revocation, - /// and usually should be an incrementing index (which makes it easier to revoke a range of certificates). - /// Since we don't have anywhere to store the incrementing index, we can just use a random number. - /// - /// - /// - private BigInteger GenerateSerialNumber(SecureRandom random) - { - var serialNumber = - BigIntegers.CreateRandomInRange( - BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); - return serialNumber; - } - - /// - /// Generate a key pair. - /// - /// The random number generator. - /// The key length in bits. For RSA, 2048 bits should be considered the minimum acceptable these days. - /// - private AsymmetricCipherKeyPair GenerateKeyPair(SecureRandom random, int strength) - { - var keyGenerationParameters = new KeyGenerationParameters(random, strength); - - var keyPairGenerator = new RsaKeyPairGenerator(); - keyPairGenerator.Init(keyGenerationParameters); - var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); - return subjectKeyPair; - } - - /// - /// Add the Authority Key Identifier. According to http://www.alvestrand.no/objectid/2.5.29.35.html, this - /// identifies the public key to be used to verify the signature on this certificate. - /// In a certificate chain, this corresponds to the "Subject Key Identifier" on the *issuer* certificate. - /// The Bouncy Castle documentation, at http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation, - /// shows how to create this from the issuing certificate. Since we're creating a self-signed certificate, we have to do this slightly differently. - /// - /// - /// - /// - /// - private void AddAuthorityKeyIdentifier(X509V3CertificateGenerator certificateGenerator, - X509Name issuerDN, - AsymmetricCipherKeyPair issuerKeyPair, - BigInteger issuerSerialNumber) - { - var authorityKeyIdentifierExtension = - new AuthorityKeyIdentifier( - SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKeyPair.Public), - new GeneralNames(new GeneralName(issuerDN)), - issuerSerialNumber); - certificateGenerator.AddExtension( - X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifierExtension); - } - - /// - /// Add the "Subject Alternative Names" extension. Note that you have to repeat - /// the value from the "Subject Name" property. - /// - /// - /// - private void AddSubjectAlternativeNames(X509V3CertificateGenerator certificateGenerator, - IEnumerable subjectAlternativeNames) - { - var subjectAlternativeNamesExtension = - new DerSequence( - subjectAlternativeNames.Select(name => new GeneralName(GeneralName.DnsName, name)) - .ToArray()); - certificateGenerator.AddExtension( - X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension); - } - - /// - /// Add the "Extended Key Usage" extension, specifying (for example) "server authentication". - /// - /// - /// - private void AddExtendedKeyUsage(X509V3CertificateGenerator certificateGenerator, KeyPurposeID[] usages) - { - certificateGenerator.AddExtension( - X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(usages)); - } - - /// - /// Add the "Basic Constraints" extension. - /// - /// - /// - private void AddBasicConstraints(X509V3CertificateGenerator certificateGenerator, - bool isCertificateAuthority) - { - certificateGenerator.AddExtension( - X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCertificateAuthority)); - } - - /// - /// Add the Subject Key Identifier. - /// - /// - /// - private void AddSubjectKeyIdentifier(X509V3CertificateGenerator certificateGenerator, - AsymmetricCipherKeyPair subjectKeyPair) - { - var subjectKeyIdentifierExtension = - new SubjectKeyIdentifier( - SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public)); - certificateGenerator.AddExtension( - X509Extensions.SubjectKeyIdentifier.Id, false, subjectKeyIdentifierExtension); - } - - private X509Certificate2 ConvertCertificate(X509Certificate certificate, - AsymmetricCipherKeyPair subjectKeyPair, - SecureRandom random) - { - // Now to convert the Bouncy Castle certificate to a .NET certificate. - // See http://web.archive.org/web/20100504192226/http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx - // ...but, basically, we create a PKCS12 store (a .PFX file) in memory, and add the public and private key to that. - var store = new Pkcs12StoreBuilder().Build(); - - // What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name". - string friendlyName = certificate.SubjectDN.ToString(); - - // Add the certificate. - var certificateEntry = new X509CertificateEntry(certificate); - store.SetCertificateEntry(friendlyName, certificateEntry); - - // Add the private key. - store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry }); - - // Convert it to an X509Certificate2 object by saving/loading it from a MemoryStream. - // It needs a password. Since we'll remove this later, it doesn't particularly matter what we use. - - var stream = new MemoryStream(); - store.Save(stream, CertificatePassword.ToCharArray(), random); - - var convertedCertificate = - new X509Certificate2(stream.ToArray(), - CertificatePassword, - X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); - return convertedCertificate; - } - - public void WriteCertificate(X509Certificate2 certificate, string outputDirectory, string certName) - { - // This password is the one attached to the PFX file. Use 'null' for no password. - // Create PFX (PKCS #12) with private key try { - var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword); - File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx); + var contents = string.Format("-----BEGIN CERTIFICATE-----\r\n{0}\r\n-----END CERTIFICATE-----", Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)); + writer.Write(contents); } catch (Exception ex) { - CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message)); + CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\r\n{0}", ex.Message)); } - // Create Base 64 encoded CER (public key only) - using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false)) - { - try - { - var contents = string.Format("-----BEGIN CERTIFICATE-----\r\n{0}\r\n-----END CERTIFICATE-----", Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)); - writer.Write(contents); - } - catch (Exception ex) - { - CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\r\n{0}", ex.Message)); - } - } - } - public bool AddCertToStore(X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl) - { - bool bRet = false; - - try - { - var store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl); - store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite); - store.Add(cert); - - store.Close(); - bRet = true; - } - catch (Exception ex) - { - CrestronConsole.PrintLine(string.Format("AddCertToStore Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace)); - } - - return bRet; } } + public bool AddCertToStore(X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl) + { + bool bRet = false; + + try + { + var store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl); + store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite); + store.Add(cert); + + store.Close(); + bRet = true; + } + catch (Exception ex) + { + CrestronConsole.PrintLine(string.Format("AddCertToStore Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace)); + } + + return bRet; + } } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs b/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs index ca19cf2f..2fee0a62 100644 --- a/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs +++ b/src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs @@ -1,7 +1,7 @@ using Crestron.SimplSharp.WebScripting; -namespace PepperDash.Core.Web.RequestHandlers -{ +namespace PepperDash.Core.Web.RequestHandlers; + /// /// Web API default request handler /// @@ -13,5 +13,4 @@ namespace PepperDash.Core.Web.RequestHandlers public DefaultRequestHandler() : base(true) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs index b1170031..e8b3e85b 100644 --- a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs +++ b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs @@ -3,161 +3,160 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -namespace PepperDash.Core.Web.RequestHandlers +namespace PepperDash.Core.Web.RequestHandlers; + +public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler { - public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler + private readonly Dictionary> _handlers; + protected readonly bool EnableCors; + + /// + /// Constructor + /// + protected WebApiBaseRequestAsyncHandler(bool enableCors) { - private readonly Dictionary> _handlers; - protected readonly bool EnableCors; + EnableCors = enableCors; - /// - /// Constructor - /// - protected WebApiBaseRequestAsyncHandler(bool enableCors) + _handlers = new Dictionary> { - EnableCors = enableCors; + {"CONNECT", HandleConnect}, + {"DELETE", HandleDelete}, + {"GET", HandleGet}, + {"HEAD", HandleHead}, + {"OPTIONS", HandleOptions}, + {"PATCH", HandlePatch}, + {"POST", HandlePost}, + {"PUT", HandlePut}, + {"TRACE", HandleTrace} + }; + } - _handlers = new Dictionary> - { - {"CONNECT", HandleConnect}, - {"DELETE", HandleDelete}, - {"GET", HandleGet}, - {"HEAD", HandleHead}, - {"OPTIONS", HandleOptions}, - {"PATCH", HandlePatch}, - {"POST", HandlePost}, - {"PUT", HandlePut}, - {"TRACE", HandleTrace} - }; + /// + /// Constructor + /// + protected WebApiBaseRequestAsyncHandler() + : this(false) + { + } + + /// + /// Handles CONNECT method requests + /// + /// + protected virtual async Task HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected virtual async Task HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected virtual async Task HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected virtual async Task HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected virtual async Task HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected virtual async Task HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected virtual async Task HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected virtual async Task HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected virtual async Task HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Process request + /// + /// + public void ProcessRequest(HttpCwsContext context) + { + if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func handler)) + { + return; } - /// - /// Constructor - /// - protected WebApiBaseRequestAsyncHandler() - : this(false) + if (EnableCors) { + context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); + context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); } - /// - /// Handles CONNECT method requests - /// - /// - protected virtual async Task HandleConnect(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } + var handlerTask = handler(context); - /// - /// Handles DELETE method requests - /// - /// - protected virtual async Task HandleDelete(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles GET method requests - /// - /// - protected virtual async Task HandleGet(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles HEAD method requests - /// - /// - protected virtual async Task HandleHead(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles OPTIONS method requests - /// - /// - protected virtual async Task HandleOptions(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles PATCH method requests - /// - /// - protected virtual async Task HandlePatch(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles POST method requests - /// - /// - protected virtual async Task HandlePost(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles PUT method requests - /// - /// - protected virtual async Task HandlePut(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles TRACE method requests - /// - /// - protected virtual async Task HandleTrace(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Process request - /// - /// - public void ProcessRequest(HttpCwsContext context) - { - if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func handler)) - { - return; - } - - if (EnableCors) - { - context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); - context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); - } - - var handlerTask = handler(context); - - handlerTask.GetAwaiter().GetResult(); - } + handlerTask.GetAwaiter().GetResult(); } } diff --git a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs index 99e4aa93..22d368a5 100644 --- a/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs +++ b/src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using Crestron.SimplSharp.WebScripting; -namespace PepperDash.Core.Web.RequestHandlers -{ +namespace PepperDash.Core.Web.RequestHandlers; + /// /// CWS Base Handler, implements IHttpCwsHandler /// @@ -161,5 +161,4 @@ namespace PepperDash.Core.Web.RequestHandlers handler(context); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/Web/WebApiServer.cs b/src/PepperDash.Core/Web/WebApiServer.cs index cf45b361..dd6ed8d7 100644 --- a/src/PepperDash.Core/Web/WebApiServer.cs +++ b/src/PepperDash.Core/Web/WebApiServer.cs @@ -7,8 +7,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Core.Web -{ +namespace PepperDash.Core.Web; + /// /// Web API server /// @@ -280,5 +280,4 @@ namespace PepperDash.Core.Web Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/WebApi/Presets/Preset.cs b/src/PepperDash.Core/WebApi/Presets/Preset.cs index bdbc5820..444d054f 100644 --- a/src/PepperDash.Core/WebApi/Presets/Preset.cs +++ b/src/PepperDash.Core/WebApi/Presets/Preset.cs @@ -1,45 +1,45 @@ using System; -namespace PepperDash.Core.WebApi.Presets -{ - /// - /// Represents a preset - /// +namespace PepperDash.Core.WebApi.Presets; + +/// +/// Represents a preset +/// public class Preset { - /// - /// ID of preset - /// + /// + /// ID of preset + /// public int Id { get; set; } - /// - /// User ID - /// + /// + /// User ID + /// public int UserId { get; set; } - /// - /// Room Type ID - /// + /// + /// Room Type ID + /// public int RoomTypeId { get; set; } - /// - /// Preset Name - /// + /// + /// Preset Name + /// public string PresetName { get; set; } - /// - /// Preset Number - /// + /// + /// Preset Number + /// public int PresetNumber { get; set; } - /// - /// Preset Data - /// + /// + /// Preset Data + /// public string Data { get; set; } - /// - /// Constructor - /// + /// + /// Constructor + /// public Preset() { PresetName = ""; @@ -53,35 +53,34 @@ namespace PepperDash.Core.WebApi.Presets /// public class PresetReceivedEventArgs : EventArgs { - /// - /// True when the preset is found - /// - public bool LookupSuccess { get; private set; } - - /// - /// S+ helper - /// - public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } + /// + /// True when the preset is found + /// + public bool LookupSuccess { get; private set; } + + /// + /// S+ helper + /// + public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } - /// - /// The preset - /// - public Preset Preset { get; private set; } + /// + /// The preset + /// + public Preset Preset { get; private set; } /// /// For Simpl+ /// public PresetReceivedEventArgs() { } - /// - /// Constructor - /// - /// - /// + /// + /// Constructor + /// + /// + /// public PresetReceivedEventArgs(Preset preset, bool success) { - LookupSuccess = success; + LookupSuccess = success; Preset = preset; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/WebApi/Presets/User.cs b/src/PepperDash.Core/WebApi/Presets/User.cs index c82824f6..ccab189e 100644 --- a/src/PepperDash.Core/WebApi/Presets/User.cs +++ b/src/PepperDash.Core/WebApi/Presets/User.cs @@ -4,31 +4,31 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Core.WebApi.Presets -{ +namespace PepperDash.Core.WebApi.Presets; + /// /// /// public class User { - /// - /// - /// + /// + /// + /// public int Id { get; set; } - /// - /// - /// + /// + /// + /// public string ExternalId { get; set; } - /// - /// - /// + /// + /// + /// public string FirstName { get; set; } - /// - /// - /// + /// + /// + /// public string LastName { get; set; } } @@ -38,19 +38,19 @@ namespace PepperDash.Core.WebApi.Presets /// public class UserReceivedEventArgs : EventArgs { - /// - /// True when user is found - /// - public bool LookupSuccess { get; private set; } + /// + /// True when user is found + /// + public bool LookupSuccess { get; private set; } - /// - /// For stupid S+ - /// - public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } + /// + /// For stupid S+ + /// + public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } - /// - /// - /// + /// + /// + /// public User User { get; private set; } /// @@ -58,14 +58,14 @@ namespace PepperDash.Core.WebApi.Presets /// public UserReceivedEventArgs() { } - /// - /// Constructor - /// - /// - /// + /// + /// Constructor + /// + /// + /// public UserReceivedEventArgs(User user, bool success) { - LookupSuccess = success; + LookupSuccess = success; User = user; } } @@ -75,19 +75,18 @@ namespace PepperDash.Core.WebApi.Presets /// public class UserAndRoomMessage { - /// - /// - /// + /// + /// + /// public int UserId { get; set; } - /// - /// - /// + /// + /// + /// public int RoomTypeId { get; set; } - /// - /// - /// + /// + /// + /// public int PresetNumber { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs b/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs index 0a9317bf..7525a27f 100644 --- a/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs +++ b/src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs @@ -8,26 +8,26 @@ using Newtonsoft.Json.Linq; using PepperDash.Core.JsonToSimpl; -namespace PepperDash.Core.WebApi.Presets -{ - /// - /// Passcode client for the WebApi - /// +namespace PepperDash.Core.WebApi.Presets; + +/// +/// Passcode client for the WebApi +/// public class WebApiPasscodeClient : IKeyed { - /// - /// Notifies when user received - /// + /// + /// Notifies when user received + /// public event EventHandler UserReceived; - /// - /// Notifies when Preset received - /// + /// + /// Notifies when Preset received + /// public event EventHandler PresetReceived; - /// - /// Unique identifier for this instance - /// + /// + /// Unique identifier for this instance + /// public string Key { get; private set; } //string JsonMasterKey; @@ -54,13 +54,13 @@ namespace PepperDash.Core.WebApi.Presets { } - /// - /// Initializes the instance - /// - /// - /// - /// - /// + /// + /// Initializes the instance + /// + /// + /// + /// + /// public void Initialize(string key, string jsonMasterKey, string urlBase, string defaultPresetJsonFilePath) { Key = key; @@ -73,41 +73,41 @@ namespace PepperDash.Core.WebApi.Presets J2SMaster.Initialize(jsonMasterKey); } - /// - /// Gets the user for a passcode - /// - /// + /// + /// Gets the user for a passcode + /// + /// public void GetUserForPasscode(string passcode) { - // Bullshit duplicate code here... These two cases should be the same - // except for https/http and the certificate ignores - if (!UrlBase.StartsWith("https")) - return; - var req = new HttpsClientRequest(); - req.Url = new UrlParser(UrlBase + "/api/users/dopin"); - req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; - req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); - req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); - var jo = new JObject(); - jo.Add("pin", passcode); - req.ContentString = jo.ToString(); + // Bullshit duplicate code here... These two cases should be the same + // except for https/http and the certificate ignores + if (!UrlBase.StartsWith("https")) + return; + var req = new HttpsClientRequest(); + req.Url = new UrlParser(UrlBase + "/api/users/dopin"); + req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; + req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); + req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); + var jo = new JObject(); + jo.Add("pin", passcode); + req.ContentString = jo.ToString(); - var client = new HttpsClient(); - client.HostVerification = false; - client.PeerVerification = false; - var resp = client.Dispatch(req); - var handler = UserReceived; - if (resp.Code == 200) - { - //CrestronConsole.PrintLine("Received: {0}", resp.ContentString); - var user = JsonConvert.DeserializeObject(resp.ContentString); - CurrentUser = user; - if (handler != null) - UserReceived(this, new UserReceivedEventArgs(user, true)); - } - else - if (handler != null) - UserReceived(this, new UserReceivedEventArgs(null, false)); + var client = new HttpsClient(); + client.HostVerification = false; + client.PeerVerification = false; + var resp = client.Dispatch(req); + var handler = UserReceived; + if (resp.Code == 200) + { + //CrestronConsole.PrintLine("Received: {0}", resp.ContentString); + var user = JsonConvert.DeserializeObject(resp.ContentString); + CurrentUser = user; + if (handler != null) + UserReceived(this, new UserReceivedEventArgs(user, true)); + } + else + if (handler != null) + UserReceived(this, new UserReceivedEventArgs(null, false)); } /// @@ -130,57 +130,57 @@ namespace PepperDash.Core.WebApi.Presets PresetNumber = presetNumber }; - var handler = PresetReceived; + var handler = PresetReceived; try { - if (!UrlBase.StartsWith("https")) - return; - var req = new HttpsClientRequest(); - req.Url = new UrlParser(UrlBase + "/api/presets/userandroom"); - req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; - req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); - req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); - req.ContentString = JsonConvert.SerializeObject(msg); + if (!UrlBase.StartsWith("https")) + return; + var req = new HttpsClientRequest(); + req.Url = new UrlParser(UrlBase + "/api/presets/userandroom"); + req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; + req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); + req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); + req.ContentString = JsonConvert.SerializeObject(msg); - var client = new HttpsClient(); - client.HostVerification = false; - client.PeerVerification = false; + var client = new HttpsClient(); + client.HostVerification = false; + client.PeerVerification = false; - // ask for the preset - var resp = client.Dispatch(req); - if (resp.Code == 200) // got it + // ask for the preset + var resp = client.Dispatch(req); + if (resp.Code == 200) // got it + { + //Debug.Console(1, this, "Received: {0}", resp.ContentString); + var preset = JsonConvert.DeserializeObject(resp.ContentString); + CurrentPreset = preset; + + //if there's no preset data, load the template + if (preset.Data == null || preset.Data.Trim() == string.Empty || JObject.Parse(preset.Data).Count == 0) { - //Debug.Console(1, this, "Received: {0}", resp.ContentString); - var preset = JsonConvert.DeserializeObject(resp.ContentString); - CurrentPreset = preset; - - //if there's no preset data, load the template - if (preset.Data == null || preset.Data.Trim() == string.Empty || JObject.Parse(preset.Data).Count == 0) - { - //Debug.Console(1, this, "Loaded preset has no data. Loading default template."); - LoadDefaultPresetData(); - return; - } - - J2SMaster.LoadWithJson(preset.Data); - if (handler != null) - PresetReceived(this, new PresetReceivedEventArgs(preset, true)); - } - else // no existing preset - { - CurrentPreset = new Preset(); + //Debug.Console(1, this, "Loaded preset has no data. Loading default template."); LoadDefaultPresetData(); - if (handler != null) - PresetReceived(this, new PresetReceivedEventArgs(null, false)); + return; } + + J2SMaster.LoadWithJson(preset.Data); + if (handler != null) + PresetReceived(this, new PresetReceivedEventArgs(preset, true)); + } + else // no existing preset + { + CurrentPreset = new Preset(); + LoadDefaultPresetData(); + if (handler != null) + PresetReceived(this, new PresetReceivedEventArgs(null, false)); + } } catch (HttpException e) { var resp = e.Response; Debug.Console(1, this, "No preset received (code {0}). Loading default template", resp.Code); LoadDefaultPresetData(); - if (handler != null) - PresetReceived(this, new PresetReceivedEventArgs(null, false)); + if (handler != null) + PresetReceived(this, new PresetReceivedEventArgs(null, false)); } } @@ -236,8 +236,8 @@ namespace PepperDash.Core.WebApi.Presets { CurrentPreset.Data = json; - if (!UrlBase.StartsWith("https")) - return; + if (!UrlBase.StartsWith("https")) + return; var req = new HttpsClientRequest(); req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; req.Url = new UrlParser(string.Format("{0}/api/presets/addorchange", UrlBase)); @@ -246,8 +246,8 @@ namespace PepperDash.Core.WebApi.Presets req.ContentString = JsonConvert.SerializeObject(CurrentPreset); var client = new HttpsClient(); - client.HostVerification = false; - client.PeerVerification = false; + client.HostVerification = false; + client.PeerVerification = false; try { var resp = client.Dispatch(req); @@ -270,4 +270,3 @@ namespace PepperDash.Core.WebApi.Presets } } } -} diff --git a/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs b/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs index 8303731e..b1dcae6b 100644 --- a/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs +++ b/src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs @@ -1,25 +1,24 @@ using System.Collections.Generic; using PepperDash.Core.Intersystem.Tokens; -namespace PepperDash.Core.Intersystem.Serialization +namespace PepperDash.Core.Intersystem.Serialization; + +/// +/// Interface to determine XSig serialization for an object. +/// +public interface IXSigSerialization { /// - /// Interface to determine XSig serialization for an object. + /// Serialize the sig data /// - public interface IXSigSerialization - { - /// - /// Serialize the sig data - /// - /// - IEnumerable Serialize(); + /// + IEnumerable Serialize(); - /// - /// Deserialize the sig data - /// - /// - /// - /// - T Deserialize(IEnumerable tokens) where T : class, IXSigSerialization; - } + /// + /// Deserialize the sig data + /// + /// + /// + /// + T Deserialize(IEnumerable tokens) where T : class, IXSigSerialization; } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs b/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs index 8f3fc047..4db0e970 100644 --- a/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs +++ b/src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs @@ -1,28 +1,27 @@ using System; -namespace PepperDash.Core.Intersystem.Serialization +namespace PepperDash.Core.Intersystem.Serialization; + +/// +/// Class to handle this specific exception type +/// +public class XSigSerializationException : Exception { /// - /// Class to handle this specific exception type + /// default constructor /// - public class XSigSerializationException : Exception - { - /// - /// default constructor - /// - public XSigSerializationException() { } + public XSigSerializationException() { } - /// - /// constructor with message - /// - /// - public XSigSerializationException(string message) : base(message) { } + /// + /// constructor with message + /// + /// + public XSigSerializationException(string message) : base(message) { } - /// - /// constructor with message and innner exception - /// - /// - /// - public XSigSerializationException(string message, Exception inner) : base(message, inner) { } - } + /// + /// constructor with message and innner exception + /// + /// + /// + public XSigSerializationException(string message, Exception inner) : base(message, inner) { } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs index 58473362..b5cb2e68 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs @@ -1,88 +1,87 @@ using System; -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents an XSigAnalogToken +/// +public sealed class XSigAnalogToken : XSigToken, IFormattable { + private readonly ushort _value; + /// - /// Represents an XSigAnalogToken + /// Constructor /// - public sealed class XSigAnalogToken : XSigToken, IFormattable + /// + /// + public XSigAnalogToken(int index, ushort value) + : base(index) { - private readonly ushort _value; + // 10-bits available for analog encoded data + if (index >= 1024 || index < 0) + throw new ArgumentOutOfRangeException("index"); - /// - /// Constructor - /// - /// - /// - public XSigAnalogToken(int index, ushort value) - : base(index) - { - // 10-bits available for analog encoded data - if (index >= 1024 || index < 0) - throw new ArgumentOutOfRangeException("index"); + _value = value; + } - _value = value; - } + /// + /// + /// + public ushort Value + { + get { return _value; } + } - /// - /// - /// - public ushort Value - { - get { return _value; } - } + /// + /// + /// + public override XSigTokenType TokenType + { + get { return XSigTokenType.Analog; } + } - /// - /// - /// - public override XSigTokenType TokenType - { - get { return XSigTokenType.Analog; } - } + /// + /// + /// + /// + public override byte[] GetBytes() + { + return new[] { + (byte)(0xC0 | ((Value & 0xC000) >> 10) | (Index - 1 >> 7)), + (byte)((Index - 1) & 0x7F), + (byte)((Value & 0x3F80) >> 7), + (byte)(Value & 0x7F) + }; + } - /// - /// - /// - /// - public override byte[] GetBytes() - { - return new[] { - (byte)(0xC0 | ((Value & 0xC000) >> 10) | (Index - 1 >> 7)), - (byte)((Index - 1) & 0x7F), - (byte)((Value & 0x3F80) >> 7), - (byte)(Value & 0x7F) - }; - } + /// + /// + /// + /// + /// + public override XSigToken GetTokenWithOffset(int offset) + { + if (offset == 0) return this; + return new XSigAnalogToken(Index + offset, Value); + } - /// - /// - /// - /// - /// - public override XSigToken GetTokenWithOffset(int offset) - { - if (offset == 0) return this; - return new XSigAnalogToken(Index + offset, Value); - } + /// + /// + /// + /// + public override string ToString() + { + return Index + " = 0x" + Value.ToString("X4"); + } - /// - /// - /// - /// - public override string ToString() - { - return Index + " = 0x" + Value.ToString("X4"); - } - - /// - /// - /// - /// - /// - /// - public string ToString(string format, IFormatProvider formatProvider) - { - return Value.ToString(format, formatProvider); - } + /// + /// + /// + /// + /// + /// + public string ToString(string format, IFormatProvider formatProvider) + { + return Value.ToString(format, formatProvider); } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs index 70ccc852..a82d0eb2 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs @@ -1,85 +1,84 @@ using System; -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents an XSigDigitalToken +/// +public sealed class XSigDigitalToken : XSigToken { + private readonly bool _value; + /// - /// Represents an XSigDigitalToken + /// /// - public sealed class XSigDigitalToken : XSigToken + /// + /// + public XSigDigitalToken(int index, bool value) + : base(index) { - private readonly bool _value; + // 12-bits available for digital encoded data + if (index >= 4096 || index < 0) + throw new ArgumentOutOfRangeException("index"); - /// - /// - /// - /// - /// - public XSigDigitalToken(int index, bool value) - : base(index) - { - // 12-bits available for digital encoded data - if (index >= 4096 || index < 0) - throw new ArgumentOutOfRangeException("index"); + _value = value; + } - _value = value; - } + /// + /// + /// + public bool Value + { + get { return _value; } + } - /// - /// - /// - public bool Value - { - get { return _value; } - } + /// + /// + /// + public override XSigTokenType TokenType + { + get { return XSigTokenType.Digital; } + } - /// - /// - /// - public override XSigTokenType TokenType - { - get { return XSigTokenType.Digital; } - } + /// + /// + /// + /// + public override byte[] GetBytes() + { + return new[] { + (byte)(0x80 | (Value ? 0 : 0x20) | ((Index - 1) >> 7)), + (byte)((Index - 1) & 0x7F) + }; + } - /// - /// - /// - /// - public override byte[] GetBytes() - { - return new[] { - (byte)(0x80 | (Value ? 0 : 0x20) | ((Index - 1) >> 7)), - (byte)((Index - 1) & 0x7F) - }; - } + /// + /// + /// + /// + /// + public override XSigToken GetTokenWithOffset(int offset) + { + if (offset == 0) return this; + return new XSigDigitalToken(Index + offset, Value); + } - /// - /// - /// - /// - /// - public override XSigToken GetTokenWithOffset(int offset) - { - if (offset == 0) return this; - return new XSigDigitalToken(Index + offset, Value); - } + /// + /// + /// + /// + public override string ToString() + { + return Index + " = " + (Value ? "High" : "Low"); + } - /// - /// - /// - /// - public override string ToString() - { - return Index + " = " + (Value ? "High" : "Low"); - } - - /// - /// - /// - /// - /// - public string ToString(IFormatProvider formatProvider) - { - return Value.ToString(formatProvider); - } + /// + /// + /// + /// + /// + public string ToString(IFormatProvider formatProvider) + { + return Value.ToString(formatProvider); } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs index 25ee3fd0..3b6a3f5f 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs @@ -1,81 +1,80 @@ using System; using System.Text; -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents an XSigSerialToken +/// +public sealed class XSigSerialToken : XSigToken { + private readonly string _value; + /// - /// Represents an XSigSerialToken + /// Constructor /// - public sealed class XSigSerialToken : XSigToken + /// + /// + public XSigSerialToken(int index, string value) + : base(index) { - private readonly string _value; + // 10-bits available for serial encoded data + if (index >= 1024 || index < 0) + throw new ArgumentOutOfRangeException("index"); - /// - /// Constructor - /// - /// - /// - public XSigSerialToken(int index, string value) - : base(index) - { - // 10-bits available for serial encoded data - if (index >= 1024 || index < 0) - throw new ArgumentOutOfRangeException("index"); + _value = value; + } - _value = value; - } + /// + /// + /// + public string Value + { + get { return _value; } + } - /// - /// - /// - public string Value - { - get { return _value; } - } + /// + /// + /// + public override XSigTokenType TokenType + { + get { return XSigTokenType.Serial; } + } - /// - /// - /// - public override XSigTokenType TokenType - { - get { return XSigTokenType.Serial; } - } + /// + /// + /// + /// + public override byte[] GetBytes() + { + var serialBytes = String.IsNullOrEmpty(Value) ? new byte[0] : Encoding.GetEncoding(28591).GetBytes(Value); + + var xsig = new byte[serialBytes.Length + 3]; + xsig[0] = (byte)(0xC8 | (Index - 1 >> 7)); + xsig[1] = (byte)((Index - 1) & 0x7F); + xsig[xsig.Length - 1] = 0xFF; - /// - /// - /// - /// - public override byte[] GetBytes() - { - var serialBytes = String.IsNullOrEmpty(Value) ? new byte[0] : Encoding.GetEncoding(28591).GetBytes(Value); - - var xsig = new byte[serialBytes.Length + 3]; - xsig[0] = (byte)(0xC8 | (Index - 1 >> 7)); - xsig[1] = (byte)((Index - 1) & 0x7F); - xsig[xsig.Length - 1] = 0xFF; + Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length); + return xsig; + } - Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length); - return xsig; - } + /// + /// + /// + /// + /// + public override XSigToken GetTokenWithOffset(int offset) + { + if (offset == 0) return this; + return new XSigSerialToken(Index + offset, Value); + } - /// - /// - /// - /// - /// - public override XSigToken GetTokenWithOffset(int offset) - { - if (offset == 0) return this; - return new XSigSerialToken(Index + offset, Value); - } - - /// - /// - /// - /// - public override string ToString() - { - return Index + " = \"" + Value + "\""; - } + /// + /// + /// + /// + public override string ToString() + { + return Index + " = \"" + Value + "\""; } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs index 4c00a2ed..cd706bd4 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs @@ -1,45 +1,44 @@ -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// Represents the base class for all XSig datatypes. +/// +public abstract class XSigToken { + private readonly int _index; + /// - /// Represents the base class for all XSig datatypes. + /// Constructs an XSigToken with the specified index. /// - public abstract class XSigToken + /// Index for the data. + protected XSigToken(int index) { - private readonly int _index; - - /// - /// Constructs an XSigToken with the specified index. - /// - /// Index for the data. - protected XSigToken(int index) - { - _index = index; - } - - /// - /// XSig 1-based index. - /// - public int Index - { - get { return _index; } - } - - /// - /// XSigToken type. - /// - public abstract XSigTokenType TokenType { get; } - - /// - /// Generates the XSig bytes for the corresponding token. - /// - /// XSig byte array. - public abstract byte[] GetBytes(); - - /// - /// Returns a new token if necessary with an updated index based on the specified offset. - /// - /// Offset to adjust the index with. - /// XSigToken - public abstract XSigToken GetTokenWithOffset(int offset); + _index = index; } + + /// + /// XSig 1-based index. + /// + public int Index + { + get { return _index; } + } + + /// + /// XSigToken type. + /// + public abstract XSigTokenType TokenType { get; } + + /// + /// Generates the XSig bytes for the corresponding token. + /// + /// XSig byte array. + public abstract byte[] GetBytes(); + + /// + /// Returns a new token if necessary with an updated index based on the specified offset. + /// + /// Offset to adjust the index with. + /// XSigToken + public abstract XSigToken GetTokenWithOffset(int offset); } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs b/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs index 26d6c123..60641b4f 100644 --- a/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs +++ b/src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs @@ -1,23 +1,22 @@ -namespace PepperDash.Core.Intersystem.Tokens +namespace PepperDash.Core.Intersystem.Tokens; + +/// +/// XSig token types. +/// +public enum XSigTokenType { /// - /// XSig token types. + /// Digital signal datatype. /// - public enum XSigTokenType - { - /// - /// Digital signal datatype. - /// - Digital, + Digital, - /// - /// Analog signal datatype. - /// - Analog, + /// + /// Analog signal datatype. + /// + Analog, - /// - /// Serial signal datatype. - /// - Serial - } + /// + /// Serial signal datatype. + /// + Serial } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/XSigHelpers.cs b/src/PepperDash.Core/XSigUtility/XSigHelpers.cs index 4ea6f634..4f970be2 100644 --- a/src/PepperDash.Core/XSigUtility/XSigHelpers.cs +++ b/src/PepperDash.Core/XSigUtility/XSigHelpers.cs @@ -18,222 +18,221 @@ using PepperDash.Core.Intersystem.Tokens; 11111111 <- denotes end of data */ -namespace PepperDash.Core.Intersystem +namespace PepperDash.Core.Intersystem; + +/// +/// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol. +/// +/// +/// Indexing is not from the start of each signal type but rather from the beginning of the first defined signal +/// the Intersystem Communications (ISC) symbol. +/// +public static class XSigHelpers { /// - /// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol. + /// Forces all outputs to 0. /// - /// - /// Indexing is not from the start of each signal type but rather from the beginning of the first defined signal - /// the Intersystem Communications (ISC) symbol. - /// - public static class XSigHelpers + /// Bytes in XSig format for clear outputs trigger. + public static byte[] ClearOutputs() { - /// - /// Forces all outputs to 0. - /// - /// Bytes in XSig format for clear outputs trigger. - public static byte[] ClearOutputs() + return new byte[] { 0xFC }; + } + + /// + /// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0. + /// + /// Bytes in XSig format for send status trigger. + public static byte[] SendStatus() + { + return new byte[] { 0xFD }; + } + + /// + /// Get bytes for an IXSigStateResolver object. + /// + /// XSig state resolver. + /// Bytes in XSig format for each token within the state representation. + public static byte[] GetBytes(IXSigSerialization xSigSerialization) + { + return GetBytes(xSigSerialization, 0); + } + + /// + /// Get bytes for an IXSigStateResolver object, with a specified offset. + /// + /// XSig state resolver. + /// Offset to which the data will be aligned. + /// Bytes in XSig format for each token within the state representation. + public static byte[] GetBytes(IXSigSerialization xSigSerialization, int offset) + { + var tokens = xSigSerialization.Serialize(); + if (tokens == null) return new byte[0]; + using (var memoryStream = new MemoryStream()) { - return new byte[] { 0xFC }; - } + using (var tokenWriter = new XSigTokenStreamWriter(memoryStream)) + tokenWriter.WriteXSigData(xSigSerialization, offset); - /// - /// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0. - /// - /// Bytes in XSig format for send status trigger. - public static byte[] SendStatus() - { - return new byte[] { 0xFD }; - } - - /// - /// Get bytes for an IXSigStateResolver object. - /// - /// XSig state resolver. - /// Bytes in XSig format for each token within the state representation. - public static byte[] GetBytes(IXSigSerialization xSigSerialization) - { - return GetBytes(xSigSerialization, 0); - } - - /// - /// Get bytes for an IXSigStateResolver object, with a specified offset. - /// - /// XSig state resolver. - /// Offset to which the data will be aligned. - /// Bytes in XSig format for each token within the state representation. - public static byte[] GetBytes(IXSigSerialization xSigSerialization, int offset) - { - var tokens = xSigSerialization.Serialize(); - if (tokens == null) return new byte[0]; - using (var memoryStream = new MemoryStream()) - { - using (var tokenWriter = new XSigTokenStreamWriter(memoryStream)) - tokenWriter.WriteXSigData(xSigSerialization, offset); - - return memoryStream.ToArray(); - } - } - - /// - /// Get bytes for a single digital signal. - /// - /// 1-based digital index - /// Digital data to be encoded - /// Bytes in XSig format for digtial information. - public static byte[] GetBytes(int index, bool value) - { - return GetBytes(index, 0, value); - } - - /// - /// Get bytes for a single digital signal. - /// - /// 1-based digital index - /// Index offset. - /// Digital data to be encoded - /// Bytes in XSig format for digtial information. - public static byte[] GetBytes(int index, int offset, bool value) - { - return new XSigDigitalToken(index + offset, value).GetBytes(); - } - - /// - /// Get byte sequence for multiple digital signals. - /// - /// Starting index of the sequence. - /// Digital signal value array. - /// Byte sequence in XSig format for digital signal information. - public static byte[] GetBytes(int startIndex, bool[] values) - { - return GetBytes(startIndex, 0, values); - } - - /// - /// Get byte sequence for multiple digital signals. - /// - /// Starting index of the sequence. - /// Index offset. - /// Digital signal value array. - /// Byte sequence in XSig format for digital signal information. - public static byte[] GetBytes(int startIndex, int offset, bool[] values) - { - // Digital XSig data is 2 bytes per value - const int fixedLength = 2; - var bytes = new byte[values.Length * fixedLength]; - for (var i = 0; i < values.Length; i++) - Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength); - - return bytes; - } - - /// - /// Get bytes for a single analog signal. - /// - /// 1-based analog index - /// Analog data to be encoded - /// Bytes in XSig format for analog signal information. - public static byte[] GetBytes(int index, ushort value) - { - return GetBytes(index, 0, value); - } - - /// - /// Get bytes for a single analog signal. - /// - /// 1-based analog index - /// Index offset. - /// Analog data to be encoded - /// Bytes in XSig format for analog signal information. - public static byte[] GetBytes(int index, int offset, ushort value) - { - return new XSigAnalogToken(index + offset, value).GetBytes(); - } - - /// - /// Get byte sequence for multiple analog signals. - /// - /// Starting index of the sequence. - /// Analog signal value array. - /// Byte sequence in XSig format for analog signal information. - public static byte[] GetBytes(int startIndex, ushort[] values) - { - return GetBytes(startIndex, 0, values); - } - - /// - /// Get byte sequence for multiple analog signals. - /// - /// Starting index of the sequence. - /// Index offset. - /// Analog signal value array. - /// Byte sequence in XSig format for analog signal information. - public static byte[] GetBytes(int startIndex, int offset, ushort[] values) - { - // Analog XSig data is 4 bytes per value - const int fixedLength = 4; - var bytes = new byte[values.Length * fixedLength]; - for (var i = 0; i < values.Length; i++) - Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength); - - return bytes; - } - - /// - /// Get bytes for a single serial signal. - /// - /// 1-based serial index - /// Serial data to be encoded - /// Bytes in XSig format for serial signal information. - public static byte[] GetBytes(int index, string value) - { - return GetBytes(index, 0, value); - } - - /// - /// Get bytes for a single serial signal. - /// - /// 1-based serial index - /// Index offset. - /// Serial data to be encoded - /// Bytes in XSig format for serial signal information. - public static byte[] GetBytes(int index, int offset, string value) - { - return new XSigSerialToken(index + offset, value).GetBytes(); - } - - /// - /// Get byte sequence for multiple serial signals. - /// - /// Starting index of the sequence. - /// Serial signal value array. - /// Byte sequence in XSig format for serial signal information. - public static byte[] GetBytes(int startIndex, string[] values) - { - return GetBytes(startIndex, 0, values); - } - - /// - /// Get byte sequence for multiple serial signals. - /// - /// Starting index of the sequence. - /// Index offset. - /// Serial signal value array. - /// Byte sequence in XSig format for serial signal information. - public static byte[] GetBytes(int startIndex, int offset, string[] values) - { - // Serial XSig data is not fixed-length like the other formats - var dstOffset = 0; - var bytes = new byte[values.Sum(v => v.Length + 3)]; - for (var i = 0; i < values.Length; i++) - { - var data = GetBytes(startIndex++, offset, values[i]); - Buffer.BlockCopy(data, 0, bytes, dstOffset, data.Length); - dstOffset += data.Length; - } - - return bytes; + return memoryStream.ToArray(); } } + + /// + /// Get bytes for a single digital signal. + /// + /// 1-based digital index + /// Digital data to be encoded + /// Bytes in XSig format for digtial information. + public static byte[] GetBytes(int index, bool value) + { + return GetBytes(index, 0, value); + } + + /// + /// Get bytes for a single digital signal. + /// + /// 1-based digital index + /// Index offset. + /// Digital data to be encoded + /// Bytes in XSig format for digtial information. + public static byte[] GetBytes(int index, int offset, bool value) + { + return new XSigDigitalToken(index + offset, value).GetBytes(); + } + + /// + /// Get byte sequence for multiple digital signals. + /// + /// Starting index of the sequence. + /// Digital signal value array. + /// Byte sequence in XSig format for digital signal information. + public static byte[] GetBytes(int startIndex, bool[] values) + { + return GetBytes(startIndex, 0, values); + } + + /// + /// Get byte sequence for multiple digital signals. + /// + /// Starting index of the sequence. + /// Index offset. + /// Digital signal value array. + /// Byte sequence in XSig format for digital signal information. + public static byte[] GetBytes(int startIndex, int offset, bool[] values) + { + // Digital XSig data is 2 bytes per value + const int fixedLength = 2; + var bytes = new byte[values.Length * fixedLength]; + for (var i = 0; i < values.Length; i++) + Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength); + + return bytes; + } + + /// + /// Get bytes for a single analog signal. + /// + /// 1-based analog index + /// Analog data to be encoded + /// Bytes in XSig format for analog signal information. + public static byte[] GetBytes(int index, ushort value) + { + return GetBytes(index, 0, value); + } + + /// + /// Get bytes for a single analog signal. + /// + /// 1-based analog index + /// Index offset. + /// Analog data to be encoded + /// Bytes in XSig format for analog signal information. + public static byte[] GetBytes(int index, int offset, ushort value) + { + return new XSigAnalogToken(index + offset, value).GetBytes(); + } + + /// + /// Get byte sequence for multiple analog signals. + /// + /// Starting index of the sequence. + /// Analog signal value array. + /// Byte sequence in XSig format for analog signal information. + public static byte[] GetBytes(int startIndex, ushort[] values) + { + return GetBytes(startIndex, 0, values); + } + + /// + /// Get byte sequence for multiple analog signals. + /// + /// Starting index of the sequence. + /// Index offset. + /// Analog signal value array. + /// Byte sequence in XSig format for analog signal information. + public static byte[] GetBytes(int startIndex, int offset, ushort[] values) + { + // Analog XSig data is 4 bytes per value + const int fixedLength = 4; + var bytes = new byte[values.Length * fixedLength]; + for (var i = 0; i < values.Length; i++) + Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength); + + return bytes; + } + + /// + /// Get bytes for a single serial signal. + /// + /// 1-based serial index + /// Serial data to be encoded + /// Bytes in XSig format for serial signal information. + public static byte[] GetBytes(int index, string value) + { + return GetBytes(index, 0, value); + } + + /// + /// Get bytes for a single serial signal. + /// + /// 1-based serial index + /// Index offset. + /// Serial data to be encoded + /// Bytes in XSig format for serial signal information. + public static byte[] GetBytes(int index, int offset, string value) + { + return new XSigSerialToken(index + offset, value).GetBytes(); + } + + /// + /// Get byte sequence for multiple serial signals. + /// + /// Starting index of the sequence. + /// Serial signal value array. + /// Byte sequence in XSig format for serial signal information. + public static byte[] GetBytes(int startIndex, string[] values) + { + return GetBytes(startIndex, 0, values); + } + + /// + /// Get byte sequence for multiple serial signals. + /// + /// Starting index of the sequence. + /// Index offset. + /// Serial signal value array. + /// Byte sequence in XSig format for serial signal information. + public static byte[] GetBytes(int startIndex, int offset, string[] values) + { + // Serial XSig data is not fixed-length like the other formats + var dstOffset = 0; + var bytes = new byte[values.Sum(v => v.Length + 3)]; + for (var i = 0; i < values.Length; i++) + { + var data = GetBytes(startIndex++, offset, values[i]); + Buffer.BlockCopy(data, 0, bytes, dstOffset, data.Length); + dstOffset += data.Length; + } + + return bytes; + } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs b/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs index 9d70d02e..3c222960 100644 --- a/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs +++ b/src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs @@ -4,144 +4,143 @@ using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; -namespace PepperDash.Core.Intersystem +namespace PepperDash.Core.Intersystem; + +/// +/// XSigToken stream reader. +/// +public sealed class XSigTokenStreamReader : IDisposable { + private readonly Stream _stream; + private readonly bool _leaveOpen; + + /// /// - /// XSigToken stream reader. + /// XSigToken stream reader constructor. /// - public sealed class XSigTokenStreamReader : IDisposable + /// Input stream to read from. + /// Stream is null. + /// Stream cannot be read from. + public XSigTokenStreamReader(Stream stream) + : this(stream, false) { } + + /// + /// XSigToken stream reader constructor. + /// + /// Input stream to read from. + /// Determines whether to leave the stream open or not. + /// Stream is null. + /// Stream cannot be read from. + public XSigTokenStreamReader(Stream stream, bool leaveOpen) { - private readonly Stream _stream; - private readonly bool _leaveOpen; + if (stream == null) + throw new ArgumentNullException("stream"); + if (!stream.CanRead) + throw new ArgumentException("The specified stream cannot be read from."); - /// - /// - /// XSigToken stream reader constructor. - /// - /// Input stream to read from. - /// Stream is null. - /// Stream cannot be read from. - public XSigTokenStreamReader(Stream stream) - : this(stream, false) { } + _stream = stream; + _leaveOpen = leaveOpen; + } - /// - /// XSigToken stream reader constructor. - /// - /// Input stream to read from. - /// Determines whether to leave the stream open or not. - /// Stream is null. - /// Stream cannot be read from. - public XSigTokenStreamReader(Stream stream, bool leaveOpen) + /// + /// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order. + /// + /// Input stream + /// Result + /// True if successful, otherwise false. + public static bool TryReadUInt16BE(Stream stream, out ushort value) + { + value = 0; + if (stream.Length < 2) + return false; + + var buffer = new byte[2]; + stream.Read(buffer, 0, 2); + value = (ushort)((buffer[0] << 8) | buffer[1]); + return true; + } + + /// + /// Read XSig token from the stream. + /// + /// XSigToken + /// Offset is less than 0. + public XSigToken ReadXSigToken() + { + ushort prefix; + if (!TryReadUInt16BE(_stream, out prefix)) + return null; + + if ((prefix & 0xF880) == 0xC800) // Serial data { - if (stream == null) - throw new ArgumentNullException("stream"); - if (!stream.CanRead) - throw new ArgumentException("The specified stream cannot be read from."); + var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F); + var n = 0; + const int maxSerialDataLength = 252; + var chars = new char[maxSerialDataLength]; + int ch; + while ((ch = _stream.ReadByte()) != 0xFF) + { + if (ch == -1) // Reached end of stream without end of data marker + return null; + + chars[n++] = (char)ch; + } - _stream = stream; - _leaveOpen = leaveOpen; + return new XSigSerialToken((ushort)(index + 1), new string(chars, 0, n)); } - /// - /// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order. - /// - /// Input stream - /// Result - /// True if successful, otherwise false. - public static bool TryReadUInt16BE(Stream stream, out ushort value) + if ((prefix & 0xC880) == 0xC000) // Analog data { - value = 0; - if (stream.Length < 2) - return false; - - var buffer = new byte[2]; - stream.Read(buffer, 0, 2); - value = (ushort)((buffer[0] << 8) | buffer[1]); - return true; - } - - /// - /// Read XSig token from the stream. - /// - /// XSigToken - /// Offset is less than 0. - public XSigToken ReadXSigToken() - { - ushort prefix; - if (!TryReadUInt16BE(_stream, out prefix)) + ushort data; + if (!TryReadUInt16BE(_stream, out data)) return null; - if ((prefix & 0xF880) == 0xC800) // Serial data - { - var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F); - var n = 0; - const int maxSerialDataLength = 252; - var chars = new char[maxSerialDataLength]; - int ch; - while ((ch = _stream.ReadByte()) != 0xFF) - { - if (ch == -1) // Reached end of stream without end of data marker - return null; - - chars[n++] = (char)ch; - } - - return new XSigSerialToken((ushort)(index + 1), new string(chars, 0, n)); - } - - if ((prefix & 0xC880) == 0xC000) // Analog data - { - ushort data; - if (!TryReadUInt16BE(_stream, out data)) - return null; - - var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F); - var value = ((prefix & 0x3000) << 2) | ((data & 0x7F00) >> 1) | (data & 0x7F); - return new XSigAnalogToken((ushort)(index + 1), (ushort)value); - } - - if ((prefix & 0xC080) == 0x8000) // Digital data - { - var index = ((prefix & 0x1F00) >> 1) | (prefix & 0x7F); - var value = (prefix & 0x2000) == 0; - return new XSigDigitalToken((ushort)(index + 1), value); - } - - return null; + var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F); + var value = ((prefix & 0x3000) << 2) | ((data & 0x7F00) >> 1) | (data & 0x7F); + return new XSigAnalogToken((ushort)(index + 1), (ushort)value); } - /// - /// Reads all available XSig tokens from the stream. - /// - /// XSigToken collection. - public IEnumerable ReadAllXSigTokens() + if ((prefix & 0xC080) == 0x8000) // Digital data { - var tokens = new List(); - XSigToken token; - while ((token = ReadXSigToken()) != null) - tokens.Add(token); - - return tokens; + var index = ((prefix & 0x1F00) >> 1) | (prefix & 0x7F); + var value = (prefix & 0x2000) == 0; + return new XSigDigitalToken((ushort)(index + 1), value); } - /// - /// Attempts to deserialize all XSig data within the stream from the current position. - /// - /// Type to deserialize the information to. - /// Deserialized object. - public T DeserializeStream() - where T : class, IXSigSerialization, new() - { - return new T().Deserialize(ReadAllXSigTokens()); - } + return null; + } - /// - /// Disposes of the internal stream if specified to not leave open. - /// - public void Dispose() - { - if (!_leaveOpen) - _stream.Dispose(); - } + /// + /// Reads all available XSig tokens from the stream. + /// + /// XSigToken collection. + public IEnumerable ReadAllXSigTokens() + { + var tokens = new List(); + XSigToken token; + while ((token = ReadXSigToken()) != null) + tokens.Add(token); + + return tokens; + } + + /// + /// Attempts to deserialize all XSig data within the stream from the current position. + /// + /// Type to deserialize the information to. + /// Deserialized object. + public T DeserializeStream() + where T : class, IXSigSerialization, new() + { + return new T().Deserialize(ReadAllXSigTokens()); + } + + /// + /// Disposes of the internal stream if specified to not leave open. + /// + public void Dispose() + { + if (!_leaveOpen) + _stream.Dispose(); } } \ No newline at end of file diff --git a/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs b/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs index 934f2c29..da973acd 100644 --- a/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs +++ b/src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs @@ -5,132 +5,131 @@ using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; -namespace PepperDash.Core.Intersystem +namespace PepperDash.Core.Intersystem; + +/// +/// XSigToken stream writer. +/// +public sealed class XSigTokenStreamWriter : IDisposable { + private readonly Stream _stream; + private readonly bool _leaveOpen; + + /// /// - /// XSigToken stream writer. + /// XSigToken stream writer constructor. /// - public sealed class XSigTokenStreamWriter : IDisposable + /// Input stream to write to. + /// Stream is null. + /// Stream cannot be written to. + public XSigTokenStreamWriter(Stream stream) + : this(stream, false) { } + + /// + /// XSigToken stream writer constructor. + /// + /// Input stream to write to. + /// Determines whether to leave the stream open or not. + /// Stream is null. + /// Stream cannot be written to. + public XSigTokenStreamWriter(Stream stream, bool leaveOpen) { - private readonly Stream _stream; - private readonly bool _leaveOpen; + if (stream == null) + throw new ArgumentNullException("stream"); + if (!stream.CanWrite) + throw new ArgumentException("The specified stream cannot be written to."); - /// - /// - /// XSigToken stream writer constructor. - /// - /// Input stream to write to. - /// Stream is null. - /// Stream cannot be written to. - public XSigTokenStreamWriter(Stream stream) - : this(stream, false) { } + _stream = stream; + _leaveOpen = leaveOpen; + } - /// - /// XSigToken stream writer constructor. - /// - /// Input stream to write to. - /// Determines whether to leave the stream open or not. - /// Stream is null. - /// Stream cannot be written to. - public XSigTokenStreamWriter(Stream stream, bool leaveOpen) + /// + /// Write XSig data gathered from an IXSigStateResolver to the stream. + /// + /// IXSigStateResolver object. + public void WriteXSigData(IXSigSerialization xSigSerialization) + { + WriteXSigData(xSigSerialization, 0); + } + + /// + /// Write XSig data gathered from an IXSigStateResolver to the stream. + /// + /// IXSigStateResolver object. + /// Index offset for each XSigToken. + public void WriteXSigData(IXSigSerialization xSigSerialization, int offset) + { + if (xSigSerialization == null) + throw new ArgumentNullException("xSigSerialization"); + + var tokens = xSigSerialization.Serialize(); + WriteXSigData(tokens, offset); + } + + /// + /// Write XSigToken to the stream. + /// + /// XSigToken object. + public void WriteXSigData(XSigToken token) + { + WriteXSigData(token, 0); + } + + /// + /// Write XSigToken to the stream. + /// + /// XSigToken object. + /// Index offset for each XSigToken. + public void WriteXSigData(XSigToken token, int offset) + { + WriteXSigData(new[] { token }, offset); + } + + /// + /// Writes an array of XSigTokens to the stream. + /// + /// XSigToken objects. + public void WriteXSigData(XSigToken[] tokens) + { + WriteXSigData(tokens.AsEnumerable()); + } + + /// + /// Write an enumerable collection of XSigTokens to the stream. + /// + /// XSigToken objects. + public void WriteXSigData(IEnumerable tokens) + { + WriteXSigData(tokens, 0); + } + + /// + /// Write an enumerable collection of XSigTokens to the stream. + /// + /// XSigToken objects. + /// Index offset for each XSigToken. + public void WriteXSigData(IEnumerable tokens, int offset) + { + if (offset < 0) + throw new ArgumentOutOfRangeException("offset", "Offset must be greater than or equal to 0."); + + if (tokens != null) { - if (stream == null) - throw new ArgumentNullException("stream"); - if (!stream.CanWrite) - throw new ArgumentException("The specified stream cannot be written to."); - - _stream = stream; - _leaveOpen = leaveOpen; - } - - /// - /// Write XSig data gathered from an IXSigStateResolver to the stream. - /// - /// IXSigStateResolver object. - public void WriteXSigData(IXSigSerialization xSigSerialization) - { - WriteXSigData(xSigSerialization, 0); - } - - /// - /// Write XSig data gathered from an IXSigStateResolver to the stream. - /// - /// IXSigStateResolver object. - /// Index offset for each XSigToken. - public void WriteXSigData(IXSigSerialization xSigSerialization, int offset) - { - if (xSigSerialization == null) - throw new ArgumentNullException("xSigSerialization"); - - var tokens = xSigSerialization.Serialize(); - WriteXSigData(tokens, offset); - } - - /// - /// Write XSigToken to the stream. - /// - /// XSigToken object. - public void WriteXSigData(XSigToken token) - { - WriteXSigData(token, 0); - } - - /// - /// Write XSigToken to the stream. - /// - /// XSigToken object. - /// Index offset for each XSigToken. - public void WriteXSigData(XSigToken token, int offset) - { - WriteXSigData(new[] { token }, offset); - } - - /// - /// Writes an array of XSigTokens to the stream. - /// - /// XSigToken objects. - public void WriteXSigData(XSigToken[] tokens) - { - WriteXSigData(tokens.AsEnumerable()); - } - - /// - /// Write an enumerable collection of XSigTokens to the stream. - /// - /// XSigToken objects. - public void WriteXSigData(IEnumerable tokens) - { - WriteXSigData(tokens, 0); - } - - /// - /// Write an enumerable collection of XSigTokens to the stream. - /// - /// XSigToken objects. - /// Index offset for each XSigToken. - public void WriteXSigData(IEnumerable tokens, int offset) - { - if (offset < 0) - throw new ArgumentOutOfRangeException("offset", "Offset must be greater than or equal to 0."); - - if (tokens != null) + foreach (var token in tokens) { - foreach (var token in tokens) - { - if (token == null) continue; - var bytes = token.GetTokenWithOffset(offset).GetBytes(); - _stream.Write(bytes, 0, bytes.Length); - } + if (token == null) continue; + var bytes = token.GetTokenWithOffset(offset).GetBytes(); + _stream.Write(bytes, 0, bytes.Length); } } + } - /// - /// Disposes of the internal stream if specified to not leave open. - /// - public void Dispose() - { - if (!_leaveOpen) - _stream.Dispose(); - } + /// + /// Disposes of the internal stream if specified to not leave open. + /// + public void Dispose() + { + if (!_leaveOpen) + _stream.Dispose(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs index c1590704..627ecf20 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs @@ -16,410 +16,408 @@ using Serilog.Events; //using PepperDash.Essentials.Devices.Common.Cameras; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Base class for bridge API variants +/// +public abstract class BridgeApi : EssentialsDevice { - /// - /// Base class for bridge API variants - /// - public abstract class BridgeApi : EssentialsDevice + protected BridgeApi(string key) : + base(key) { - protected BridgeApi(string key) : - base(key) - { + } +} + +/// +/// Bridge API using EISC +/// +public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor +{ + public EiscApiPropertiesConfig PropertiesConfig { get; private set; } + + public Dictionary JoinMaps { get; private set; } + + public BasicTriList Eisc { get; private set; } + + public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : + base(dc.Key) + { + JoinMaps = new Dictionary(); + + PropertiesConfig = dc.Properties.ToObject(); + //PropertiesConfig = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + Eisc = eisc; + + Eisc.SigChange += Eisc_SigChange; + + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); + + AddPostActivationAction(LinkDevices); + AddPostActivationAction(LinkRooms); + AddPostActivationAction(RegisterEisc); + } + + public override bool CustomActivate() + { + CommunicationMonitor.Start(); + return base.CustomActivate(); + } + + public override bool Deactivate() + { + CommunicationMonitor.Stop(); + return base.Deactivate(); + } + + private void LinkDevices() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking Devices..."); + + if (PropertiesConfig.Devices == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "No devices linked to this bridge"); + return; + } + + foreach (var d in PropertiesConfig.Devices) + { + var device = DeviceManager.GetDeviceForKey(d.DeviceKey); + + if (device == null) + { + continue; + } + + Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key); + + if (device is IBridgeAdvanced bridge) + { + bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); + continue; + } + + Debug.LogMessage(LogEventLevel.Information, this, + "{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.", + device.Key); + } + } + + private void RegisterEisc() + { + if (Eisc.Registered) + { + return; + } + + var registerResult = Eisc.Register(); + + if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Registration result: {0}", registerResult); + return; + } + + Debug.LogMessage(LogEventLevel.Debug, this, "EISC registration successful"); + } + + public void LinkRooms() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking Rooms..."); + + if (PropertiesConfig.Rooms == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "No rooms linked to this bridge."); + return; + } + + foreach (var room in PropertiesConfig.Rooms) + { + var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced; + + if (rm == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, + "Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); + continue; + } + + rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this); } } /// - /// Bridge API using EISC + /// Adds a join map /// - public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor + /// + /// + public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap) { - public EiscApiPropertiesConfig PropertiesConfig { get; private set; } - - public Dictionary JoinMaps { get; private set; } - - public BasicTriList Eisc { get; private set; } - - public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : - base(dc.Key) + if (!JoinMaps.ContainsKey(deviceKey)) { - JoinMaps = new Dictionary(); - - PropertiesConfig = dc.Properties.ToObject(); - //PropertiesConfig = JsonConvert.DeserializeObject(dc.Properties.ToString()); - - Eisc = eisc; - - Eisc.SigChange += Eisc_SigChange; - - CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); - - AddPostActivationAction(LinkDevices); - AddPostActivationAction(LinkRooms); - AddPostActivationAction(RegisterEisc); + JoinMaps.Add(deviceKey, joinMap); } - - public override bool CustomActivate() + else { - CommunicationMonitor.Start(); - return base.CustomActivate(); + Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey); } - - public override bool Deactivate() - { - CommunicationMonitor.Stop(); - return base.Deactivate(); - } - - private void LinkDevices() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking Devices..."); - - if (PropertiesConfig.Devices == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "No devices linked to this bridge"); - return; - } - - foreach (var d in PropertiesConfig.Devices) - { - var device = DeviceManager.GetDeviceForKey(d.DeviceKey); - - if (device == null) - { - continue; - } - - Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key); - - if (device is IBridgeAdvanced bridge) - { - bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); - continue; - } - - Debug.LogMessage(LogEventLevel.Information, this, - "{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.", - device.Key); - } - } - - private void RegisterEisc() - { - if (Eisc.Registered) - { - return; - } - - var registerResult = Eisc.Register(); - - if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Registration result: {0}", registerResult); - return; - } - - Debug.LogMessage(LogEventLevel.Debug, this, "EISC registration successful"); - } - - public void LinkRooms() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking Rooms..."); - - if (PropertiesConfig.Rooms == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "No rooms linked to this bridge."); - return; - } - - foreach (var room in PropertiesConfig.Rooms) - { - var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced; - - if (rm == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, - "Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); - continue; - } - - rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this); - } - } - - /// - /// Adds a join map - /// - /// - /// - public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap) - { - if (!JoinMaps.ContainsKey(deviceKey)) - { - JoinMaps.Add(deviceKey, joinMap); - } - else - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey); - } - } - - /// - /// Prints all the join maps on this bridge - /// - public virtual void PrintJoinMaps() - { - CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X")); - - foreach (var joinMap in JoinMaps) - { - CrestronConsole.ConsoleCommandResponse("Join map for device '{0}':", joinMap.Key); - joinMap.Value.PrintJoinMapInfo(); - } - } - /// - /// Generates markdown for all join maps on this bridge - /// - public virtual void MarkdownForBridge(string bridgeKey) - { - Debug.LogMessage(LogEventLevel.Information, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X")); - - foreach (var joinMap in JoinMaps) - { - Debug.LogMessage(LogEventLevel.Information, "Generating markdown for device '{0}':", joinMap.Key); - joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey); - } - } - - /// - /// Prints the join map for a device by key - /// - /// - public void PrintJoinMapForDevice(string deviceKey) - { - var joinMap = JoinMaps[deviceKey]; - - if (joinMap == null) - { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); - return; - } - - Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); - joinMap.PrintJoinMapInfo(); - } - /// - /// Prints the join map for a device by key - /// - /// - public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey) - { - var joinMap = JoinMaps[deviceKey]; - - if (joinMap == null) - { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); - return; - } - - Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); - joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey); - } - - /// - /// Used for debugging to trigger an action based on a join number and type - /// - /// - /// - /// - public void ExecuteJoinAction(uint join, string type, object state) - { - try - { - switch (type.ToLower()) - { - case "digital": - { - var uo = Eisc.BooleanOutput[join].UserObject as Action; - if (uo != null) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); - uo(Convert.ToBoolean(state)); - } - else - Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); - break; - } - case "analog": - { - var uo = Eisc.BooleanOutput[join].UserObject as Action; - if (uo != null) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); - uo(Convert.ToUInt16(state)); - } - else - Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break; - } - case "serial": - { - var uo = Eisc.BooleanOutput[join].UserObject as Action; - if (uo != null) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); - uo(Convert.ToString(state)); - } - else - Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); - break; - } - default: - { - Debug.LogMessage(LogEventLevel.Verbose, "Unknown join type. Use digital/serial/analog"); - break; - } - } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); - } - - } - - /// - /// Handles incoming sig changes - /// - /// - /// - protected void Eisc_SigChange(object currentDevice, SigEventArgs args) - { - try - { - Debug.LogMessage(LogEventLevel.Verbose, this, "EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); - var uo = args.Sig.UserObject; - - if (uo == null) return; - - Debug.LogMessage(LogEventLevel.Debug, this, "Executing Action: {0}", uo.ToString()); - if (uo is Action) - (uo as Action)(args.Sig.BoolValue); - else if (uo is Action) - (uo as Action)(args.Sig.UShortValue); - else if (uo is Action) - (uo as Action)(args.Sig.StringValue); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error in Eisc_SigChange handler: {0}", e); - } - } - - #region Implementation of ICommunicationMonitor - - public StatusMonitorBase CommunicationMonitor { get; private set; } - - #endregion } - public class EiscApiPropertiesConfig + /// + /// Prints all the join maps on this bridge + /// + public virtual void PrintJoinMaps() { - [JsonProperty("control")] - public EssentialsControlPropertiesConfig Control { get; set; } + CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X")); - [JsonProperty("devices")] - public List Devices { get; set; } - - [JsonProperty("rooms")] - public List Rooms { get; set; } - - - public class ApiDevicePropertiesConfig + foreach (var joinMap in JoinMaps) { - [JsonProperty("deviceKey")] - public string DeviceKey { get; set; } - - [JsonProperty("joinStart")] - public uint JoinStart { get; set; } - - [JsonProperty("joinMapKey")] - public string JoinMapKey { get; set; } + CrestronConsole.ConsoleCommandResponse("Join map for device '{0}':", joinMap.Key); + joinMap.Value.PrintJoinMapInfo(); } + } + /// + /// Generates markdown for all join maps on this bridge + /// + public virtual void MarkdownForBridge(string bridgeKey) + { + Debug.LogMessage(LogEventLevel.Information, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X")); - public class ApiRoomPropertiesConfig + foreach (var joinMap in JoinMaps) { - [JsonProperty("roomKey")] - public string RoomKey { get; set; } - - [JsonProperty("joinStart")] - public uint JoinStart { get; set; } - - [JsonProperty("joinMapKey")] - public string JoinMapKey { get; set; } + Debug.LogMessage(LogEventLevel.Information, "Generating markdown for device '{0}':", joinMap.Key); + joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey); } - } - public class EiscApiAdvancedFactory : EssentialsDeviceFactory + /// + /// Prints the join map for a device by key + /// + /// + public void PrintJoinMapForDevice(string deviceKey) { - public EiscApiAdvancedFactory() + var joinMap = JoinMaps[deviceKey]; + + if (joinMap == null) { - TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" }; + Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); + return; } - public override EssentialsDevice BuildDevice(DeviceConfig dc) + Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); + joinMap.PrintJoinMapInfo(); + } + /// + /// Prints the join map for a device by key + /// + /// + public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey) + { + var joinMap = JoinMaps[deviceKey]; + + if (joinMap == null) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EiscApiAdvanced Device"); + Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); + return; + } - var controlProperties = CommFactory.GetControlPropertiesConfig(dc); + Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); + joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey); + } - BasicTriList eisc; - - switch (dc.Type.ToLower()) + /// + /// Used for debugging to trigger an action based on a join number and type + /// + /// + /// + /// + public void ExecuteJoinAction(uint join, string type, object state) + { + try + { + switch (type.ToLower()) { - case "eiscapiadv": - case "eiscapiadvanced": + case "digital": { - eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt, - controlProperties.TcpSshProperties.Address, Global.ControlSystem); - break; - } - case "eiscapiadvancedserver": - { - eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem); - break; - } - case "eiscapiadvancedclient": - { - eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem); - break; - } - case "vceiscapiadv": - case "vceiscapiadvanced": - { - if (string.IsNullOrEmpty(controlProperties.RoomId)) + var uo = Eisc.BooleanOutput[join].UserObject as Action; + if (uo != null) { - Debug.LogMessage(LogEventLevel.Information, "Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key); - eisc = null; - break; + Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); + uo(Convert.ToBoolean(state)); } - eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, controlProperties.RoomId, - Global.ControlSystem); + else + Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); + break; + } + case "analog": + { + var uo = Eisc.BooleanOutput[join].UserObject as Action; + if (uo != null) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); + uo(Convert.ToUInt16(state)); + } + else + Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break; + } + case "serial": + { + var uo = Eisc.BooleanOutput[join].UserObject as Action; + if (uo != null) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); + uo(Convert.ToString(state)); + } + else + Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break; } default: - eisc = null; - break; + { + Debug.LogMessage(LogEventLevel.Verbose, "Unknown join type. Use digital/serial/analog"); + break; + } } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } - if (eisc == null) - { - return null; - } + } - return new EiscApiAdvanced(dc, eisc); + /// + /// Handles incoming sig changes + /// + /// + /// + protected void Eisc_SigChange(object currentDevice, SigEventArgs args) + { + try + { + Debug.LogMessage(LogEventLevel.Verbose, this, "EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); + var uo = args.Sig.UserObject; + + if (uo == null) return; + + Debug.LogMessage(LogEventLevel.Debug, this, "Executing Action: {0}", uo.ToString()); + if (uo is Action) + (uo as Action)(args.Sig.BoolValue); + else if (uo is Action) + (uo as Action)(args.Sig.UShortValue); + else if (uo is Action) + (uo as Action)(args.Sig.StringValue); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error in Eisc_SigChange handler: {0}", e); } } + #region Implementation of ICommunicationMonitor + + public StatusMonitorBase CommunicationMonitor { get; private set; } + + #endregion +} + +public class EiscApiPropertiesConfig +{ + [JsonProperty("control")] + public EssentialsControlPropertiesConfig Control { get; set; } + + [JsonProperty("devices")] + public List Devices { get; set; } + + [JsonProperty("rooms")] + public List Rooms { get; set; } + + + public class ApiDevicePropertiesConfig + { + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + [JsonProperty("joinStart")] + public uint JoinStart { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + } + + public class ApiRoomPropertiesConfig + { + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("joinStart")] + public uint JoinStart { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + } + +} + +public class EiscApiAdvancedFactory : EssentialsDeviceFactory +{ + public EiscApiAdvancedFactory() + { + TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EiscApiAdvanced Device"); + + var controlProperties = CommFactory.GetControlPropertiesConfig(dc); + + BasicTriList eisc; + + switch (dc.Type.ToLower()) + { + case "eiscapiadv": + case "eiscapiadvanced": + { + eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt, + controlProperties.TcpSshProperties.Address, Global.ControlSystem); + break; + } + case "eiscapiadvancedserver": + { + eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem); + break; + } + case "eiscapiadvancedclient": + { + eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem); + break; + } + case "vceiscapiadv": + case "vceiscapiadvanced": + { + if (string.IsNullOrEmpty(controlProperties.RoomId)) + { + Debug.LogMessage(LogEventLevel.Information, "Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key); + eisc = null; + break; + } + eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, controlProperties.RoomId, + Global.ControlSystem); + break; + } + default: + eisc = null; + break; + } + + if (eisc == null) + { + return null; + } + + return new EiscApiAdvanced(dc, eisc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs index 0254cd0d..3a3ceff2 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs @@ -3,64 +3,62 @@ using Serilog.Events; //using PepperDash.Essentials.Devices.Common.Cameras; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Helper methods for bridges +/// +public static class BridgeHelper { - /// - /// Helper methods for bridges - /// - public static class BridgeHelper + public static void PrintJoinMap(string command) { - public static void PrintJoinMap(string command) + var targets = command.Split(' '); + + var bridgeKey = targets[0].Trim(); + + if (!(DeviceManager.GetDeviceForKey(bridgeKey) is EiscApiAdvanced bridge)) { - var targets = command.Split(' '); - - var bridgeKey = targets[0].Trim(); - - if (!(DeviceManager.GetDeviceForKey(bridgeKey) is EiscApiAdvanced bridge)) - { - Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); - return; - } - - if (targets.Length > 1) - { - var deviceKey = targets[1].Trim(); - - if (string.IsNullOrEmpty(deviceKey)) return; - bridge.PrintJoinMapForDevice(deviceKey); - } - else - { - bridge.PrintJoinMaps(); - } + Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); + return; } - public static void JoinmapMarkdown(string command) + + if (targets.Length > 1) { - var targets = command.Split(' '); + var deviceKey = targets[1].Trim(); - var bridgeKey = targets[0].Trim(); - - var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced; - - if (bridge == null) - { - Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); - return; - } - - if (targets.Length > 1) - { - var deviceKey = targets[1].Trim(); - - if (string.IsNullOrEmpty(deviceKey)) return; - bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey); - } - else - { - bridge.MarkdownForBridge(bridgeKey); - - } + if (string.IsNullOrEmpty(deviceKey)) return; + bridge.PrintJoinMapForDevice(deviceKey); + } + else + { + bridge.PrintJoinMaps(); } } + public static void JoinmapMarkdown(string command) + { + var targets = command.Split(' '); + var bridgeKey = targets[0].Trim(); + + var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced; + + if (bridge == null) + { + Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); + return; + } + + if (targets.Length > 1) + { + var deviceKey = targets[1].Trim(); + + if (string.IsNullOrEmpty(deviceKey)) return; + bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey); + } + else + { + bridge.MarkdownForBridge(bridgeKey); + + } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/IBridge.cs b/src/PepperDash.Essentials.Core/Bridges/IBridge.cs index 0c6b44ed..87b4bd35 100644 --- a/src/PepperDash.Essentials.Core/Bridges/IBridge.cs +++ b/src/PepperDash.Essentials.Core/Bridges/IBridge.cs @@ -1,12 +1,11 @@ using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Defines a device that uses JoinMapBaseAdvanced for its join map +/// +public interface IBridgeAdvanced { - /// - /// Defines a device that uses JoinMapBaseAdvanced for its join map - /// - public interface IBridgeAdvanced - { - void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); - } + void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs index c46df18c..33fca20e 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs @@ -1,71 +1,70 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class AirMediaControllerJoinMap : JoinMapBaseAdvanced { - public class AirMediaControllerJoinMap : JoinMapBaseAdvanced + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IsInSession")] + public JoinDataComplete IsInSession = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media In Sharing Session", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HdmiVideoSync")] + public JoinDataComplete HdmiVideoSync = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Has HDMI Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("AutomaticInputRoutingEnabled")] + public JoinDataComplete AutomaticInputRoutingEnabled = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Automatic Input Routing Enable(d)", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoOut")] + public JoinDataComplete VideoOut = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Video Route Select / Feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("ErrorFB")] + public JoinDataComplete ErrorFB = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Error Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("NumberOfUsersConnectedFB")] + public JoinDataComplete NumberOfUsersConnectedFB = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Number of Users Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("LoginCode")] + public JoinDataComplete LoginCode = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Login Code Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("ConnectionAddressFB")] + public JoinDataComplete ConnectionAddressFB = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media IP Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("HostnameFB")] + public JoinDataComplete HostnameFB = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Hostname", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("SerialNumberFeedback")] + public JoinDataComplete SerialNumberFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Air Media Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public AirMediaControllerJoinMap(uint joinStart) + : this(joinStart, typeof(AirMediaControllerJoinMap)) { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IsInSession")] - public JoinDataComplete IsInSession = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media In Sharing Session", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HdmiVideoSync")] - public JoinDataComplete HdmiVideoSync = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Has HDMI Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("AutomaticInputRoutingEnabled")] - public JoinDataComplete AutomaticInputRoutingEnabled = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Automatic Input Routing Enable(d)", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VideoOut")] - public JoinDataComplete VideoOut = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Video Route Select / Feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("ErrorFB")] - public JoinDataComplete ErrorFB = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Error Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("NumberOfUsersConnectedFB")] - public JoinDataComplete NumberOfUsersConnectedFB = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Number of Users Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("LoginCode")] - public JoinDataComplete LoginCode = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Login Code Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("ConnectionAddressFB")] - public JoinDataComplete ConnectionAddressFB = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media IP Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("HostnameFB")] - public JoinDataComplete HostnameFB = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Hostname", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("SerialNumberFeedback")] - public JoinDataComplete SerialNumberFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Air Media Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public AirMediaControllerJoinMap(uint joinStart) - : this(joinStart, typeof(AirMediaControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} } + + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs index 7a9dfa74..3b3eaa06 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs @@ -1,53 +1,52 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class AppleTvJoinMap : JoinMapBaseAdvanced { - public class AppleTvJoinMap : JoinMapBaseAdvanced + [JoinName("UpArrow")] + public JoinDataComplete UpArrow = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DnArrow")] + public JoinDataComplete DnArrow = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("LeftArrow")] + public JoinDataComplete LeftArrow = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RightArrow")] + public JoinDataComplete RightArrow = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Select")] + public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PlayPause")] + public JoinDataComplete PlayPause = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "AppleTv Play/Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public AppleTvJoinMap(uint joinStart) + : base(joinStart, typeof(AppleTvJoinMap)) { - [JoinName("UpArrow")] - public JoinDataComplete UpArrow = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("DnArrow")] - public JoinDataComplete DnArrow = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("LeftArrow")] - public JoinDataComplete LeftArrow = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RightArrow")] - public JoinDataComplete RightArrow = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Menu")] - public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Select")] - public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PlayPause")] - public JoinDataComplete PlayPause = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "AppleTv Play/Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public AppleTvJoinMap(uint joinStart) - : base(joinStart, typeof(AppleTvJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs index dd141c8e..17f8f4db 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs @@ -1,45 +1,44 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced { - public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Temp Sensor Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("TemperatureFormat")] + public JoinDataComplete TemperatureFormat = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Temp Sensor Unit Format", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Temperature")] + public JoinDataComplete Temperature = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Temp Sensor Temperature Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Humidity")] + public JoinDataComplete Humidity = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Temp Sensor Humidity Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Temp Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public C2nRthsControllerJoinMap(uint joinStart) + : this(joinStart, typeof(C2nRthsControllerJoinMap)) { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Temp Sensor Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("TemperatureFormat")] - public JoinDataComplete TemperatureFormat = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Temp Sensor Unit Format", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Temperature")] - public JoinDataComplete Temperature = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Temp Sensor Temperature Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Humidity")] - public JoinDataComplete Humidity = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Temp Sensor Humidity Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Temp Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public C2nRthsControllerJoinMap(uint joinStart) - : this(joinStart, typeof(C2nRthsControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs index 5c07b4a7..0cb011fa 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs @@ -1,69 +1,68 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Join map for CameraBase devices +/// +public class CameraControllerJoinMap : JoinMapBaseAdvanced { + [JoinName("TiltUp")] + public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("TiltDown")] + public JoinDataComplete TiltDown = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PanLeft")] + public JoinDataComplete PanLeft = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PanRight")] + public JoinDataComplete PanRight = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ZoomIn")] + public JoinDataComplete ZoomIn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom In", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ZoomOut")] + public JoinDataComplete ZoomOut = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom Out", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("NumberOfPresets")] + public JoinDataComplete NumberOfPresets = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Tells Essentials the number of defined presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("PresetRecallStart")] + public JoinDataComplete PresetRecallStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Recall Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PresetLabelStart")] + public JoinDataComplete PresetLabelStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Label Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("PresetSaveStart")] + public JoinDataComplete PresetSaveStart = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Save Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraModeAuto")] + public JoinDataComplete CameraModeAuto = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Auto", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraModeManual")] + public JoinDataComplete CameraModeManual = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Manual", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraModeOff")] + public JoinDataComplete CameraModeOff = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SupportsCameraModeAuto")] + public JoinDataComplete SupportsCameraModeAuto = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Camera Mode Auto", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SupportsCameraModeOff")] + public JoinDataComplete SupportsCameraModeOff = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Camera Mode Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SupportsPresets")] + public JoinDataComplete SupportsPresets = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + /// - /// Join map for CameraBase devices + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class CameraControllerJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public CameraControllerJoinMap(uint joinStart) + : this(joinStart, typeof(CameraControllerJoinMap)) { - [JoinName("TiltUp")] - public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("TiltDown")] - public JoinDataComplete TiltDown = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("PanLeft")] - public JoinDataComplete PanLeft = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("PanRight")] - public JoinDataComplete PanRight = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("ZoomIn")] - public JoinDataComplete ZoomIn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom In", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("ZoomOut")] - public JoinDataComplete ZoomOut = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom Out", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("PowerOn")] - public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("PowerOff")] - public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("NumberOfPresets")] - public JoinDataComplete NumberOfPresets = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Tells Essentials the number of defined presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - [JoinName("PresetRecallStart")] - public JoinDataComplete PresetRecallStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Recall Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("PresetLabelStart")] - public JoinDataComplete PresetLabelStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Label Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); - [JoinName("PresetSaveStart")] - public JoinDataComplete PresetSaveStart = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Save Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("CameraModeAuto")] - public JoinDataComplete CameraModeAuto = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Auto", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("CameraModeManual")] - public JoinDataComplete CameraModeManual = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Manual", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("CameraModeOff")] - public JoinDataComplete CameraModeOff = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SupportsCameraModeAuto")] - public JoinDataComplete SupportsCameraModeAuto = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Camera Mode Auto", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("SupportsCameraModeOff")] - public JoinDataComplete SupportsCameraModeOff = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Camera Mode Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("SupportsPresets")] - public JoinDataComplete SupportsPresets = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public CameraControllerJoinMap(uint joinStart) - : this(joinStart, typeof(CameraControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} } + + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs index e306bf85..b585916b 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs @@ -1,198 +1,196 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced { - public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced + #region Digitals + + [JoinName("Online")] + public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ForceOccupied")] + public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Force Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ForceVacant")] + public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Force Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableRawStates")] + public JoinDataComplete EnableRawStates = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Raw States", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RoomOccupiedFeedback")] + public JoinDataComplete RoomOccupiedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Room Occupied Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("GraceOccupancyDetectedFeedback")] + public JoinDataComplete GraceOccupancyDetectedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Grace Occupancy Detected Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RoomVacantFeedback")] + public JoinDataComplete RoomVacantFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Room Vacant Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RawOccupancyFeedback")] + public JoinDataComplete RawOccupancyFeedback = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Raw Occupancy Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RawOccupancyPirFeedback")] + public JoinDataComplete RawOccupancyPirFeedback = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Raw Occupancy Pir Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RawOccupancyUsFeedback")] + public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Raw Occupancy Us Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IdentityModeOn")] + public JoinDataComplete IdentityMode = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Identity Mode", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IdentityModeFeedback")] + public JoinDataComplete IdentityModeFeedback = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Identity Mode Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableLedFlash")] + public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Led Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableLedFlash")] + public JoinDataComplete DisableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Disable Led Flash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableShortTimeout")] + public JoinDataComplete EnableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Short Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableShortTimeout")] + public JoinDataComplete DisableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Disable Short Timeout", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OrWhenVacated")] + public JoinDataComplete OrWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Or When Vacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("AndWhenVacated")] + public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "AndWhenVacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableUsA")] + public JoinDataComplete EnableUsA = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Us A", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableUsA")] + public JoinDataComplete DisableUsA = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "Disable Us A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableUsB")] + public JoinDataComplete EnableUsB = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Us B", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableUsB")] + public JoinDataComplete DisableUsB = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "Disable Us B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnablePir")] + public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Pir", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisablePir")] + public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Disable Pir", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementUsInOccupiedState")] + public JoinDataComplete IncrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "Increment Us In OccupiedState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementUsInOccupiedState")] + public JoinDataComplete DecrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "Dencrement Us In Occupied State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementUsInVacantState")] + public JoinDataComplete IncrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Increment Us In VacantState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementUsInVacantState")] + public JoinDataComplete DecrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "Decrement Us In VacantState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementPirInOccupiedState")] + public JoinDataComplete IncrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "Increment Pir In Occupied State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementPirInOccupiedState")] + public JoinDataComplete DecrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "Decrement Pir In OccupiedState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementPirInVacantState")] + public JoinDataComplete IncrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "Increment Pir In Vacant State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementPirInVacantState")] + public JoinDataComplete DecrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Decrement Pir In Vacant State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + #endregion + + #region Analog + + [JoinName("Timeout")] + public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("TimeoutLocalFeedback")] + public JoinDataComplete TimeoutLocalFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Timeout Local Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("InternalPhotoSensorValue")] + public JoinDataComplete InternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Internal PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("UsSensitivityInOccupiedState")] + public JoinDataComplete UsSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Us Sensitivity In Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("UsSensitivityInVacantState")] + public JoinDataComplete UsSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Us Sensitivity In Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("PirSensitivityInOccupiedState")] + public JoinDataComplete PirSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Pir Sensitivity In Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("PirSensitivityInVacantState")] + public JoinDataComplete PirSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Pir Sensitivity In Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + #endregion + + #region Serial + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + #endregion + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public CenOdtOccupancySensorBaseJoinMap(uint joinStart) + : this(joinStart, typeof(CenOdtOccupancySensorBaseJoinMap)) { - #region Digitals - - [JoinName("Online")] - public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ForceOccupied")] - public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Force Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ForceVacant")] - public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Force Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableRawStates")] - public JoinDataComplete EnableRawStates = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Raw States", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RoomOccupiedFeedback")] - public JoinDataComplete RoomOccupiedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Room Occupied Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("GraceOccupancyDetectedFeedback")] - public JoinDataComplete GraceOccupancyDetectedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Grace Occupancy Detected Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RoomVacantFeedback")] - public JoinDataComplete RoomVacantFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Room Vacant Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RawOccupancyFeedback")] - public JoinDataComplete RawOccupancyFeedback = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Raw Occupancy Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RawOccupancyPirFeedback")] - public JoinDataComplete RawOccupancyPirFeedback = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Raw Occupancy Pir Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RawOccupancyUsFeedback")] - public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Raw Occupancy Us Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IdentityModeOn")] - public JoinDataComplete IdentityMode = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Identity Mode", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IdentityModeFeedback")] - public JoinDataComplete IdentityModeFeedback = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Identity Mode Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableLedFlash")] - public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Led Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableLedFlash")] - public JoinDataComplete DisableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Disable Led Flash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableShortTimeout")] - public JoinDataComplete EnableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Short Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableShortTimeout")] - public JoinDataComplete DisableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Disable Short Timeout", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OrWhenVacated")] - public JoinDataComplete OrWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "Or When Vacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("AndWhenVacated")] - public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, - new JoinMetadata { Description = "AndWhenVacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableUsA")] - public JoinDataComplete EnableUsA = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Us A", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableUsA")] - public JoinDataComplete DisableUsA = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, - new JoinMetadata { Description = "Disable Us A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableUsB")] - public JoinDataComplete EnableUsB = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Us B", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableUsB")] - public JoinDataComplete DisableUsB = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, - new JoinMetadata { Description = "Disable Us B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnablePir")] - public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Pir", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisablePir")] - public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "Disable Pir", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementUsInOccupiedState")] - public JoinDataComplete IncrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, - new JoinMetadata { Description = "Increment Us In OccupiedState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementUsInOccupiedState")] - public JoinDataComplete DecrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata { Description = "Dencrement Us In Occupied State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementUsInVacantState")] - public JoinDataComplete IncrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, - new JoinMetadata { Description = "Increment Us In VacantState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementUsInVacantState")] - public JoinDataComplete DecrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, - new JoinMetadata { Description = "Decrement Us In VacantState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementPirInOccupiedState")] - public JoinDataComplete IncrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, - new JoinMetadata { Description = "Increment Pir In Occupied State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementPirInOccupiedState")] - public JoinDataComplete DecrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, - new JoinMetadata { Description = "Decrement Pir In OccupiedState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementPirInVacantState")] - public JoinDataComplete IncrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, - new JoinMetadata { Description = "Increment Pir In Vacant State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementPirInVacantState")] - public JoinDataComplete DecrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, - new JoinMetadata { Description = "Decrement Pir In Vacant State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - #endregion - - #region Analog - - [JoinName("Timeout")] - public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("TimeoutLocalFeedback")] - public JoinDataComplete TimeoutLocalFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Timeout Local Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("InternalPhotoSensorValue")] - public JoinDataComplete InternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Internal PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("UsSensitivityInOccupiedState")] - public JoinDataComplete UsSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Us Sensitivity In Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("UsSensitivityInVacantState")] - public JoinDataComplete UsSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Us Sensitivity In Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("PirSensitivityInOccupiedState")] - public JoinDataComplete PirSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Pir Sensitivity In Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("PirSensitivityInVacantState")] - public JoinDataComplete PirSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Pir Sensitivity In Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - #endregion - - #region Serial - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - #endregion - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public CenOdtOccupancySensorBaseJoinMap(uint joinStart) - : this(joinStart, typeof(CenOdtOccupancySensorBaseJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type) + { + } } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs index 8e51c952..2ab95b8e 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs @@ -1,85 +1,84 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DisplayControllerJoinMap : JoinMapBaseAdvanced { - public class DisplayControllerJoinMap : JoinMapBaseAdvanced + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IsTwoWayDisplay")] + public JoinDataComplete IsTwoWayDisplay = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Is Two Way Display", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeUp")] + public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeLevel")] + public JoinDataComplete VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Level", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("VolumeDown")] + public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeMute")] + public JoinDataComplete VolumeMute = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Mute", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeMuteOn")] + public JoinDataComplete VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Mute On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeMuteOff")] + public JoinDataComplete VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "Volume Mute Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputSelectOffset")] + public JoinDataComplete InputSelectOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, + new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputNamesOffset")] + public JoinDataComplete InputNamesOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, + new JoinMetadata { Description = "Input Names Offset", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputSelect")] + public JoinDataComplete InputSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("ButtonVisibilityOffset")] + public JoinDataComplete ButtonVisibilityOffset = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 10 }, + new JoinMetadata { Description = "Button Visibility Offset", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DisplayControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DisplayControllerJoinMap)) { - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + } - [JoinName("PowerOff")] - public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PowerOn")] - public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IsTwoWayDisplay")] - public JoinDataComplete IsTwoWayDisplay = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Is Two Way Display", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeUp")] - public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Volume Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeLevel")] - public JoinDataComplete VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Volume Level", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("VolumeDown")] - public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Volume Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeMute")] - public JoinDataComplete VolumeMute = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Volume Mute", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeMuteOn")] - public JoinDataComplete VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Volume Mute On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeMuteOff")] - public JoinDataComplete VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata { Description = "Volume Mute Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputSelectOffset")] - public JoinDataComplete InputSelectOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, - new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputNamesOffset")] - public JoinDataComplete InputNamesOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, - new JoinMetadata { Description = "Input Names Offset", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputSelect")] - public JoinDataComplete InputSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("ButtonVisibilityOffset")] - public JoinDataComplete ButtonVisibilityOffset = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 10 }, - new JoinMetadata { Description = "Button Visibility Offset", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); - - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, - new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DisplayControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DisplayControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs index 3a4c4255..3edd1222 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs @@ -1,74 +1,73 @@ using System; -namespace PepperDash.Essentials.Core.Bridges { - public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced { +namespace PepperDash.Essentials.Core.Bridges; +public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "DM Blade Chassis Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "DM Blade Chassis Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("VideoSyncStatus")] - public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("VideoSyncStatus")] + public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("InputEndpointOnline")] - public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("InputEndpointOnline")] + public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("OutputEndpointOnline")] - public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("OutputEndpointOnline")] + public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("TxAdvancedIsPresent")] - public JoinDataComplete TxAdvancedIsPresent = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Tx Advanced Is Present", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("TxAdvancedIsPresent")] + public JoinDataComplete TxAdvancedIsPresent = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Tx Advanced Is Present", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("OutputVideo")] - public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Output Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("OutputVideo")] + public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Output Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - [JoinName("HdcpSupportState")] - public JoinDataComplete HdcpSupportState = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Input HDCP Support State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("HdcpSupportState")] + public JoinDataComplete HdcpSupportState = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Input HDCP Support State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - [JoinName("HdcpSupportCapability")] - public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("HdcpSupportCapability")] + public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - [JoinName("InputNames")] - public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("InputNames")] + public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("OutputNames")] - public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("OutputNames")] + public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("OutputCurrentVideoInputNames")] - public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("OutputCurrentVideoInputNames")] + public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("InputCurrentResolution")] - public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 128 }, - new JoinMetadata { Description = "DM Blade Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("InputCurrentResolution")] + public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 128 }, + new JoinMetadata { Description = "DM Blade Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmBladeChassisControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmBladeChassisControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmBladeChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } - + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmBladeChassisControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmBladeChassisControllerJoinMap)) + { } + + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmBladeChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { + } + } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs index 539e8d29..db3701b3 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs @@ -1,170 +1,169 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmChassisControllerJoinMap : JoinMapBaseAdvanced { - public class DmChassisControllerJoinMap : JoinMapBaseAdvanced + [JoinName("EnableAudioBreakaway")] + public JoinDataComplete EnableAudioBreakaway = new JoinDataComplete( + new JoinData {JoinNumber = 4, JoinSpan = 1}, + new JoinMetadata + { + Description = "DM Chassis enable audio breakaway routing", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("EnableUsbBreakaway")] + public JoinDataComplete EnableUsbBreakaway = new JoinDataComplete( + new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata + { + Description = "DM Chassis enable USB breakaway routing", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM Chassis Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("SystemId")] + public JoinDataComplete SystemId = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "DM Chassis SystemId Get/Set/Trigger/", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalog }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "DM Chassis Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoSyncStatus")] + public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputEndpointOnline")] + public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutputEndpointOnline")] + public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("TxAdvancedIsPresent")] + public JoinDataComplete TxAdvancedIsPresent = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Tx Advanced Is Present", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutputDisabledByHdcp")] + public JoinDataComplete OutputDisabledByHdcp = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Disabled by HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutputVideo")] + public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Video Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("OutputAudio")] + public JoinDataComplete OutputAudio = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Audio Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("OutputUsb")] + public JoinDataComplete OutputUsb = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output USB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("InputUsb")] + public JoinDataComplete InputUsb = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Usb Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("HdcpSupportState")] + public JoinDataComplete HdcpSupportState = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input HDCP Support State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("HdcpSupportCapability")] + public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("InputStreamCardState")] + public JoinDataComplete InputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1501, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("OutputStreamCardState")] + public JoinDataComplete OutputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1601, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("NoRouteName")] + public JoinDataComplete NoRouteName = new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, + new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputNames")] + public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("OutputNames")] + public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputVideoNames")] public JoinDataComplete InputVideoNames = + new JoinDataComplete(new JoinData {JoinNumber = 501, JoinSpan = 200}, + new JoinMetadata + { + Description = "DM Chassis Video Input Names", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("InputAudioNames")] + public JoinDataComplete InputAudioNames = + new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 200 }, + new JoinMetadata + { + Description = "DM Chassis Audio Input Names", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("OutputVideoNames")] + public JoinDataComplete OutputVideoNames = + new JoinDataComplete(new JoinData { JoinNumber = 901, JoinSpan = 200 }, + new JoinMetadata + { + Description = "DM Chassis Video Output Names", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("OutputAudioNames")] + public JoinDataComplete OutputAudioNames = + new JoinDataComplete(new JoinData { JoinNumber = 1101, JoinSpan = 200 }, + new JoinMetadata + { + Description = "DM Chassis Audio Output Names", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("OutputCurrentVideoInputNames")] + public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("OutputCurrentAudioInputNames")] + public JoinDataComplete OutputCurrentAudioInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2201, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Audio Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputCurrentResolution")] + public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmChassisControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmChassisControllerJoinMap)) { - [JoinName("EnableAudioBreakaway")] - public JoinDataComplete EnableAudioBreakaway = new JoinDataComplete( - new JoinData {JoinNumber = 4, JoinSpan = 1}, - new JoinMetadata - { - Description = "DM Chassis enable audio breakaway routing", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + } - [JoinName("EnableUsbBreakaway")] - public JoinDataComplete EnableUsbBreakaway = new JoinDataComplete( - new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata - { - Description = "DM Chassis enable USB breakaway routing", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM Chassis Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("SystemId")] - public JoinDataComplete SystemId = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, - new JoinMetadata { Description = "DM Chassis SystemId Get/Set/Trigger/", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalog }); - - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "DM Chassis Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VideoSyncStatus")] - public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputEndpointOnline")] - public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutputEndpointOnline")] - public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("TxAdvancedIsPresent")] - public JoinDataComplete TxAdvancedIsPresent = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Tx Advanced Is Present", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutputDisabledByHdcp")] - public JoinDataComplete OutputDisabledByHdcp = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Disabled by HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutputVideo")] - public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Video Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("OutputAudio")] - public JoinDataComplete OutputAudio = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Audio Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("OutputUsb")] - public JoinDataComplete OutputUsb = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output USB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("InputUsb")] - public JoinDataComplete InputUsb = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Usb Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("HdcpSupportState")] - public JoinDataComplete HdcpSupportState = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input HDCP Support State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("HdcpSupportCapability")] - public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("InputStreamCardState")] - public JoinDataComplete InputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1501, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("OutputStreamCardState")] - public JoinDataComplete OutputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1601, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("NoRouteName")] - public JoinDataComplete NoRouteName = new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, - new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputNames")] - public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("OutputNames")] - public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputVideoNames")] public JoinDataComplete InputVideoNames = - new JoinDataComplete(new JoinData {JoinNumber = 501, JoinSpan = 200}, - new JoinMetadata - { - Description = "DM Chassis Video Input Names", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("InputAudioNames")] - public JoinDataComplete InputAudioNames = - new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 200 }, - new JoinMetadata - { - Description = "DM Chassis Audio Input Names", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - [JoinName("OutputVideoNames")] - public JoinDataComplete OutputVideoNames = - new JoinDataComplete(new JoinData { JoinNumber = 901, JoinSpan = 200 }, - new JoinMetadata - { - Description = "DM Chassis Video Output Names", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - [JoinName("OutputAudioNames")] - public JoinDataComplete OutputAudioNames = - new JoinDataComplete(new JoinData { JoinNumber = 1101, JoinSpan = 200 }, - new JoinMetadata - { - Description = "DM Chassis Audio Output Names", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("OutputCurrentVideoInputNames")] - public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("OutputCurrentAudioInputNames")] - public JoinDataComplete OutputCurrentAudioInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2201, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Audio Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputCurrentResolution")] - public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmChassisControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmChassisControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs index bdcc3a69..4ddb9ff4 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs @@ -1,92 +1,91 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmRmcControllerJoinMap : JoinMapBaseAdvanced { - public class DmRmcControllerJoinMap : JoinMapBaseAdvanced + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoMuteOn")] + public JoinDataComplete VideoMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Mute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoMuteOff")] + public JoinDataComplete VideoMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC UnMute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoMuteToggle")] + public JoinDataComplete VideoMuteToggle = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Mute Video Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CurrentOutputResolution")] + public JoinDataComplete CurrentOutputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Current Output Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("EdidManufacturer")] + public JoinDataComplete EdidManufacturer = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC EDID Manufacturer", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("EdidName")] + public JoinDataComplete EdidName = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC EDID Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("EdidPrefferedTiming")] + public JoinDataComplete EdidPrefferedTiming = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC EDID Preferred Timing", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("EdidSerialNumber")] + public JoinDataComplete EdidSerialNumber = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC EDID Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("AudioVideoSource")] + public JoinDataComplete AudioVideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Audio Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("HdcpSupportCapability")] + public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Port1HdcpState")] + public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC Port 1 (DM) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Port2HdcpState")] + public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Port 2 (HDMI) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("HdmiInputSync")] + public JoinDataComplete HdmiInputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "DM RMC HDMI Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HdcpInputPortCount")] + public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmRmcControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmRmcControllerJoinMap)) { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("VideoMuteOn")] - public JoinDataComplete VideoMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Mute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VideoMuteOff")] - public JoinDataComplete VideoMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC UnMute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VideoMuteToggle")] - public JoinDataComplete VideoMuteToggle = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Mute Video Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("CurrentOutputResolution")] - public JoinDataComplete CurrentOutputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Current Output Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("EdidManufacturer")] - public JoinDataComplete EdidManufacturer = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC EDID Manufacturer", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("EdidName")] - public JoinDataComplete EdidName = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC EDID Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("EdidPrefferedTiming")] - public JoinDataComplete EdidPrefferedTiming = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC EDID Preferred Timing", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("EdidSerialNumber")] - public JoinDataComplete EdidSerialNumber = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC EDID Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("AudioVideoSource")] - public JoinDataComplete AudioVideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Audio Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("HdcpSupportCapability")] - public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Port1HdcpState")] - public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC Port 1 (DM) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Port2HdcpState")] - public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Port 2 (HDMI) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("HdmiInputSync")] - public JoinDataComplete HdmiInputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "DM RMC HDMI Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HdcpInputPortCount")] - public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmRmcControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmRmcControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmRmcControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmRmcControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs index c6f8f89f..8fb99f33 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs @@ -1,96 +1,95 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmTxControllerJoinMap : JoinMapBaseAdvanced { - public class DmTxControllerJoinMap : JoinMapBaseAdvanced + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoSyncStatus")] + public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FreeRunEnabled")] + public JoinDataComplete FreeRunEnabled = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Enable Free Run Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Input1VideoSyncStatus")] + public JoinDataComplete Input1VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Input 1 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Input2VideoSyncStatus")] + public JoinDataComplete Input2VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Input 2 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Input3VideoSyncStatus")] + public JoinDataComplete Input3VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Input 3 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CurrentInputResolution")] + public JoinDataComplete CurrentInputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Current Input Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("VideoInput")] + public JoinDataComplete VideoInput = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Video Input Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("AudioInput")] + public JoinDataComplete AudioInput = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Audio Input Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("HdcpSupportCapability")] + public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Port1HdcpState")] + public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Port 1 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Port2HdcpState")] + public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Port 2 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("VgaBrightness")] + public JoinDataComplete VgaBrightness = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX VGA Brightness", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("VgaContrast")] + public JoinDataComplete VgaContrast = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Port3HdcpState")] + public JoinDataComplete Port3HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "DM TX Port 3 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("HdcpInputPortCount")] + public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmTxControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmTxControllerJoinMap)) { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("VideoSyncStatus")] - public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("FreeRunEnabled")] - public JoinDataComplete FreeRunEnabled = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Enable Free Run Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Input1VideoSyncStatus")] - public JoinDataComplete Input1VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Input 1 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Input2VideoSyncStatus")] - public JoinDataComplete Input2VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Input 2 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Input3VideoSyncStatus")] - public JoinDataComplete Input3VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Input 3 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("CurrentInputResolution")] - public JoinDataComplete CurrentInputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Current Input Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("VideoInput")] - public JoinDataComplete VideoInput = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Video Input Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("AudioInput")] - public JoinDataComplete AudioInput = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Audio Input Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("HdcpSupportCapability")] - public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Port1HdcpState")] - public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Port 1 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Port2HdcpState")] - public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Port 2 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("VgaBrightness")] - public JoinDataComplete VgaBrightness = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX VGA Brightness", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("VgaContrast")] - public JoinDataComplete VgaContrast = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Port3HdcpState")] - public JoinDataComplete Port3HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "DM TX Port 3 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("HdcpInputPortCount")] - public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmTxControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmTxControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmTxControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmTxControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs index 11509acf..9ad04691 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs @@ -1,174 +1,173 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced { - public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced + + [JoinName("MasterVolumeLevel")] + public JoinDataComplete MasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MasterVolumeLevelScaled")] + public JoinDataComplete MasterVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MixerPresetRecall")] + public JoinDataComplete MixerPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Mixer Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MixerEqPresetRecall")] + public JoinDataComplete MixerEqPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Mixer Eq Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MasterVolumeMuteOn")] + public JoinDataComplete MasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MasterVolumeMuteOff")] + public JoinDataComplete MasterVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MasterVolumeUp")] + public JoinDataComplete MasterVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MasterVolumeDown")] + public JoinDataComplete MasterVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MasterVolumeLevelScaledSend")] + public JoinDataComplete MasterVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Master Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceVolumeLevel")] + public JoinDataComplete SourceVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("SourceVolumeLevelScaled")] + public JoinDataComplete SourceVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("SourceVolumeMuteOn")] + public JoinDataComplete SourceVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceVolumeMuteOff")] + public JoinDataComplete SourceVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceVolumeUp")] + public JoinDataComplete SourceVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceVolumeDown")] + public JoinDataComplete SourceVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceVolumeLevelScaledSend")] + public JoinDataComplete SourceVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Source Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec1VolumeLevel")] + public JoinDataComplete Codec1VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Codec1VolumeLevelScaled")] + public JoinDataComplete Codec1VolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Codec1VolumeMuteOn")] + public JoinDataComplete Codec1VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec1VolumeMuteOff")] + public JoinDataComplete Codec1VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec1VolumeUp")] + public JoinDataComplete Codec1VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec1VolumeDown")] + public JoinDataComplete Codec1VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec1VolumeLevelScaledSend")] + public JoinDataComplete Codec1VolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec1 Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec2VolumeLevel")] + public JoinDataComplete Codec2VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Codec2VolumeLevelScaled")] + public JoinDataComplete Codec2VolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Codec2VolumeMuteOn")] + public JoinDataComplete Codec2VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec2VolumeMuteOff")] + public JoinDataComplete Codec2VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec2VolumeUp")] + public JoinDataComplete Codec2VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec2VolumeDown")] + public JoinDataComplete Codec2VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Codec2VolumeLevelScaledSend")] + public JoinDataComplete Codec2VolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "Codec2 Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicsMasterVolumeLevel")] + public JoinDataComplete MicsMasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "MicsMaster Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MicsMasterVolumeLevelScaled")] + public JoinDataComplete MicsMasterVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "MicsMaster Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MicsMasterVolumeMuteOn")] + public JoinDataComplete MicsMasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "MicsMaster Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicsMasterVolumeMuteOff")] + public JoinDataComplete MicsMasterVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "MicsMaster Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicsMasterVolumeUp")] + public JoinDataComplete MicsMasterVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "MicsMaster Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicsMasterVolumeDown")] + public JoinDataComplete MicsMasterVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, + new JoinMetadata { Description = "MicsMaster Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicsMasterVolumeLevelScaledSend")] + public JoinDataComplete MicsMasterVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, + new JoinMetadata { Description = "Mics Master Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmpsAudioOutputControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmpsAudioOutputControllerJoinMap)) { + } - [JoinName("MasterVolumeLevel")] - public JoinDataComplete MasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MasterVolumeLevelScaled")] - public JoinDataComplete MasterVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MixerPresetRecall")] - public JoinDataComplete MixerPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Mixer Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MixerEqPresetRecall")] - public JoinDataComplete MixerEqPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Mixer Eq Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MasterVolumeMuteOn")] - public JoinDataComplete MasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MasterVolumeMuteOff")] - public JoinDataComplete MasterVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MasterVolumeUp")] - public JoinDataComplete MasterVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MasterVolumeDown")] - public JoinDataComplete MasterVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MasterVolumeLevelScaledSend")] - public JoinDataComplete MasterVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Master Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SourceVolumeLevel")] - public JoinDataComplete SourceVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("SourceVolumeLevelScaled")] - public JoinDataComplete SourceVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("SourceVolumeMuteOn")] - public JoinDataComplete SourceVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SourceVolumeMuteOff")] - public JoinDataComplete SourceVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SourceVolumeUp")] - public JoinDataComplete SourceVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SourceVolumeDown")] - public JoinDataComplete SourceVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SourceVolumeLevelScaledSend")] - public JoinDataComplete SourceVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "Source Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec1VolumeLevel")] - public JoinDataComplete Codec1VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Codec1VolumeLevelScaled")] - public JoinDataComplete Codec1VolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Codec1VolumeMuteOn")] - public JoinDataComplete Codec1VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec1VolumeMuteOff")] - public JoinDataComplete Codec1VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec1VolumeUp")] - public JoinDataComplete Codec1VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec1VolumeDown")] - public JoinDataComplete Codec1VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec1VolumeLevelScaledSend")] - public JoinDataComplete Codec1VolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec1 Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec2VolumeLevel")] - public JoinDataComplete Codec2VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Codec2VolumeLevelScaled")] - public JoinDataComplete Codec2VolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Codec2VolumeMuteOn")] - public JoinDataComplete Codec2VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec2VolumeMuteOff")] - public JoinDataComplete Codec2VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec2VolumeUp")] - public JoinDataComplete Codec2VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec2VolumeDown")] - public JoinDataComplete Codec2VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Codec2VolumeLevelScaledSend")] - public JoinDataComplete Codec2VolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, - new JoinMetadata { Description = "Codec2 Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicsMasterVolumeLevel")] - public JoinDataComplete MicsMasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, - new JoinMetadata { Description = "MicsMaster Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MicsMasterVolumeLevelScaled")] - public JoinDataComplete MicsMasterVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "MicsMaster Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MicsMasterVolumeMuteOn")] - public JoinDataComplete MicsMasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, - new JoinMetadata { Description = "MicsMaster Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicsMasterVolumeMuteOff")] - public JoinDataComplete MicsMasterVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "MicsMaster Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicsMasterVolumeUp")] - public JoinDataComplete MicsMasterVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, - new JoinMetadata { Description = "MicsMaster Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicsMasterVolumeDown")] - public JoinDataComplete MicsMasterVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, - new JoinMetadata { Description = "MicsMaster Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicsMasterVolumeLevelScaledSend")] - public JoinDataComplete MicsMasterVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, - new JoinMetadata { Description = "Mics Master Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmpsAudioOutputControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmpsAudioOutputControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs index 6922c569..90efc964 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs @@ -1,50 +1,49 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced { - public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced + [JoinName("MicGain")] + public JoinDataComplete MicGain = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Mic Gain dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MicGainScaled")] + public JoinDataComplete MicGainScaled = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Mic Gain 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("MicMuteOn")] + public JoinDataComplete MicMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Mic Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicMuteOff")] + public JoinDataComplete MicMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Mic Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicGainScaledSend")] + public JoinDataComplete MicGainScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Mic Gain Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("MicName")] + public JoinDataComplete MicName = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Mic Name Get", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmpsMicrophoneControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmpsMicrophoneControllerJoinMap)) { - [JoinName("MicGain")] - public JoinDataComplete MicGain = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Mic Gain dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + } - [JoinName("MicGainScaled")] - public JoinDataComplete MicGainScaled = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Mic Gain 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("MicMuteOn")] - public JoinDataComplete MicMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Mic Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicMuteOff")] - public JoinDataComplete MicMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Mic Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicGainScaledSend")] - public JoinDataComplete MicGainScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Mic Gain Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("MicName")] - public JoinDataComplete MicName = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Mic Name Get", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmpsMicrophoneControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmpsMicrophoneControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmpsMicrophoneControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmpsMicrophoneControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs index a0d8d7b8..e39e38c6 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs @@ -1,123 +1,122 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced { - public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced + [JoinName("EnableRouting")] + public JoinDataComplete EnableRouting = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS Enable Audio and Video Routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SystemPowerOn")] + public JoinDataComplete SystemPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS System Power On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SystemPowerOff")] + public JoinDataComplete SystemPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS System Power Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FrontPanelLockOn")] + public JoinDataComplete FrontPanelLockOn = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS Front Panel Lock On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FrontPanelLockOff")] + public JoinDataComplete FrontPanelLockOff = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "DMPS Front Panel Lock Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoSyncStatus")] + public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputEndpointOnline")] + public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutputEndpointOnline")] + public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutputVideo")] + public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Video Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("OutputAudio")] + public JoinDataComplete OutputAudio = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Audio Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("InputNames")] + public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("OutputNames")] + public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputVideoNames")] + public JoinDataComplete InputVideoNames = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, + new JoinMetadata + { + Description = "Video Input Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("InputAudioNames")] + public JoinDataComplete InputAudioNames = + new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, + new JoinMetadata + { + Description = "Audio Input Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("OutputVideoNames")] + public JoinDataComplete OutputVideoNames = + new JoinDataComplete(new JoinData { JoinNumber = 901, JoinSpan = 32 }, + new JoinMetadata + { + Description = "Video Output Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + [JoinName("OutputAudioNames")] + public JoinDataComplete OutputAudioNames = + new JoinDataComplete(new JoinData { JoinNumber = 1101, JoinSpan = 32 }, + new JoinMetadata + { + Description = "Audio Output Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("OutputCurrentVideoInputNames")] + public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("OutputCurrentAudioInputNames")] + public JoinDataComplete OutputCurrentAudioInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2201, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Audio Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputCurrentResolution")] + public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public DmpsRoutingControllerJoinMap(uint joinStart) + : this(joinStart, typeof(DmpsRoutingControllerJoinMap)) { - [JoinName("EnableRouting")] - public JoinDataComplete EnableRouting = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "DMPS Enable Audio and Video Routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("SystemPowerOn")] - public JoinDataComplete SystemPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "DMPS System Power On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SystemPowerOff")] - public JoinDataComplete SystemPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "DMPS System Power Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("FrontPanelLockOn")] - public JoinDataComplete FrontPanelLockOn = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "DMPS Front Panel Lock On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("FrontPanelLockOff")] - public JoinDataComplete FrontPanelLockOff = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "DMPS Front Panel Lock Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VideoSyncStatus")] - public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputEndpointOnline")] - public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutputEndpointOnline")] - public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutputVideo")] - public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Video Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("OutputAudio")] - public JoinDataComplete OutputAudio = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Audio Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("InputNames")] - public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("OutputNames")] - public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputVideoNames")] - public JoinDataComplete InputVideoNames = - new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, - new JoinMetadata - { - Description = "Video Input Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("InputAudioNames")] - public JoinDataComplete InputAudioNames = - new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, - new JoinMetadata - { - Description = "Audio Input Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - [JoinName("OutputVideoNames")] - public JoinDataComplete OutputVideoNames = - new JoinDataComplete(new JoinData { JoinNumber = 901, JoinSpan = 32 }, - new JoinMetadata - { - Description = "Video Output Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - [JoinName("OutputAudioNames")] - public JoinDataComplete OutputAudioNames = - new JoinDataComplete(new JoinData { JoinNumber = 1101, JoinSpan = 32 }, - new JoinMetadata - { - Description = "Audio Output Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("OutputCurrentVideoInputNames")] - public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("OutputCurrentAudioInputNames")] - public JoinDataComplete OutputCurrentAudioInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2201, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Audio Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputCurrentResolution")] - public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 32 }, - new JoinMetadata { Description = "DM Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public DmpsRoutingControllerJoinMap(uint joinStart) - : this(joinStart, typeof(DmpsRoutingControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs index 388e6ac1..50cb4b7d 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs @@ -1,7 +1,7 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges.JoinMaps -{ +namespace PepperDash.Essentials.Core.Bridges.JoinMaps; + public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced { [JoinName("PLAY")] @@ -823,5 +823,4 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps : base(joinStart, typeof(GenericIrControllerJoinMap)) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs index 2a3015f1..179b4124 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs @@ -1,49 +1,48 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class GenericLightingJoinMap : JoinMapBaseAdvanced { - public class GenericLightingJoinMap : JoinMapBaseAdvanced + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Lighting Controller Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SelectScene")] + public JoinDataComplete SelectScene = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Lighting Controller Select Scene By Index", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SelectSceneDirect")] + public JoinDataComplete SelectSceneDirect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, + new JoinMetadata { Description = "Lighting Controller Select Scene", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); + + [JoinName("ButtonVisibility")] + public JoinDataComplete ButtonVisibility = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 10 }, + new JoinMetadata { Description = "Lighting Controller Button Visibility", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IntegrationIdSet")] + public JoinDataComplete IntegrationIdSet = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Lighting Controller Set Integration Id", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public GenericLightingJoinMap(uint joinStart) + : this(joinStart, typeof(GenericLightingJoinMap)) { + } - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Lighting Controller Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SelectScene")] - public JoinDataComplete SelectScene = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Lighting Controller Select Scene By Index", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SelectSceneDirect")] - public JoinDataComplete SelectSceneDirect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, - new JoinMetadata { Description = "Lighting Controller Select Scene", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); - - [JoinName("ButtonVisibility")] - public JoinDataComplete ButtonVisibility = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 10 }, - new JoinMetadata { Description = "Lighting Controller Button Visibility", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IntegrationIdSet")] - public JoinDataComplete IntegrationIdSet = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Lighting Controller Set Integration Id", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); - - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public GenericLightingJoinMap(uint joinStart) - : this(joinStart, typeof(GenericLightingJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected GenericLightingJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected GenericLightingJoinMap(uint joinStart, Type type) : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs index 68897767..03aaf041 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs @@ -1,31 +1,30 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced { - public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced + + [JoinName("Relay")] + public JoinDataComplete Relay = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Relay State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public GenericRelayControllerJoinMap(uint joinStart) + : this(joinStart, typeof(GenericRelayControllerJoinMap)) { + } - [JoinName("Relay")] - public JoinDataComplete Relay = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Relay State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public GenericRelayControllerJoinMap(uint joinStart) - : this(joinStart, typeof(GenericRelayControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected GenericRelayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected GenericRelayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs index ded7343f..228cb4f0 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs @@ -1,184 +1,184 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class GlsOccupancySensorBaseJoinMap : JoinMapBaseAdvanced { - public class GlsOccupancySensorBaseJoinMap : JoinMapBaseAdvanced + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ForceOccupied")] + public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Set to Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ForceVacant")] + public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Set to Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableRawStates")] + public JoinDataComplete EnableRawStates = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Enable Raw", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RoomOccupiedFeedback")] + public JoinDataComplete RoomOccupiedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Room Is Occupied", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("GraceOccupancyDetectedFeedback")] + public JoinDataComplete GraceOccupancyDetectedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Grace Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RoomVacantFeedback")] + public JoinDataComplete RoomVacantFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Room Is Vacant", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RawOccupancyFeedback")] + public JoinDataComplete RawOccupancyFeedback = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Raw Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RawOccupancyPirFeedback")] + public JoinDataComplete RawOccupancyPirFeedback = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Raw PIR Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RawOccupancyUsFeedback")] + public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Raw US Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableLedFlash")] + public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Enable LED Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableLedFlash")] + public JoinDataComplete DisableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Disable LED Flash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableShortTimeout")] + public JoinDataComplete EnableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Enable Short Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableShortTimeout")] + public JoinDataComplete DisableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Disable Short Timeout", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OrWhenVacated")] + public JoinDataComplete OrWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Set To Vacant when Either Sensor is Vacant", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("AndWhenVacated")] + public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Set To Vacant when Both Sensors are Vacant", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableUsA")] + public JoinDataComplete EnableUsA = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Enable Ultrasonic Sensor A", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableUsA")] + public JoinDataComplete DisableUsA = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Disable Ultrasonic Sensor A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnableUsB")] + public JoinDataComplete EnableUsB = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Enable Ultrasonic Sensor B", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableUsB")] + public JoinDataComplete DisableUsB = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Disable Ultrasonic Sensor B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("EnablePir")] + public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Enable IR Sensor", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisablePir")] + public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Disable IR Sensor", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementUsInOccupiedState")] + public JoinDataComplete IncrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Increment US Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementUsInOccupiedState")] + public JoinDataComplete DecrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Decrement US Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementUsInVacantState")] + public JoinDataComplete IncrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Increment US Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementUsInVacantState")] + public JoinDataComplete DecrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Decrement US Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementPirInOccupiedState")] + public JoinDataComplete IncrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Increment IR Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementPirInOccupiedState")] + public JoinDataComplete DecrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Decrement IR Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IncrementPirInVacantState")] + public JoinDataComplete IncrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Increment IR Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DecrementPirInVacantState")] + public JoinDataComplete DecrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Decrement IR Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Timeout")] + public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Timeout Value", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("TimeoutLocalFeedback")] + public JoinDataComplete TimeoutLocalFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Local Timeout Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("InternalPhotoSensorValue")] + public JoinDataComplete InternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Internal PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("ExternalPhotoSensorValue")] + public JoinDataComplete ExternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor External PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("UsSensitivityInOccupiedState")] + public JoinDataComplete UsSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Ultrasonic Sensitivity in Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("UsSensitivityInVacantState")] + public JoinDataComplete UsSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Ultrasonic Sensitivity in Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("PirSensitivityInOccupiedState")] + public JoinDataComplete PirSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor PIR Sensitivity in Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("PirSensitivityInVacantState")] + public JoinDataComplete PirSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor PIR Sensitivity in Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Occ Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public GlsOccupancySensorBaseJoinMap(uint joinStart) + : this(joinStart, typeof(GlsOccupancySensorBaseJoinMap)) { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ForceOccupied")] - public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Set to Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ForceVacant")] - public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Set to Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableRawStates")] - public JoinDataComplete EnableRawStates = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Enable Raw", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RoomOccupiedFeedback")] - public JoinDataComplete RoomOccupiedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Room Is Occupied", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("GraceOccupancyDetectedFeedback")] - public JoinDataComplete GraceOccupancyDetectedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Grace Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RoomVacantFeedback")] - public JoinDataComplete RoomVacantFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Room Is Vacant", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RawOccupancyFeedback")] - public JoinDataComplete RawOccupancyFeedback = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Raw Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RawOccupancyPirFeedback")] - public JoinDataComplete RawOccupancyPirFeedback = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Raw PIR Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RawOccupancyUsFeedback")] - public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Raw US Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableLedFlash")] - public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Enable LED Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableLedFlash")] - public JoinDataComplete DisableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Disable LED Flash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableShortTimeout")] - public JoinDataComplete EnableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Enable Short Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableShortTimeout")] - public JoinDataComplete DisableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Disable Short Timeout", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OrWhenVacated")] - public JoinDataComplete OrWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Set To Vacant when Either Sensor is Vacant", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("AndWhenVacated")] - public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Set To Vacant when Both Sensors are Vacant", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableUsA")] - public JoinDataComplete EnableUsA = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Enable Ultrasonic Sensor A", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableUsA")] - public JoinDataComplete DisableUsA = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Disable Ultrasonic Sensor A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnableUsB")] - public JoinDataComplete EnableUsB = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Enable Ultrasonic Sensor B", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableUsB")] - public JoinDataComplete DisableUsB = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Disable Ultrasonic Sensor B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("EnablePir")] - public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Enable IR Sensor", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisablePir")] - public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Disable IR Sensor", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementUsInOccupiedState")] - public JoinDataComplete IncrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Increment US Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementUsInOccupiedState")] - public JoinDataComplete DecrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Decrement US Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementUsInVacantState")] - public JoinDataComplete IncrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Increment US Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementUsInVacantState")] - public JoinDataComplete DecrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Decrement US Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementPirInOccupiedState")] - public JoinDataComplete IncrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Increment IR Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementPirInOccupiedState")] - public JoinDataComplete DecrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Decrement IR Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IncrementPirInVacantState")] - public JoinDataComplete IncrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Increment IR Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DecrementPirInVacantState")] - public JoinDataComplete DecrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Decrement IR Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Timeout")] - public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Timeout Value", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("TimeoutLocalFeedback")] - public JoinDataComplete TimeoutLocalFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Local Timeout Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("InternalPhotoSensorValue")] - public JoinDataComplete InternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Internal PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("ExternalPhotoSensorValue")] - public JoinDataComplete ExternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor External PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("UsSensitivityInOccupiedState")] - public JoinDataComplete UsSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Ultrasonic Sensitivity in Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("UsSensitivityInVacantState")] - public JoinDataComplete UsSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Ultrasonic Sensitivity in Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("PirSensitivityInOccupiedState")] - public JoinDataComplete PirSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor PIR Sensitivity in Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("PirSensitivityInVacantState")] - public JoinDataComplete PirSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor PIR Sensitivity in Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Occ Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public GlsOccupancySensorBaseJoinMap(uint joinStart) - : this(joinStart, typeof(GlsOccupancySensorBaseJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected GlsOccupancySensorBaseJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } - } -} + + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected GlsOccupancySensorBaseJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { + } + +} + diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs index cb0f07b2..7515c8c2 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs @@ -1,157 +1,156 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges.JoinMaps +namespace PepperDash.Essentials.Core.Bridges.JoinMaps; + +public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced { - public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced + + #region Digital + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete( + new JoinData + { + JoinNumber = 1, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Is Online", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("Enable")] + public JoinDataComplete Enable = new JoinDataComplete( + new JoinData + { + JoinNumber = 2, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Enable", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PartitionSensed")] + public JoinDataComplete PartitionSensed = new JoinDataComplete( + new JoinData + { + JoinNumber = 3, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Partition Sensed", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PartitionNotSensed")] + public JoinDataComplete PartitionNotSensed = new JoinDataComplete( + new JoinData + { + JoinNumber = 4, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Partition Not Sensed", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncreaseSensitivity")] + public JoinDataComplete IncreaseSensitivity = new JoinDataComplete( + new JoinData + { + JoinNumber = 6, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Increase Sensitivity", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DecreaseSensitivity")] + public JoinDataComplete DecreaseSensitivity = new JoinDataComplete( + new JoinData + { + JoinNumber = 7, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Decrease Sensitivity", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + #endregion + + #region Analog + + [JoinName("Sensitivity")] + public JoinDataComplete Sensitivity = new JoinDataComplete( + new JoinData + { + JoinNumber = 2, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Sensitivity", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + #endregion + + + #region Serial + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete( + new JoinData + { + JoinNumber = 1, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sensor Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + #endregion + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public GlsPartitionSensorJoinMap(uint joinStart) + : this(joinStart, typeof(GlsPartitionSensorJoinMap)) { - #region Digital + } - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete( - new JoinData - { - JoinNumber = 1, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Is Online", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected GlsPartitionSensorJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { - - [JoinName("Enable")] - public JoinDataComplete Enable = new JoinDataComplete( - new JoinData - { - JoinNumber = 2, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Enable", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("PartitionSensed")] - public JoinDataComplete PartitionSensed = new JoinDataComplete( - new JoinData - { - JoinNumber = 3, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Partition Sensed", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("PartitionNotSensed")] - public JoinDataComplete PartitionNotSensed = new JoinDataComplete( - new JoinData - { - JoinNumber = 4, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Partition Not Sensed", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("IncreaseSensitivity")] - public JoinDataComplete IncreaseSensitivity = new JoinDataComplete( - new JoinData - { - JoinNumber = 6, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Increase Sensitivity", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DecreaseSensitivity")] - public JoinDataComplete DecreaseSensitivity = new JoinDataComplete( - new JoinData - { - JoinNumber = 7, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Decrease Sensitivity", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - #endregion - - #region Analog - - [JoinName("Sensitivity")] - public JoinDataComplete Sensitivity = new JoinDataComplete( - new JoinData - { - JoinNumber = 2, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Sensitivity", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Analog - }); - - #endregion - - - #region Serial - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete( - new JoinData - { - JoinNumber = 1, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - #endregion - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public GlsPartitionSensorJoinMap(uint joinStart) - : this(joinStart, typeof(GlsPartitionSensorJoinMap)) - { - - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected GlsPartitionSensorJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - - } } } diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs index e69946ea..43ed25c9 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs @@ -1,66 +1,65 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class HdMdNxM4kEControllerJoinMap : JoinMapBaseAdvanced { - public class HdMdNxM4kEControllerJoinMap : JoinMapBaseAdvanced + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("EnableAutoRoute")] + public JoinDataComplete EnableAutoRoute = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Enable Automatic Routing on 4x1 Switchers", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputName")] + public JoinDataComplete InputName = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, + new JoinMetadata { Description = "Device Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("InputSync")] + public JoinDataComplete InputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, + new JoinMetadata { Description = "Device Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutputName")] + public JoinDataComplete OutputName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 2 }, + new JoinMetadata { Description = "Device Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("OutputRoute")] + public JoinDataComplete OutputRoute = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 2 }, + new JoinMetadata { Description = "Device Output Route Set/Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("OutputRoutedName")] + public JoinDataComplete OutputRoutedName = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 2 }, + new JoinMetadata { Description = "Device Output Route Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("EnableInputHdcp")] + public JoinDataComplete EnableInputHdcp = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 8 }, + new JoinMetadata { Description = "Device Enable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DisableInputHdcp")] + public JoinDataComplete DisableInputHdcp = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 8 }, + new JoinMetadata { Description = "Device Disnable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Onlne", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public HdMdNxM4kEControllerJoinMap(uint joinStart) + : this(joinStart, typeof(HdMdNxM4kEControllerJoinMap)) { - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + } - [JoinName("EnableAutoRoute")] - public JoinDataComplete EnableAutoRoute = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Enable Automatic Routing on 4x1 Switchers", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputName")] - public JoinDataComplete InputName = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, - new JoinMetadata { Description = "Device Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("InputSync")] - public JoinDataComplete InputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, - new JoinMetadata { Description = "Device Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutputName")] - public JoinDataComplete OutputName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 2 }, - new JoinMetadata { Description = "Device Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("OutputRoute")] - public JoinDataComplete OutputRoute = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 2 }, - new JoinMetadata { Description = "Device Output Route Set/Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("OutputRoutedName")] - public JoinDataComplete OutputRoutedName = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 2 }, - new JoinMetadata { Description = "Device Output Route Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("EnableInputHdcp")] - public JoinDataComplete EnableInputHdcp = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 8 }, - new JoinMetadata { Description = "Device Enable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DisableInputHdcp")] - public JoinDataComplete DisableInputHdcp = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 8 }, - new JoinMetadata { Description = "Device Disnable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Onlne", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public HdMdNxM4kEControllerJoinMap(uint joinStart) - : this(joinStart, typeof(HdMdNxM4kEControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected HdMdNxM4kEControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected HdMdNxM4kEControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs index 0936f75d..32bc5651 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs @@ -1,76 +1,75 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class HdMdxxxCEControllerJoinMap : JoinMapBaseAdvanced { - public class HdMdxxxCEControllerJoinMap : JoinMapBaseAdvanced + + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RemoteEndDetected")] + public JoinDataComplete RemoteEndDetected = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Remote End Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("AutoRouteOn")] + public JoinDataComplete AutoRouteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Auto Route On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("AutoRouteOff")] + public JoinDataComplete AutoRouteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Auto Route Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PriorityRoutingOn")] + public JoinDataComplete PriorityRoutingOn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Priority Routing On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PriorityRoutingOff")] + public JoinDataComplete PriorityRoutingOff = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Priority Routing Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputOnScreenDisplayEnabled")] + public JoinDataComplete InputOnScreenDisplayEnabled = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Input OSD Enabled", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("InputOnScreenDisplayDisabled")] + public JoinDataComplete InputOnScreenDisplayDisabled = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Device Input OSD Disabled", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SyncDetected")] + public JoinDataComplete SyncDetected = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 5 }, + new JoinMetadata { Description = "Device Sync Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VideoSource")] + public JoinDataComplete VideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 5 }, + new JoinMetadata { Description = "Device Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("SourceCount")] + public JoinDataComplete SourceCount = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 5 }, + new JoinMetadata { Description = "Device Video Source Count", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("SourceNames")] + public JoinDataComplete SourceNames = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 5 }, + new JoinMetadata { Description = "Device Video Source Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public HdMdxxxCEControllerJoinMap(uint joinStart) + : this(joinStart, typeof(HdMdxxxCEControllerJoinMap)) { + } - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RemoteEndDetected")] - public JoinDataComplete RemoteEndDetected = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Remote End Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("AutoRouteOn")] - public JoinDataComplete AutoRouteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Auto Route On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("AutoRouteOff")] - public JoinDataComplete AutoRouteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Auto Route Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PriorityRoutingOn")] - public JoinDataComplete PriorityRoutingOn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Priority Routing On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PriorityRoutingOff")] - public JoinDataComplete PriorityRoutingOff = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Priority Routing Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputOnScreenDisplayEnabled")] - public JoinDataComplete InputOnScreenDisplayEnabled = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Input OSD Enabled", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("InputOnScreenDisplayDisabled")] - public JoinDataComplete InputOnScreenDisplayDisabled = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Device Input OSD Disabled", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("SyncDetected")] - public JoinDataComplete SyncDetected = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 5 }, - new JoinMetadata { Description = "Device Sync Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VideoSource")] - public JoinDataComplete VideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 5 }, - new JoinMetadata { Description = "Device Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("SourceCount")] - public JoinDataComplete SourceCount = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 5 }, - new JoinMetadata { Description = "Device Video Source Count", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("SourceNames")] - public JoinDataComplete SourceNames = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 5 }, - new JoinMetadata { Description = "Device Video Source Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public HdMdxxxCEControllerJoinMap(uint joinStart) - : this(joinStart, typeof(HdMdxxxCEControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected HdMdxxxCEControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected HdMdxxxCEControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs index 04d75d41..56420b24 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs @@ -1,8 +1,8 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges -{ +namespace PepperDash.Essentials.Core.Bridges; + public class HdPsXxxControllerJoinMap : JoinMapBaseAdvanced { @@ -186,5 +186,4 @@ namespace PepperDash.Essentials.Core.Bridges : base(joinStart, type) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs index 23305b20..ca9ef3c6 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs @@ -1,246 +1,245 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class Hrxxx0WirelessRemoteControllerJoinMap : JoinMapBaseAdvanced { - public class Hrxxx0WirelessRemoteControllerJoinMap : JoinMapBaseAdvanced + [JoinName("Power")] + public JoinDataComplete Power = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Power", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Guide")] + public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Info")] + public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeUp")] + public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "VolumeUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("VolumeDown")] + public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "VolumeDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadUp")] + public JoinDataComplete DialPadUp = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadDown")] + public JoinDataComplete DialPadDown = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadLeft")] + public JoinDataComplete DialPadLeft = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadLeft", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadRight")] + public JoinDataComplete DialPadRight = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadRight", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DialPadSelect")] + public JoinDataComplete DialPadSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "DialPadSelect", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelUp")] + public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "ChannelUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelDown")] + public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "ChannelDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Mute")] + public JoinDataComplete Mute = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Mute", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Exit")] + public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Last")] + public JoinDataComplete Last = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "Last", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Play")] + public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Pause")] + public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Rewind")] + public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FastForward")] + public JoinDataComplete FastForward = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "FastForward", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PreviousTrack")] + public JoinDataComplete PreviousTrack = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "PreviousTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("NextTrack")] + public JoinDataComplete NextTrack = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "NextTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Stop")] + public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Record")] + public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Dvr")] + public JoinDataComplete Dvr = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Dvr", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad1")] + public JoinDataComplete Keypad1 = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad2Abc")] + public JoinDataComplete Keypad2 = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad2Abc", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad3Def")] + public JoinDataComplete Keypad3Def = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad3Def", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad4Ghi")] + public JoinDataComplete Keypad4Ghi = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad4Ghi", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad5Jkl")] + public JoinDataComplete Keypad5Jkl = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad5Jkl", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad6Mno")] + public JoinDataComplete Keypad6Mno = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad6Mno", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad7Pqrs")] + public JoinDataComplete Keypad7Pqrs = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad7Pqrs", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad8Tuv")] + public JoinDataComplete Keypad8Tuv = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad8Tuv", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad9Wxyz")] + public JoinDataComplete Keypad9Wxyz = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad9Wxyz", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Keypad0")] + public JoinDataComplete Keypad0 = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Clear")] + public JoinDataComplete Clear = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, + new JoinMetadata { Description = "Clear", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Enter")] + public JoinDataComplete Enter = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, + new JoinMetadata { Description = "Enter", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Red")] + public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, + new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Green")] + public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, + new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Yellow")] + public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, + new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Blue")] + public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom1")] + public JoinDataComplete Custom1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom2")] + public JoinDataComplete Custom2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom3")] + public JoinDataComplete Custom3 = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom4")] + public JoinDataComplete Custom4 = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom5")] + public JoinDataComplete Custom5 = new JoinDataComplete(new JoinData { JoinNumber = 46, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom6")] + public JoinDataComplete Custom6 = new JoinDataComplete(new JoinData { JoinNumber = 47, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom7")] + public JoinDataComplete Custom7 = new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom8")] + public JoinDataComplete Custom8 = new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Custom9")] + public JoinDataComplete Custom9 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata { Description = "Custom9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Fav")] + public JoinDataComplete Fav = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata { Description = "Fav", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Home")] + public JoinDataComplete Home = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata { Description = "Home", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BatteryLow")] + public JoinDataComplete BatteryLow = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, + new JoinMetadata { Description = "BatteryLow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BatteryCritical")] + public JoinDataComplete BatteryCritical = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1 }, + new JoinMetadata { Description = "BatteryCritical", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BatteryVoltage")] + public JoinDataComplete BatteryVoltage = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "BatteryVoltage", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart) + : this(joinStart, typeof(Hrxxx0WirelessRemoteControllerJoinMap)) { - [JoinName("Power")] - public JoinDataComplete Power = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Power", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("Menu")] - public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Guide")] - public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Info")] - public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeUp")] - public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "VolumeUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("VolumeDown")] - public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "VolumeDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DialPadUp")] - public JoinDataComplete DialPadUp = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "DialPadUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DialPadDown")] - public JoinDataComplete DialPadDown = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "DialPadDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DialPadLeft")] - public JoinDataComplete DialPadLeft = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata { Description = "DialPadLeft", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DialPadRight")] - public JoinDataComplete DialPadRight = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, - new JoinMetadata { Description = "DialPadRight", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DialPadSelect")] - public JoinDataComplete DialPadSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "DialPadSelect", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChannelUp")] - public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "ChannelUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChannelDown")] - public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "ChannelDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Mute")] - public JoinDataComplete Mute = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Mute", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Exit")] - public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Last")] - public JoinDataComplete Last = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, - new JoinMetadata { Description = "Last", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Play")] - public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, - new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Pause")] - public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, - new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Rewind")] - public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, - new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("FastForward")] - public JoinDataComplete FastForward = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, - new JoinMetadata { Description = "FastForward", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PreviousTrack")] - public JoinDataComplete PreviousTrack = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "PreviousTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("NextTrack")] - public JoinDataComplete NextTrack = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "NextTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Stop")] - public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, - new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Record")] - public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Dvr")] - public JoinDataComplete Dvr = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, - new JoinMetadata { Description = "Dvr", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad1")] - public JoinDataComplete Keypad1 = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad2Abc")] - public JoinDataComplete Keypad2 = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad2Abc", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad3Def")] - public JoinDataComplete Keypad3Def = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad3Def", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad4Ghi")] - public JoinDataComplete Keypad4Ghi = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad4Ghi", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad5Jkl")] - public JoinDataComplete Keypad5Jkl = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad5Jkl", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad6Mno")] - public JoinDataComplete Keypad6Mno = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad6Mno", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad7Pqrs")] - public JoinDataComplete Keypad7Pqrs = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad7Pqrs", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad8Tuv")] - public JoinDataComplete Keypad8Tuv = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad8Tuv", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad9Wxyz")] - public JoinDataComplete Keypad9Wxyz = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad9Wxyz", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Keypad0")] - public JoinDataComplete Keypad0 = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Clear")] - public JoinDataComplete Clear = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, - new JoinMetadata { Description = "Clear", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Enter")] - public JoinDataComplete Enter = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, - new JoinMetadata { Description = "Enter", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Red")] - public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, - new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Green")] - public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, - new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Yellow")] - public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, - new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Blue")] - public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, - new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom1")] - public JoinDataComplete Custom1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom2")] - public JoinDataComplete Custom2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom3")] - public JoinDataComplete Custom3 = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom4")] - public JoinDataComplete Custom4 = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom5")] - public JoinDataComplete Custom5 = new JoinDataComplete(new JoinData { JoinNumber = 46, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom6")] - public JoinDataComplete Custom6 = new JoinDataComplete(new JoinData { JoinNumber = 47, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom7")] - public JoinDataComplete Custom7 = new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom8")] - public JoinDataComplete Custom8 = new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Custom9")] - public JoinDataComplete Custom9 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, - new JoinMetadata { Description = "Custom9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Fav")] - public JoinDataComplete Fav = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, - new JoinMetadata { Description = "Fav", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Home")] - public JoinDataComplete Home = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, - new JoinMetadata { Description = "Home", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("BatteryLow")] - public JoinDataComplete BatteryLow = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, - new JoinMetadata { Description = "BatteryLow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("BatteryCritical")] - public JoinDataComplete BatteryCritical = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1 }, - new JoinMetadata { Description = "BatteryCritical", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("BatteryVoltage")] - public JoinDataComplete BatteryVoltage = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "BatteryVoltage", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart) - : this(joinStart, typeof(Hrxxx0WirelessRemoteControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs index eaf70f3a..80509ecc 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs @@ -1,34 +1,33 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IAnalogInputJoinMap : JoinMapBaseAdvanced { - public class IAnalogInputJoinMap : JoinMapBaseAdvanced + + [JoinName("InputValue")] + public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("MinimumChange")] + public JoinDataComplete MinimumChange = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Minimum voltage change required to reflect a change", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public IAnalogInputJoinMap(uint joinStart) + : this(joinStart, typeof(IAnalogInputJoinMap)) { + } - [JoinName("InputValue")] - public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - [JoinName("MinimumChange")] - public JoinDataComplete MinimumChange = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Minimum voltage change required to reflect a change", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public IAnalogInputJoinMap(uint joinStart) - : this(joinStart, typeof(IAnalogInputJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected IAnalogInputJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IAnalogInputJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs index 0d077284..1db5b1ff 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs @@ -1,50 +1,49 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced { - public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced + [JoinName("TextReceived")] + public JoinDataComplete TextReceived = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Text Received From Remote Device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("SendText")] + public JoinDataComplete SendText = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Text Sent To Remote Device", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("SetPortConfig")] + public JoinDataComplete SetPortConfig = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Set Port Config", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("Connect")] + public JoinDataComplete Connect = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Connected")] + public JoinDataComplete Connected = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Status")] + public JoinDataComplete Status = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public IBasicCommunicationJoinMap(uint joinStart) + : this(joinStart, typeof(IBasicCommunicationJoinMap)) { - [JoinName("TextReceived")] - public JoinDataComplete TextReceived = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Text Received From Remote Device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + } - [JoinName("SendText")] - public JoinDataComplete SendText = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Text Sent To Remote Device", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("SetPortConfig")] - public JoinDataComplete SetPortConfig = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Set Port Config", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("Connect")] - public JoinDataComplete Connect = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Connected")] - public JoinDataComplete Connected = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Status")] - public JoinDataComplete Status = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public IBasicCommunicationJoinMap(uint joinStart) - : this(joinStart, typeof(IBasicCommunicationJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected IBasicCommunicationJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IBasicCommunicationJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs index aa31ac76..ceed325d 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs @@ -1,31 +1,30 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IDigitalInputJoinMap : JoinMapBaseAdvanced { - public class IDigitalInputJoinMap : JoinMapBaseAdvanced + + [JoinName("InputState")] + public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public IDigitalInputJoinMap(uint joinStart) + : this(joinStart, typeof(IDigitalInputJoinMap)) { + } - [JoinName("InputState")] - public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public IDigitalInputJoinMap(uint joinStart) - : this(joinStart, typeof(IDigitalInputJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected IDigitalInputJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IDigitalInputJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs index cbe62398..8abb2b74 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs @@ -1,31 +1,30 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class IDigitalOutputJoinMap : JoinMapBaseAdvanced { - public class IDigitalOutputJoinMap : JoinMapBaseAdvanced + + [JoinName("OutputState")] + public JoinDataComplete OutputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Get / Set state of Digital Input", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public IDigitalOutputJoinMap(uint joinStart) + : this(joinStart, typeof(IDigitalOutputJoinMap)) { + } - [JoinName("OutputState")] - public JoinDataComplete OutputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Get / Set state of Digital Input", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public IDigitalOutputJoinMap(uint joinStart) - : this(joinStart, typeof(IDigitalOutputJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected IDigitalOutputJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IDigitalOutputJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs index 991489e9..d63a1f52 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs @@ -4,219 +4,218 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +/// +/// Join map for IRBlurayBase devices +/// +public class IRBlurayBaseJoinMap : JoinMapBaseAdvanced { - /// - /// Join map for IRBlurayBase devices + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerToggle")] + public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Up")] + public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Down")] + public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Left")] + public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Right")] + public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Select")] + public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Exit")] + public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit0")] + public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit1")] + public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit2")] + public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit3")] + public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit4")] + public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit5")] + public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit6")] + public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit7")] + public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit8")] + public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit9")] + public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadClear")] + public JoinDataComplete KeypadClear = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad Clear", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadEnter")] + public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelUp")] + public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Channel Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelDown")] + public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Channel Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("LastChannel")] + public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Guide")] + public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Info")] + public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Red")] + public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Green")] + public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Yellow")] + public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Blue")] + public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + + [JoinName("Play")] + public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Pause")] + public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Stop")] + public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FFwd")] + public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, + new JoinMetadata { Description = "FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Rewind")] + public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, + new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChapPlus")] + public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, + new JoinMetadata { Description = "Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChapMinus")] + public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, + new JoinMetadata { Description = "Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Replay")] + public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, + new JoinMetadata { Description = "Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Record")] + public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasKeypadAccessoryButton1")] + public JoinDataComplete HasKeypadAccessoryButton1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "Has Keypad Accessory Button 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasKeypadAccessoryButton2")] + public JoinDataComplete HasKeypadAccessoryButton2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "Has Keypad Accessory Button 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadAccessoryButton1Press")] + public JoinDataComplete KeypadAccessoryButton1Press = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 2 }, + new JoinMetadata { Description = "Keypad Accessory Button 1 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadAccessoryButton2Press")] + public JoinDataComplete KeypadAccessoryButton2Press = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 2 }, + new JoinMetadata { Description = "Keypad Accessory Button 2 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadAccessoryButton1Label")] + public JoinDataComplete KeypadAccessoryButton1Label = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("KeypadAccessoryButton2Label")] + public JoinDataComplete KeypadAccessoryButton2Label = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it /// - public class IRBlurayBaseJoinMap : JoinMapBaseAdvanced + /// Join this join map will start at + public IRBlurayBaseJoinMap(uint joinStart) + : this(joinStart, typeof(IRBlurayBaseJoinMap)) { - [JoinName("PowerOn")] - public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("PowerOff")] - public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PowerToggle")] - public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Up")] - public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Down")] - public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Left")] - public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Right")] - public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Select")] - public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Menu")] - public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Exit")] - public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, - new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit0")] - public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit1")] - public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit2")] - public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit3")] - public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit4")] - public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit5")] - public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit6")] - public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit7")] - public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit8")] - public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit9")] - public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, - new JoinMetadata { Description = "Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadClear")] - public JoinDataComplete KeypadClear = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad Clear", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadEnter")] - public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChannelUp")] - public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Channel Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChannelDown")] - public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Channel Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("LastChannel")] - public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, - new JoinMetadata { Description = "Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Guide")] - public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, - new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Info")] - public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, - new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Red")] - public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, - new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Green")] - public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, - new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Yellow")] - public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, - new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Blue")] - public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, - new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - - [JoinName("Play")] - public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, - new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Pause")] - public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, - new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Stop")] - public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, - new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("FFwd")] - public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, - new JoinMetadata { Description = "FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Rewind")] - public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, - new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChapPlus")] - public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, - new JoinMetadata { Description = "Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChapMinus")] - public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, - new JoinMetadata { Description = "Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Replay")] - public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, - new JoinMetadata { Description = "Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Record")] - public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, - new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasKeypadAccessoryButton1")] - public JoinDataComplete HasKeypadAccessoryButton1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "Has Keypad Accessory Button 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasKeypadAccessoryButton2")] - public JoinDataComplete HasKeypadAccessoryButton2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, - new JoinMetadata { Description = "Has Keypad Accessory Button 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadAccessoryButton1Press")] - public JoinDataComplete KeypadAccessoryButton1Press = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 2 }, - new JoinMetadata { Description = "Keypad Accessory Button 1 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadAccessoryButton2Press")] - public JoinDataComplete KeypadAccessoryButton2Press = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 2 }, - new JoinMetadata { Description = "Keypad Accessory Button 2 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadAccessoryButton1Label")] - public JoinDataComplete KeypadAccessoryButton1Label = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("KeypadAccessoryButton2Label")] - public JoinDataComplete KeypadAccessoryButton2Label = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, - new JoinMetadata { Description = "Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public IRBlurayBaseJoinMap(uint joinStart) - : this(joinStart, typeof(IRBlurayBaseJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected IRBlurayBaseJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected IRBlurayBaseJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs index 0c2e9ed9..10bf590d 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs @@ -1,60 +1,59 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class PduJoinMapBase : JoinMapBaseAdvanced { - public class PduJoinMapBase : JoinMapBaseAdvanced - { - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("Online")] - public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("Online")] + public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("OutletCount")] - public JoinDataComplete OutletCount = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Number of COntrolled Outlets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("OutletCount")] + public JoinDataComplete OutletCount = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Number of COntrolled Outlets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - [JoinName("OutletName")] - public JoinDataComplete OutletName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Outlet Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("OutletName")] + public JoinDataComplete OutletName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("OutletEnabled")] - public JoinDataComplete OutletEnabled = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Outlet Enabled", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("OutletEnabled")] + public JoinDataComplete OutletEnabled = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Enabled", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - [JoinName("OutletPowerCycle")] - public JoinDataComplete OutletPowerCycle = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Outlet Power Cycle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("OutletPowerCycle")] + public JoinDataComplete OutletPowerCycle = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Power Cycle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("OutletPowerOn")] - public JoinDataComplete OutletPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Outlet Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("OutletPowerOff")] - public JoinDataComplete OutletPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Outlet Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - + [JoinName("OutletPowerOn")] + public JoinDataComplete OutletPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("OutletPowerOff")] + public JoinDataComplete OutletPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Outlet Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public PduJoinMapBase(uint joinStart) - :base(joinStart, typeof(PduJoinMapBase)) - { - } + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public PduJoinMapBase(uint joinStart) + :base(joinStart, typeof(PduJoinMapBase)) + { + } - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - public PduJoinMapBase(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + public PduJoinMapBase(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs index ec0ff8d2..0705eb93 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs @@ -1,240 +1,239 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class SetTopBoxControllerJoinMap : JoinMapBaseAdvanced { - public class SetTopBoxControllerJoinMap : JoinMapBaseAdvanced + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PowerToggle")] + public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasDpad")] + public JoinDataComplete HasDpad = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Has DPad", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Up")] + public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Down")] + public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Left")] + public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Right")] + public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Select")] + public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Menu")] + public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Exit")] + public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasNumeric")] + public JoinDataComplete HasNumeric = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Has Numeric", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit0")] + public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit1")] + public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit2")] + public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit3")] + public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit4")] + public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit5")] + public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit6")] + public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit7")] + public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit8")] + public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Digit9")] + public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Dash")] + public JoinDataComplete Dash = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Dash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadEnter")] + public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelUp")] + public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Channel Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChannelDown")] + public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Channel Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("LastChannel")] + public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Guide")] + public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Info")] + public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Red")] + public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Green")] + public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Yellow")] + public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Blue")] + public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasDvr")] + public JoinDataComplete HasDvr = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Has DVR", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DvrList")] + public JoinDataComplete DvrList = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, + new JoinMetadata { Description = "STB DvrList", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Play")] + public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Pause")] + public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Stop")] + public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("FFwd")] + public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, + new JoinMetadata { Description = "STB FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Rewind")] + public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChapPlus")] + public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ChapMinus")] + public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Replay")] + public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Record")] + public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasKeypadAccessoryButton1")] + public JoinDataComplete HasKeypadAccessoryButton1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Has Keypad Accessory Button 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasKeypadAccessoryButton2")] + public JoinDataComplete HasKeypadAccessoryButton2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Has Keypad Accessory Button 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadAccessoryButton1Press")] + public JoinDataComplete KeypadAccessoryButton1Press = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 2 }, + new JoinMetadata { Description = "STB Keypad Accessory Button 1 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadAccessoryButton2Press")] + public JoinDataComplete KeypadAccessoryButton2Press = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 2 }, + new JoinMetadata { Description = "STB Keypad Accessory Button 2 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("KeypadAccessoryButton1Label")] + public JoinDataComplete KeypadAccessoryButton1Label = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("KeypadAccessoryButton2Label")] + public JoinDataComplete KeypadAccessoryButton2Label = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("LoadPresets")] + public JoinDataComplete LoadPresets = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Load Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("HasPresets")] + public JoinDataComplete HasPresets = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata { Description = "STB Load Presets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public SetTopBoxControllerJoinMap(uint joinStart) + : this(joinStart, typeof(SetTopBoxControllerJoinMap)) { - [JoinName("PowerOn")] - public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + } - [JoinName("PowerOff")] - public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("PowerToggle")] - public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasDpad")] - public JoinDataComplete HasDpad = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Has DPad", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Up")] - public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Down")] - public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Left")] - public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Right")] - public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Select")] - public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Menu")] - public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Exit")] - public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasNumeric")] - public JoinDataComplete HasNumeric = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Has Numeric", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit0")] - public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit1")] - public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit2")] - public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit3")] - public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit4")] - public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit5")] - public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit6")] - public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit7")] - public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit8")] - public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Digit9")] - public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Dash")] - public JoinDataComplete Dash = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Dash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadEnter")] - public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChannelUp")] - public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Channel Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChannelDown")] - public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Channel Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("LastChannel")] - public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Guide")] - public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Info")] - public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Red")] - public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Green")] - public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Yellow")] - public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Blue")] - public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasDvr")] - public JoinDataComplete HasDvr = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Has DVR", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("DvrList")] - public JoinDataComplete DvrList = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, - new JoinMetadata { Description = "STB DvrList", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Play")] - public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Pause")] - public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Stop")] - public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("FFwd")] - public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, - new JoinMetadata { Description = "STB FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Rewind")] - public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChapPlus")] - public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("ChapMinus")] - public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Replay")] - public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Record")] - public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasKeypadAccessoryButton1")] - public JoinDataComplete HasKeypadAccessoryButton1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Has Keypad Accessory Button 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasKeypadAccessoryButton2")] - public JoinDataComplete HasKeypadAccessoryButton2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Has Keypad Accessory Button 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadAccessoryButton1Press")] - public JoinDataComplete KeypadAccessoryButton1Press = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 2 }, - new JoinMetadata { Description = "STB Keypad Accessory Button 1 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadAccessoryButton2Press")] - public JoinDataComplete KeypadAccessoryButton2Press = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 2 }, - new JoinMetadata { Description = "STB Keypad Accessory Button 2 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("KeypadAccessoryButton1Label")] - public JoinDataComplete KeypadAccessoryButton1Label = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("KeypadAccessoryButton2Label")] - public JoinDataComplete KeypadAccessoryButton2Label = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("LoadPresets")] - public JoinDataComplete LoadPresets = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Load Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("HasPresets")] - public JoinDataComplete HasPresets = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, - new JoinMetadata { Description = "STB Load Presets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public SetTopBoxControllerJoinMap(uint joinStart) - : this(joinStart, typeof(SetTopBoxControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected SetTopBoxControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected SetTopBoxControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs index ba441ef0..98cd9218 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs @@ -1,59 +1,58 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class StatusSignControllerJoinMap : JoinMapBaseAdvanced { - public class StatusSignControllerJoinMap : JoinMapBaseAdvanced + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Sign Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("Name")] + public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Sign Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("RedControl")] + public JoinDataComplete RedControl = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Red LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RedLed")] + public JoinDataComplete RedLed = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Red LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("GreenControl")] + public JoinDataComplete GreenControl = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Green LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("GreenLed")] + public JoinDataComplete GreenLed = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Green LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("BlueControl")] + public JoinDataComplete BlueControl = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Blue LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("BlueLed")] + public JoinDataComplete BlueLed = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Status Blue LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public StatusSignControllerJoinMap(uint joinStart) + : this(joinStart, typeof(StatusSignControllerJoinMap)) { - [JoinName("IsOnline")] - public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Sign Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Sign Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - - [JoinName("RedControl")] - public JoinDataComplete RedControl = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Red LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("RedLed")] - public JoinDataComplete RedLed = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Red LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("GreenControl")] - public JoinDataComplete GreenControl = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Green LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("GreenLed")] - public JoinDataComplete GreenLed = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Green LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - [JoinName("BlueControl")] - public JoinDataComplete BlueControl = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Blue LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - - [JoinName("BlueLed")] - public JoinDataComplete BlueLed = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Status Blue LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public StatusSignControllerJoinMap(uint joinStart) - : this(joinStart, typeof(StatusSignControllerJoinMap)) - { - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected StatusSignControllerJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } - } + + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected StatusSignControllerJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs index 9adabfce..6cd482af 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs @@ -1,136 +1,136 @@ using System; -namespace PepperDash.Essentials.Core.Bridges +namespace PepperDash.Essentials.Core.Bridges; + +public class SystemMonitorJoinMap : JoinMapBaseAdvanced { - public class SystemMonitorJoinMap : JoinMapBaseAdvanced - { - [JoinName("TimeZone")] - public JoinDataComplete TimeZone = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Timezone", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); + [JoinName("TimeZone")] + public JoinDataComplete TimeZone = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Timezone", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); - [JoinName("TimeZoneName")] - public JoinDataComplete TimeZoneName = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Timezone Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("TimeZoneName")] + public JoinDataComplete TimeZoneName = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Timezone Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("IOControllerVersion")] - public JoinDataComplete IOControllerVersion = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor IO Controller Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("IOControllerVersion")] + public JoinDataComplete IOControllerVersion = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor IO Controller Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("SnmpAppVersion")] - public JoinDataComplete SnmpAppVersion = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor SNMP App Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("SnmpAppVersion")] + public JoinDataComplete SnmpAppVersion = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor SNMP App Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("BACnetAppVersion")] - public JoinDataComplete BACnetAppVersion = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor BACNet App Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("BACnetAppVersion")] + public JoinDataComplete BACnetAppVersion = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor BACNet App Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("ControllerVersion")] - public JoinDataComplete ControllerVersion = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Controller Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ControllerVersion")] + public JoinDataComplete ControllerVersion = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Controller Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("SerialNumber")] - public JoinDataComplete SerialNumber = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("SerialNumber")] + public JoinDataComplete SerialNumber = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("Model")] - public JoinDataComplete Model = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Model", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("Model")] + public JoinDataComplete Model = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Model", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("Uptime")] - public JoinDataComplete Uptime = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Uptime", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("Uptime")] + public JoinDataComplete Uptime = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Uptime", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("LastBoot")] - public JoinDataComplete LastBoot = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Last Boot", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("LastBoot")] + public JoinDataComplete LastBoot = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Last Boot", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("ProgramOffsetJoin")] - public JoinDataComplete ProgramOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 5 }, - new JoinMetadata { Description = "All Program Data is offset between slots by 5 - First Joins Start at 11", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None }); + [JoinName("ProgramOffsetJoin")] + public JoinDataComplete ProgramOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 5 }, + new JoinMetadata { Description = "All Program Data is offset between slots by 5 - First Joins Start at 11", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None }); - [JoinName("ProgramStart")] - public JoinDataComplete ProgramStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Start / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ProgramStart")] + public JoinDataComplete ProgramStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Start / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("ProgramStop")] - public JoinDataComplete ProgramStop = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Stop / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ProgramStop")] + public JoinDataComplete ProgramStop = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Stop / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("ProgramRegister")] - public JoinDataComplete ProgramRegister = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Register / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ProgramRegister")] + public JoinDataComplete ProgramRegister = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Register / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("ProgramUnregister")] - public JoinDataComplete ProgramUnregister = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program UnRegister / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ProgramUnregister")] + public JoinDataComplete ProgramUnregister = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program UnRegister / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); - [JoinName("ProgramName")] - public JoinDataComplete ProgramName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ProgramName")] + public JoinDataComplete ProgramName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("ProgramCompiledTime")] - public JoinDataComplete ProgramCompiledTime = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Compile Time", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ProgramCompiledTime")] + public JoinDataComplete ProgramCompiledTime = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Compile Time", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("ProgramCrestronDatabaseVersion")] - public JoinDataComplete ProgramCrestronDatabaseVersion = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Database Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ProgramCrestronDatabaseVersion")] + public JoinDataComplete ProgramCrestronDatabaseVersion = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Database Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("ProgramEnvironmentVersion")] - public JoinDataComplete ProgramEnvironmentVersion = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Environment Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ProgramEnvironmentVersion")] + public JoinDataComplete ProgramEnvironmentVersion = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Environment Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("AggregatedProgramInfo")] - public JoinDataComplete AggregatedProgramInfo = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Program Aggregate Info Json", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("AggregatedProgramInfo")] + public JoinDataComplete AggregatedProgramInfo = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Program Aggregate Info Json", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("EthernetOffsetJoin")] - public JoinDataComplete EthernetOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, - new JoinMetadata { Description = "All Ethernet Data is offset between Nics by 5 - First Joins Start at 76", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None }); + [JoinName("EthernetOffsetJoin")] + public JoinDataComplete EthernetOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, + new JoinMetadata { Description = "All Ethernet Data is offset between Nics by 5 - First Joins Start at 76", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None }); - [JoinName("HostName")] - public JoinDataComplete HostName = new JoinDataComplete(new JoinData { JoinNumber = 76, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Hostname", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("HostName")] + public JoinDataComplete HostName = new JoinDataComplete(new JoinData { JoinNumber = 76, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Hostname", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("CurrentIpAddress")] - public JoinDataComplete CurrentIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 77, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Current Ip Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentIpAddress")] + public JoinDataComplete CurrentIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 77, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Current Ip Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("CurrentSubnetMask")] - public JoinDataComplete CurrentSubnetMask = new JoinDataComplete(new JoinData { JoinNumber = 78, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Current Subnet Mask", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentSubnetMask")] + public JoinDataComplete CurrentSubnetMask = new JoinDataComplete(new JoinData { JoinNumber = 78, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Current Subnet Mask", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("CurrentDefaultGateway")] - public JoinDataComplete CurrentDefaultGateway = new JoinDataComplete(new JoinData { JoinNumber = 79, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Current Default Gateway", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentDefaultGateway")] + public JoinDataComplete CurrentDefaultGateway = new JoinDataComplete(new JoinData { JoinNumber = 79, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Current Default Gateway", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("StaticIpAddress")] - public JoinDataComplete StaticIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 80, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Static Ip Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("StaticIpAddress")] + public JoinDataComplete StaticIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 80, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Static Ip Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("StaticSubnetMask")] - public JoinDataComplete StaticSubnetMask = new JoinDataComplete(new JoinData { JoinNumber = 81, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Static Subnet Mask", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("StaticSubnetMask")] + public JoinDataComplete StaticSubnetMask = new JoinDataComplete(new JoinData { JoinNumber = 81, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Static Subnet Mask", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("StaticDefaultGateway")] - public JoinDataComplete StaticDefaultGateway = new JoinDataComplete(new JoinData { JoinNumber = 82, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Static Default Gateway", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("StaticDefaultGateway")] + public JoinDataComplete StaticDefaultGateway = new JoinDataComplete(new JoinData { JoinNumber = 82, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Static Default Gateway", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("Domain")] - public JoinDataComplete Domain = new JoinDataComplete(new JoinData { JoinNumber = 83, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Domain", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("Domain")] + public JoinDataComplete Domain = new JoinDataComplete(new JoinData { JoinNumber = 83, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Domain", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("DnsServer")] - public JoinDataComplete DnsServer = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Dns Server", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("DnsServer")] + public JoinDataComplete DnsServer = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Dns Server", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("MacAddress")] - public JoinDataComplete MacAddress = new JoinDataComplete(new JoinData { JoinNumber = 85, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Mac Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("MacAddress")] + public JoinDataComplete MacAddress = new JoinDataComplete(new JoinData { JoinNumber = 85, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Mac Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); - [JoinName("DhcpStatus")] - public JoinDataComplete DhcpStatus = new JoinDataComplete(new JoinData { JoinNumber = 86, JoinSpan = 1 }, - new JoinMetadata { Description = "Processor Ethernet Dhcp Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("DhcpStatus")] + public JoinDataComplete DhcpStatus = new JoinDataComplete(new JoinData { JoinNumber = 86, JoinSpan = 1 }, + new JoinMetadata { Description = "Processor Ethernet Dhcp Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("ProcessorRebot")] public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, @@ -149,23 +149,22 @@ namespace PepperDash.Essentials.Core.Bridges new JoinMetadata { Description = "Resets the program", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public SystemMonitorJoinMap(uint joinStart) - : this(joinStart, typeof(SystemMonitorJoinMap)) - { - } + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public SystemMonitorJoinMap(uint joinStart) + : this(joinStart, typeof(SystemMonitorJoinMap)) + { + } - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - protected SystemMonitorJoinMap(uint joinStart, Type type) - : base(joinStart, type) - { - } + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + protected SystemMonitorJoinMap(uint joinStart, Type type) + : base(joinStart, type) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index 755a586e..c4526e47 100644 --- a/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -1,7 +1,7 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Bridges.JoinMaps -{ +namespace PepperDash.Essentials.Core.Bridges.JoinMaps; + public class VideoCodecControllerJoinMap : JoinMapBaseAdvanced { #region Digital @@ -20,21 +20,21 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("SendDtmfToSpecificCallIndex")] - public JoinDataComplete SendDtmfToSpecificCallIndex = new JoinDataComplete( - new JoinData - { - JoinNumber = 10, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "If High, will send DTMF tones to the call set by SelectCall analog. If low sends DTMF tones to last connected call.", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("SendDtmfToSpecificCallIndex")] + public JoinDataComplete SendDtmfToSpecificCallIndex = new JoinDataComplete( + new JoinData + { + JoinNumber = 10, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "If High, will send DTMF tones to the call set by SelectCall analog. If low sends DTMF tones to last connected call.", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("Dtmf1")] + [JoinName("Dtmf1")] public JoinDataComplete Dtmf1 = new JoinDataComplete( new JoinData { @@ -48,7 +48,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf2")] + [JoinName("Dtmf2")] public JoinDataComplete Dtmf2 = new JoinDataComplete( new JoinData { @@ -62,7 +62,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf3")] + [JoinName("Dtmf3")] public JoinDataComplete Dtmf3 = new JoinDataComplete( new JoinData { @@ -76,7 +76,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf4")] + [JoinName("Dtmf4")] public JoinDataComplete Dtmf4 = new JoinDataComplete( new JoinData { @@ -90,7 +90,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf5")] + [JoinName("Dtmf5")] public JoinDataComplete Dtmf5 = new JoinDataComplete( new JoinData { @@ -104,7 +104,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf6")] + [JoinName("Dtmf6")] public JoinDataComplete Dtmf6 = new JoinDataComplete( new JoinData { @@ -118,7 +118,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf7")] + [JoinName("Dtmf7")] public JoinDataComplete Dtmf7 = new JoinDataComplete( new JoinData { @@ -132,7 +132,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf8")] + [JoinName("Dtmf8")] public JoinDataComplete Dtmf8 = new JoinDataComplete( new JoinData { @@ -146,7 +146,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf9")] + [JoinName("Dtmf9")] public JoinDataComplete Dtmf9 = new JoinDataComplete( new JoinData { @@ -160,7 +160,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Dtmf0")] + [JoinName("Dtmf0")] public JoinDataComplete Dtmf0 = new JoinDataComplete( new JoinData { @@ -174,7 +174,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("DtmfStar")] + [JoinName("DtmfStar")] public JoinDataComplete DtmfStar = new JoinDataComplete( new JoinData { @@ -188,7 +188,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("DtmfPound")] + [JoinName("DtmfPound")] public JoinDataComplete DtmfPound = new JoinDataComplete( new JoinData { @@ -202,7 +202,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("EndAllCalls")] + [JoinName("EndAllCalls")] public JoinDataComplete EndAllCalls = new JoinDataComplete( new JoinData { @@ -300,7 +300,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("DialPhone")] + [JoinName("DialPhone")] public JoinDataComplete DialPhone = new JoinDataComplete( new JoinData { @@ -328,7 +328,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("HangUpPhone")] + [JoinName("HangUpPhone")] public JoinDataComplete HangUpPhone = new JoinDataComplete( new JoinData { @@ -342,47 +342,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("EndCallStart")] - public JoinDataComplete EndCallStart = new JoinDataComplete( - new JoinData - { - JoinNumber = 81, - JoinSpan = 8 - }, - new JoinMetadata - { - Description = "End a specific call by call index. ", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("EndCallStart")] + public JoinDataComplete EndCallStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 81, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "End a specific call by call index. ", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("JoinAllCalls")] - public JoinDataComplete JoinAllCalls = new JoinDataComplete( - new JoinData - { - JoinNumber = 90, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Join all calls", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("JoinAllCalls")] + public JoinDataComplete JoinAllCalls = new JoinDataComplete( + new JoinData + { + JoinNumber = 90, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Join all calls", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("JoinCallStart")] - public JoinDataComplete JoinCallStart = new JoinDataComplete( - new JoinData - { - JoinNumber = 91, - JoinSpan = 8 - }, - new JoinMetadata - { - Description = "Join a specific call by call index. ", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("JoinCallStart")] + public JoinDataComplete JoinCallStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 91, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "Join a specific call by call index. ", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); [JoinName("DirectorySearchBusy")] public JoinDataComplete DirectorySearchBusy = new JoinDataComplete( @@ -497,47 +497,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("DirectoryDisableAutoDialSelectedLine")] - public JoinDataComplete DirectoryDisableAutoDialSelectedLine = new JoinDataComplete( - new JoinData - { - JoinNumber = 107, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Set high to disable automatic dialing of a contact when selected", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("DirectoryDisableAutoDialSelectedLine")] + public JoinDataComplete DirectoryDisableAutoDialSelectedLine = new JoinDataComplete( + new JoinData + { + JoinNumber = 107, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Set high to disable automatic dialing of a contact when selected", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("DirectoryDialSelectedContactMethod")] - public JoinDataComplete DirectoryDialSelectedContactMethod = new JoinDataComplete( - new JoinData - { - JoinNumber = 108, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Pulse to dial the selected contact method", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("DirectoryDialSelectedContactMethod")] + public JoinDataComplete DirectoryDialSelectedContactMethod = new JoinDataComplete( + new JoinData + { + JoinNumber = 108, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Pulse to dial the selected contact method", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("DirectoryClearSelected")] - public JoinDataComplete DirectoryClearSelected = new JoinDataComplete( - new JoinData - { - JoinNumber = 110, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Clear Selected Entry and String from Search", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("DirectoryClearSelected")] + public JoinDataComplete DirectoryClearSelected = new JoinDataComplete( + new JoinData + { + JoinNumber = 110, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Clear Selected Entry and String from Search", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); [JoinName("CameraTiltUp")] @@ -624,47 +624,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("CameraFocusNear")] - public JoinDataComplete CameraFocusNear = new JoinDataComplete( - new JoinData - { - JoinNumber = 117, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Camera Focus Near", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("CameraFocusNear")] + public JoinDataComplete CameraFocusNear = new JoinDataComplete( + new JoinData + { + JoinNumber = 117, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Camera Focus Near", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("CameraFocusFar")] - public JoinDataComplete CameraFocusFar = new JoinDataComplete( - new JoinData - { - JoinNumber = 118, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Camera Focus Far", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("CameraFocusFar")] + public JoinDataComplete CameraFocusFar = new JoinDataComplete( + new JoinData + { + JoinNumber = 118, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Camera Focus Far", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("CameraFocusAuto")] - public JoinDataComplete CameraFocusAuto = new JoinDataComplete( - new JoinData - { - JoinNumber = 119, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Camera Auto Focus Trigger", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("CameraFocusAuto")] + public JoinDataComplete CameraFocusAuto = new JoinDataComplete( + new JoinData + { + JoinNumber = 119, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Camera Auto Focus Trigger", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); [JoinName("CameraPresetSave")] public JoinDataComplete CameraPresetSave = new JoinDataComplete( @@ -792,7 +792,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("DialMeetingStart")] + [JoinName("DialMeetingStart")] public JoinDataComplete DialMeetingStart = new JoinDataComplete( new JoinData { @@ -918,33 +918,33 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("RemoveSelectedRecentCallItem")] - public JoinDataComplete RemoveSelectedRecentCallItem = new JoinDataComplete( - new JoinData - { - JoinNumber = 181, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Pulse to remove the selected recent call item specified by the SelectRecentCallItem analog join", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("RemoveSelectedRecentCallItem")] + public JoinDataComplete RemoveSelectedRecentCallItem = new JoinDataComplete( + new JoinData + { + JoinNumber = 181, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Pulse to remove the selected recent call item specified by the SelectRecentCallItem analog join", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("DialSelectedRecentCallItem")] - public JoinDataComplete DialSelectedRecentCallItem = new JoinDataComplete( - new JoinData - { - JoinNumber = 182, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Pulse to dial the selected recent call item specified by the SelectRecentCallItem analog join", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("DialSelectedRecentCallItem")] + public JoinDataComplete DialSelectedRecentCallItem = new JoinDataComplete( + new JoinData + { + JoinNumber = 182, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Pulse to dial the selected recent call item specified by the SelectRecentCallItem analog join", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); [JoinName("SourceShareStart")] public JoinDataComplete SourceShareStart = new JoinDataComplete( @@ -1016,117 +1016,117 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("HoldAllCalls")] - public JoinDataComplete HoldAllCalls = new JoinDataComplete( - new JoinData - { - JoinNumber = 220, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Holds all calls", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("HoldAllCalls")] + public JoinDataComplete HoldAllCalls = new JoinDataComplete( + new JoinData + { + JoinNumber = 220, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Holds all calls", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("HoldCallsStart")] - public JoinDataComplete HoldCallsStart = new JoinDataComplete( - new JoinData - { - JoinNumber = 221, - JoinSpan = 8 - }, - new JoinMetadata - { - Description = "Holds Call at specified index. FB reported on Call Status XSIG", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("HoldCallsStart")] + public JoinDataComplete HoldCallsStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 221, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "Holds Call at specified index. FB reported on Call Status XSIG", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("ResumeCallsStart")] - public JoinDataComplete ResumeCallsStart = new JoinDataComplete( - new JoinData - { - JoinNumber = 231, - JoinSpan = 8 - }, - new JoinMetadata - { - Description = "Resume Call at specified index", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("ResumeCallsStart")] + public JoinDataComplete ResumeCallsStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 231, + JoinSpan = 8 + }, + new JoinMetadata + { + Description = "Resume Call at specified index", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("MultiSiteOptionIsEnabled")] - public JoinDataComplete MultiSiteOptionIsEnabled = new JoinDataComplete( - new JoinData - { - JoinNumber = 301, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Multi site option is enabled FB", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("MultiSiteOptionIsEnabled")] + public JoinDataComplete MultiSiteOptionIsEnabled = new JoinDataComplete( + new JoinData + { + JoinNumber = 301, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Multi site option is enabled FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("AutoAnswerEnabled")] - public JoinDataComplete AutoAnswerEnabled = new JoinDataComplete( - new JoinData - { - JoinNumber = 302, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Auto Answer is enabled FB", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("AutoAnswerEnabled")] + public JoinDataComplete AutoAnswerEnabled = new JoinDataComplete( + new JoinData + { + JoinNumber = 302, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Auto Answer is enabled FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("ParticipantAudioMuteToggleStart")] - public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete( + [JoinName("ParticipantAudioMuteToggleStart")] + public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete( new JoinData { JoinNumber = 501, JoinSpan = 50 }, - new JoinMetadata - { - Description = "Toggles the participant's audio mute status", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + new JoinMetadata + { + Description = "Toggles the participant's audio mute status", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("ParticipantVideoMuteToggleStart")] - public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete( + [JoinName("ParticipantVideoMuteToggleStart")] + public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete( new JoinData { JoinNumber = 801, JoinSpan = 50 }, - new JoinMetadata - { - Description = "Toggles the participant's video mute status", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + new JoinMetadata + { + Description = "Toggles the participant's video mute status", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("ParticipantPinToggleStart")] - public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete( + [JoinName("ParticipantPinToggleStart")] + public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete( new JoinData { JoinNumber = 1101, JoinSpan = 50 }, - new JoinMetadata - { - Description = "Toggles the participant's pin status", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + new JoinMetadata + { + Description = "Toggles the participant's pin status", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); #endregion @@ -1135,49 +1135,49 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps #region Analog - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - [JoinName("MeetingsToDisplay")] - public JoinDataComplete MeetingsToDisplay = new JoinDataComplete( - new JoinData - { - JoinNumber = 40, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Set/FB the number of meetings to display via the bridge xsig; default: 3 meetings.", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Analog - }); + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + [JoinName("MeetingsToDisplay")] + public JoinDataComplete MeetingsToDisplay = new JoinDataComplete( + new JoinData + { + JoinNumber = 40, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Set/FB the number of meetings to display via the bridge xsig; default: 3 meetings.", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); - [JoinName("SelectCall")] - public JoinDataComplete SelectCall = new JoinDataComplete( - new JoinData - { - JoinNumber = 24, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sets the selected Call for DTMF commands. Valid values 1-8", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("SelectCall")] + public JoinDataComplete SelectCall = new JoinDataComplete( + new JoinData + { + JoinNumber = 24, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Sets the selected Call for DTMF commands. Valid values 1-8", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); - [JoinName("ConnectedCallCount")] - public JoinDataComplete ConnectedCallCount = new JoinDataComplete( - new JoinData - { - JoinNumber = 25, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Reports the number of currently connected calls", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("ConnectedCallCount")] + public JoinDataComplete ConnectedCallCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 25, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Reports the number of currently connected calls", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); [JoinName("MinutesBeforeMeetingStart")] public JoinDataComplete MinutesBeforeMeetingStart = new JoinDataComplete( @@ -1207,19 +1207,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); - [JoinName("CameraCount")] - public JoinDataComplete CameraCount = new JoinDataComplete( - new JoinData - { - JoinNumber = 61, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Reports the number of cameras", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("CameraCount")] + public JoinDataComplete CameraCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 61, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Reports the number of cameras", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); [JoinName("DirectoryRowCount")] public JoinDataComplete DirectoryRowCount = new JoinDataComplete( @@ -1250,47 +1250,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps }); - [JoinName("SelectedContactMethodCount")] - public JoinDataComplete SelectedContactMethodCount = new JoinDataComplete( - new JoinData - { - JoinNumber = 102, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Reports the number of contact methods for the selected contact", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("SelectedContactMethodCount")] + public JoinDataComplete SelectedContactMethodCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 102, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Reports the number of contact methods for the selected contact", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); - [JoinName("SelectContactMethod")] - public JoinDataComplete SelectContactMethod = new JoinDataComplete( - new JoinData - { - JoinNumber = 103, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Selects a contact method by index", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("SelectContactMethod")] + public JoinDataComplete SelectContactMethod = new JoinDataComplete( + new JoinData + { + JoinNumber = 103, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Selects a contact method by index", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); - [JoinName("DirectorySelectRowFeedback")] - public JoinDataComplete DirectorySelectRowFeedback = new JoinDataComplete( - new JoinData - { - JoinNumber = 104, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Directory Select Row and Feedback", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("DirectorySelectRowFeedback")] + public JoinDataComplete DirectorySelectRowFeedback = new JoinDataComplete( + new JoinData + { + JoinNumber = 104, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Directory Select Row and Feedback", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); @@ -1308,19 +1308,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); - [JoinName("FarEndPresetSelect")] - public JoinDataComplete FarEndPresetSelect = new JoinDataComplete( - new JoinData - { - JoinNumber = 122, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Far End Preset Preset Select", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("FarEndPresetSelect")] + public JoinDataComplete FarEndPresetSelect = new JoinDataComplete( + new JoinData + { + JoinNumber = 122, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Far End Preset Preset Select", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); [JoinName("ParticipantCount")] public JoinDataComplete ParticipantCount = new JoinDataComplete( @@ -1364,47 +1364,47 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Analog }); - [JoinName("SelectRecentCallItem")] - public JoinDataComplete SelectRecentCallItem = new JoinDataComplete( - new JoinData - { - JoinNumber = 180, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Select/FB for Recent Call Item. Valid values 1 - 10", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("SelectRecentCallItem")] + public JoinDataComplete SelectRecentCallItem = new JoinDataComplete( + new JoinData + { + JoinNumber = 180, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Select/FB for Recent Call Item. Valid values 1 - 10", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); - [JoinName("RecentCallOccurrenceType")] - public JoinDataComplete RecentCallOccurrenceType = new JoinDataComplete( - new JoinData - { - JoinNumber = 181, - JoinSpan = 10 - }, - new JoinMetadata - { - Description = "Recent Call Occurrence Type. [0-3] 0 = Unknown, 1 = Placed, 2 = Received, 3 = NoAnswer", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("RecentCallOccurrenceType")] + public JoinDataComplete RecentCallOccurrenceType = new JoinDataComplete( + new JoinData + { + JoinNumber = 181, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Recent Call Occurrence Type. [0-3] 0 = Unknown, 1 = Placed, 2 = Received, 3 = NoAnswer", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); - [JoinName("RecentCallCount")] - public JoinDataComplete RecentCallCount = new JoinDataComplete( - new JoinData - { - JoinNumber = 191, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Recent Call Count", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); + [JoinName("RecentCallCount")] + public JoinDataComplete RecentCallCount = new JoinDataComplete( + new JoinData + { + JoinNumber = 191, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Recent Call Count", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); #endregion @@ -1426,7 +1426,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("PhoneDialString")] + [JoinName("PhoneDialString")] public JoinDataComplete PhoneDialString = new JoinDataComplete( new JoinData { @@ -1440,7 +1440,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("CurrentCallData")] + [JoinName("CurrentCallData")] public JoinDataComplete CurrentCallData = new JoinDataComplete( new JoinData { @@ -1539,19 +1539,19 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("ContactMethods")] - public JoinDataComplete ContactMethods = new JoinDataComplete( - new JoinData - { - JoinNumber = 103, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Contact Methods - XSig, 10 entries", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("ContactMethods")] + public JoinDataComplete ContactMethods = new JoinDataComplete( + new JoinData + { + JoinNumber = 103, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Contact Methods - XSig, 10 entries", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); [JoinName("CameraPresetNames")] public JoinDataComplete CameraPresetNames = new JoinDataComplete( @@ -1567,7 +1567,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("CurrentLayoutStringFb")] + [JoinName("CurrentLayoutStringFb")] public JoinDataComplete CurrentLayoutStringFb = new JoinDataComplete( new JoinData { @@ -1581,33 +1581,33 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("AvailableLayoutsFb")] - public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete( - new JoinData - { - JoinNumber = 142, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "xSig of all available layouts", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("AvailableLayoutsFb")] + public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete( + new JoinData + { + JoinNumber = 142, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "xSig of all available layouts", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("SelectLayout")] - public JoinDataComplete SelectLayout = new JoinDataComplete( - new JoinData - { - JoinNumber = 142, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Select Layout by string", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("SelectLayout")] + public JoinDataComplete SelectLayout = new JoinDataComplete( + new JoinData + { + JoinNumber = 142, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Select Layout by string", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); @@ -1625,75 +1625,75 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("CameraNamesFb")] - public JoinDataComplete CameraNamesFb = new JoinDataComplete( - new JoinData - { - JoinNumber = 161, - JoinSpan = 10 - }, - new JoinMetadata - { - Description = "Camera Name Fb", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("CameraNamesFb")] + public JoinDataComplete CameraNamesFb = new JoinDataComplete( + new JoinData + { + JoinNumber = 161, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Camera Name Fb", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("SelectedRecentCallName")] - public JoinDataComplete SelectedRecentCallName = new JoinDataComplete( - new JoinData - { - JoinNumber = 171, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Selected Recent Call Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("SelectedRecentCallName")] + public JoinDataComplete SelectedRecentCallName = new JoinDataComplete( + new JoinData + { + JoinNumber = 171, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Selected Recent Call Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("SelectedRecentCallNumber")] - public JoinDataComplete SelectedRecentCallNumber = new JoinDataComplete( - new JoinData - { - JoinNumber = 172, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Selected Recent Call Number", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("SelectedRecentCallNumber")] + public JoinDataComplete SelectedRecentCallNumber = new JoinDataComplete( + new JoinData + { + JoinNumber = 172, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Selected Recent Call Number", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("RecentCallNamesStart")] - public JoinDataComplete RecentCallNamesStart = new JoinDataComplete( - new JoinData - { - JoinNumber = 181, - JoinSpan = 10 - }, - new JoinMetadata - { - Description = "Recent Call Names", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("RecentCallNamesStart")] + public JoinDataComplete RecentCallNamesStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 181, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Recent Call Names", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("RecentCallTimesStart")] - public JoinDataComplete RecentCallTimesStart = new JoinDataComplete( - new JoinData - { - JoinNumber = 191, - JoinSpan = 10 - }, - new JoinMetadata - { - Description = "Recent Calls Times", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("RecentCallTimesStart")] + public JoinDataComplete RecentCallTimesStart = new JoinDataComplete( + new JoinData + { + JoinNumber = 191, + JoinSpan = 10 + }, + new JoinMetadata + { + Description = "Recent Calls Times", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); [JoinName("CurrentSource")] public JoinDataComplete CurrentSource = new JoinDataComplete( @@ -1723,75 +1723,75 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Serial }); - [JoinName("DeviceIpAddresss")] - public JoinDataComplete DeviceIpAddresss = new JoinDataComplete( - new JoinData - { - JoinNumber = 301, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "IP Address of device", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("DeviceIpAddresss")] + public JoinDataComplete DeviceIpAddresss = new JoinDataComplete( + new JoinData + { + JoinNumber = 301, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "IP Address of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("SipPhoneNumber")] - public JoinDataComplete SipPhoneNumber = new JoinDataComplete( - new JoinData - { - JoinNumber = 302, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "SIP phone number of device", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("SipPhoneNumber")] + public JoinDataComplete SipPhoneNumber = new JoinDataComplete( + new JoinData + { + JoinNumber = 302, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "SIP phone number of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("E164Alias")] - public JoinDataComplete E164Alias = new JoinDataComplete( - new JoinData - { - JoinNumber = 303, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "E164 alias of device", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("E164Alias")] + public JoinDataComplete E164Alias = new JoinDataComplete( + new JoinData + { + JoinNumber = 303, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "E164 alias of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("H323Id")] - public JoinDataComplete H323Id = new JoinDataComplete( - new JoinData - { - JoinNumber = 304, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "H323 ID of device", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("H323Id")] + public JoinDataComplete H323Id = new JoinDataComplete( + new JoinData + { + JoinNumber = 304, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "H323 ID of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); - [JoinName("SipUri")] - public JoinDataComplete SipUri = new JoinDataComplete( - new JoinData - { - JoinNumber = 305, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "SIP URI of device", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); + [JoinName("SipUri")] + public JoinDataComplete SipUri = new JoinDataComplete( + new JoinData + { + JoinNumber = 305, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "SIP URI of device", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); [JoinName("DirectoryEntrySelectedName")] public JoinDataComplete DirectoryEntrySelectedName = new JoinDataComplete( @@ -1848,4 +1848,3 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps { } } -} diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs index 544a682f..0c053d6b 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs @@ -10,117 +10,116 @@ using Crestron.SimplSharpPro.DM; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class CecPortController : Device, IBasicCommunicationWithStreamDebugging - { +{ public CommunicationStreamDebugging StreamDebugging { get; private set; } - public event EventHandler BytesReceived; - public event EventHandler TextReceived; + public event EventHandler BytesReceived; + public event EventHandler TextReceived; - public bool IsConnected { get { return true; } } + public bool IsConnected { get { return true; } } - ICec Port; + ICec Port; - public CecPortController(string key, Func postActivationFunc, - EssentialsControlPropertiesConfig config):base(key) - { + public CecPortController(string key, Func postActivationFunc, + EssentialsControlPropertiesConfig config):base(key) + { StreamDebugging = new CommunicationStreamDebugging(key); - AddPostActivationAction(() => - { - Port = postActivationFunc(config); - - Port.StreamCec.CecChange += StreamCec_CecChange; - }); - } - - public CecPortController(string key, ICec port) - : base(key) + AddPostActivationAction(() => { - Port = port; + Port = postActivationFunc(config); - Port.StreamCec.CecChange += new CecChangeEventHandler(StreamCec_CecChange); - } + Port.StreamCec.CecChange += StreamCec_CecChange; + }); + } - void StreamCec_CecChange(Cec cecDevice, CecEventArgs args) - { - if (args.EventId == CecEventIds.CecMessageReceivedEventId) - OnDataReceived(cecDevice.Received.StringValue); - else if (args.EventId == CecEventIds.ErrorFeedbackEventId) - if(cecDevice.ErrorFeedback.BoolValue) - Debug.LogMessage(LogEventLevel.Verbose, this, "CEC NAK Error"); - } + public CecPortController(string key, ICec port) + : base(key) + { + Port = port; - void OnDataReceived(string s) - { + Port.StreamCec.CecChange += new CecChangeEventHandler(StreamCec_CecChange); + } + + void StreamCec_CecChange(Cec cecDevice, CecEventArgs args) + { + if (args.EventId == CecEventIds.CecMessageReceivedEventId) + OnDataReceived(cecDevice.Received.StringValue); + else if (args.EventId == CecEventIds.ErrorFeedbackEventId) + if(cecDevice.ErrorFeedback.BoolValue) + Debug.LogMessage(LogEventLevel.Verbose, this, "CEC NAK Error"); + } + + void OnDataReceived(string s) + { var bytesHandler = BytesReceived; - if (bytesHandler != null) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(s); + if (bytesHandler != null) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(s); if (StreamDebugging.RxStreamDebuggingIsEnabled) Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes)); - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - } - var textHandler = TextReceived; + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + var textHandler = TextReceived; if (textHandler != null) { if (StreamDebugging.RxStreamDebuggingIsEnabled) Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s); textHandler(this, new GenericCommMethodReceiveTextArgs(s)); } - } + } - #region IBasicCommunication Members + #region IBasicCommunication Members - public void SendText(string text) - { - if (Port == null) - return; + public void SendText(string text) + { + if (Port == null) + return; if (StreamDebugging.TxStreamDebuggingIsEnabled) Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); - Port.StreamCec.Send.StringValue = text; - } + Port.StreamCec.Send.StringValue = text; + } - public void SendBytes(byte[] bytes) - { - if (Port == null) - return; - var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + public void SendBytes(byte[] bytes) + { + if (Port == null) + return; + var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); if (StreamDebugging.TxStreamDebuggingIsEnabled) Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); - Port.StreamCec.Send.StringValue = text; - } + Port.StreamCec.Send.StringValue = text; + } - public void Connect() + public void Connect() + { + } + + public void Disconnect() + { + } + + #endregion + + /// + /// + /// + /// + public void SimulateReceive(string s) + { + // split out hex chars and build string + var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])"); + StringBuilder b = new StringBuilder(); + foreach (var t in split) { + if (t.StartsWith(@"\") && t.Length == 4) + b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16))); + else + b.Append(t); } - public void Disconnect() - { - } - - #endregion - - /// - /// - /// - /// - public void SimulateReceive(string s) - { - // split out hex chars and build string - var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])"); - StringBuilder b = new StringBuilder(); - foreach (var t in split) - { - if (t.StartsWith(@"\") && t.Length == 4) - b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16))); - else - b.Append(t); - } - - OnDataReceived(b.ToString()); - } + OnDataReceived(b.ToString()); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs b/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs index 41420b7c..a011e29c 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs @@ -10,11 +10,11 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class ComPortController : Device, IBasicCommunicationWithStreamDebugging { - public CommunicationStreamDebugging StreamDebugging { get; private set; } + public CommunicationStreamDebugging StreamDebugging { get; private set; } public event EventHandler BytesReceived; public event EventHandler TextReceived; @@ -27,16 +27,16 @@ namespace PepperDash.Essentials.Core public ComPortController(string key, Func postActivationFunc, ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key) { - StreamDebugging = new CommunicationStreamDebugging(key); + StreamDebugging = new CommunicationStreamDebugging(key); Spec = spec; - AddPostActivationAction(() => - { - Port = postActivationFunc(config); + AddPostActivationAction(() => + { + Port = postActivationFunc(config); - RegisterAndConfigureComPort(); - }); + RegisterAndConfigureComPort(); + }); } public ComPortController(string key, ComPort port, ComPort.ComPortSpec spec) @@ -62,15 +62,15 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Information, this, "Configured com Port for this device does not exist."); return; } - if (Port.Parent is CrestronControlSystem) + if (Port.Parent is CrestronControlSystem) + { + var result = Port.Register(); + if (result != eDeviceRegistrationUnRegistrationResponse.Success) { - var result = Port.Register(); - if (result != eDeviceRegistrationUnRegistrationResponse.Success) - { - Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Com port: {0}", result); - return; // false - } + Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Com port: {0}", result); + return; // false } + } var specResult = Port.SetComPortSpec(Spec); if (specResult != 0) @@ -88,33 +88,33 @@ namespace PepperDash.Essentials.Core void Port_SerialDataReceived(ComPort ReceivingComPort, ComPortSerialDataEventArgs args) { - OnDataReceived(args.SerialData); + OnDataReceived(args.SerialData); } - void OnDataReceived(string s) - { + void OnDataReceived(string s) + { var eventSubscribed = false; - var bytesHandler = BytesReceived; - if (bytesHandler != null) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(s); + var bytesHandler = BytesReceived; + if (bytesHandler != null) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(s); if (StreamDebugging.RxStreamDebuggingIsEnabled) Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes)); - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); eventSubscribed = true; - } - var textHandler = TextReceived; - if (textHandler != null) - { + } + var textHandler = TextReceived; + if (textHandler != null) + { if (StreamDebugging.RxStreamDebuggingIsEnabled) Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s); - textHandler(this, new GenericCommMethodReceiveTextArgs(s)); + textHandler(this, new GenericCommMethodReceiveTextArgs(s)); eventSubscribed = true; - } + } if(!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered"); - } + } public override bool Deactivate() { @@ -128,9 +128,9 @@ namespace PepperDash.Essentials.Core if (Port == null) return; - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); - Port.Send(text); + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text); + Port.Send(text); } public void SendBytes(byte[] bytes) @@ -138,8 +138,8 @@ namespace PepperDash.Essentials.Core if (Port == null) return; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Port.Send(text); } @@ -154,24 +154,23 @@ namespace PepperDash.Essentials.Core #endregion - /// - /// - /// - /// - public void SimulateReceive(string s) + /// + /// + /// + /// + public void SimulateReceive(string s) + { + // split out hex chars and build string + var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])"); + StringBuilder b = new StringBuilder(); + foreach (var t in split) { - // split out hex chars and build string - var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])"); - StringBuilder b = new StringBuilder(); - foreach (var t in split) - { - if (t.StartsWith(@"\") && t.Length == 4) - b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16))); - else - b.Append(t); - } - - OnDataReceived(b.ToString()); + if (t.StartsWith(@"\") && t.Length == 4) + b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16))); + else + b.Append(t); } - } -} \ No newline at end of file + + OnDataReceived(b.ToString()); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs b/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs index bfdccb65..6ef2f916 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs @@ -13,92 +13,89 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// This converter creates a proper ComPort.ComPortSpec struct from more-friendly JSON values. It uses +/// ComSpecPropsJsonConverter to finish the individual properties. +/// +public class ComSpecJsonConverter : JsonConverter { - /// - /// This converter creates a proper ComPort.ComPortSpec struct from more-friendly JSON values. It uses - /// ComSpecPropsJsonConverter to finish the individual properties. - /// - public class ComSpecJsonConverter : JsonConverter + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + if (objectType == typeof(ComPort.ComPortSpec?)) { - if (objectType == typeof(ComPort.ComPortSpec?)) - { - var newSer = new JsonSerializer(); - newSer.Converters.Add(new ComSpecPropsJsonConverter()); - newSer.ObjectCreationHandling = ObjectCreationHandling.Replace; - return newSer.Deserialize(reader); - } - return null; - } - - /// - /// - /// - public override bool CanConvert(Type objectType) - { - return objectType == typeof(ComPort.ComPortSpec?); - } - - public override bool CanRead { get { return true; } } - - /// - /// This converter will not be used for writing - /// - public override bool CanWrite { get { return false; } } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException(); + var newSer = new JsonSerializer(); + newSer.Converters.Add(new ComSpecPropsJsonConverter()); + newSer.ObjectCreationHandling = ObjectCreationHandling.Replace; + return newSer.Deserialize(reader); } + return null; } /// - /// The gist of this converter: The comspec JSON comes in with normal values that need to be converted - /// into enum names. This converter takes the value and applies the appropriate enum's name prefix to the value - /// and then returns the enum value using Enum.Parse. NOTE: Does not write + /// /// - public class ComSpecPropsJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) - { - return objectType == typeof(ComPort.eComBaudRates) - || objectType == typeof(ComPort.eComDataBits) - || objectType == typeof(ComPort.eComParityType) - || objectType == typeof(ComPort.eComHardwareHandshakeType) - || objectType == typeof(ComPort.eComSoftwareHandshakeType) - || objectType == typeof(ComPort.eComProtocolType) - || objectType == typeof(ComPort.eComStopBits); - } - - public override bool CanRead { get { return true; } } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - //Debug.LogMessage(LogEventLevel.Verbose, "ReadJson type: " + objectType.Name); - if (objectType == typeof(ComPort.eComBaudRates)) - return Enum.Parse(typeof(ComPort.eComBaudRates), "ComspecBaudRate" + reader.Value, false); - else if (objectType == typeof(ComPort.eComDataBits)) - return Enum.Parse(typeof(ComPort.eComDataBits), "ComspecDataBits" + reader.Value, true); - else if (objectType == typeof(ComPort.eComHardwareHandshakeType)) - return Enum.Parse(typeof(ComPort.eComHardwareHandshakeType), "ComspecHardwareHandshake" + reader.Value, true); - else if (objectType == typeof(ComPort.eComParityType)) - return Enum.Parse(typeof(ComPort.eComParityType), "ComspecParity" + reader.Value, true); - else if (objectType == typeof(ComPort.eComProtocolType)) - return Enum.Parse(typeof(ComPort.eComProtocolType), "ComspecProtocol" + reader.Value, true); - else if (objectType == typeof(ComPort.eComSoftwareHandshakeType)) - return Enum.Parse(typeof(ComPort.eComSoftwareHandshakeType), "ComspecSoftwareHandshake" + reader.Value, true); - else if (objectType == typeof(ComPort.eComStopBits)) - return Enum.Parse(typeof(ComPort.eComStopBits), "ComspecStopBits" + reader.Value, true); - return null; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException(); - } + return objectType == typeof(ComPort.ComPortSpec?); } + public override bool CanRead { get { return true; } } + /// + /// This converter will not be used for writing + /// + public override bool CanWrite { get { return false; } } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } +} + +/// +/// The gist of this converter: The comspec JSON comes in with normal values that need to be converted +/// into enum names. This converter takes the value and applies the appropriate enum's name prefix to the value +/// and then returns the enum value using Enum.Parse. NOTE: Does not write +/// +public class ComSpecPropsJsonConverter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + return objectType == typeof(ComPort.eComBaudRates) + || objectType == typeof(ComPort.eComDataBits) + || objectType == typeof(ComPort.eComParityType) + || objectType == typeof(ComPort.eComHardwareHandshakeType) + || objectType == typeof(ComPort.eComSoftwareHandshakeType) + || objectType == typeof(ComPort.eComProtocolType) + || objectType == typeof(ComPort.eComStopBits); + } + + public override bool CanRead { get { return true; } } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + //Debug.LogMessage(LogEventLevel.Verbose, "ReadJson type: " + objectType.Name); + if (objectType == typeof(ComPort.eComBaudRates)) + return Enum.Parse(typeof(ComPort.eComBaudRates), "ComspecBaudRate" + reader.Value, false); + else if (objectType == typeof(ComPort.eComDataBits)) + return Enum.Parse(typeof(ComPort.eComDataBits), "ComspecDataBits" + reader.Value, true); + else if (objectType == typeof(ComPort.eComHardwareHandshakeType)) + return Enum.Parse(typeof(ComPort.eComHardwareHandshakeType), "ComspecHardwareHandshake" + reader.Value, true); + else if (objectType == typeof(ComPort.eComParityType)) + return Enum.Parse(typeof(ComPort.eComParityType), "ComspecParity" + reader.Value, true); + else if (objectType == typeof(ComPort.eComProtocolType)) + return Enum.Parse(typeof(ComPort.eComProtocolType), "ComspecProtocol" + reader.Value, true); + else if (objectType == typeof(ComPort.eComSoftwareHandshakeType)) + return Enum.Parse(typeof(ComPort.eComSoftwareHandshakeType), "ComspecSoftwareHandshake" + reader.Value, true); + else if (objectType == typeof(ComPort.eComStopBits)) + return Enum.Parse(typeof(ComPort.eComStopBits), "ComspecStopBits" + reader.Value, true); + return null; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs index 8fa4076a..7a41ed8e 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs @@ -10,8 +10,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -53,35 +53,35 @@ namespace PepperDash.Essentials.Core case eControlMethod.Com: comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams.Value, controlConfig); break; - case eControlMethod.Cec: - comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig); - break; + case eControlMethod.Cec: + comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig); + break; case eControlMethod.IR: break; - case eControlMethod.Ssh: - { - var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password); - ssh.AutoReconnect = c.AutoReconnect; - if(ssh.AutoReconnect) - ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; - comm = ssh; - break; - } - case eControlMethod.Tcpip: - { - var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize); - tcp.AutoReconnect = c.AutoReconnect; - if (tcp.AutoReconnect) - tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; - comm = tcp; - break; - } - case eControlMethod.Udp: - { - var udp = new GenericUdpServer(deviceConfig.Key + "-udp", c.Address, c.Port, c.BufferSize); - comm = udp; - break; - } + case eControlMethod.Ssh: + { + var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password); + ssh.AutoReconnect = c.AutoReconnect; + if(ssh.AutoReconnect) + ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; + comm = ssh; + break; + } + case eControlMethod.Tcpip: + { + var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize); + tcp.AutoReconnect = c.AutoReconnect; + if (tcp.AutoReconnect) + tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; + comm = tcp; + break; + } + case eControlMethod.Udp: + { + var udp = new GenericUdpServer(deviceConfig.Key + "-udp", c.Address, c.Port, c.BufferSize); + comm = udp; + break; + } case eControlMethod.Telnet: break; case eControlMethod.SecureTcpIp: @@ -120,13 +120,13 @@ namespace PepperDash.Essentials.Core return null; } - /// - /// Gets an ICec port from a RoutingInput or RoutingOutput on a device - /// - /// - /// - public static ICec GetCecPort(ControlPropertiesConfig config) - { + /// + /// Gets an ICec port from a RoutingInput or RoutingOutput on a device + /// + /// + /// + public static ICec GetCecPort(ControlPropertiesConfig config) + { try { var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey); @@ -175,7 +175,7 @@ namespace PepperDash.Essentials.Core config.ControlPortDevKey, config.ControlPortName); return null; - } + } /// /// Helper to grab the IComPorts device for this PortDeviceKey. Key "controlSystem" will @@ -198,66 +198,65 @@ namespace PepperDash.Essentials.Core } } +/// +/// +/// +public class EssentialsControlPropertiesConfig : + ControlPropertiesConfig +{ + + [JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(ComSpecJsonConverter))] + public ComPort.ComPortSpec? ComParams { get; set; } + + [JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)] + public string CresnetId { get; set; } + /// - /// + /// Attempts to provide uint conversion of string CresnetId /// - public class EssentialsControlPropertiesConfig : - ControlPropertiesConfig + [JsonIgnore] + public uint CresnetIdInt { - - [JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(ComSpecJsonConverter))] - public ComPort.ComPortSpec? ComParams { get; set; } - - [JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)] - public string CresnetId { get; set; } - - /// - /// Attempts to provide uint conversion of string CresnetId - /// - [JsonIgnore] - public uint CresnetIdInt + get { - get + try { - try - { - return Convert.ToUInt32(CresnetId, 16); - } - catch (Exception) - { - throw new FormatException(string.Format("ERROR:Unable to convert Cresnet ID: {0} to hex. Error:\n{1}", CresnetId)); - } + return Convert.ToUInt32(CresnetId, 16); } - } - - [JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)] - public string InfinetId { get; set; } - - /// - /// Attepmts to provide uiont conversion of string InifinetId - /// - [JsonIgnore] - public uint InfinetIdInt - { - get + catch (Exception) { - try - { - return Convert.ToUInt32(InfinetId, 16); - } - catch (Exception) - { - throw new FormatException(string.Format("ERROR:Unable to conver Infinet ID: {0} to hex. Error:\n{1}", InfinetId)); - } + throw new FormatException(string.Format("ERROR:Unable to convert Cresnet ID: {0} to hex. Error:\n{1}", CresnetId)); } } } - public class IrControlSpec + [JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)] + public string InfinetId { get; set; } + + /// + /// Attepmts to provide uiont conversion of string InifinetId + /// + [JsonIgnore] + public uint InfinetIdInt { - public string PortDeviceKey { get; set; } - public uint PortNumber { get; set; } - public string File { get; set; } + get + { + try + { + return Convert.ToUInt32(InfinetId, 16); + } + catch (Exception) + { + throw new FormatException(string.Format("ERROR:Unable to conver Infinet ID: {0} to hex. Error:\n{1}", InfinetId)); + } + } } +} + +public class IrControlSpec +{ + public string PortDeviceKey { get; set; } + public uint PortNumber { get; set; } + public string File { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs b/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs index 995004b9..e335157f 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs @@ -13,13 +13,12 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// public interface IComPortsDevice { IComPorts Device { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs b/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs index fd7184aa..3960d38b 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs @@ -9,8 +9,8 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class ConsoleCommMockDevice : EssentialsDevice, ICommunicationMonitor { public IBasicCommunication Communication { get; private set; } @@ -67,21 +67,19 @@ namespace PepperDash.Essentials.Core } } - public class ConsoleCommMockDeviceFactory : EssentialsDeviceFactory +public class ConsoleCommMockDeviceFactory : EssentialsDeviceFactory +{ + public ConsoleCommMockDeviceFactory() { - public ConsoleCommMockDeviceFactory() - { - TypeNames = new List() { "commmock" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Comm Mock Device"); - var comm = CommFactory.CreateCommForDevice(dc); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject( - dc.Properties.ToString()); - return new ConsoleCommMockDevice(dc.Key, dc.Name, props, comm); - } + TypeNames = new List() { "commmock" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Comm Mock Device"); + var comm = CommFactory.CreateCommForDevice(dc); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject( + dc.Properties.ToString()); + return new ConsoleCommMockDevice(dc.Key, dc.Name, props, comm); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs b/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs index ddd7ec5d..6e913968 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs @@ -13,133 +13,132 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Serves as a generic wrapper class for all styles of IBasicCommuncation ports +/// +[Description("Generic communication wrapper class for any IBasicCommunication type")] +public class GenericComm : ReconfigurableBridgableDevice { - /// - /// Serves as a generic wrapper class for all styles of IBasicCommuncation ports - /// - [Description("Generic communication wrapper class for any IBasicCommunication type")] - public class GenericComm : ReconfigurableBridgableDevice + EssentialsControlPropertiesConfig PropertiesConfig; + + public IBasicCommunication CommPort { get; private set; } + + public GenericComm(DeviceConfig config) + : base(config) { - EssentialsControlPropertiesConfig PropertiesConfig; - public IBasicCommunication CommPort { get; private set; } + PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); - public GenericComm(DeviceConfig config) - : base(config) + var commPort = CommFactory.CreateCommForDevice(config); + + //Fixing decision to require '-comPorts' in delcaration for DGE in order to get a device with comports included + if (commPort == null) { - - PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); - - var commPort = CommFactory.CreateCommForDevice(config); - - //Fixing decision to require '-comPorts' in delcaration for DGE in order to get a device with comports included - if (commPort == null) - { - config.Key = config.Key + "-comPorts"; - commPort = CommFactory.CreateCommForDevice(config); - } - - CommPort = commPort; - + config.Key = config.Key + "-comPorts"; + commPort = CommFactory.CreateCommForDevice(config); } - public static IKeyed BuildDevice(DeviceConfig dc) + CommPort = commPort; + + } + + public static IKeyed BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); + return new GenericComm(dc); + } + + public void SetPortConfig(string portConfig) + { + // TODO: Deserialize new EssentialsControlPropertiesConfig and handle as necessary + try { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); - return new GenericComm(dc); + PropertiesConfig = JsonConvert.DeserializeObject + (portConfig); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error deserializing port config: {0}", e); + } + } + + protected override void CustomSetConfig(DeviceConfig config) + { + PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); + + ConfigWriter.UpdateDeviceConfig(config); + } + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new IBasicCommunicationJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); } - public void SetPortConfig(string portConfig) + if (CommPort == null) { - // TODO: Deserialize new EssentialsControlPropertiesConfig and handle as necessary - try - { - PropertiesConfig = JsonConvert.DeserializeObject - (portConfig); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error deserializing port config: {0}", e); - } + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. CommPort is null", Key); + return; } - protected override void CustomSetConfig(DeviceConfig config) + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + // this is a permanent event handler. This cannot be -= from event + CommPort.TextReceived += (s, a) => { - PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); + trilist.SetString(joinMap.TextReceived.JoinNumber, a.Text); + }; + trilist.SetStringSigAction(joinMap.SendText.JoinNumber, s => CommPort.SendText(s)); + trilist.SetStringSigAction(joinMap.SetPortConfig.JoinNumber, SetPortConfig); - ConfigWriter.UpdateDeviceConfig(config); - } - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + var sComm = CommPort as ISocketStatus; + if (sComm == null) return; + sComm.ConnectionChange += (s, a) => { - var joinMap = new IBasicCommunicationJoinMap(joinStart); + trilist.SetUshort(joinMap.Status.JoinNumber, (ushort)(a.Client.ClientStatus)); + trilist.SetBool(joinMap.Connected.JoinNumber, a.Client.ClientStatus == + SocketStatus.SOCKET_STATUS_CONNECTED); + }; - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); - - if (bridge != null) + trilist.SetBoolSigAction(joinMap.Connect.JoinNumber, b => + { + if (b) { - bridge.AddJoinMap(Key, joinMap); + sComm.Connect(); } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + sComm.Disconnect(); } + }); + } +} - if (CommPort == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. CommPort is null", Key); - return; - } - - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - - // this is a permanent event handler. This cannot be -= from event - CommPort.TextReceived += (s, a) => - { - trilist.SetString(joinMap.TextReceived.JoinNumber, a.Text); - }; - trilist.SetStringSigAction(joinMap.SendText.JoinNumber, s => CommPort.SendText(s)); - trilist.SetStringSigAction(joinMap.SetPortConfig.JoinNumber, SetPortConfig); - - - var sComm = CommPort as ISocketStatus; - if (sComm == null) return; - sComm.ConnectionChange += (s, a) => - { - trilist.SetUshort(joinMap.Status.JoinNumber, (ushort)(a.Client.ClientStatus)); - trilist.SetBool(joinMap.Connected.JoinNumber, a.Client.ClientStatus == - SocketStatus.SOCKET_STATUS_CONNECTED); - }; - - trilist.SetBoolSigAction(joinMap.Connect.JoinNumber, b => - { - if (b) - { - sComm.Connect(); - } - else - { - sComm.Disconnect(); - } - }); - } +public class GenericCommFactory : EssentialsDeviceFactory +{ + public GenericCommFactory() + { + TypeNames = new List() { "genericComm" }; } - public class GenericCommFactory : EssentialsDeviceFactory + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - public GenericCommFactory() - { - TypeNames = new List() { "genericComm" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); - return new GenericComm(dc); - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); + return new GenericComm(dc); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs b/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs index d88e9728..3fa52162 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs @@ -2,9 +2,9 @@ using PepperDash.Core; using System; -namespace PepperDash.Essentials.Core -{ - [Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")] +namespace PepperDash.Essentials.Core; + +[Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")] public class GenericHttpClient : Device, IBasicCommunication { private readonly HttpClient Client; @@ -13,13 +13,13 @@ namespace PepperDash.Essentials.Core public GenericHttpClient(string key, string name, string hostname) : base(key, name) { - Client = new HttpClient - { - HostName = hostname - }; + Client = new HttpClient + { + HostName = hostname + }; - } + } /// /// @@ -56,8 +56,8 @@ namespace PepperDash.Essentials.Core if (responseReceived.ContentString.Length > 0) { - ResponseRecived?.Invoke(this, new GenericHttpClientEventArgs(responseReceived.ContentString, (request as HttpClientRequest).Url.ToString(), error)); - } + ResponseRecived?.Invoke(this, new GenericHttpClientEventArgs(responseReceived.ContentString, (request as HttpClientRequest).Url.ToString(), error)); + } } } @@ -108,5 +108,4 @@ namespace PepperDash.Essentials.Core RequestPath = request; Error = error; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs b/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs index 498df9d2..52474d42 100644 --- a/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs +++ b/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs @@ -12,8 +12,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -137,89 +137,89 @@ namespace PepperDash.Essentials.Core var port = irDev.IROutputPorts[portNum]; - + return port; } public static IrOutputPortController GetIrOutputPortController(DeviceConfig config) { - Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Ir Port Controller"); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Ir Port Controller"); if (config == null) { return null; } - var postActivationFunc = new Func (GetIrOutputPort); + var postActivationFunc = new Func (GetIrOutputPort); var irDevice = new IrOutputPortController(config.Key + "-ir", postActivationFunc, config); return irDevice; } /* - /// - /// Returns a ready-to-go IrOutputPortController from a DeviceConfig object. - /// - public static IrOutputPortController GetIrOutputPortController(DeviceConfig devConf) + /// + /// Returns a ready-to-go IrOutputPortController from a DeviceConfig object. + /// + public static IrOutputPortController GetIrOutputPortController(DeviceConfig devConf) + { + var irControllerKey = devConf.Key + "-ir"; + if (devConf.Properties == null) { - var irControllerKey = devConf.Key + "-ir"; - if (devConf.Properties == null) - { - Debug.LogMessage(LogEventLevel.Information, "[{0}] WARNING: Device config does not include properties. IR will not function.", devConf.Key); - return new IrOutputPortController(irControllerKey, null, ""); - } + Debug.LogMessage(LogEventLevel.Information, "[{0}] WARNING: Device config does not include properties. IR will not function.", devConf.Key); + return new IrOutputPortController(irControllerKey, null, ""); + } - var control = devConf.Properties["control"]; - if (control == null) - { - var c = new IrOutputPortController(irControllerKey, null, ""); - Debug.LogMessage(LogEventLevel.Information, c, "WARNING: Device config does not include control properties. IR will not function"); - return c; - } + var control = devConf.Properties["control"]; + if (control == null) + { + var c = new IrOutputPortController(irControllerKey, null, ""); + Debug.LogMessage(LogEventLevel.Information, c, "WARNING: Device config does not include control properties. IR will not function"); + return c; + } - var portDevKey = control.Value("controlPortDevKey"); - var portNum = control.Value("controlPortNumber"); - IIROutputPorts irDev = null; + var portDevKey = control.Value("controlPortDevKey"); + var portNum = control.Value("controlPortNumber"); + IIROutputPorts irDev = null; - if (portDevKey == null) - { - var c = new IrOutputPortController(irControllerKey, null, ""); - Debug.LogMessage(LogEventLevel.Information, c, "WARNING: control properties is missing ir device"); - return c; - } + if (portDevKey == null) + { + var c = new IrOutputPortController(irControllerKey, null, ""); + Debug.LogMessage(LogEventLevel.Information, c, "WARNING: control properties is missing ir device"); + return c; + } - if (portNum == 0) - { - var c = new IrOutputPortController(irControllerKey, null, ""); - Debug.LogMessage(LogEventLevel.Information, c, "WARNING: control properties is missing ir port number"); - return c; - } + if (portNum == 0) + { + var c = new IrOutputPortController(irControllerKey, null, ""); + Debug.LogMessage(LogEventLevel.Information, c, "WARNING: control properties is missing ir port number"); + return c; + } - if (portDevKey.Equals("controlSystem", StringComparison.OrdinalIgnoreCase) - || portDevKey.Equals("processor", StringComparison.OrdinalIgnoreCase)) - irDev = Global.ControlSystem; - else - irDev = DeviceManager.GetDeviceForKey(portDevKey) as IIROutputPorts; + if (portDevKey.Equals("controlSystem", StringComparison.OrdinalIgnoreCase) + || portDevKey.Equals("processor", StringComparison.OrdinalIgnoreCase)) + irDev = Global.ControlSystem; + else + irDev = DeviceManager.GetDeviceForKey(portDevKey) as IIROutputPorts; - if (irDev == null) - { - var c = new IrOutputPortController(irControllerKey, null, ""); - Debug.LogMessage(LogEventLevel.Information, c, "WARNING: device with IR ports '{0}' not found", portDevKey); - return c; - } + if (irDev == null) + { + var c = new IrOutputPortController(irControllerKey, null, ""); + Debug.LogMessage(LogEventLevel.Information, c, "WARNING: device with IR ports '{0}' not found", portDevKey); + return c; + } - if (portNum <= irDev.NumberOfIROutputPorts) // success! - return new IrOutputPortController(irControllerKey, irDev.IROutputPorts[portNum], - IrDriverPathPrefix + control["irFile"].Value()); - else - { - var c = new IrOutputPortController(irControllerKey, null, ""); - Debug.LogMessage(LogEventLevel.Information, c, "WARNING: device '{0}' IR port {1} out of range", - portDevKey, portNum); - return c; - } - }*/ + if (portNum <= irDev.NumberOfIROutputPorts) // success! + return new IrOutputPortController(irControllerKey, irDev.IROutputPorts[portNum], + IrDriverPathPrefix + control["irFile"].Value()); + else + { + var c = new IrOutputPortController(irControllerKey, null, ""); + Debug.LogMessage(LogEventLevel.Information, c, "WARNING: device '{0}' IR port {1} out of range", + portDevKey, portNum); + return c; + } + }*/ } /// @@ -240,5 +240,4 @@ namespace PepperDash.Essentials.Core { FileName = ""; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs b/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs index 3552c2b2..3a3e2fc8 100644 --- a/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs +++ b/src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs @@ -6,15 +6,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public class AudioControlPointListItem { - public class AudioControlPointListItem - { - [JsonProperty("levelControls")] - public Dictionary LevelControls { get; set; } = new Dictionary(); + [JsonProperty("levelControls")] + public Dictionary LevelControls { get; set; } = new Dictionary(); - [JsonProperty("presets")] - public Dictionary Presets { get; set; } = new Dictionary(); + [JsonProperty("presets")] + public Dictionary Presets { get; set; } = new Dictionary(); - } } diff --git a/src/PepperDash.Essentials.Core/Config/BasicConfig.cs b/src/PepperDash.Essentials.Core/Config/BasicConfig.cs index 0e3e1e35..c210dd02 100644 --- a/src/PepperDash.Essentials.Core/Config/BasicConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/BasicConfig.cs @@ -7,8 +7,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.Devices; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Override this and splice on specific room type behavior, as well as other properties /// @@ -23,32 +23,32 @@ namespace PepperDash.Essentials.Core.Config [JsonProperty("sourceLists")] public Dictionary> SourceLists { get; set; } - [JsonProperty("destinationLists")] - public Dictionary> DestinationLists { get; set; } + [JsonProperty("destinationLists")] + public Dictionary> DestinationLists { get; set; } - [JsonProperty("audioControlPointLists")] - public Dictionary AudioControlPointLists { get; set; } + [JsonProperty("audioControlPointLists")] + public Dictionary AudioControlPointLists { get; set; } - [JsonProperty("cameraLists")] - public Dictionary> CameraLists { get; set; } + [JsonProperty("cameraLists")] + public Dictionary> CameraLists { get; set; } - [JsonProperty("tieLines")] + [JsonProperty("tieLines")] public List TieLines { get; set; } - [JsonProperty("joinMaps")] - public Dictionary JoinMaps { get; set; } + [JsonProperty("joinMaps")] + public Dictionary JoinMaps { get; set; } - public BasicConfig() - { - Info = new InfoConfig(); - Devices = new List(); - SourceLists = new Dictionary>(); - DestinationLists = new Dictionary>(); - AudioControlPointLists = new Dictionary(); - CameraLists = new Dictionary>(); - TieLines = new List(); - JoinMaps = new Dictionary(); - } + public BasicConfig() + { + Info = new InfoConfig(); + Devices = new List(); + SourceLists = new Dictionary>(); + DestinationLists = new Dictionary>(); + AudioControlPointLists = new Dictionary(); + CameraLists = new Dictionary>(); + TieLines = new List(); + JoinMaps = new Dictionary(); + } /// /// Checks SourceLists for a given list and returns it if found. Otherwise, returns null @@ -61,11 +61,11 @@ namespace PepperDash.Essentials.Core.Config return SourceLists[key]; } - /// - /// Retrieves a DestinationListItem based on the key - /// - /// key of the list to retrieve - /// DestinationList if the key exists, null otherwise + /// + /// Retrieves a DestinationListItem based on the key + /// + /// key of the list to retrieve + /// DestinationList if the key exists, null otherwise public Dictionary GetDestinationListForKey(string key) { if (DestinationLists == null || string.IsNullOrEmpty(key) || !DestinationLists.ContainsKey(key)) @@ -76,48 +76,47 @@ namespace PepperDash.Essentials.Core.Config return DestinationLists[key]; } - /// - /// Retrieves a AudioControlPointList based on the key - /// - /// key of the list to retrieve - /// AudioControlPointList if the key exists, null otherwise - public AudioControlPointListItem GetAudioControlPointListForKey(string key) + /// + /// Retrieves a AudioControlPointList based on the key + /// + /// key of the list to retrieve + /// AudioControlPointList if the key exists, null otherwise + public AudioControlPointListItem GetAudioControlPointListForKey(string key) + { + if (AudioControlPointLists == null || string.IsNullOrEmpty(key) || !AudioControlPointLists.ContainsKey(key)) + return null; + + return AudioControlPointLists[key]; + } + + /// + /// Checks CameraLists for a given list and returns it if found. Otherwise, returns null + /// + public Dictionary GetCameraListForKey(string key) + { + if (CameraLists == null || string.IsNullOrEmpty(key) || !CameraLists.ContainsKey(key)) + return null; + + return CameraLists[key]; + } + + /// + /// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null + /// + /// Key of desired device + /// + public DeviceConfig GetDeviceForKey(string key) + { + if (string.IsNullOrEmpty(key)) + return null; + + var deviceConfig = Devices.FirstOrDefault(d => d.Key.Equals(key)); + + if (deviceConfig != null) + return deviceConfig; + else { - if (AudioControlPointLists == null || string.IsNullOrEmpty(key) || !AudioControlPointLists.ContainsKey(key)) - return null; - - return AudioControlPointLists[key]; + return null; } - - /// - /// Checks CameraLists for a given list and returns it if found. Otherwise, returns null - /// - public Dictionary GetCameraListForKey(string key) - { - if (CameraLists == null || string.IsNullOrEmpty(key) || !CameraLists.ContainsKey(key)) - return null; - - return CameraLists[key]; - } - - /// - /// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null - /// - /// Key of desired device - /// - public DeviceConfig GetDeviceForKey(string key) - { - if (string.IsNullOrEmpty(key)) - return null; - - var deviceConfig = Devices.FirstOrDefault(d => d.Key.Equals(key)); - - if (deviceConfig != null) - return deviceConfig; - else - { - return null; - } - } - } -} \ No newline at end of file + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs b/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs index 0950d62e..9eb8e61d 100644 --- a/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs +++ b/src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs @@ -9,24 +9,23 @@ using PepperDash.Essentials.Core; using PepperDash.Core; using Newtonsoft.Json.Linq; -namespace PepperDash.Essentials.Core.Config -{ - public class ConfigPropertiesHelpers - { - /// - /// Returns the value of properties.hasAudio, or false if not defined - /// - public static bool GetHasAudio(DeviceConfig deviceConfig) - { - return deviceConfig.Properties.Value("hasAudio"); - } +namespace PepperDash.Essentials.Core.Config; - /// - /// Returns the value of properties.hasControls, or false if not defined - /// - public static bool GetHasControls(DeviceConfig deviceConfig) - { - return deviceConfig.Properties.Value("hasControls"); - } +public class ConfigPropertiesHelpers +{ + /// + /// Returns the value of properties.hasAudio, or false if not defined + /// + public static bool GetHasAudio(DeviceConfig deviceConfig) + { + return deviceConfig.Properties.Value("hasAudio"); + } + + /// + /// Returns the value of properties.hasControls, or false if not defined + /// + public static bool GetHasControls(DeviceConfig deviceConfig) + { + return deviceConfig.Properties.Value("hasControls"); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs b/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs index 3eac80d9..49994abc 100644 --- a/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs @@ -11,72 +11,71 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public class DeviceConfig { - public class DeviceConfig + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("uid")] + public int Uid { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("group")] + public string Group { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("properties")] + [JsonConverter(typeof(DevicePropertiesConverter))] + public JToken Properties { get; set; } + + public DeviceConfig(DeviceConfig dc) { - [JsonProperty("key")] - public string Key { get; set; } + Key = dc.Key; + Uid = dc.Uid; + Name = dc.Name; + Group = dc.Group; + Type = dc.Type; - [JsonProperty("uid")] - public int Uid { get; set; } + Properties = JToken.Parse(dc.Properties.ToString()); - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("group")] - public string Group { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("properties")] - [JsonConverter(typeof(DevicePropertiesConverter))] - public JToken Properties { get; set; } - - public DeviceConfig(DeviceConfig dc) - { - Key = dc.Key; - Uid = dc.Uid; - Name = dc.Name; - Group = dc.Group; - Type = dc.Type; - - Properties = JToken.Parse(dc.Properties.ToString()); - - //Properties = JToken.FromObject(dc.Properties); - } - - public DeviceConfig() {} + //Properties = JToken.FromObject(dc.Properties); } - /// - /// - /// - public class DevicePropertiesConverter : JsonConverter + public DeviceConfig() {} +} + +/// +/// +/// +public class DevicePropertiesConverter : JsonConverter +{ + + public override bool CanConvert(Type objectType) { + return objectType == typeof(JToken); + } - public override bool CanConvert(Type objectType) - { - return objectType == typeof(JToken); - } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return JToken.ReadFrom(reader); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override bool CanWrite + { + get { - return JToken.ReadFrom(reader); + return false; } + } - public override bool CanWrite - { - get - { - return false; - } - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException("SOD OFF HOSER"); - } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException("SOD OFF HOSER"); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs index 8549ecd8..d81223e3 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs @@ -11,15 +11,15 @@ using PepperDash.Core; using PepperDash.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Loads the ConfigObject from the file /// public class ConfigReader { public const string LocalConfigPresent = - @" + @" *************************************************** ************* Using Local config file ************* ***************************************************"; @@ -31,227 +31,226 @@ namespace PepperDash.Essentials.Core.Config Debug.LogMessage(LogEventLevel.Information, "Loading unmerged system/template portal configuration file."); try { - // Check for local config file first - var filePath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder + Global.DirectorySeparator + Global.ConfigFileName; + // Check for local config file first + var filePath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder + Global.DirectorySeparator + Global.ConfigFileName; - bool localConfigFound = false; + bool localConfigFound = false; - Debug.LogMessage(LogEventLevel.Information, "Attempting to load Local config file: '{0}'", filePath); + Debug.LogMessage(LogEventLevel.Information, "Attempting to load Local config file: '{0}'", filePath); - // Check for local config directory first + // Check for local config directory first - var configFiles = GetConfigFiles(filePath); + var configFiles = GetConfigFiles(filePath); + + if (configFiles != null) + { + if (configFiles.Length > 1) + { + Debug.LogMessage(LogEventLevel.Information, + "****Error: Multiple Local Configuration files present. Please ensure only a single file exists and reset program.****"); + return false; + } + if(configFiles.Length == 1) + { + localConfigFound = true; + + } + } + else + { + Debug.LogMessage(LogEventLevel.Information, + "Local Configuration file not present.", filePath); + + } + + // Check for Portal Config + if(!localConfigFound) + { + filePath = Global.FilePathPrefix + Global.ConfigFileName; + + Debug.LogMessage(LogEventLevel.Information, "Attempting to load Portal config file: '{0}'", filePath); + + configFiles = GetConfigFiles(filePath); if (configFiles != null) { + Debug.LogMessage(LogEventLevel.Verbose, "{0} config files found matching pattern", configFiles.Length); + if (configFiles.Length > 1) { Debug.LogMessage(LogEventLevel.Information, - "****Error: Multiple Local Configuration files present. Please ensure only a single file exists and reset program.****"); + "****Error: Multiple Portal Configuration files present. Please ensure only a single file exists and reset program.****"); return false; } - if(configFiles.Length == 1) + else if (configFiles.Length == 1) { - localConfigFound = true; - + Debug.LogMessage(LogEventLevel.Information, "Found Portal config file: '{0}'", filePath); + } + else + { + Debug.LogMessage(LogEventLevel.Information, "No config file found."); + return false; } } else { Debug.LogMessage(LogEventLevel.Information, - "Local Configuration file not present.", filePath); - + "ERROR: Portal Configuration file not present. Please load file and reset program."); + return false; } + } - // Check for Portal Config - if(!localConfigFound) - { - filePath = Global.FilePathPrefix + Global.ConfigFileName; + // Get the actual file path + filePath = configFiles[0].FullName; - Debug.LogMessage(LogEventLevel.Information, "Attempting to load Portal config file: '{0}'", filePath); - - configFiles = GetConfigFiles(filePath); - - if (configFiles != null) - { - Debug.LogMessage(LogEventLevel.Verbose, "{0} config files found matching pattern", configFiles.Length); - - if (configFiles.Length > 1) - { - Debug.LogMessage(LogEventLevel.Information, - "****Error: Multiple Portal Configuration files present. Please ensure only a single file exists and reset program.****"); - return false; - } - else if (configFiles.Length == 1) - { - Debug.LogMessage(LogEventLevel.Information, "Found Portal config file: '{0}'", filePath); - } - else - { - Debug.LogMessage(LogEventLevel.Information, "No config file found."); - return false; - } - } - else - { - Debug.LogMessage(LogEventLevel.Information, - "ERROR: Portal Configuration file not present. Please load file and reset program."); - return false; - } - } - - // Get the actual file path - filePath = configFiles[0].FullName; - - // Generate debug statement if using a local file. + // Generate debug statement if using a local file. if (localConfigFound) { - GetLocalFileMessage(filePath); + GetLocalFileMessage(filePath); } - // Read the file - using (StreamReader fs = new StreamReader(filePath)) + // Read the file + using (StreamReader fs = new StreamReader(filePath)) + { + Debug.LogMessage(LogEventLevel.Information, "Loading config file: '{0}'", filePath); + + if (localConfigFound) { - Debug.LogMessage(LogEventLevel.Information, "Loading config file: '{0}'", filePath); + ConfigObject = JObject.Parse(fs.ReadToEnd()).ToObject(); - if (localConfigFound) - { - ConfigObject = JObject.Parse(fs.ReadToEnd()).ToObject(); - - Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Local Config"); - - return true; - } - else - { - var doubleObj = JObject.Parse(fs.ReadToEnd()); - ConfigObject = PortalConfigReader.MergeConfigs(doubleObj).ToObject(); - - // Extract SystemUrl and TemplateUrl into final config output - - if (doubleObj["system_url"] != null) - { - ConfigObject.SystemUrl = doubleObj["system_url"].Value(); - } - - if (doubleObj["template_url"] != null) - { - ConfigObject.TemplateUrl = doubleObj["template_url"].Value(); - } - } - - Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Merged Config"); + Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Local Config"); return true; } + else + { + var doubleObj = JObject.Parse(fs.ReadToEnd()); + ConfigObject = PortalConfigReader.MergeConfigs(doubleObj).ToObject(); + + // Extract SystemUrl and TemplateUrl into final config output + + if (doubleObj["system_url"] != null) + { + ConfigObject.SystemUrl = doubleObj["system_url"].Value(); + } + + if (doubleObj["template_url"] != null) + { + ConfigObject.TemplateUrl = doubleObj["template_url"].Value(); + } + } + + Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Merged Config"); + + return true; + } } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Information, "ERROR: Config load failed: \r{0}", e); + Debug.LogMessage(LogEventLevel.Information, "ERROR: Config load failed: \r{0}", e); return false; } } - /// - /// Returns all the files from the directory specified. - /// - /// - /// - public static FileInfo[] GetConfigFiles(string filePath) + /// + /// Returns all the files from the directory specified. + /// + /// + /// + public static FileInfo[] GetConfigFiles(string filePath) + { + // Get the directory + var dir = Path.GetDirectoryName(filePath); + + if (Directory.Exists(dir)) { - // Get the directory - var dir = Path.GetDirectoryName(filePath); + Debug.LogMessage(LogEventLevel.Debug, "Searching in Directory '{0}'", dir); + // Get the directory info + var dirInfo = new DirectoryInfo(dir); - if (Directory.Exists(dir)) - { - Debug.LogMessage(LogEventLevel.Debug, "Searching in Directory '{0}'", dir); - // Get the directory info - var dirInfo = new DirectoryInfo(dir); + // Get the file name + var fileName = Path.GetFileName(filePath); + Debug.LogMessage(LogEventLevel.Debug, "For Config Files matching: '{0}'", fileName); - // Get the file name - var fileName = Path.GetFileName(filePath); - Debug.LogMessage(LogEventLevel.Debug, "For Config Files matching: '{0}'", fileName); - - // Get the files that match from the directory - return dirInfo.GetFiles(fileName); - } - else - { - Debug.LogMessage(LogEventLevel.Information, - "Directory not found: ", dir); - - return null; - } + // Get the files that match from the directory + return dirInfo.GetFiles(fileName); } + else + { + Debug.LogMessage(LogEventLevel.Information, + "Directory not found: ", dir); + + return null; + } + } /// /// Returns the group for a given device key in config /// /// /// - public static string GetGroupForDeviceKey(string key) - { - var dev = ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - return dev == null ? null : dev.Group; - } + public static string GetGroupForDeviceKey(string key) + { + var dev = ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); + return dev == null ? null : dev.Group; + } private static void GetLocalFileMessage(string filePath) { - var filePathLength = filePath.Length + 2; - var debugStringWidth = filePathLength + 12; + var filePathLength = filePath.Length + 2; + var debugStringWidth = filePathLength + 12; - if (debugStringWidth < 51) - { - debugStringWidth = 51; - } - var qualifier = (filePathLength % 2 != 0) - ? " Using Local Config File " - : " Using Local Config File "; - var bookend1 = (debugStringWidth - qualifier.Length) / 2; - var bookend2 = (debugStringWidth - filePathLength) / 2; + if (debugStringWidth < 51) + { + debugStringWidth = 51; + } + var qualifier = (filePathLength % 2 != 0) + ? " Using Local Config File " + : " Using Local Config File "; + var bookend1 = (debugStringWidth - qualifier.Length) / 2; + var bookend2 = (debugStringWidth - filePathLength) / 2; var newDebugString = new StringBuilder() .Append(CrestronEnvironment.NewLine) - // Line 1 + // Line 1 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) - // Line 2 + // Line 2 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) - // Line 3 + // Line 3 .Append(new string('*', 2)) .Append(new string(' ', debugStringWidth - 4)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) - // Line 4 + // Line 4 .Append(new string('*', 2)) .Append(new string(' ', bookend1 - 2)) .Append(qualifier) .Append(new string(' ', bookend1 - 2)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) - // Line 5 + // Line 5 .Append(new string('*', 2)) .Append(new string(' ', bookend2 - 2)) .Append(" " + filePath + " ") .Append(new string(' ', bookend2 - 2)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) - // Line 6 + // Line 6 .Append(new string('*', 2)) .Append(new string(' ', debugStringWidth - 4)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) - // Line 7 + // Line 7 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) - // Line 8 + // Line 8 .Append(new string('*', debugStringWidth)); - Debug.LogMessage(LogEventLevel.Verbose, "Found Local config file: '{0}'", filePath); - Debug.LogMessage(LogEventLevel.Information, newDebugString.ToString()); + Debug.LogMessage(LogEventLevel.Verbose, "Found Local config file: '{0}'", filePath); + Debug.LogMessage(LogEventLevel.Information, newDebugString.ToString()); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs index 141ffc25..0f14e455 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs @@ -14,213 +14,212 @@ using Crestron.SimplSharpPro.Diagnostics; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +public static class ConfigUpdater { - public static class ConfigUpdater + public static event EventHandler ConfigStatusChanged; + + public static void GetConfigFromServer(string url) { - public static event EventHandler ConfigStatusChanged; + Debug.LogMessage(LogEventLevel.Information, "Attempting to get new config from '{0}'", url); - public static void GetConfigFromServer(string url) + // HTTP GET + var req = new HttpClientRequest(); + + try { - Debug.LogMessage(LogEventLevel.Information, "Attempting to get new config from '{0}'", url); + req.RequestType = RequestType.Get; + req.Url.Parse(url); - // HTTP GET - var req = new HttpClientRequest(); - - try - { - req.RequestType = RequestType.Get; - req.Url.Parse(url); - - new HttpClient().DispatchAsync(req, (r, e) => + new HttpClient().DispatchAsync(req, (r, e) => + { + if (e == HTTP_CALLBACK_ERROR.COMPLETED) { - if (e == HTTP_CALLBACK_ERROR.COMPLETED) + if (r.Code == 200) { - if (r.Code == 200) - { - var newConfig = r.ContentString; + var newConfig = r.ContentString; - OnStatusUpdate(eUpdateStatus.ConfigFileReceived); + OnStatusUpdate(eUpdateStatus.ConfigFileReceived); - ArchiveExistingPortalConfigs(); + ArchiveExistingPortalConfigs(); - CheckForLocalConfigAndDelete(); + CheckForLocalConfigAndDelete(); - WriteConfigToFile(newConfig); + WriteConfigToFile(newConfig); - RestartProgram(); - } - else - { - Debug.LogMessage(LogEventLevel.Information, "Config Update Process Stopped. Failed to get config file from server: {0}", r.Code); - OnStatusUpdate(eUpdateStatus.UpdateFailed); - } + RestartProgram(); } else - Debug.LogMessage(LogEventLevel.Information, "Request for config from Server Failed: {0}", e); - }); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, "Error Getting Config from Server: {0}", e); - } - - } - - static void OnStatusUpdate(eUpdateStatus status) - { - var handler = ConfigStatusChanged; - - if(handler != null) - { - handler(typeof(ConfigUpdater), new ConfigStatusEventArgs(status)); - } - } - - static void WriteConfigToFile(string configData) - { - var filePath = Global.FilePathPrefix+ "configurationFile-updated.json"; - - try - { - var config = JObject.Parse(configData).ToObject(); - - ConfigWriter.WriteFile(filePath, configData); - - OnStatusUpdate(eUpdateStatus.WritingConfigFile); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, "Error parsing new config: {0}", e); - - OnStatusUpdate(eUpdateStatus.UpdateFailed); - } - } - - /// - /// Checks for any existing portal config files and archives them - /// - static void ArchiveExistingPortalConfigs() - { - var filePath = Global.FilePathPrefix + Global.ConfigFileName; - - var configFiles = ConfigReader.GetConfigFiles(filePath); - - if (configFiles != null) - { - Debug.LogMessage(LogEventLevel.Information, "Existing config files found. Moving to Archive folder."); - - OnStatusUpdate(eUpdateStatus.ArchivingConfigs); - - MoveFilesToArchiveFolder(configFiles); - } - else - { - Debug.LogMessage(LogEventLevel.Information, "No Existing config files found in '{0}'. Nothing to archive", filePath); - } - } - - /// - /// Checks for presence of archive folder and if found deletes contents. - /// Moves any config files to the archive folder and adds a .bak suffix - /// - /// - static void MoveFilesToArchiveFolder(FileInfo[] files) - { - string archiveDirectoryPath = Global.FilePathPrefix + "archive"; - - if (!Directory.Exists(archiveDirectoryPath)) - { - // Directory does not exist, create it - Directory.Create(archiveDirectoryPath); - } - else - { - // Directory exists, first clear any contents - var archivedConfigFiles = ConfigReader.GetConfigFiles(archiveDirectoryPath + Global.DirectorySeparator + Global.ConfigFileName + ".bak"); - - if(archivedConfigFiles != null || archivedConfigFiles.Length > 0) - { - Debug.LogMessage(LogEventLevel.Information, "{0} Existing files found in archive folder. Deleting.", archivedConfigFiles.Length); - - for (int i = 0; i < archivedConfigFiles.Length; i++ ) - { - var file = archivedConfigFiles[i]; - Debug.LogMessage(LogEventLevel.Information, "Deleting archived file: '{0}'", file.FullName); - file.Delete(); + { + Debug.LogMessage(LogEventLevel.Information, "Config Update Process Stopped. Failed to get config file from server: {0}", r.Code); + OnStatusUpdate(eUpdateStatus.UpdateFailed); + } } - } + else + Debug.LogMessage(LogEventLevel.Information, "Request for config from Server Failed: {0}", e); + }); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, "Error Getting Config from Server: {0}", e); + } - } + } - // Move any files from the program folder to the archive folder - foreach (var file in files) + static void OnStatusUpdate(eUpdateStatus status) + { + var handler = ConfigStatusChanged; + + if(handler != null) + { + handler(typeof(ConfigUpdater), new ConfigStatusEventArgs(status)); + } + } + + static void WriteConfigToFile(string configData) + { + var filePath = Global.FilePathPrefix+ "configurationFile-updated.json"; + + try + { + var config = JObject.Parse(configData).ToObject(); + + ConfigWriter.WriteFile(filePath, configData); + + OnStatusUpdate(eUpdateStatus.WritingConfigFile); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, "Error parsing new config: {0}", e); + + OnStatusUpdate(eUpdateStatus.UpdateFailed); + } + } + + /// + /// Checks for any existing portal config files and archives them + /// + static void ArchiveExistingPortalConfigs() + { + var filePath = Global.FilePathPrefix + Global.ConfigFileName; + + var configFiles = ConfigReader.GetConfigFiles(filePath); + + if (configFiles != null) + { + Debug.LogMessage(LogEventLevel.Information, "Existing config files found. Moving to Archive folder."); + + OnStatusUpdate(eUpdateStatus.ArchivingConfigs); + + MoveFilesToArchiveFolder(configFiles); + } + else + { + Debug.LogMessage(LogEventLevel.Information, "No Existing config files found in '{0}'. Nothing to archive", filePath); + } + } + + /// + /// Checks for presence of archive folder and if found deletes contents. + /// Moves any config files to the archive folder and adds a .bak suffix + /// + /// + static void MoveFilesToArchiveFolder(FileInfo[] files) + { + string archiveDirectoryPath = Global.FilePathPrefix + "archive"; + + if (!Directory.Exists(archiveDirectoryPath)) + { + // Directory does not exist, create it + Directory.Create(archiveDirectoryPath); + } + else + { + // Directory exists, first clear any contents + var archivedConfigFiles = ConfigReader.GetConfigFiles(archiveDirectoryPath + Global.DirectorySeparator + Global.ConfigFileName + ".bak"); + + if(archivedConfigFiles != null || archivedConfigFiles.Length > 0) { - Debug.LogMessage(LogEventLevel.Information, "Moving config file '{0}' to archive folder", file.FullName); + Debug.LogMessage(LogEventLevel.Information, "{0} Existing files found in archive folder. Deleting.", archivedConfigFiles.Length); - // Moves the file and appends the .bak extension - var fileDest = archiveDirectoryPath + "/" + file.Name + ".bak"; - if(!File.Exists(fileDest)) + for (int i = 0; i < archivedConfigFiles.Length; i++ ) { - file.MoveTo(fileDest); + var file = archivedConfigFiles[i]; + Debug.LogMessage(LogEventLevel.Information, "Deleting archived file: '{0}'", file.FullName); + file.Delete(); } - else - Debug.LogMessage(LogEventLevel.Information, "Cannot move file to archive folder. Existing file already exists with same name: '{0}'", fileDest); } + } - /// - /// Checks for LocalConfig folder in file system and deletes if found - /// - static void CheckForLocalConfigAndDelete() + // Move any files from the program folder to the archive folder + foreach (var file in files) { - var folderPath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder; + Debug.LogMessage(LogEventLevel.Information, "Moving config file '{0}' to archive folder", file.FullName); - if (Directory.Exists(folderPath)) + // Moves the file and appends the .bak extension + var fileDest = archiveDirectoryPath + "/" + file.Name + ".bak"; + if(!File.Exists(fileDest)) { - OnStatusUpdate(eUpdateStatus.DeletingLocalConfig); - Directory.Delete(folderPath); - Debug.LogMessage(LogEventLevel.Information, "Local Config Found in '{0}'. Deleting.", folderPath); + file.MoveTo(fileDest); } + else + Debug.LogMessage(LogEventLevel.Information, "Cannot move file to archive folder. Existing file already exists with same name: '{0}'", fileDest); } - - /// - /// Connects to the processor via SSH and restarts the program - /// - static void RestartProgram() - { - Debug.LogMessage(LogEventLevel.Information, "Attempting to Reset Program"); - - OnStatusUpdate(eUpdateStatus.RestartingProgram); - - string response = string.Empty; - - CrestronConsole.SendControlSystemCommand(string.Format("progreset -p:{0}", InitialParametersClass.ApplicationNumber), ref response); - - Debug.LogMessage(LogEventLevel.Debug, "Console Response: {0}", response); - } - } - public enum eUpdateStatus + /// + /// Checks for LocalConfig folder in file system and deletes if found + /// + static void CheckForLocalConfigAndDelete() { - UpdateStarted, - ConfigFileReceived, - ArchivingConfigs, - DeletingLocalConfig, - WritingConfigFile, - RestartingProgram, - UpdateSucceeded, - UpdateFailed + var folderPath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder; + + if (Directory.Exists(folderPath)) + { + OnStatusUpdate(eUpdateStatus.DeletingLocalConfig); + Directory.Delete(folderPath); + Debug.LogMessage(LogEventLevel.Information, "Local Config Found in '{0}'. Deleting.", folderPath); + } } - public class ConfigStatusEventArgs : EventArgs + /// + /// Connects to the processor via SSH and restarts the program + /// + static void RestartProgram() { - public eUpdateStatus UpdateStatus { get; private set; } + Debug.LogMessage(LogEventLevel.Information, "Attempting to Reset Program"); - public ConfigStatusEventArgs(eUpdateStatus status) - { - UpdateStatus = status; - } + OnStatusUpdate(eUpdateStatus.RestartingProgram); + + string response = string.Empty; + + CrestronConsole.SendControlSystemCommand(string.Format("progreset -p:{0}", InitialParametersClass.ApplicationNumber), ref response); + + Debug.LogMessage(LogEventLevel.Debug, "Console Response: {0}", response); + } + +} + + public enum eUpdateStatus +{ + UpdateStarted, + ConfigFileReceived, + ArchivingConfigs, + DeletingLocalConfig, + WritingConfigFile, + RestartingProgram, + UpdateSucceeded, + UpdateFailed +} + +public class ConfigStatusEventArgs : EventArgs +{ + public eUpdateStatus UpdateStatus { get; private set; } + + public ConfigStatusEventArgs(eUpdateStatus status) + { + UpdateStatus = status; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs index 58ced97e..a688b378 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs @@ -11,155 +11,154 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config +namespace PepperDash.Essentials.Core.Config; + +/// +/// Responsible for updating config at runtime, and writing the updates out to a local file +/// +public class ConfigWriter { - /// - /// Responsible for updating config at runtime, and writing the updates out to a local file - /// - public class ConfigWriter - { - public const string LocalConfigFolder = "LocalConfig"; + public const string LocalConfigFolder = "LocalConfig"; - public const long WriteTimeout = 30000; + public const long WriteTimeout = 30000; - public static CTimer WriteTimer; + public static CTimer WriteTimer; static CCriticalSection fileLock = new CCriticalSection(); - /// - /// Updates the config properties of a device - /// - /// - /// - /// - public static bool UpdateDeviceProperties(string deviceKey, JToken properties) + /// + /// Updates the config properties of a device + /// + /// + /// + /// + public static bool UpdateDeviceProperties(string deviceKey, JToken properties) + { + bool success = false; + + // Get the current device config + var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey)); + + if (deviceConfig != null) { - bool success = false; + // Replace the current properties JToken with the new one passed into this method + deviceConfig.Properties = properties; - // Get the current device config - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey)); + Debug.LogMessage(LogEventLevel.Debug, "Updated properties of device: '{0}'", deviceKey); - if (deviceConfig != null) - { - // Replace the current properties JToken with the new one passed into this method - deviceConfig.Properties = properties; - - Debug.LogMessage(LogEventLevel.Debug, "Updated properties of device: '{0}'", deviceKey); - - success = true; - } - - ResetTimer(); - - return success; + success = true; } - public static bool UpdateDeviceConfig(DeviceConfig config) + ResetTimer(); + + return success; + } + + public static bool UpdateDeviceConfig(DeviceConfig config) + { + bool success = false; + + var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key)); + + if (deviceConfigIndex >= 0) { - bool success = false; + ConfigReader.ConfigObject.Devices[deviceConfigIndex] = config; - var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key)); + Debug.LogMessage(LogEventLevel.Debug, "Updated config of device: '{0}'", config.Key); - if (deviceConfigIndex >= 0) - { - ConfigReader.ConfigObject.Devices[deviceConfigIndex] = config; - - Debug.LogMessage(LogEventLevel.Debug, "Updated config of device: '{0}'", config.Key); - - success = true; - } - - ResetTimer(); - - return success; + success = true; } - public static bool UpdateRoomConfig(DeviceConfig config) - { - bool success = false; + ResetTimer(); + + return success; + } + + public static bool UpdateRoomConfig(DeviceConfig config) + { + bool success = false; var roomConfigIndex = ConfigReader.ConfigObject.Rooms.FindIndex(d => d.Key.Equals(config.Key)); if (roomConfigIndex >= 0) - { - ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config; - - Debug.LogMessage(LogEventLevel.Debug, "Updated room of device: '{0}'", config.Key); - - success = true; - } - - ResetTimer(); - - return success; - } - - /// - /// Resets (or starts) the write timer - /// - static void ResetTimer() { - if (WriteTimer == null) - WriteTimer = new CTimer(WriteConfigFile, WriteTimeout); + ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config; - WriteTimer.Reset(WriteTimeout); + Debug.LogMessage(LogEventLevel.Debug, "Updated room of device: '{0}'", config.Key); - Debug.LogMessage(LogEventLevel.Debug, "Config File write timer has been reset."); - } - - /// - /// Writes the current config to a file in the LocalConfig subfolder - /// - /// - private static void WriteConfigFile(object o) - { - var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json"; - - var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject); - - WriteFile(filePath, configData); - } - - /// - /// Writes - /// - /// - /// - public static void WriteFile(string filePath, string configData) - { - if (WriteTimer != null) - WriteTimer.Stop(); - - Debug.LogMessage(LogEventLevel.Information, "Writing Configuration to file"); - - Debug.LogMessage(LogEventLevel.Information, "Attempting to write config file: '{0}'", filePath); - - try - { - if (fileLock.TryEnter()) - { - using (StreamWriter sw = new StreamWriter(filePath)) - { - sw.Write(configData); - sw.Flush(); - } - } - else - { - Debug.LogMessage(LogEventLevel.Information, "Unable to enter FileLock"); - } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Information, "Error: Config write failed: \r{0}", e); - } - finally - { - if (fileLock != null && !fileLock.Disposed) - fileLock.Leave(); - - } + success = true; } + ResetTimer(); + return success; } + + /// + /// Resets (or starts) the write timer + /// + static void ResetTimer() + { + if (WriteTimer == null) + WriteTimer = new CTimer(WriteConfigFile, WriteTimeout); + + WriteTimer.Reset(WriteTimeout); + + Debug.LogMessage(LogEventLevel.Debug, "Config File write timer has been reset."); + } + + /// + /// Writes the current config to a file in the LocalConfig subfolder + /// + /// + private static void WriteConfigFile(object o) + { + var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json"; + + var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject); + + WriteFile(filePath, configData); + } + + /// + /// Writes + /// + /// + /// + public static void WriteFile(string filePath, string configData) + { + if (WriteTimer != null) + WriteTimer.Stop(); + + Debug.LogMessage(LogEventLevel.Information, "Writing Configuration to file"); + + Debug.LogMessage(LogEventLevel.Information, "Attempting to write config file: '{0}'", filePath); + + try + { + if (fileLock.TryEnter()) + { + using (StreamWriter sw = new StreamWriter(filePath)) + { + sw.Write(configData); + sw.Flush(); + } + } + else + { + Debug.LogMessage(LogEventLevel.Information, "Unable to enter FileLock"); + } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Information, "Error: Config write failed: \r{0}", e); + } + finally + { + if (fileLock != null && !fileLock.Disposed) + fileLock.Leave(); + + } + } + + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs b/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs index b42ec94c..bab6ae1d 100644 --- a/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs @@ -9,25 +9,25 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Loads the ConfigObject from the file /// public class EssentialsConfig : BasicConfig { [JsonProperty("system_url")] - public string SystemUrl { get; set; } + public string SystemUrl { get; set; } [JsonProperty("template_url")] - public string TemplateUrl { get; set; } + public string TemplateUrl { get; set; } [JsonProperty("systemUuid")] public string SystemUuid + { + get { - get - { if (string.IsNullOrEmpty(SystemUrl)) return "missing url"; @@ -38,18 +38,18 @@ namespace PepperDash.Essentials.Core.Config return uuid; } else { - var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*"); - string uuid = result.Groups[1].Value; - return uuid; - } + var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*"); + string uuid = result.Groups[1].Value; + return uuid; } } + } [JsonProperty("templateUuid")] public string TemplateUuid + { + get { - get - { if (string.IsNullOrEmpty(TemplateUrl)) return "missing template url"; @@ -60,22 +60,22 @@ namespace PepperDash.Essentials.Core.Config return uuid; } else { - var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*"); - string uuid = result.Groups[2].Value; - return uuid; - } + var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*"); + string uuid = result.Groups[2].Value; + return uuid; } } + } [JsonProperty("rooms")] - public List Rooms { get; set; } + public List Rooms { get; set; } - public EssentialsConfig() - : base() - { - Rooms = new List(); - } + public EssentialsConfig() + : base() + { + Rooms = new List(); + } } /// @@ -86,5 +86,4 @@ namespace PepperDash.Essentials.Core.Config public EssentialsConfig System { get; set; } public EssentialsConfig Template { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs b/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs index 00bbf5f6..a02baa8c 100644 --- a/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/ILoadConfig.cs @@ -4,10 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface ILoadConfig { - public interface ILoadConfig - { - void GoWithLoad(); - } + void GoWithLoad(); } diff --git a/src/PepperDash.Essentials.Core/Config/InfoConfig.cs b/src/PepperDash.Essentials.Core/Config/InfoConfig.cs index 12ca49f4..95b7860e 100644 --- a/src/PepperDash.Essentials.Core/Config/InfoConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/InfoConfig.cs @@ -5,12 +5,12 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Config -{ - /// - /// Represents the info section of a Config file - /// - public class InfoConfig +namespace PepperDash.Essentials.Core.Config; + +/// +/// Represents the info section of a Config file +/// +public class InfoConfig { [JsonProperty("name")] public string Name { get; set; } @@ -24,17 +24,17 @@ namespace PepperDash.Essentials.Core.Config [JsonProperty("version")] public string Version { get; set; } - [JsonProperty("runtimeInfo")] - public RuntimeInfo RuntimeInfo { get; set; } + [JsonProperty("runtimeInfo")] + public RuntimeInfo RuntimeInfo { get; set; } [JsonProperty("comment")] public string Comment { get; set; } - [JsonProperty("hostname")] - public string HostName { get; set; } + [JsonProperty("hostname")] + public string HostName { get; set; } - [JsonProperty("appNumber")] - public uint AppNumber { get; set; } + [JsonProperty("appNumber")] + public uint AppNumber { get; set; } public InfoConfig() { @@ -43,49 +43,49 @@ namespace PepperDash.Essentials.Core.Config Type = ""; Version = ""; Comment = ""; - HostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - AppNumber = InitialParametersClass.ApplicationNumber; + HostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + AppNumber = InitialParametersClass.ApplicationNumber; - RuntimeInfo = new RuntimeInfo(); + RuntimeInfo = new RuntimeInfo(); } } - + +/// +/// Represents runtime information about the program/processor +/// +public class RuntimeInfo +{ /// - /// Represents runtime information about the program/processor + /// The name of the running application /// - public class RuntimeInfo - { - /// - /// The name of the running application - /// - [JsonProperty("appName")] - public string AppName {get; set;} - //{ - // get - // { - // return Assembly.GetExecutingAssembly().GetName().Name; - // } - //} + [JsonProperty("appName")] + public string AppName {get; set;} + //{ + // get + // { + // return Assembly.GetExecutingAssembly().GetName().Name; + // } + //} - /// - /// The Assembly version of the running application - /// - [JsonProperty("assemblyVersion")] - public string AssemblyVersion {get; set;} - //{ - // get - // { - // var version = Assembly.GetExecutingAssembly().GetName().Version; - // return string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); - // } - //} + /// + /// The Assembly version of the running application + /// + [JsonProperty("assemblyVersion")] + public string AssemblyVersion {get; set;} + //{ + // get + // { + // var version = Assembly.GetExecutingAssembly().GetName().Version; + // return string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); + // } + //} - /// , - /// The OS Version of the processor (Firmware Version) - /// - [JsonProperty("osVersion")] - public string OsVersion {get; set;} + /// , + /// The OS Version of the processor (Firmware Version) + /// + [JsonProperty("osVersion")] + public string OsVersion {get; set;} //{ // get // { @@ -93,17 +93,15 @@ namespace PepperDash.Essentials.Core.Config // } //} - /// - /// The information gathered by the processor at runtime about it's NICs and their IP addresses. - /// - [JsonProperty("ipInfo")] - public Dictionary IpInfo + /// + /// The information gathered by the processor at runtime about it's NICs and their IP addresses. + /// + [JsonProperty("ipInfo")] + public Dictionary IpInfo + { + get { - get - { - return Global.EthernetAdapterInfoCollection; - } + return Global.EthernetAdapterInfoCollection; } } - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs b/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs index e6d13339..cc02289c 100644 --- a/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs +++ b/src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs @@ -4,10 +4,9 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + public class SourceDevicePropertiesConfigBase { public bool DisableSharing { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs b/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs index ce543885..8ad90b14 100644 --- a/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs +++ b/src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs @@ -7,16 +7,16 @@ using PepperDash.Core.JsonStandardObjects; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public abstract class CrestronGenericBaseDevice : EssentialsDevice, IOnline, IHasFeedback, ICommunicationMonitor, IUsageTracking { protected GenericBase Hardware; - /// - /// Returns a list containing the Outputs that we want to expose. - /// - public FeedbackCollection Feedbacks { get; private set; } + /// + /// Returns a list containing the Outputs that we want to expose. + /// + public FeedbackCollection Feedbacks { get; private set; } public BoolFeedback IsOnline { get; private set; } public BoolFeedback IsRegistered { get; private set; } @@ -29,35 +29,35 @@ namespace PepperDash.Essentials.Core public bool PreventRegistration { get; protected set; } protected CrestronGenericBaseDevice(string key, string name, GenericBase hardware) - : base(key, name) - { - Feedbacks = new FeedbackCollection(); + : base(key, name) + { + Feedbacks = new FeedbackCollection(); - Hardware = hardware; - IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline); - IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered); - IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty); - AddToFeedbackList(IsOnline, IpConnectionsText); + Hardware = hardware; + IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline); + IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered); + IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty); + AddToFeedbackList(IsOnline, IpConnectionsText); - CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); - } + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); + } - protected CrestronGenericBaseDevice(string key, string name) - : base(key, name) - { - Feedbacks = new FeedbackCollection(); + protected CrestronGenericBaseDevice(string key, string name) + : base(key, name) + { + Feedbacks = new FeedbackCollection(); - } + } protected void RegisterCrestronGenericBase(GenericBase hardware) { - Hardware = hardware; - IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline); - IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered); - IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty); - AddToFeedbackList(IsOnline, IpConnectionsText); + Hardware = hardware; + IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline); + IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered); + IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty); + AddToFeedbackList(IsOnline, IpConnectionsText); - CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); } /// @@ -66,43 +66,43 @@ namespace PepperDash.Essentials.Core /// public override bool CustomActivate() { - Debug.LogMessage(LogEventLevel.Information, this, "Activating"); - if (!PreventRegistration) - { - //Debug.LogMessage(LogEventLevel.Debug, this, " Does not require registration. Skipping"); + Debug.LogMessage(LogEventLevel.Information, this, "Activating"); + if (!PreventRegistration) + { + //Debug.LogMessage(LogEventLevel.Debug, this, " Does not require registration. Skipping"); - if (Hardware.Registerable && !Hardware.Registered) + if (Hardware.Registerable && !Hardware.Registered) + { + var response = Hardware.RegisterWithLogging(Key); + if (response != eDeviceRegistrationUnRegistrationResponse.Success) { - var response = Hardware.RegisterWithLogging(Key); - if (response != eDeviceRegistrationUnRegistrationResponse.Success) - { - //Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Crestron device: {0}", response); - return false; - } + //Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Crestron device: {0}", response); + return false; } - - IsRegistered.FireUpdate(); } - else - { - AddPostActivationAction(() => + + IsRegistered.FireUpdate(); + } + else + { + AddPostActivationAction(() => + { + if (Hardware.Registerable && !Hardware.Registered) { - if (Hardware.Registerable && !Hardware.Registered) - { - var response = Hardware.RegisterWithLogging(Key); - } + var response = Hardware.RegisterWithLogging(Key); + } - IsRegistered.FireUpdate(); - }); - } + IsRegistered.FireUpdate(); + }); + } - foreach (var f in Feedbacks) - { - f.FireUpdate(); - } + foreach (var f in Feedbacks) + { + f.FireUpdate(); + } - Hardware.OnlineStatusChange += Hardware_OnlineStatusChange; - CommunicationMonitor.Start(); + Hardware.OnlineStatusChange += Hardware_OnlineStatusChange; + CommunicationMonitor.Start(); return base.CustomActivate(); } @@ -118,42 +118,42 @@ namespace PepperDash.Essentials.Core var success = Hardware.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success; - IsRegistered.FireUpdate(); + IsRegistered.FireUpdate(); - return success; + return success; } /// - /// Adds feedback(s) to the list - /// - /// - public void AddToFeedbackList(params Feedback[] newFbs) + /// Adds feedback(s) to the list + /// + /// + public void AddToFeedbackList(params Feedback[] newFbs) + { + foreach (var f in newFbs) { - foreach (var f in newFbs) - { - if (f == null) continue; + if (f == null) continue; - if (!Feedbacks.Contains(f)) - { - Feedbacks.Add(f); - } + if (!Feedbacks.Contains(f)) + { + Feedbacks.Add(f); } } + } void Hardware_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) { - Debug.LogMessage(LogEventLevel.Verbose, this, "OnlineStatusChange Event. Online = {0}", args.DeviceOnLine); + Debug.LogMessage(LogEventLevel.Verbose, this, "OnlineStatusChange Event. Online = {0}", args.DeviceOnLine); - if (!Hardware.Registered) - { - return; // protects in cases where device has been unregistered and feedbacks would attempt to access null sigs. - } + if (!Hardware.Registered) + { + return; // protects in cases where device has been unregistered and feedbacks would attempt to access null sigs. + } - foreach (var feedback in Feedbacks) - { - if (feedback != null) - feedback.FireUpdate(); - } + foreach (var feedback in Feedbacks) + { + if (feedback != null) + feedback.FireUpdate(); + } } #region IStatusMonitor Members @@ -161,28 +161,28 @@ namespace PepperDash.Essentials.Core public StatusMonitorBase CommunicationMonitor { get; private set; } #endregion - #region IUsageTracking Members + #region IUsageTracking Members - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } - #endregion + #endregion } - public abstract class CrestronGenericBridgeableBaseDevice : CrestronGenericBaseDevice, IBridgeAdvanced +public abstract class CrestronGenericBridgeableBaseDevice : CrestronGenericBaseDevice, IBridgeAdvanced +{ + protected CrestronGenericBridgeableBaseDevice(string key, string name, GenericBase hardware) : base(key, name, hardware) { - protected CrestronGenericBridgeableBaseDevice(string key, string name, GenericBase hardware) : base(key, name, hardware) - { - } - - protected CrestronGenericBridgeableBaseDevice(string key, string name) - : base(key, name) - { - } - - - public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } + protected CrestronGenericBridgeableBaseDevice(string key, string name) + : base(key, name) + { + } + + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); +} + //*********************************************************************************** public class CrestronGenericBaseDeviceEventIds @@ -208,5 +208,4 @@ namespace PepperDash.Essentials.Core return result; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs index a5923011..34b36371 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs @@ -14,155 +14,152 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +[Description("Wrapper class for Digital Input")] +public class GenericDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput { - [Description("Wrapper class for Digital Input")] - public class GenericDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput + public DigitalInput InputPort { get; private set; } + + public BoolFeedback InputStateFeedback { get; private set; } + + Func InputStateFeedbackFunc { - public DigitalInput InputPort { get; private set; } - - public BoolFeedback InputStateFeedback { get; private set; } - - Func InputStateFeedbackFunc + get { - get - { - return () => InputPort.State; - } + return () => InputPort.State; } - - - public GenericDigitalInputDevice(string key, string name, Func postActivationFunc, - IOPortConfig config) - : base(key, name) - { - InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); - - AddPostActivationAction(() => - { - InputPort = postActivationFunc(config); - - InputPort.Register(); - - InputPort.StateChange += InputPort_StateChange; - - }); - } - - #region Events - - void InputPort_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) - { - InputStateFeedback.FireUpdate(); - } - - #endregion - - #region PreActivate - - private static DigitalInput GetDigitalInput(IOPortConfig dc) - { - IDigitalInputPorts ioPortDevice; - - if (dc.PortDeviceKey.Equals("processor")) - { - if (!Global.ControlSystem.SupportsDigitalInput) - { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Processor does not support Digital Inputs"); - return null; - } - ioPortDevice = Global.ControlSystem; - } - else - { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IDigitalInputPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device '0' is not a valid IDigitalInputPorts Device", dc.PortDeviceKey); - return null; - } - - if (dc.PortNumber > ioPortDevice.NumberOfDigitalInputPorts) - { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - } - - return ioPortDevice.DigitalInputPorts[dc.PortNumber]; - - - } - - #endregion - - #region Bridge Linking - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new IDigitalInputJoinMap(joinStart); - - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(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."); - } - - try - { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - - // Link feedback for input state - InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); - } - } - - #endregion - - #region Factory - - public class GenericDigitalInputDeviceFactory : EssentialsDeviceFactory - { - public GenericDigitalInputDeviceFactory() - { - TypeNames = new List() { "digitalinput" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Digital Input Device"); - - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); - - if (props == null) return null; - - var portDevice = new GenericDigitalInputDevice(dc.Key, dc.Name, GetDigitalInput, props); - - return portDevice; - } - } - - #endregion - } + public GenericDigitalInputDevice(string key, string name, Func postActivationFunc, + IOPortConfig config) + : base(key, name) + { + InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); + + AddPostActivationAction(() => + { + InputPort = postActivationFunc(config); + + InputPort.Register(); + + InputPort.StateChange += InputPort_StateChange; + + }); + } + + #region Events + + void InputPort_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) + { + InputStateFeedback.FireUpdate(); + } + + #endregion + + #region PreActivate + + private static DigitalInput GetDigitalInput(IOPortConfig dc) + { + IDigitalInputPorts ioPortDevice; + + if (dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsDigitalInput) + { + Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Processor does not support Digital Inputs"); + return null; + } + ioPortDevice = Global.ControlSystem; + } + else + { + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IDigitalInputPorts; + if (ioPortDev == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device {0} is not a valid device", dc.PortDeviceKey); + return null; + } + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device '0' is not a valid IDigitalInputPorts Device", dc.PortDeviceKey); + return null; + } + + if (dc.PortNumber > ioPortDevice.NumberOfDigitalInputPorts) + { + Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + } + + return ioPortDevice.DigitalInputPorts[dc.PortNumber]; + + + } + + #endregion + + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new IDigitalInputJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); + } + + try + { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + // Link feedback for input state + InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } + } + + #endregion + + #region Factory + + public class GenericDigitalInputDeviceFactory : EssentialsDeviceFactory + { + public GenericDigitalInputDeviceFactory() + { + TypeNames = new List() { "digitalinput" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Digital Input Device"); + + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + if (props == null) return null; + + var portDevice = new GenericDigitalInputDevice(dc.Key, dc.Name, GetDigitalInput, props); + + return portDevice; + } + } + + #endregion + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs index 2bc2c50b..15dfcd36 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs @@ -13,212 +13,209 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a generic device controlled by relays +/// +[Description("Wrapper class for a Relay")] +public class GenericRelayDevice : EssentialsBridgeableDevice, ISwitchedOutput { - /// - /// Represents a generic device controlled by relays - /// - [Description("Wrapper class for a Relay")] - public class GenericRelayDevice : EssentialsBridgeableDevice, ISwitchedOutput + public Relay RelayOutput { get; private set; } + + public BoolFeedback OutputIsOnFeedback { get; private set; } + + //Maintained for compatibility with PepperDash.Essentials.Core.Devices.CrestronProcessor + public GenericRelayDevice(string key, Relay relay) : + base(key) { - public Relay RelayOutput { get; private set; } + OutputIsOnFeedback = new BoolFeedback(new Func(() => RelayOutput.State)); - public BoolFeedback OutputIsOnFeedback { get; private set; } + RelayOutput = relay; + RelayOutput.Register(); - //Maintained for compatibility with PepperDash.Essentials.Core.Devices.CrestronProcessor - public GenericRelayDevice(string key, Relay relay) : - base(key) + RelayOutput.StateChange += RelayOutput_StateChange; + } + + public GenericRelayDevice(string key, string name, Func postActivationFunc, + IOPortConfig config) + : base(key, name) + { + OutputIsOnFeedback = new BoolFeedback(() => RelayOutput.State); + + AddPostActivationAction(() => { - OutputIsOnFeedback = new BoolFeedback(new Func(() => RelayOutput.State)); - - RelayOutput = relay; - RelayOutput.Register(); - - RelayOutput.StateChange += RelayOutput_StateChange; - } - - public GenericRelayDevice(string key, string name, Func postActivationFunc, - IOPortConfig config) - : base(key, name) - { - OutputIsOnFeedback = new BoolFeedback(() => RelayOutput.State); - - AddPostActivationAction(() => - { - RelayOutput = postActivationFunc(config); - - if (RelayOutput == null) - { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to get parent relay device for device key {0} and port {1}", config.PortDeviceKey, config.PortNumber); - return; - } - - RelayOutput.Register(); - - RelayOutput.StateChange += RelayOutput_StateChange; - }); - } - - #region PreActivate - - private static Relay GetRelay(IOPortConfig dc) - { - - IRelayPorts relayDevice; - - if(dc.PortDeviceKey.Equals("processor")) - { - if (!Global.ControlSystem.SupportsRelay) - { - Debug.LogMessage(LogEventLevel.Information, "Processor does not support relays"); - return null; - } - relayDevice = Global.ControlSystem; - - return relayDevice.RelayPorts[dc.PortNumber]; - } - - var essentialsDevice = DeviceManager.GetDeviceForKey(dc.PortDeviceKey); - if (essentialsDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "Device {0} was not found in Device Manager. Check configuration or for errors with device.", dc.PortDeviceKey); - return null; - } - - relayDevice = essentialsDevice as IRelayPorts; - - if (relayDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "Device {0} is not a valid relay parent. Please check configuration.", dc.PortDeviceKey); - return null; - } - - if (dc.PortNumber <= relayDevice.NumberOfRelayPorts) - { - return relayDevice.RelayPorts[dc.PortNumber]; - } - - Debug.LogMessage(LogEventLevel.Information, "Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - return null; - } - - #endregion - - #region Events - - void RelayOutput_StateChange(Relay relay, RelayEventArgs args) - { - OutputIsOnFeedback.FireUpdate(); - } - - #endregion - - #region Methods - - public void OpenRelay() - { - RelayOutput.State = false; - } - - public void CloseRelay() - { - RelayOutput.State = true; - } - - public void ToggleRelayState() - { - if (RelayOutput.State == true) - OpenRelay(); - else - CloseRelay(); - } - - #endregion - - #region ISwitchedOutput Members - - void ISwitchedOutput.On() - { - CloseRelay(); - } - - void ISwitchedOutput.Off() - { - OpenRelay(); - } - - #endregion - - #region Bridge Linking - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new GenericRelayControllerJoinMap(joinStart); - - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(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."); - } + RelayOutput = postActivationFunc(config); if (RelayOutput == null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Relay is null", Key); + Debug.LogMessage(LogEventLevel.Information, this, "Unable to get parent relay device for device key {0} and port {1}", config.PortDeviceKey, config.PortNumber); return; } - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - - trilist.SetBoolSigAction(joinMap.Relay.JoinNumber, b => - { - if (b) - CloseRelay(); - else - OpenRelay(); - }); - - // feedback for relay state - - OutputIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Relay.JoinNumber]); - } - - #endregion - - #region Factory - - public class GenericRelayDeviceFactory : EssentialsDeviceFactory - { - public GenericRelayDeviceFactory() - { - TypeNames = new List() { "relayoutput" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Relay Device"); - - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); - - if (props == null) return null; - - var portDevice = new GenericRelayDevice(dc.Key, dc.Name, GetRelay, props); - - return portDevice; - } - } - - #endregion - + RelayOutput.Register(); + RelayOutput.StateChange += RelayOutput_StateChange; + }); } + #region PreActivate + + private static Relay GetRelay(IOPortConfig dc) + { + + IRelayPorts relayDevice; + + if(dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsRelay) + { + Debug.LogMessage(LogEventLevel.Information, "Processor does not support relays"); + return null; + } + relayDevice = Global.ControlSystem; + + return relayDevice.RelayPorts[dc.PortNumber]; + } + + var essentialsDevice = DeviceManager.GetDeviceForKey(dc.PortDeviceKey); + if (essentialsDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "Device {0} was not found in Device Manager. Check configuration or for errors with device.", dc.PortDeviceKey); + return null; + } + + relayDevice = essentialsDevice as IRelayPorts; + + if (relayDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "Device {0} is not a valid relay parent. Please check configuration.", dc.PortDeviceKey); + return null; + } + + if (dc.PortNumber <= relayDevice.NumberOfRelayPorts) + { + return relayDevice.RelayPorts[dc.PortNumber]; + } + + Debug.LogMessage(LogEventLevel.Information, "Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + return null; + } + + #endregion + + #region Events + + void RelayOutput_StateChange(Relay relay, RelayEventArgs args) + { + OutputIsOnFeedback.FireUpdate(); + } + + #endregion + + #region Methods + + public void OpenRelay() + { + RelayOutput.State = false; + } + + public void CloseRelay() + { + RelayOutput.State = true; + } + + public void ToggleRelayState() + { + if (RelayOutput.State == true) + OpenRelay(); + else + CloseRelay(); + } + + #endregion + + #region ISwitchedOutput Members + + void ISwitchedOutput.On() + { + CloseRelay(); + } + + void ISwitchedOutput.Off() + { + OpenRelay(); + } + + #endregion + + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new GenericRelayControllerJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); + } + + if (RelayOutput == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Relay is null", Key); + return; + } + + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + trilist.SetBoolSigAction(joinMap.Relay.JoinNumber, b => + { + if (b) + CloseRelay(); + else + OpenRelay(); + }); + + // feedback for relay state + + OutputIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Relay.JoinNumber]); + } + + #endregion + + #region Factory + + public class GenericRelayDeviceFactory : EssentialsDeviceFactory + { + public GenericRelayDeviceFactory() + { + TypeNames = new List() { "relayoutput" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Relay Device"); + + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + if (props == null) return null; + + var portDevice = new GenericRelayDevice(dc.Key, dc.Name, GetRelay, props); + + return portDevice; + } + } + + #endregion + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs index af83b3d6..42b83dfd 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs @@ -16,196 +16,195 @@ using PepperDash.Essentials.Core.Bridges; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a generic digital input deviced tied to a versiport +/// +public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput { - /// - /// Represents a generic digital input deviced tied to a versiport - /// - public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput + public Versiport InputPort { get; private set; } + + public IntFeedback InputValueFeedback { get; private set; } + public IntFeedback InputMinimumChangeFeedback { get; private set; } + + Func InputValueFeedbackFunc { - public Versiport InputPort { get; private set; } - - public IntFeedback InputValueFeedback { get; private set; } - public IntFeedback InputMinimumChangeFeedback { get; private set; } - - Func InputValueFeedbackFunc + get { - get - { - return () => InputPort.AnalogIn; - } + return () => InputPort.AnalogIn; } + } - Func InputMinimumChangeFeedbackFunc + Func InputMinimumChangeFeedbackFunc + { + get { return () => InputPort.AnalogMinChange; } + } + + public GenericVersiportAnalogInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : + base(key, name) + { + InputValueFeedback = new IntFeedback(InputValueFeedbackFunc); + InputMinimumChangeFeedback = new IntFeedback(InputMinimumChangeFeedbackFunc); + + AddPostActivationAction(() => { - get { return () => InputPort.AnalogMinChange; } - } + InputPort = postActivationFunc(config); - public GenericVersiportAnalogInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : - base(key, name) - { - InputValueFeedback = new IntFeedback(InputValueFeedbackFunc); - InputMinimumChangeFeedback = new IntFeedback(InputMinimumChangeFeedbackFunc); + InputPort.Register(); - AddPostActivationAction(() => - { - InputPort = postActivationFunc(config); + InputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput); + InputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655); + if (config.DisablePullUpResistor) + InputPort.DisablePullUpResistor = true; - InputPort.Register(); + InputPort.VersiportChange += InputPort_VersiportChange; - InputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput); - InputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655); - if (config.DisablePullUpResistor) - InputPort.DisablePullUpResistor = true; + Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportAnalogInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); - InputPort.VersiportChange += InputPort_VersiportChange; + }); - Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportAnalogInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); + } - }); + /// + /// Set minimum voltage change for device to update voltage changed method + /// + /// valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details + public void SetMinimumChange(ushort value) + { + InputPort.AnalogMinChange = value; + } - } - - /// - /// Set minimum voltage change for device to update voltage changed method - /// - /// valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details - public void SetMinimumChange(ushort value) - { - InputPort.AnalogMinChange = value; - } - - void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) - { + void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) + { Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); - if(args.Event == eVersiportEvent.AnalogInChange) - InputValueFeedback.FireUpdate(); - if (args.Event == eVersiportEvent.AnalogMinChangeChange) - InputMinimumChangeFeedback.FireUpdate(); - } - - - #region Bridge Linking - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new IAnalogInputJoinMap(joinStart); - - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(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."); - } - - try - { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - - // Link feedback for input state - InputValueFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputValue.JoinNumber]); - InputMinimumChangeFeedback.LinkInputSig(trilist.UShortInput[joinMap.MinimumChange.JoinNumber]); - trilist.SetUShortSigAction(joinMap.MinimumChange.JoinNumber, SetMinimumChange); - - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); - } - - trilist.OnlineStatusChange += (d, args) => - { - if (!args.DeviceOnLine) return; - InputValueFeedback.FireUpdate(); - InputMinimumChangeFeedback.FireUpdate(); - }; - - } - - void trilist_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) - { - throw new NotImplementedException(); - } - - #endregion - - - public static Versiport GetVersiportDigitalInput(IOPortConfig dc) - { - - IIOPorts ioPortDevice; - - if (dc.PortDeviceKey.Equals("processor")) - { - if (!Global.ControlSystem.SupportsVersiport) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Processor does not support Versiports"); - return null; - } - ioPortDevice = Global.ControlSystem; - } - else - { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); - return null; - } - - if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - return null; - } - if(!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} does not support AnalogInput on port {1}", dc.PortDeviceKey, dc.PortNumber); - return null; - } - - - return ioPortDevice.VersiPorts[dc.PortNumber]; - - - } + if(args.Event == eVersiportEvent.AnalogInChange) + InputValueFeedback.FireUpdate(); + if (args.Event == eVersiportEvent.AnalogMinChangeChange) + InputMinimumChangeFeedback.FireUpdate(); } - public class GenericVersiportAbalogInputDeviceFactory : EssentialsDeviceFactory + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { - public GenericVersiportAbalogInputDeviceFactory() + var joinMap = new IAnalogInputJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + + if (bridge != null) { - TypeNames = new List() { "versiportanaloginput" }; + 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."); } - public override EssentialsDevice BuildDevice(DeviceConfig dc) + try { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + // Link feedback for input state + InputValueFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputValue.JoinNumber]); + InputMinimumChangeFeedback.LinkInputSig(trilist.UShortInput[joinMap.MinimumChange.JoinNumber]); + trilist.SetUShortSigAction(joinMap.MinimumChange.JoinNumber, SetMinimumChange); - if (props == null) return null; - - var portDevice = new GenericVersiportAnalogInputDevice(dc.Key, dc.Name, GenericVersiportAnalogInputDevice.GetVersiportDigitalInput, props); - - return portDevice; } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } + + trilist.OnlineStatusChange += (d, args) => + { + if (!args.DeviceOnLine) return; + InputValueFeedback.FireUpdate(); + InputMinimumChangeFeedback.FireUpdate(); + }; + + } + + void trilist_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) + { + throw new NotImplementedException(); + } + + #endregion + + + public static Versiport GetVersiportDigitalInput(IOPortConfig dc) + { + + IIOPorts ioPortDevice; + + if (dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsVersiport) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Processor does not support Versiports"); + return null; + } + ioPortDevice = Global.ControlSystem; + } + else + { + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; + if (ioPortDev == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} is not a valid device", dc.PortDeviceKey); + return null; + } + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); + return null; + } + + if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + return null; + } + if(!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} does not support AnalogInput on port {1}", dc.PortDeviceKey, dc.PortNumber); + return null; + } + + + return ioPortDevice.VersiPorts[dc.PortNumber]; + + + } +} + + +public class GenericVersiportAbalogInputDeviceFactory : EssentialsDeviceFactory +{ + public GenericVersiportAbalogInputDeviceFactory() + { + TypeNames = new List() { "versiportanaloginput" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + if (props == null) return null; + + var portDevice = new GenericVersiportAnalogInputDevice(dc.Key, dc.Name, GenericVersiportAnalogInputDevice.GetVersiportDigitalInput, props); + + return portDevice; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs index c9133a60..c71ffc50 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs @@ -16,165 +16,164 @@ using PepperDash.Essentials.Core.Bridges; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a generic digital input deviced tied to a versiport +/// +public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider { - /// - /// Represents a generic digital input deviced tied to a versiport - /// - public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider + public Versiport InputPort { get; private set; } + + public BoolFeedback InputStateFeedback { get; private set; } + + Func InputStateFeedbackFunc { - public Versiport InputPort { get; private set; } - - public BoolFeedback InputStateFeedback { get; private set; } - - Func InputStateFeedbackFunc + get { - get - { - return () => InputPort.DigitalIn; - } + return () => InputPort.DigitalIn; } + } - public BoolFeedback PartitionPresentFeedback { get; } + public BoolFeedback PartitionPresentFeedback { get; } - public bool PartitionPresent => !InputStateFeedbackFunc(); + public bool PartitionPresent => !InputStateFeedbackFunc(); - public GenericVersiportDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : - base(key, name) + public GenericVersiportDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : + base(key, name) + { + InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); + PartitionPresentFeedback = new BoolFeedback(() => !InputStateFeedbackFunc()); + + AddPostActivationAction(() => { - InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); - PartitionPresentFeedback = new BoolFeedback(() => !InputStateFeedbackFunc()); + InputPort = postActivationFunc(config); - AddPostActivationAction(() => - { - InputPort = postActivationFunc(config); + InputPort.Register(); - InputPort.Register(); + InputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); + if (config.DisablePullUpResistor) + InputPort.DisablePullUpResistor = true; - InputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); - if (config.DisablePullUpResistor) - InputPort.DisablePullUpResistor = true; + InputPort.VersiportChange += InputPort_VersiportChange; - InputPort.VersiportChange += InputPort_VersiportChange; + InputStateFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); - InputStateFeedback.FireUpdate(); - PartitionPresentFeedback.FireUpdate(); + Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportDigitalInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); - Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportDigitalInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); + }); - }); + } - } - - void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) - { + void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) + { Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); - if(args.Event == eVersiportEvent.DigitalInChange) - { - InputStateFeedback.FireUpdate(); - PartitionPresentFeedback.FireUpdate(); - } + if(args.Event == eVersiportEvent.DigitalInChange) + { + InputStateFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); + } + } + + + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new IDigitalInputJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); } - - #region Bridge Linking - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + try { - var joinMap = new IDigitalInputJoinMap(joinStart); + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(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."); - } - - try - { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - - // Link feedback for input state - InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); - } + // Link feedback for input state + InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); } - - #endregion - - - public static Versiport GetVersiportDigitalInput(IOPortConfig dc) + catch (Exception e) { - - IIOPorts ioPortDevice; + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } + } - if (dc.PortDeviceKey.Equals("processor")) + #endregion + + + public static Versiport GetVersiportDigitalInput(IOPortConfig dc) + { + + IIOPorts ioPortDevice; + + if (dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsVersiport) { - if (!Global.ControlSystem.SupportsVersiport) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Processor does not support Versiports"); - return null; - } - ioPortDevice = Global.ControlSystem; - } - else - { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Processor does not support Versiports"); return null; } - - if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - } - - return ioPortDevice.VersiPorts[dc.PortNumber]; - - + ioPortDevice = Global.ControlSystem; } + else + { + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; + if (ioPortDev == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device {0} is not a valid device", dc.PortDeviceKey); + return null; + } + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); + return null; + } + + if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + } + + return ioPortDevice.VersiPorts[dc.PortNumber]; + + + } +} + + +public class GenericVersiportDigitalInputDeviceFactory : EssentialsDeviceFactory +{ + public GenericVersiportDigitalInputDeviceFactory() + { + TypeNames = new List() { "versiportinput" }; } - - public class GenericVersiportDigitalInputDeviceFactory : EssentialsDeviceFactory + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - public GenericVersiportDigitalInputDeviceFactory() - { - TypeNames = new List() { "versiportinput" }; - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + if (props == null) return null; - if (props == null) return null; + var portDevice = new GenericVersiportDigitalInputDevice(dc.Key, dc.Name, GenericVersiportDigitalInputDevice.GetVersiportDigitalInput, props); - var portDevice = new GenericVersiportDigitalInputDevice(dc.Key, dc.Name, GenericVersiportDigitalInputDevice.GetVersiportDigitalInput, props); - - return portDevice; - } + return portDevice; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs index 030dc613..e2304baf 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs @@ -16,177 +16,176 @@ using PepperDash.Essentials.Core.Bridges; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a generic digital input deviced tied to a versiport +/// +public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput { - /// - /// Represents a generic digital input deviced tied to a versiport - /// - public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput + public Versiport OutputPort { get; private set; } + + public BoolFeedback OutputStateFeedback { get; private set; } + + Func OutputStateFeedbackFunc { - public Versiport OutputPort { get; private set; } - - public BoolFeedback OutputStateFeedback { get; private set; } - - Func OutputStateFeedbackFunc + get { - get + return () => OutputPort.DigitalOut; + } + } + + public GenericVersiportDigitalOutputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : + base(key, name) + { + OutputStateFeedback = new BoolFeedback(OutputStateFeedbackFunc); + + AddPostActivationAction(() => + { + OutputPort = postActivationFunc(config); + + OutputPort.Register(); + + + if (!OutputPort.SupportsDigitalOutput) { - return () => OutputPort.DigitalOut; + Debug.LogMessage(LogEventLevel.Information, this, "Device does not support configuration as a Digital Output"); + return; } - } - public GenericVersiportDigitalOutputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : - base(key, name) - { - OutputStateFeedback = new BoolFeedback(OutputStateFeedbackFunc); - - AddPostActivationAction(() => - { - OutputPort = postActivationFunc(config); - - OutputPort.Register(); + OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput); - if (!OutputPort.SupportsDigitalOutput) - { - Debug.LogMessage(LogEventLevel.Information, this, "Device does not support configuration as a Digital Output"); - return; - } + OutputPort.VersiportChange += OutputPort_VersiportChange; - OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput); + }); + } - OutputPort.VersiportChange += OutputPort_VersiportChange; - - }); - - } - - void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args) - { + void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args) + { Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); - if(args.Event == eVersiportEvent.DigitalOutChange) - OutputStateFeedback.FireUpdate(); - } + if(args.Event == eVersiportEvent.DigitalOutChange) + OutputStateFeedback.FireUpdate(); + } - /// - /// Set value of the versiport digital output - /// - /// value to set the output to - public void SetOutput(bool state) - { - if (OutputPort.SupportsDigitalOutput) - { - Debug.LogMessage(LogEventLevel.Information, this, "Passed the Check"); - - OutputPort.DigitalOut = state; - - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Versiport does not support Digital Output Mode"); - } - - } - - #region Bridge Linking - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new IDigitalOutputJoinMap(joinStart); - - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); - - if (bridge != null) + /// + /// Set value of the versiport digital output + /// + /// value to set the output to + public void SetOutput(bool state) + { + if (OutputPort.SupportsDigitalOutput) { - bridge.AddJoinMap(Key, joinMap); + Debug.LogMessage(LogEventLevel.Information, this, "Passed the Check"); + + OutputPort.DigitalOut = state; + } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + Debug.LogMessage(LogEventLevel.Information, this, "Versiport does not support Digital Output Mode"); } - try - { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + } - // Link feedback for input state - OutputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.OutputState.JoinNumber]); - trilist.SetBoolSigAction(joinMap.OutputState.JoinNumber, SetOutput); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); - } + #region Bridge Linking + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new IDigitalOutputJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); } - #endregion - - - public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) + try { + Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - IIOPorts ioPortDevice; + // Link feedback for input state + OutputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.OutputState.JoinNumber]); + trilist.SetBoolSigAction(joinMap.OutputState.JoinNumber, SetOutput); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); + Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + } + } - if (dc.PortDeviceKey.Equals("processor")) + #endregion + + + public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) + { + + IIOPorts ioPortDevice; + + if (dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsVersiport) { - if (!Global.ControlSystem.SupportsVersiport) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Processor does not support Versiports"); - return null; - } - ioPortDevice = Global.ControlSystem; - } - else - { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts Device", dc.PortDeviceKey); + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Processor does not support Versiports"); return null; } - - if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) + ioPortDevice = Global.ControlSystem; + } + else + { + var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; + if (ioPortDev == null) { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey); + return null; } - var port = ioPortDevice.VersiPorts[dc.PortNumber]; - return port; + ioPortDevice = ioPortDev; + } + if (ioPortDevice == null) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts Device", dc.PortDeviceKey); + return null; + } - } + if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + } + var port = ioPortDevice.VersiPorts[dc.PortNumber]; + return port; + + } +} + + +public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory +{ + public GenericVersiportDigitalOutputDeviceFactory() + { + TypeNames = new List() { "versiportoutput" }; } - - public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - public GenericVersiportDigitalOutputDeviceFactory() - { - TypeNames = new List() { "versiportoutput" }; - } + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + if (props == null) return null; - if (props == null) return null; + var portDevice = new GenericVersiportDigitalOutputDevice(dc.Key, dc.Name, GenericVersiportDigitalOutputDevice.GetVersiportDigitalOutput, props); - var portDevice = new GenericVersiportDigitalOutputDevice(dc.Key, dc.Name, GenericVersiportDigitalOutputDevice.GetVersiportDigitalOutput, props); - - return portDevice; - } + return portDevice; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs index 44af9954..a202be39 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs @@ -5,10 +5,9 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +public interface IAnalogInput { - public interface IAnalogInput - { - IntFeedback InputValueFeedback { get; } - } + IntFeedback InputValueFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs index 7c63b92c..be41769b 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs @@ -4,13 +4,12 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a device that provides digital input +/// +public interface IDigitalInput { - /// - /// Represents a device that provides digital input - /// - public interface IDigitalInput - { - BoolFeedback InputStateFeedback { get; } - } + BoolFeedback InputStateFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs index b4151941..a99a29e4 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs @@ -4,14 +4,13 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Represents a device that provides digital input +/// +public interface IDigitalOutput { - /// - /// Represents a device that provides digital input - /// - public interface IDigitalOutput - { - BoolFeedback OutputStateFeedback { get; } - void SetOutput(bool state); - } + BoolFeedback OutputStateFeedback { get; } + void SetOutput(bool state); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs b/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs index a13aca1a..90b144cc 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs @@ -6,10 +6,9 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IHasCresnetBranches { - public interface IHasCresnetBranches - { - CrestronCollection CresnetBranches { get; } - } + CrestronCollection CresnetBranches { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs b/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs index ab269f08..06561f61 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs @@ -7,17 +7,16 @@ using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +public class IOPortConfig { - public class IOPortConfig - { - [JsonProperty("portDeviceKey")] - public string PortDeviceKey { get; set; } - [JsonProperty("portNumber")] - public uint PortNumber { get; set; } - [JsonProperty("disablePullUpResistor")] - public bool DisablePullUpResistor { get; set; } - [JsonProperty("minimumChange")] - public int MinimumChange { get; set; } - } + [JsonProperty("portDeviceKey")] + public string PortDeviceKey { get; set; } + [JsonProperty("portNumber")] + public uint PortNumber { get; set; } + [JsonProperty("disablePullUpResistor")] + public bool DisablePullUpResistor { get; set; } + [JsonProperty("minimumChange")] + public int MinimumChange { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs b/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs index 19f8e0df..63ed96a2 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs @@ -6,21 +6,20 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.CrestronIO +namespace PepperDash.Essentials.Core.CrestronIO; + +/// +/// Describes an output capable of switching on and off +/// +public interface ISwitchedOutput { - /// - /// Describes an output capable of switching on and off - /// - public interface ISwitchedOutput - { - BoolFeedback OutputIsOnFeedback {get;} + BoolFeedback OutputIsOnFeedback {get;} - void On(); - void Off(); - } + void On(); + void Off(); +} - public interface ISwitchedOutputCollection - { - Dictionary SwitchedOutputs { get; } - } +public interface ISwitchedOutputCollection +{ + Dictionary SwitchedOutputs { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs b/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs index 9b03ec11..42957938 100644 --- a/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs +++ b/src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs @@ -1,11 +1,10 @@ -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +public class DeviceInfo { - public class DeviceInfo - { - public string HostName { get; set; } - public string IpAddress { get; set; } - public string MacAddress { get; set; } - public string SerialNumber { get; set; } - public string FirmwareVersion { get; set; } - } + public string HostName { get; set; } + public string IpAddress { get; set; } + public string MacAddress { get; set; } + public string SerialNumber { get; set; } + public string FirmwareVersion { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs b/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs index 6727bce6..1095051c 100644 --- a/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs @@ -1,19 +1,18 @@ using System; -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +public class DeviceInfoEventArgs:EventArgs { - public class DeviceInfoEventArgs:EventArgs + public DeviceInfo DeviceInfo { get; set; } + + public DeviceInfoEventArgs() { - public DeviceInfo DeviceInfo { get; set; } + + } - public DeviceInfoEventArgs() - { - - } - - public DeviceInfoEventArgs(DeviceInfo devInfo) - { - DeviceInfo = devInfo; - } + public DeviceInfoEventArgs(DeviceInfo devInfo) + { + DeviceInfo = devInfo; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs b/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs index ea9c16e6..b949dcea 100644 --- a/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs +++ b/src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs @@ -1,16 +1,15 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +public interface IDeviceInfoProvider:IKeyed { - public interface IDeviceInfoProvider:IKeyed - { - DeviceInfo DeviceInfo { get; } + DeviceInfo DeviceInfo { get; } - event DeviceInfoChangeHandler DeviceInfoChanged; + event DeviceInfoChangeHandler DeviceInfoChanged; - void UpdateDeviceInfo(); - } + void UpdateDeviceInfo(); +} - public delegate void DeviceInfoChangeHandler(IKeyed device, DeviceInfoEventArgs args); -} \ No newline at end of file +public delegate void DeviceInfoChangeHandler(IKeyed device, DeviceInfoEventArgs args); \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs b/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs index a1cc1e2f..14390754 100644 --- a/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs +++ b/src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs @@ -6,214 +6,213 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.DeviceInfo +namespace PepperDash.Essentials.Core.DeviceInfo; + +public static class NetworkDeviceHelpers { - public static class NetworkDeviceHelpers + /// + /// Event raised when ArpTable changes + /// + public static event ArpTableEventHandler ArpTableUpdated; + + /// + /// Delegate called by ArpTableUpdated + /// + /// contains the entire ARP table and a bool to note if there was an error in retrieving the data + public delegate void ArpTableEventHandler(ArpTableEventArgs args); + + private static readonly char NewLineSplitter = CrestronEnvironment.NewLine.ToCharArray().First(); + private static readonly string NewLine = CrestronEnvironment.NewLine; + + private static readonly CCriticalSection Lock = new CCriticalSection(); + + /// + /// Last resolved ARP table - it is recommended to refresh the arp before using this. + /// + public static List ArpTable { get; private set; } + + /// + /// Force recheck of ARP table + /// + public static void RefreshArp() { - /// - /// Event raised when ArpTable changes - /// - public static event ArpTableEventHandler ArpTableUpdated; - - /// - /// Delegate called by ArpTableUpdated - /// - /// contains the entire ARP table and a bool to note if there was an error in retrieving the data - public delegate void ArpTableEventHandler(ArpTableEventArgs args); - - private static readonly char NewLineSplitter = CrestronEnvironment.NewLine.ToCharArray().First(); - private static readonly string NewLine = CrestronEnvironment.NewLine; - - private static readonly CCriticalSection Lock = new CCriticalSection(); - - /// - /// Last resolved ARP table - it is recommended to refresh the arp before using this. - /// - public static List ArpTable { get; private set; } - - /// - /// Force recheck of ARP table - /// - public static void RefreshArp() + var error = false; + try { - var error = false; - try + Lock.Enter(); + var consoleResponse = string.Empty; + if (!CrestronConsole.SendControlSystemCommand("showarptable", ref consoleResponse)) return; + if (string.IsNullOrEmpty(consoleResponse)) { - Lock.Enter(); - var consoleResponse = string.Empty; - if (!CrestronConsole.SendControlSystemCommand("showarptable", ref consoleResponse)) return; - if (string.IsNullOrEmpty(consoleResponse)) - { - error = true; - return; - } - ArpTable.Clear(); - - Debug.LogMessage(LogEventLevel.Verbose, "ConsoleResponse of 'showarptable' : {0}{1}", NewLine, consoleResponse); - - var myLines = - consoleResponse.Split(NewLineSplitter) - .ToList() - .Where(o => (o.Contains(':') && !o.Contains("Type", StringComparison.OrdinalIgnoreCase))) - .ToList(); - foreach (var line in myLines) - { - var item = line; - var seperator = item.Contains('\t') ? '\t' : ' '; - var dataPoints = item.Split(seperator); - if (dataPoints == null || dataPoints.Length < 2) continue; - var ipAddress = SanitizeIpAddress(dataPoints.First().TrimAll()); - var macAddress = dataPoints.Last(); - ArpTable.Add(new ArpEntry(ipAddress, macAddress)); - } - } - catch (Exception ex) - { - Debug.LogMessage(LogEventLevel.Information, "Exception in \"RefreshArp\" : {0}", ex.Message); error = true; + return; } - finally + ArpTable.Clear(); + + Debug.LogMessage(LogEventLevel.Verbose, "ConsoleResponse of 'showarptable' : {0}{1}", NewLine, consoleResponse); + + var myLines = + consoleResponse.Split(NewLineSplitter) + .ToList() + .Where(o => (o.Contains(':') && !o.Contains("Type", StringComparison.OrdinalIgnoreCase))) + .ToList(); + foreach (var line in myLines) { - Lock.Leave(); - OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error)); + var item = line; + var seperator = item.Contains('\t') ? '\t' : ' '; + var dataPoints = item.Split(seperator); + if (dataPoints == null || dataPoints.Length < 2) continue; + var ipAddress = SanitizeIpAddress(dataPoints.First().TrimAll()); + var macAddress = dataPoints.Last(); + ArpTable.Add(new ArpEntry(ipAddress, macAddress)); } } - - - private static void OnArpTableUpdated(ArpTableEventArgs args) + catch (Exception ex) { - if (args == null) return; - var handler = ArpTableUpdated; - if (handler == null) return; - handler.Invoke(args); + Debug.LogMessage(LogEventLevel.Information, "Exception in \"RefreshArp\" : {0}", ex.Message); + error = true; } - - static NetworkDeviceHelpers() + finally { - ArpTable = new List(); + Lock.Leave(); + OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error)); } + } - /// - /// Removes leading zeros, leading whitespace, and trailing whitespace from an IPAddress string - /// - /// Ip Address to Santitize - /// Sanitized Ip Address - public static string SanitizeIpAddress(string ipAddressIn) - { - try - { - var ipAddress = IPAddress.Parse(ipAddressIn.TrimStart('0')); - return ipAddress.ToString(); - } - catch (Exception ex) - { - Debug.LogMessage(LogEventLevel.Information, "Unable to Santize Ip : {0}", ex.Message); - return ipAddressIn; - } - } - /// - /// Resolves a hostname by IP Address using DNS - /// - /// IP Address to resolve from - /// Resolved Hostname - on failure to determine hostname, will return IP Address - public static string ResolveHostnameFromIp(string ipAddress) - { - try - { - var santitizedIp = SanitizeIpAddress(ipAddress); - var hostEntry = Dns.GetHostEntry(santitizedIp); - return hostEntry == null ? ipAddress : hostEntry.HostName; - } - catch (Exception ex) - { - Debug.LogMessage(LogEventLevel.Information, "Exception Resolving Hostname from IP Address : {0}", ex.Message); - return ipAddress; - } - } - - /// - /// Resolves an IP Address by hostname using DNS - /// - /// Hostname to resolve from - /// Resolved IP Address - on a failure to determine IP Address, will return hostname - public static string ResolveIpFromHostname(string hostName) - { - try - { - var hostEntry = Dns.GetHostEntry(hostName); - return hostEntry == null ? hostName : hostEntry.AddressList.First().ToString(); - } - catch (Exception ex) - { - Debug.LogMessage(LogEventLevel.Information, "Exception Resolving IP Address from Hostname : {0}", ex.Message); - return hostName; - } - } + private static void OnArpTableUpdated(ArpTableEventArgs args) + { + if (args == null) return; + var handler = ArpTableUpdated; + if (handler == null) return; + handler.Invoke(args); + } + static NetworkDeviceHelpers() + { + ArpTable = new List(); } /// - /// Object to hold data about an arp entry + /// Removes leading zeros, leading whitespace, and trailing whitespace from an IPAddress string /// - public class ArpEntry + /// Ip Address to Santitize + /// Sanitized Ip Address + public static string SanitizeIpAddress(string ipAddressIn) { - public readonly IPAddress IpAddress; - public readonly string MacAddress; - - /// - /// Constructs new ArpEntry object - /// - /// string formatted as ipv4 address - /// mac address string - format is unimportant - public ArpEntry(string ipAddress, string macAddress) + try { - if (string.IsNullOrEmpty(ipAddress)) - { - throw new ArgumentException("\"ipAddress\" cannot be null or empty"); - } - if (string.IsNullOrEmpty(macAddress)) - { - throw new ArgumentException("\"macAddress\" cannot be null or empty"); - } - IpAddress = IPAddress.Parse(ipAddress.TrimStart().TrimStart('0').TrimEnd()); - MacAddress = macAddress; + var ipAddress = IPAddress.Parse(ipAddressIn.TrimStart('0')); + return ipAddress.ToString(); + } + catch (Exception ex) + { + Debug.LogMessage(LogEventLevel.Information, "Unable to Santize Ip : {0}", ex.Message); + return ipAddressIn; } } /// - /// Arguments passed by the ArpTableUpdated event + /// Resolves a hostname by IP Address using DNS /// - public class ArpTableEventArgs : EventArgs + /// IP Address to resolve from + /// Resolved Hostname - on failure to determine hostname, will return IP Address + public static string ResolveHostnameFromIp(string ipAddress) { - /// - /// The retrieved ARP Table - /// - public readonly List ArpTable; - /// - /// True if there was a problem retrieving the ARP Table - /// - public readonly bool Error; - - /// - /// Constructor for ArpTableEventArgs - /// - /// The entirety of the retrieved ARP table - /// True of an error was encountered updating the ARP table - public ArpTableEventArgs(List arpTable, bool error) + try { - ArpTable = arpTable; - Error = error; + var santitizedIp = SanitizeIpAddress(ipAddress); + var hostEntry = Dns.GetHostEntry(santitizedIp); + return hostEntry == null ? ipAddress : hostEntry.HostName; } - - /// - /// Constructor for ArpTableEventArgs - assumes no error encountered in retrieving ARP Table - /// - /// The entirety of the retrieved ARP table - public ArpTableEventArgs(List arpTable) + catch (Exception ex) { - ArpTable = arpTable; - Error = false; + Debug.LogMessage(LogEventLevel.Information, "Exception Resolving Hostname from IP Address : {0}", ex.Message); + return ipAddress; } } + + /// + /// Resolves an IP Address by hostname using DNS + /// + /// Hostname to resolve from + /// Resolved IP Address - on a failure to determine IP Address, will return hostname + public static string ResolveIpFromHostname(string hostName) + { + try + { + var hostEntry = Dns.GetHostEntry(hostName); + return hostEntry == null ? hostName : hostEntry.AddressList.First().ToString(); + } + catch (Exception ex) + { + Debug.LogMessage(LogEventLevel.Information, "Exception Resolving IP Address from Hostname : {0}", ex.Message); + return hostName; + } + } + +} + +/// +/// Object to hold data about an arp entry +/// +public class ArpEntry +{ + public readonly IPAddress IpAddress; + public readonly string MacAddress; + + /// + /// Constructs new ArpEntry object + /// + /// string formatted as ipv4 address + /// mac address string - format is unimportant + public ArpEntry(string ipAddress, string macAddress) + { + if (string.IsNullOrEmpty(ipAddress)) + { + throw new ArgumentException("\"ipAddress\" cannot be null or empty"); + } + if (string.IsNullOrEmpty(macAddress)) + { + throw new ArgumentException("\"macAddress\" cannot be null or empty"); + } + IpAddress = IPAddress.Parse(ipAddress.TrimStart().TrimStart('0').TrimEnd()); + MacAddress = macAddress; + } +} + +/// +/// Arguments passed by the ArpTableUpdated event +/// +public class ArpTableEventArgs : EventArgs +{ + /// + /// The retrieved ARP Table + /// + public readonly List ArpTable; + /// + /// True if there was a problem retrieving the ARP Table + /// + public readonly bool Error; + + /// + /// Constructor for ArpTableEventArgs + /// + /// The entirety of the retrieved ARP table + /// True of an error was encountered updating the ARP table + public ArpTableEventArgs(List arpTable, bool error) + { + ArpTable = arpTable; + Error = error; + } + + /// + /// Constructor for ArpTableEventArgs - assumes no error encountered in retrieving ARP Table + /// + /// The entirety of the retrieved ARP table + public ArpTableEventArgs(List arpTable) + { + ArpTable = arpTable; + Error = false; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs index 5a38c703..5242b496 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -43,5 +43,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(129); triList.ClearBoolSigAction(134); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs index 232362e9..8997da6c 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -37,5 +37,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(157); triList.ClearBoolSigAction(158); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs index a69cfe3b..287d7f77 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs @@ -4,8 +4,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -46,5 +46,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(130); triList.ClearBoolSigAction(134); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs index 024bac27..0c7fe5ef 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs @@ -3,11 +3,9 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; - public interface IDiscPlayerControls : IColor, IDPad, INumericKeypad, IHasPowerControl, ITransport, IUiDisplayInfo + +public interface IDiscPlayerControls : IColor, IDPad, INumericKeypad, IHasPowerControl, ITransport, IUiDisplayInfo { - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs index 9b82cacd..049d0878 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs @@ -1,8 +1,7 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IDisplay: IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName { - public interface IDisplay: IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName - { - } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs index 5624f77c..5a825cc9 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Devices.DeviceTypeInterfaces -{ +namespace PepperDash.Essentials.Core.Devices.DeviceTypeInterfaces; + public interface IDisplayBasic { void InputHdmi1(); @@ -18,5 +18,4 @@ namespace PepperDash.Essentials.Core.Devices.DeviceTypeInterfaces void InputVga1(); void InputVga2(); void InputRgb1(); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs index 1d4829cd..c0063821 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs @@ -4,9 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public interface IDumbSource { - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs index 9e55702c..4d9276af 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs @@ -9,8 +9,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -36,5 +36,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(136); triList.ClearBoolSigAction(152); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs index 7d158027..593fe7eb 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs @@ -4,11 +4,10 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IEmergencyOSD { - public interface IEmergencyOSD - { - void ShowEmergencyMessage(string url); - void HideEmergencyMessage(); - } + void ShowEmergencyMessage(string url); + void HideEmergencyMessage(); } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs index 10db107f..414082a9 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs @@ -1,10 +1,9 @@ using System; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IHasBranding { - public interface IHasBranding - { - bool BrandingEnabled { get; } - void InitializeBranding(string roomKey); - } + bool BrandingEnabled { get; } + void InitializeBranding(string roomKey); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs index 21bde91f..071ac71f 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs @@ -1,7 +1,6 @@ -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IHasFarEndContentStatus { - public interface IHasFarEndContentStatus - { - BoolFeedback ReceivingContent { get; } - } + BoolFeedback ReceivingContent { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs index ff9511fa..5851c7ba 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs @@ -1,16 +1,15 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// Describes a device that has selectable inputs +/// +/// the type to use as the key for each input item. Most likely an enum or string\ +/// +/// See MockDisplay for example implemntation +/// +public interface IHasInputs : IKeyName { - /// - /// Describes a device that has selectable inputs - /// - /// the type to use as the key for each input item. Most likely an enum or string\ - /// - /// See MockDisplay for example implemntation - /// - public interface IHasInputs : IKeyName - { - ISelectableItems Inputs { get; } - } + ISelectableItems Inputs { get; } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs index cd208d4b..417d6963 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs @@ -1,15 +1,14 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IHasPhoneDialing { - public interface IHasPhoneDialing - { - BoolFeedback PhoneOffHookFeedback { get; } - StringFeedback CallerIdNameFeedback { get; } - StringFeedback CallerIdNumberFeedback { get; } - void DialPhoneCall(string number); - void EndPhoneCall(); - void SendDtmfToPhone(string digit); - } + BoolFeedback PhoneOffHookFeedback { get; } + StringFeedback CallerIdNameFeedback { get; } + StringFeedback CallerIdNumberFeedback { get; } + void DialPhoneCall(string number); + void EndPhoneCall(); + void SendDtmfToPhone(string digit); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs index 439462c6..2a67e39b 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs @@ -5,103 +5,102 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// This defines a device that has screens with layouts +/// Simply decorative +/// +public interface IHasScreensWithLayouts { /// - /// This defines a device that has screens with layouts - /// Simply decorative + /// A dictionary of screens, keyed by screen ID, that contains information about each screen and its layouts. /// - public interface IHasScreensWithLayouts - { - /// - /// A dictionary of screens, keyed by screen ID, that contains information about each screen and its layouts. - /// - Dictionary Screens { get; } - - /// - /// Applies a specific layout to a screen based on the provided screen ID and layout index. - /// - /// - /// - void ApplyLayout(uint screenId, uint layoutIndex); - } + Dictionary Screens { get; } /// - /// Represents information about a screen and its layouts. + /// Applies a specific layout to a screen based on the provided screen ID and layout index. /// - public class ScreenInfo - { - - /// - /// Indicates whether the screen is enabled or not. - /// - [JsonProperty("enabled")] - public bool Enabled { get; set; } - - /// - /// The name of the screen. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// The index of the screen. - /// - [JsonProperty("screenIndex")] - public int ScreenIndex { get; set; } - - /// - /// A dictionary of layout information for the screen, keyed by layout ID. - /// - [JsonProperty("layouts")] - public Dictionary Layouts { get; set; } - } - - /// - /// Represents information about a layout on a screen. - /// - public class LayoutInfo - { - /// - /// The name of the layout. - /// - [JsonProperty("layoutName")] - public string LayoutName { get; set; } - - /// - /// The index of the layout. - /// - [JsonProperty("layoutIndex")] - public int LayoutIndex { get; set; } - - /// - /// The type of the layout, which can be "single", "double", "triple", or "quad". - /// - [JsonProperty("layoutType")] - public string LayoutType { get; set; } - - /// - /// A dictionary of window configurations for the layout, keyed by window ID. - /// - [JsonProperty("windows")] - public Dictionary Windows { get; set; } - } - - /// - /// Represents the configuration of a window within a layout on a screen. - /// - public class WindowConfig - { - /// - /// The display label for the window - /// - [JsonProperty("label")] - public string Label { get; set; } - - /// - /// The input for the window - /// - [JsonProperty("input")] - public string Input { get; set; } - } + /// + /// + void ApplyLayout(uint screenId, uint layoutIndex); +} + +/// +/// Represents information about a screen and its layouts. +/// +public class ScreenInfo +{ + + /// + /// Indicates whether the screen is enabled or not. + /// + [JsonProperty("enabled")] + public bool Enabled { get; set; } + + /// + /// The name of the screen. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The index of the screen. + /// + [JsonProperty("screenIndex")] + public int ScreenIndex { get; set; } + + /// + /// A dictionary of layout information for the screen, keyed by layout ID. + /// + [JsonProperty("layouts")] + public Dictionary Layouts { get; set; } +} + +/// +/// Represents information about a layout on a screen. +/// +public class LayoutInfo +{ + /// + /// The name of the layout. + /// + [JsonProperty("layoutName")] + public string LayoutName { get; set; } + + /// + /// The index of the layout. + /// + [JsonProperty("layoutIndex")] + public int LayoutIndex { get; set; } + + /// + /// The type of the layout, which can be "single", "double", "triple", or "quad". + /// + [JsonProperty("layoutType")] + public string LayoutType { get; set; } + + /// + /// A dictionary of window configurations for the layout, keyed by window ID. + /// + [JsonProperty("windows")] + public Dictionary Windows { get; set; } +} + +/// +/// Represents the configuration of a window within a layout on a screen. +/// +public class WindowConfig +{ + /// + /// The display label for the window + /// + [JsonProperty("label")] + public string Label { get; set; } + + /// + /// The input for the window + /// + [JsonProperty("input")] + public string Input { get; set; } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs index c1c4ec86..bd6e4289 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs @@ -5,16 +5,15 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ - /// - /// Describes a device that has selectable surround sound modes - /// - /// the type to use as the key for each input item. Most likely an enum or string - public interface IHasSurroundSoundModes: IKeyName - { - ISelectableItems SurroundSoundModes { get; } +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; - void SetSurroundSoundMode(TSelector selector); - } +/// +/// Describes a device that has selectable surround sound modes +/// +/// the type to use as the key for each input item. Most likely an enum or string +public interface IHasSurroundSoundModes: IKeyName +{ + ISelectableItems SurroundSoundModes { get; } + + void SetSurroundSoundMode(TSelector selector); } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs index 84177a89..ebb3f0e5 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs @@ -4,23 +4,22 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IHasWebView { - public interface IHasWebView - { - bool WebviewIsVisible { get; } - void ShowWebView(string url, string mode, string title, string target); - void HideWebView(); - event EventHandler WebViewStatusChanged; - } + bool WebviewIsVisible { get; } + void ShowWebView(string url, string mode, string title, string target); + void HideWebView(); + event EventHandler WebViewStatusChanged; +} - public class WebViewStatusChangedEventArgs : EventArgs - { - public string Status { get; } +public class WebViewStatusChangedEventArgs : EventArgs +{ + public string Status { get; } - public WebViewStatusChangedEventArgs(string status) - { - Status = status; - } + public WebViewStatusChangedEventArgs(string status) + { + Status = status; } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs index 8e9a369b..e8a61494 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs @@ -4,15 +4,14 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ - public interface IHumiditySensor - { - /// - /// Reports the relative humidity level. Level ranging from 0 to 100 (for 0% to 100% - /// RH). EventIds: HumidityFeedbackFeedbackEventId will trigger to indicate change. - /// - IntFeedback HumidityFeedback { get; } +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IHumiditySensor +{ + /// + /// Reports the relative humidity level. Level ranging from 0 to 100 (for 0% to 100% + /// RH). EventIds: HumidityFeedbackFeedbackEventId will trigger to indicate change. + /// + IntFeedback HumidityFeedback { get; } - } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs index 181cac35..ff17353e 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs @@ -1,18 +1,17 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface ILanguageDefinition { - public interface ILanguageDefinition - { - string LocaleName { get; set; } - string FriendlyName { get; set; } - bool Enable { get; set; } - List UiLabels { get; set; } - List Sources { get; set; } - List Destinations { get; set; } - List SourceGroupNames { get; set; } - List DestinationGroupNames { get; set; } - List RoomNames { get; set; } - } + string LocaleName { get; set; } + string FriendlyName { get; set; } + bool Enable { get; set; } + List UiLabels { get; set; } + List Sources { get; set; } + List Destinations { get; set; } + List SourceGroupNames { get; set; } + List DestinationGroupNames { get; set; } + List RoomNames { get; set; } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs index 428f78c3..8112b4be 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs @@ -1,13 +1,11 @@ using System; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +public interface ILanguageProvider { - - public interface ILanguageProvider - { - ILanguageDefinition CurrentLanguage { get; set; } - - event EventHandler CurrentLanguageChanged; - } + ILanguageDefinition CurrentLanguage { get; set; } + event EventHandler CurrentLanguageChanged; } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs index f4cb4b71..736d122a 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs @@ -4,10 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface ILevelControls { - public interface ILevelControls - { - Dictionary LevelControlPoints { get; } - } + Dictionary LevelControlPoints { get; } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs index c30edebd..0d2541d5 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs @@ -3,117 +3,116 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +/// +/// Use this interface on a device or room if it uses custom Mobile Control messengers +/// +public interface ICustomMobileControl : IKeyed { - /// - /// Use this interface on a device or room if it uses custom Mobile Control messengers - /// - public interface ICustomMobileControl : IKeyed - { - } +} - /*/// - /// Describes a MobileControlSystemController - /// - public interface IMobileControl : IKeyed - { - void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent); +/*/// +/// Describes a MobileControlSystemController +/// +public interface IMobileControl : IKeyed +{ + void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent); - void LinkSystemMonitorToAppServer(); - }*/ + void LinkSystemMonitorToAppServer(); +}*/ - /// - /// Describes a MobileSystemController that accepts IEssentialsRoom - /// - public interface IMobileControl : IKeyed - { - string Host { get; } +/// +/// Describes a MobileSystemController that accepts IEssentialsRoom +/// +public interface IMobileControl : IKeyed +{ + string Host { get; } - string ClientAppUrl { get; } + string ClientAppUrl { get; } - string SystemUuid { get; } + string SystemUuid { get; } - BoolFeedback ApiOnlineAndAuthorized { get;} + BoolFeedback ApiOnlineAndAuthorized { get;} - void SendMessageObject(IMobileControlMessage o); + void SendMessageObject(IMobileControlMessage o); - void AddAction(T messenger, Action action) where T:IMobileControlMessenger; + void AddAction(T messenger, Action action) where T:IMobileControlMessenger; - void RemoveAction(string key); + void RemoveAction(string key); - void AddDeviceMessenger(IMobileControlMessenger messenger); + void AddDeviceMessenger(IMobileControlMessenger messenger); - bool CheckForDeviceMessenger(string key); + bool CheckForDeviceMessenger(string key); IMobileControlRoomMessenger GetRoomMessenger(string key); } - /// - /// Describes a mobile control messenger - /// - public interface IMobileControlMessenger: IKeyed - { - IMobileControl AppServerController { get; } - string MessagePath { get; } +/// +/// Describes a mobile control messenger +/// +public interface IMobileControlMessenger: IKeyed +{ + IMobileControl AppServerController { get; } + string MessagePath { get; } - string DeviceKey { get; } - void RegisterWithAppServer(IMobileControl appServerController); - } + string DeviceKey { get; } + void RegisterWithAppServer(IMobileControl appServerController); +} - public interface IMobileControlMessage - { - [JsonProperty("type")] - string Type { get; } +public interface IMobileControlMessage +{ + [JsonProperty("type")] + string Type { get; } - [JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)] - string ClientId { get; } + [JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)] + string ClientId { get; } - [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] - JToken Content { get; } + [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] + JToken Content { get; } - } +} - /// - /// Describes a MobileControl Room Bridge - /// - public interface IMobileControlRoomMessenger : IKeyed - { - event EventHandler UserCodeChanged; +/// +/// Describes a MobileControl Room Bridge +/// +public interface IMobileControlRoomMessenger : IKeyed +{ + event EventHandler UserCodeChanged; - event EventHandler UserPromptedForCode; + event EventHandler UserPromptedForCode; - event EventHandler ClientJoined; + event EventHandler ClientJoined; - event EventHandler AppUrlChanged; + event EventHandler AppUrlChanged; - string UserCode { get; } + string UserCode { get; } - string QrCodeUrl { get; } + string QrCodeUrl { get; } - string QrCodeChecksum { get; } + string QrCodeChecksum { get; } - string McServerUrl { get; } + string McServerUrl { get; } - string RoomName { get; } + string RoomName { get; } - string AppUrl { get; } + string AppUrl { get; } - void UpdateAppUrl(string url); - } + void UpdateAppUrl(string url); +} - public interface IMobileControlAction - { - IMobileControlMessenger Messenger { get; } +public interface IMobileControlAction +{ + IMobileControlMessenger Messenger { get; } - Action Action { get; } - } + Action Action { get; } +} - public interface IMobileControlTouchpanelController : IKeyed - { - string DefaultRoomKey { get; } - void SetAppUrl(string url); - bool UseDirectServer { get; } - bool ZoomRoomController { get; } - } +public interface IMobileControlTouchpanelController : IKeyed +{ + string DefaultRoomKey { get; } + void SetAppUrl(string url); + bool UseDirectServer { get; } + bool ZoomRoomController { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INumeric.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INumeric.cs index 62ea8b3f..e308fe59 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INumeric.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INumeric.cs @@ -3,8 +3,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -80,5 +80,4 @@ namespace PepperDash.Essentials.Core trilist.ClearBoolSigAction(120); trilist.ClearBoolSigAction(121); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs index 6ecdd775..cfdcf0ce 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs @@ -4,53 +4,52 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Describes the functionality required to prompt a user to enter a password +/// +public interface IPasswordPrompt { /// - /// Describes the functionality required to prompt a user to enter a password + /// Notifies when a password is required or is entered incorrectly /// - public interface IPasswordPrompt + event EventHandler PasswordRequired; + + /// + /// Submits the password + /// + /// + void SubmitPassword(string password); +} + +public class PasswordPromptEventArgs : EventArgs +{ + /// + /// Indicates if the last submitted password was incorrect + /// + public bool LastAttemptWasIncorrect { get; private set; } + + /// + /// Indicates that the login attempt has failed + /// + public bool LoginAttemptFailed { get; private set; } + + /// + /// Indicates that the process was cancelled and the prompt should be dismissed + /// + public bool LoginAttemptCancelled { get; private set; } + + /// + /// A message to be displayed to the user + /// + public string Message { get; private set; } + + public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message) { - /// - /// Notifies when a password is required or is entered incorrectly - /// - event EventHandler PasswordRequired; - - /// - /// Submits the password - /// - /// - void SubmitPassword(string password); - } - - public class PasswordPromptEventArgs : EventArgs - { - /// - /// Indicates if the last submitted password was incorrect - /// - public bool LastAttemptWasIncorrect { get; private set; } - - /// - /// Indicates that the login attempt has failed - /// - public bool LoginAttemptFailed { get; private set; } - - /// - /// Indicates that the process was cancelled and the prompt should be dismissed - /// - public bool LoginAttemptCancelled { get; private set; } - - /// - /// A message to be displayed to the user - /// - public string Message { get; private set; } - - public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message) - { - LastAttemptWasIncorrect = lastAttemptIncorrect; - LoginAttemptFailed = loginFailed; - LoginAttemptCancelled = loginCancelled; - Message = message; - } + LastAttemptWasIncorrect = lastAttemptIncorrect; + LoginAttemptFailed = loginFailed; + LoginAttemptCancelled = loginCancelled; + Message = message; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs index b7c3345e..b88abafe 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs @@ -11,56 +11,55 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Adds feedback for current power state +/// +public interface IHasPowerControlWithFeedback : IHasPowerControl { + BoolFeedback PowerIsOnFeedback { get; } +} - /// - /// Adds feedback for current power state - /// - public interface IHasPowerControlWithFeedback : IHasPowerControl - { - BoolFeedback PowerIsOnFeedback { get; } - } - - /// - /// Defines the ability to power a device on and off - /// - public interface IHasPowerControl - { - void PowerOn(); - void PowerOff(); - void PowerToggle(); - } +/// +/// Defines the ability to power a device on and off +/// +public interface IHasPowerControl +{ + void PowerOn(); + void PowerOff(); + void PowerToggle(); +} /// /// /// public static class IHasPowerControlExtensions { - public static void LinkButtons(this IHasPowerControl dev, BasicTriList triList) + public static void LinkButtons(this IHasPowerControl dev, BasicTriList triList) { triList.SetSigFalseAction(101, dev.PowerOn); triList.SetSigFalseAction(102, dev.PowerOff); triList.SetSigFalseAction(103, dev.PowerToggle); - var fbdev = dev as IHasPowerControlWithFeedback; - if (fbdev != null) - { - fbdev.PowerIsOnFeedback.LinkInputSig(triList.BooleanInput[101]); - } + var fbdev = dev as IHasPowerControlWithFeedback; + if (fbdev != null) + { + fbdev.PowerIsOnFeedback.LinkInputSig(triList.BooleanInput[101]); + } } - public static void UnlinkButtons(this IHasPowerControl dev, BasicTriList triList) + public static void UnlinkButtons(this IHasPowerControl dev, BasicTriList triList) { triList.ClearBoolSigAction(101); triList.ClearBoolSigAction(102); triList.ClearBoolSigAction(103); - var fbdev = dev as IHasPowerControlWithFeedback; - if (fbdev != null) - { - fbdev.PowerIsOnFeedback.UnlinkInputSig(triList.BooleanInput[101]); - } + var fbdev = dev as IHasPowerControlWithFeedback; + if (fbdev != null) + { + fbdev.PowerIsOnFeedback.UnlinkInputSig(triList.BooleanInput[101]); + } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs index 26895114..5d77aa1f 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs @@ -3,8 +3,8 @@ using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + /// /// Defines a class that has warm up and cool down /// @@ -23,5 +23,4 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { lift, screen - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs index 0f7408f6..a3c23f41 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs @@ -2,18 +2,17 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + + +/// +/// Describes an item that can be selected +/// +public interface ISelectableItem : IKeyName { + event EventHandler ItemUpdated; - /// - /// Describes an item that can be selected - /// - public interface ISelectableItem : IKeyName - { - event EventHandler ItemUpdated; - - [JsonProperty("isSelected")] - bool IsSelected { get; set; } - void Select(); - } + [JsonProperty("isSelected")] + bool IsSelected { get; set; } + void Select(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs index 9479099c..195283ea 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs @@ -2,26 +2,25 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface ISelectableItems where TValue : ISelectableItem { - public interface ISelectableItems where TValue : ISelectableItem - { - event EventHandler ItemsUpdated; - event EventHandler CurrentItemChanged; + event EventHandler ItemsUpdated; + event EventHandler CurrentItemChanged; - [JsonProperty("items")] - Dictionary Items { get; set; } + [JsonProperty("items")] + Dictionary Items { get; set; } - [JsonProperty("currentItem")] - TKey CurrentItem { get; set; } + [JsonProperty("currentItem")] + TKey CurrentItem { get; set; } - } +} - /// - /// Describes a collection of items that can be selected - /// - /// type for the keys in the collection. Probably a string or enum - public interface ISelectableItems : ISelectableItems - { - } +/// +/// Describes a collection of items that can be selected +/// +/// type for the keys in the collection. Probably a string or enum +public interface ISelectableItems : ISelectableItems +{ } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs index a9a92126..0d7018d4 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs @@ -3,8 +3,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -51,5 +51,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(136); triList.ClearBoolSigAction(152); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs index fe1c560c..cc0f2a26 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs @@ -4,19 +4,18 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface ITemperatureSensor { - public interface ITemperatureSensor - { - /// - /// The values will range from -400 to +1760 (for -40° to +176° F) or -400 to +800 - /// (for -40° to +80° C)in tenths of a degree. - /// - IntFeedback TemperatureFeedback { get; } + /// + /// The values will range from -400 to +1760 (for -40° to +176° F) or -400 to +800 + /// (for -40° to +80° C)in tenths of a degree. + /// + IntFeedback TemperatureFeedback { get; } - BoolFeedback TemperatureInCFeedback { get; } + BoolFeedback TemperatureInCFeedback { get; } - void SetTemperatureFormat(bool setToC); - } + void SetTemperatureFormat(bool setToC); } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs index 1189c10b..6e9ba724 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs @@ -1,7 +1,7 @@ using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -49,5 +49,4 @@ namespace PepperDash.Essentials.Core triList.ClearBoolSigAction(151); triList.ClearBoolSigAction(154); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs index 61b8ec09..199c6235 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs @@ -1,9 +1,8 @@ using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface ITvPresetsProvider { - public interface ITvPresetsProvider - { - DevicePresetsModel TvPresets { get; } - } + DevicePresetsModel TvPresets { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs index fb51f7e2..6a607b1e 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs @@ -1,12 +1,11 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Describes things needed to show on UI /// public interface IUiDisplayInfo : IKeyed { uint DisplayUiType { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs index 2baf1548..82984859 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines a class that has warm up and cool down /// @@ -13,5 +13,4 @@ namespace PepperDash.Essentials.Core { BoolFeedback IsWarmingUpFeedback { get; } BoolFeedback IsCoolingDownFeedback { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs index 890d1416..a7150706 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs @@ -1,13 +1,12 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public class LanguageLabel { - public class LanguageLabel - { - public string Key { get; set; } - public string Description { get; set; } - public string DisplayText { get; set; } - public uint JoinNumber { get; set; } - } + public string Key { get; set; } + public string Description { get; set; } + public string DisplayText { get; set; } + public uint JoinNumber { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs index 31f71df9..bf8dedd6 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs @@ -3,7 +3,6 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; -namespace PepperDash.Essentials.Core -{ - -} \ No newline at end of file +namespace PepperDash.Essentials.Core; + + \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs b/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs index 295fd25c..4294374a 100644 --- a/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs +++ b/src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs @@ -5,38 +5,37 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public abstract class AudioControlListItemBase { - public abstract class AudioControlListItemBase - { - /// - /// Key of the parent device in the DeviceManager - /// - [JsonProperty("parentDeviceKey")] - public string ParentDeviceKey { get; set; } + /// + /// Key of the parent device in the DeviceManager + /// + [JsonProperty("parentDeviceKey")] + public string ParentDeviceKey { get; set; } - /// - /// Optional key of the item in the parent device - /// - [JsonProperty("itemKey")] - public string ItemKey { get; set; } + /// + /// Optional key of the item in the parent device + /// + [JsonProperty("itemKey")] + public string ItemKey { get; set; } - /// - /// A name that will override the items's name on the UI - /// - [JsonProperty("name")] - public string Name { get; set; } + /// + /// A name that will override the items's name on the UI + /// + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Indicates if the item should be included in the user accessible list - /// - [JsonProperty("includeInUserList")] - public bool IncludeInUserList { get; set; } + /// + /// Indicates if the item should be included in the user accessible list + /// + [JsonProperty("includeInUserList")] + public bool IncludeInUserList { get; set; } - /// - /// Used to specify the order of the items in the source list when displayed - /// - [JsonProperty("order")] - public int Order { get; set; } - } + /// + /// Used to specify the order of the items in the source list when displayed + /// + [JsonProperty("order")] + public int Order { get; set; } } diff --git a/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs index 90aa4909..2eb93d3b 100644 --- a/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public enum AudioChangeType { @@ -24,5 +24,4 @@ namespace PepperDash.Essentials.Core ChangeType = changeType; AudioDevice = device; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs b/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs index d519feb4..f0707c9a 100644 --- a/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/CameraListItem.cs @@ -1,76 +1,75 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CameraListItem { - public class CameraListItem + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + /// + /// Returns the source Device for this, if it exists in DeviceManager + /// + [JsonIgnore] + public Device CameraDevice { - [JsonProperty("deviceKey")] - public string DeviceKey { get; set; } - - /// - /// Returns the source Device for this, if it exists in DeviceManager - /// - [JsonIgnore] - public Device CameraDevice + get { - get - { - if (_cameraDevice == null) - _cameraDevice = DeviceManager.GetDeviceForKey(DeviceKey) as Device; - return _cameraDevice; - } + if (_cameraDevice == null) + _cameraDevice = DeviceManager.GetDeviceForKey(DeviceKey) as Device; + return _cameraDevice; } - Device _cameraDevice; - - /// - /// Gets either the source's Name or this AlternateName property, if - /// defined. If source doesn't exist, returns "Missing source" - /// - [JsonProperty("preferredName")] - public string PreferredName - { - get - { - if (string.IsNullOrEmpty(Name)) - { - if (CameraDevice == null) - return "---"; - return CameraDevice.Name; - } - return Name; - } - } - - /// - /// A name that will override the source's name on the UI - /// - [JsonProperty("name")] - public string Name { get; set; } - - - /// - /// Specifies and icon for the source list item - /// - [JsonProperty("icon")] - public string Icon { get; set; } - - /// - /// Alternate icon - /// - [JsonProperty("altIcon", NullValueHandling = NullValueHandling.Ignore)] - public string AltIcon { get; set; } - - /// - /// Indicates if the item should be included in the user facing list - /// - [JsonProperty("includeInUserList")] - public bool IncludeInUserList { get; set; } - - /// - /// Used to specify the order of the items in the source list when displayed - /// - [JsonProperty("order")] - public int Order { get; set; } } + Device _cameraDevice; + + /// + /// Gets either the source's Name or this AlternateName property, if + /// defined. If source doesn't exist, returns "Missing source" + /// + [JsonProperty("preferredName")] + public string PreferredName + { + get + { + if (string.IsNullOrEmpty(Name)) + { + if (CameraDevice == null) + return "---"; + return CameraDevice.Name; + } + return Name; + } + } + + /// + /// A name that will override the source's name on the UI + /// + [JsonProperty("name")] + public string Name { get; set; } + + + /// + /// Specifies and icon for the source list item + /// + [JsonProperty("icon")] + public string Icon { get; set; } + + /// + /// Alternate icon + /// + [JsonProperty("altIcon", NullValueHandling = NullValueHandling.Ignore)] + public string AltIcon { get; set; } + + /// + /// Indicates if the item should be included in the user facing list + /// + [JsonProperty("includeInUserList")] + public bool IncludeInUserList { get; set; } + + /// + /// Used to specify the order of the items in the source list when displayed + /// + [JsonProperty("order")] + public int Order { get; set; } } diff --git a/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs index afb1da17..0d3e1c99 100644 --- a/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs @@ -4,43 +4,42 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Adds control of codec receive volume +/// +public interface IReceiveVolume { - /// - /// Adds control of codec receive volume - /// - public interface IReceiveVolume - { - // Break this out into 3 interfaces - void SetReceiveVolume(ushort level); - void ReceiveMuteOn(); - void ReceiveMuteOff(); - void ReceiveMuteToggle(); - IntFeedback ReceiveLevelFeedback { get; } - BoolFeedback ReceiveMuteIsOnFeedback { get; } - } + // Break this out into 3 interfaces + void SetReceiveVolume(ushort level); + void ReceiveMuteOn(); + void ReceiveMuteOff(); + void ReceiveMuteToggle(); + IntFeedback ReceiveLevelFeedback { get; } + BoolFeedback ReceiveMuteIsOnFeedback { get; } +} - /// - /// Adds control of codec transmit volume - /// - public interface ITransmitVolume - { - void SetTransmitVolume(ushort level); - void TransmitMuteOn(); - void TransmitMuteOff(); - void TransmitMuteToggle(); - IntFeedback TransmitLevelFeedback { get; } - BoolFeedback TransmitMuteIsOnFeedback { get; } - } +/// +/// Adds control of codec transmit volume +/// +public interface ITransmitVolume +{ + void SetTransmitVolume(ushort level); + void TransmitMuteOn(); + void TransmitMuteOff(); + void TransmitMuteToggle(); + IntFeedback TransmitLevelFeedback { get; } + BoolFeedback TransmitMuteIsOnFeedback { get; } +} - /// - /// Adds control of codec privacy function (microphone mute) - /// - public interface IPrivacy - { - void PrivacyModeOn(); - void PrivacyModeOff(); - void PrivacyModeToggle(); - BoolFeedback PrivacyModeIsOnFeedback { get; } - } +/// +/// Adds control of codec privacy function (microphone mute) +/// +public interface IPrivacy +{ + void PrivacyModeOn(); + void PrivacyModeOff(); + void PrivacyModeToggle(); + BoolFeedback PrivacyModeIsOnFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs b/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs index 57d99df8..29481b34 100644 --- a/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs +++ b/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs @@ -8,46 +8,45 @@ using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; using Serilog.Events; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// This wrapper class is meant to allow interfaces to be applied to any Crestron processor +/// +public class CrestronProcessor : Device, ISwitchedOutputCollection { - /// - /// This wrapper class is meant to allow interfaces to be applied to any Crestron processor - /// - public class CrestronProcessor : Device, ISwitchedOutputCollection + public Dictionary SwitchedOutputs { get; private set; } + + public Crestron.SimplSharpPro.CrestronControlSystem Processor { get; private set; } + + public CrestronProcessor(string key) + : base(key) { - public Dictionary SwitchedOutputs { get; private set; } + SwitchedOutputs = new Dictionary(); + Processor = Global.ControlSystem; - public Crestron.SimplSharpPro.CrestronControlSystem Processor { get; private set; } + GetRelays(); + } - public CrestronProcessor(string key) - : base(key) + /// + /// Creates a GenericRelayDevice for each relay on the processor and adds them to the SwitchedOutputs collection + /// + void GetRelays() + { + try { - SwitchedOutputs = new Dictionary(); - Processor = Global.ControlSystem; - - GetRelays(); - } - - /// - /// Creates a GenericRelayDevice for each relay on the processor and adds them to the SwitchedOutputs collection - /// - void GetRelays() - { - try + if (Processor.SupportsRelay) { - if (Processor.SupportsRelay) + for (uint i = 1; i <= Processor.NumberOfRelayPorts; i++) { - for (uint i = 1; i <= Processor.NumberOfRelayPorts; i++) - { - var relay = new GenericRelayDevice(string.Format("{0}-relay-{1}", this.Key, i), Processor.RelayPorts[i]); - SwitchedOutputs.Add(i, relay); - } + var relay = new GenericRelayDevice(string.Format("{0}-relay-{1}", this.Key, i), Processor.RelayPorts[i]); + SwitchedOutputs.Add(i, relay); } } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error Getting Relays from processor:\n '{0}'", e); - } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error Getting Relays from processor:\n '{0}'", e); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index 0c21216a..525a8929 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -3,60 +3,59 @@ using Newtonsoft.Json; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class DestinationListItem { - public class DestinationListItem + [JsonProperty("sinkKey")] + public string SinkKey { get; set; } + + private EssentialsDevice _sinkDevice; + + [JsonIgnore] + public EssentialsDevice SinkDevice { - [JsonProperty("sinkKey")] - public string SinkKey { get; set; } - - private EssentialsDevice _sinkDevice; - - [JsonIgnore] - public EssentialsDevice SinkDevice - { - get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as EssentialsDevice); } - } - - [JsonProperty("preferredName")] - public string PreferredName - { - get - { - if (!string.IsNullOrEmpty(Name)) - { - return Name; - } - - return SinkDevice == null ? "---" : SinkDevice.Name; - } - } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("includeInDestinationList")] - public bool IncludeInDestinationList { get; set; } - - [JsonProperty("order")] - public int Order { get; set; } - - [JsonProperty("surfaceLocation")] - public int SurfaceLocation { get; set; } - - [JsonProperty("verticalLocation")] - public int VerticalLocation { get; set; } - - [JsonProperty("horizontalLocation")] - public int HorizontalLocation { get; set; } - - [JsonProperty("sinkType")] - public eRoutingSignalType SinkType { get; set; } - - [JsonProperty("isCodecContentDestination")] - public bool isCodecContentDestination { get; set; } - - [JsonProperty("isProgramAudioDestination")] - public bool isProgramAudioDestination { get; set; } + get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as EssentialsDevice); } } + + [JsonProperty("preferredName")] + public string PreferredName + { + get + { + if (!string.IsNullOrEmpty(Name)) + { + return Name; + } + + return SinkDevice == null ? "---" : SinkDevice.Name; + } + } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("includeInDestinationList")] + public bool IncludeInDestinationList { get; set; } + + [JsonProperty("order")] + public int Order { get; set; } + + [JsonProperty("surfaceLocation")] + public int SurfaceLocation { get; set; } + + [JsonProperty("verticalLocation")] + public int VerticalLocation { get; set; } + + [JsonProperty("horizontalLocation")] + public int HorizontalLocation { get; set; } + + [JsonProperty("sinkType")] + public eRoutingSignalType SinkType { get; set; } + + [JsonProperty("isCodecContentDestination")] + public bool isCodecContentDestination { get; set; } + + [JsonProperty("isProgramAudioDestination")] + public bool isProgramAudioDestination { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs b/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs index 34669ff5..79f3ea86 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs @@ -4,14 +4,13 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// Base class for all Device APIs +/// +public abstract class DeviceApiBase { - /// - /// Base class for all Device APIs - /// - public abstract class DeviceApiBase - { - public Dictionary ActionApi { get; protected set; } - public Dictionary FeedbackApi { get; protected set; } - } + public Dictionary ActionApi { get; protected set; } + public Dictionary FeedbackApi { get; protected set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs b/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs index 1ef59b0f..e732e9f4 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs @@ -6,27 +6,26 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public static class DeviceFeedbackExtensions { - public static class DeviceFeedbackExtensions + /// + /// Attempts to get and return a feedback property from a device by name. + /// If unsuccessful, returns null. + /// + /// + /// + /// + public static Feedback GetFeedbackProperty(this Device device, string propertyName) { - /// - /// Attempts to get and return a feedback property from a device by name. - /// If unsuccessful, returns null. - /// - /// - /// - /// - public static Feedback GetFeedbackProperty(this Device device, string propertyName) + var feedback = DeviceJsonApi.GetPropertyByName(device.Key, propertyName) as Feedback; + + if (feedback != null) { - var feedback = DeviceJsonApi.GetPropertyByName(device.Key, propertyName) as Feedback; - - if (feedback != null) - { - return feedback; - } - - return null; + return feedback; } + + return null; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs b/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs index 816251ba..3422376a 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs @@ -9,443 +9,442 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class DeviceJsonApi { - public class DeviceJsonApi + /// + /// + /// + /// + public static void DoDeviceActionWithJson(string json) { - /// - /// - /// - /// - public static void DoDeviceActionWithJson(string json) + if (String.IsNullOrEmpty(json)) { - if (String.IsNullOrEmpty(json)) + CrestronConsole.ConsoleCommandResponse( + "Please provide a JSON object matching the format {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}.\r\nIf the method has no parameters, the \"params\" object may be omitted."); + return; + } + try + { + var action = JsonConvert.DeserializeObject(json); + + DoDeviceAction(action); + } + catch (Exception) + { + CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}"); + } + + } + + + /// + /// + /// + /// + public static void DoDeviceAction(DeviceActionWrapper action) + { + var key = action.DeviceKey; + var obj = FindObjectOnPath(key); + if (obj == null) + { + CrestronConsole.ConsoleCommandResponse("Unable to find object at path {0}", key); + return; + } + + if (action.Params == null) + { + //no params, so setting action.Params to empty array + action.Params = new object[0]; + } + + Type t = obj.GetType(); + try + { + var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList(); + + var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length); + + if (method == null) { CrestronConsole.ConsoleCommandResponse( - "Please provide a JSON object matching the format {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}.\r\nIf the method has no parameters, the \"params\" object may be omitted."); + "Unable to find method with name {0} and that matches parameters {1}", action.MethodName, + action.Params); return; } - try - { - var action = JsonConvert.DeserializeObject(json); + var mParams = method.GetParameters(); - DoDeviceAction(action); - } - catch (Exception) - { - CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}"); - } + var convertedParams = mParams + .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) + .ToArray(); - } - - - /// - /// - /// - /// - public static void DoDeviceAction(DeviceActionWrapper action) - { - var key = action.DeviceKey; - var obj = FindObjectOnPath(key); - if (obj == null) - { - CrestronConsole.ConsoleCommandResponse("Unable to find object at path {0}", key); - return; - } - - if (action.Params == null) - { - //no params, so setting action.Params to empty array - action.Params = new object[0]; - } - - Type t = obj.GetType(); - try - { - var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList(); - - var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length); - - if (method == null) - { - CrestronConsole.ConsoleCommandResponse( - "Unable to find method with name {0} and that matches parameters {1}", action.MethodName, - action.Params); - return; - } - var mParams = method.GetParameters(); - - var convertedParams = mParams - .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) - .ToArray(); - - Task.Run(() => - { - try - { - Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); - method.Invoke(obj, convertedParams); - } - catch (Exception e) - { - Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); - } - }); - - CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name, - action.DeviceKey); - } - catch (Exception ex) - { - CrestronConsole.ConsoleCommandResponse("Unable to call method with name {0}. {1}", action.MethodName, - ex.Message); - } - } - - public static async Task DoDeviceActionAsync(DeviceActionWrapper action) - { - var key = action.DeviceKey; - var obj = FindObjectOnPath(key); - if (obj == null) - { - Debug.LogMessage(LogEventLevel.Warning, "Unable to find object at path {deviceKey}", null, key); - return; - } - - if (action.Params == null) - { - //no params, so setting action.Params to empty array - action.Params = new object[0]; - } - - Type t = obj.GetType(); - try - { - var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList(); - - var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length); - - if (method == null) - { - Debug.LogMessage(LogEventLevel.Warning, - "Unable to find method with name {methodName} and that matches parameters {@parameters}", null, action.MethodName, - action.Params); - return; - } - var mParams = method.GetParameters(); - - var convertedParams = mParams - .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) - .ToArray(); - - try - { - Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey} with {@params}", null, method.Name, action.DeviceKey, action.Params); - var result = method.Invoke(obj, convertedParams); - - // If the method returns a Task, await it - if (result is Task task) - { - await task; - } - // If the method returns a Task, await it - else if (result != null && result.GetType().IsGenericType && result.GetType().GetGenericTypeDefinition() == typeof(Task<>)) - { - await (Task)result; - } - } - catch (Exception e) - { - Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); - } - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Unable to call method with name {methodName} with {@parameters}", null, action.MethodName, action.Params); - } - } - - private static object ConvertType(object value, Type conversionType) - { - if (!conversionType.IsEnum) - { - return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture); - } - - var stringValue = Convert.ToString(value); - - if (String.IsNullOrEmpty(stringValue)) - { - throw new InvalidCastException( - String.Format("{0} cannot be converted to a string prior to conversion to enum")); - } - return Enum.Parse(conversionType, stringValue, true); - } - - /// - /// Gets the properties on a device - /// - /// - /// - public static string GetProperties(string deviceObjectPath) - { - var obj = FindObjectOnPath(deviceObjectPath); - if (obj == null) - return "{ \"error\":\"No Device\"}"; - - Type t = obj.GetType(); - // get the properties and set them into a new collection of NameType wrappers - var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); - return JsonConvert.SerializeObject(props, Formatting.Indented); - } - - /// - /// Gets a property from a device path by name - /// - /// - /// - /// - public static object GetPropertyByName(string deviceObjectPath, string propertyName) - { - var dev = FindObjectOnPath(deviceObjectPath); - if (dev == null) - return "{ \"error\":\"No Device\"}"; - - object prop = dev.GetType().GetProperty(propertyName).GetValue(dev, null); - - // var prop = t.GetProperty(propertyName); - if (prop != null) - { - return prop; - } - else - { - Debug.LogMessage(LogEventLevel.Debug, "Unable to find Property: {0} on Device with path: {1}", propertyName, deviceObjectPath); - return null; - } - } - - /// - /// Gets the methods on a device - /// - /// - /// - public static string GetMethods(string deviceObjectPath) - { - var obj = FindObjectOnPath(deviceObjectPath); - if (obj == null) - return "{ \"error\":\"No Device\"}"; - - // Package up method names using helper objects - Type t = obj.GetType(); - var methods = t.GetMethods() - .Where(m => !m.IsSpecialName) - .Select(p => new MethodNameParams(p)); - return JsonConvert.SerializeObject(methods, Formatting.Indented); - } - - public static string GetApiMethods(string deviceObjectPath) - { - var obj = FindObjectOnPath(deviceObjectPath); - if (obj == null) - return "{ \"error\":\"No Device\"}"; - - // Package up method names using helper objects - Type t = obj.GetType(); - var methods = t.GetMethods() - .Where(m => !m.IsSpecialName) - .Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any()) - .Select(p => new MethodNameParams(p)); - return JsonConvert.SerializeObject(methods, Formatting.Indented); - } - - - /// - /// Walks down a dotted object path, starting with a Device, and returns the object - /// at the end of the path - /// - public static object FindObjectOnPath(string deviceObjectPath) - { - var path = deviceObjectPath.Split('.'); - - var dev = DeviceManager.GetDeviceForKey(path[0]); - if (dev == null) - { - Debug.LogMessage(LogEventLevel.Information, "Device {0} not found", path[0]); - return null; - } - - // loop through any dotted properties - object obj = dev; - if (path.Length > 1) - { - for (int i = 1; i < path.Length; i++) - { - var objName = path[i]; - string indexStr = null; - var indexOpen = objName.IndexOf('['); - if (indexOpen != -1) - { - var indexClose = objName.IndexOf(']'); - if (indexClose == -1) - { - Debug.LogMessage(LogEventLevel.Information, dev, "ERROR Unmatched index brackets"); - return null; - } - // Get the index and strip quotes if any - indexStr = objName.Substring(indexOpen + 1, indexClose - indexOpen - 1).Replace("\"", ""); - objName = objName.Substring(0, indexOpen); - Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr); - } - - Type oType = obj.GetType(); - var prop = oType.GetProperty(objName); - if (prop == null) - { - Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} not found on {1}", objName, path[i - 1]); - return null; - } - // if there's an index, try to get the property - if (indexStr != null) - { - if (!typeof(ICollection).IsAssignableFrom(prop.PropertyType)) - { - Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} is not collection", objName); - return null; - } - var collection = prop.GetValue(obj, null) as ICollection; - // Get the indexed items "property" - var indexedPropInfo = prop.PropertyType.GetProperty("Item"); - // These are the parameters for the indexing. Only care about one - var indexParams = indexedPropInfo.GetIndexParameters(); - if (indexParams.Length > 0) - { - Debug.LogMessage(LogEventLevel.Information, " Indexed, param type: {0}", indexParams[0].ParameterType.Name); - var properParam = Convert.ChangeType(indexStr, indexParams[0].ParameterType, - System.Globalization.CultureInfo.InvariantCulture); - try - { - obj = indexedPropInfo.GetValue(collection, new object[] { properParam }); - } - // if the index is bad, catch it here. - catch (TargetInvocationException e) - { - if (e.InnerException is ArgumentOutOfRangeException) - Debug.LogMessage(LogEventLevel.Information, " Index Out of range"); - else if (e.InnerException is KeyNotFoundException) - Debug.LogMessage(LogEventLevel.Information, " Key not found"); - return null; - } - } - - } - else - obj = prop.GetValue(obj, null); - } - } - return obj; - } - - /// - /// Sets a property on an object. - /// - /// - /// - public static string SetProperty(string deviceObjectPath) - { - throw new NotImplementedException("This could be really useful. Finish it please"); - - //var obj = FindObjectOnPath(deviceObjectPath); - //if (obj == null) - // return "{\"error\":\"No object found\"}"; - - //Type t = obj.GetType(); - - - //// get the properties and set them into a new collection of NameType wrappers - //var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); - //return JsonConvert.SerializeObject(props, Formatting.Indented); - } - - - } - - public class DeviceActionWrapper - { - public string DeviceKey { get; set; } - public string MethodName { get; set; } - public object[] Params { get; set; } - } - - public class PropertyNameType - { - private object Parent; - - [JsonIgnore] - public PropertyInfo PropInfo { get; private set; } - public string Name { get { return PropInfo.Name; } } - public string Type { get { return PropInfo.PropertyType.Name; } } - public string Value - { - get - { - if (PropInfo.CanRead) + Task.Run(() => { try { - return PropInfo.GetValue(Parent, null).ToString(); + Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); + method.Invoke(obj, convertedParams); } - catch (Exception) + catch (Exception e) { + Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); + } + }); + + CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name, + action.DeviceKey); + } + catch (Exception ex) + { + CrestronConsole.ConsoleCommandResponse("Unable to call method with name {0}. {1}", action.MethodName, + ex.Message); + } + } + + public static async Task DoDeviceActionAsync(DeviceActionWrapper action) + { + var key = action.DeviceKey; + var obj = FindObjectOnPath(key); + if (obj == null) + { + Debug.LogMessage(LogEventLevel.Warning, "Unable to find object at path {deviceKey}", null, key); + return; + } + + if (action.Params == null) + { + //no params, so setting action.Params to empty array + action.Params = new object[0]; + } + + Type t = obj.GetType(); + try + { + var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList(); + + var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length); + + if (method == null) + { + Debug.LogMessage(LogEventLevel.Warning, + "Unable to find method with name {methodName} and that matches parameters {@parameters}", null, action.MethodName, + action.Params); + return; + } + var mParams = method.GetParameters(); + + var convertedParams = mParams + .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) + .ToArray(); + + try + { + Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey} with {@params}", null, method.Name, action.DeviceKey, action.Params); + var result = method.Invoke(obj, convertedParams); + + // If the method returns a Task, await it + if (result is Task task) + { + await task; + } + // If the method returns a Task, await it + else if (result != null && result.GetType().IsGenericType && result.GetType().GetGenericTypeDefinition() == typeof(Task<>)) + { + await (Task)result; + } + } + catch (Exception e) + { + Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); + } + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Unable to call method with name {methodName} with {@parameters}", null, action.MethodName, action.Params); + } + } + + private static object ConvertType(object value, Type conversionType) + { + if (!conversionType.IsEnum) + { + return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture); + } + + var stringValue = Convert.ToString(value); + + if (String.IsNullOrEmpty(stringValue)) + { + throw new InvalidCastException( + String.Format("{0} cannot be converted to a string prior to conversion to enum")); + } + return Enum.Parse(conversionType, stringValue, true); + } + + /// + /// Gets the properties on a device + /// + /// + /// + public static string GetProperties(string deviceObjectPath) + { + var obj = FindObjectOnPath(deviceObjectPath); + if (obj == null) + return "{ \"error\":\"No Device\"}"; + + Type t = obj.GetType(); + // get the properties and set them into a new collection of NameType wrappers + var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); + return JsonConvert.SerializeObject(props, Formatting.Indented); + } + + /// + /// Gets a property from a device path by name + /// + /// + /// + /// + public static object GetPropertyByName(string deviceObjectPath, string propertyName) + { + var dev = FindObjectOnPath(deviceObjectPath); + if (dev == null) + return "{ \"error\":\"No Device\"}"; + + object prop = dev.GetType().GetProperty(propertyName).GetValue(dev, null); + + // var prop = t.GetProperty(propertyName); + if (prop != null) + { + return prop; + } + else + { + Debug.LogMessage(LogEventLevel.Debug, "Unable to find Property: {0} on Device with path: {1}", propertyName, deviceObjectPath); + return null; + } + } + + /// + /// Gets the methods on a device + /// + /// + /// + public static string GetMethods(string deviceObjectPath) + { + var obj = FindObjectOnPath(deviceObjectPath); + if (obj == null) + return "{ \"error\":\"No Device\"}"; + + // Package up method names using helper objects + Type t = obj.GetType(); + var methods = t.GetMethods() + .Where(m => !m.IsSpecialName) + .Select(p => new MethodNameParams(p)); + return JsonConvert.SerializeObject(methods, Formatting.Indented); + } + + public static string GetApiMethods(string deviceObjectPath) + { + var obj = FindObjectOnPath(deviceObjectPath); + if (obj == null) + return "{ \"error\":\"No Device\"}"; + + // Package up method names using helper objects + Type t = obj.GetType(); + var methods = t.GetMethods() + .Where(m => !m.IsSpecialName) + .Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any()) + .Select(p => new MethodNameParams(p)); + return JsonConvert.SerializeObject(methods, Formatting.Indented); + } + + + /// + /// Walks down a dotted object path, starting with a Device, and returns the object + /// at the end of the path + /// + public static object FindObjectOnPath(string deviceObjectPath) + { + var path = deviceObjectPath.Split('.'); + + var dev = DeviceManager.GetDeviceForKey(path[0]); + if (dev == null) + { + Debug.LogMessage(LogEventLevel.Information, "Device {0} not found", path[0]); + return null; + } + + // loop through any dotted properties + object obj = dev; + if (path.Length > 1) + { + for (int i = 1; i < path.Length; i++) + { + var objName = path[i]; + string indexStr = null; + var indexOpen = objName.IndexOf('['); + if (indexOpen != -1) + { + var indexClose = objName.IndexOf(']'); + if (indexClose == -1) + { + Debug.LogMessage(LogEventLevel.Information, dev, "ERROR Unmatched index brackets"); return null; } + // Get the index and strip quotes if any + indexStr = objName.Substring(indexOpen + 1, indexClose - indexOpen - 1).Replace("\"", ""); + objName = objName.Substring(0, indexOpen); + Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr); + } + + Type oType = obj.GetType(); + var prop = oType.GetProperty(objName); + if (prop == null) + { + Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} not found on {1}", objName, path[i - 1]); + return null; + } + // if there's an index, try to get the property + if (indexStr != null) + { + if (!typeof(ICollection).IsAssignableFrom(prop.PropertyType)) + { + Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} is not collection", objName); + return null; + } + var collection = prop.GetValue(obj, null) as ICollection; + // Get the indexed items "property" + var indexedPropInfo = prop.PropertyType.GetProperty("Item"); + // These are the parameters for the indexing. Only care about one + var indexParams = indexedPropInfo.GetIndexParameters(); + if (indexParams.Length > 0) + { + Debug.LogMessage(LogEventLevel.Information, " Indexed, param type: {0}", indexParams[0].ParameterType.Name); + var properParam = Convert.ChangeType(indexStr, indexParams[0].ParameterType, + System.Globalization.CultureInfo.InvariantCulture); + try + { + obj = indexedPropInfo.GetValue(collection, new object[] { properParam }); + } + // if the index is bad, catch it here. + catch (TargetInvocationException e) + { + if (e.InnerException is ArgumentOutOfRangeException) + Debug.LogMessage(LogEventLevel.Information, " Index Out of range"); + else if (e.InnerException is KeyNotFoundException) + Debug.LogMessage(LogEventLevel.Information, " Key not found"); + return null; + } + } + } else - return null; + obj = prop.GetValue(obj, null); } } - - public bool CanRead { get { return PropInfo.CanRead; } } - public bool CanWrite { get { return PropInfo.CanWrite; } } - - - public PropertyNameType(PropertyInfo info, object parent) - { - PropInfo = info; - Parent = parent; - } + return obj; } - public class MethodNameParams + /// + /// Sets a property on an object. + /// + /// + /// + public static string SetProperty(string deviceObjectPath) { - [JsonIgnore] - public MethodInfo MethodInfo { get; private set; } + throw new NotImplementedException("This could be really useful. Finish it please"); - public string Name { get { return MethodInfo.Name; } } - public IEnumerable Params + //var obj = FindObjectOnPath(deviceObjectPath); + //if (obj == null) + // return "{\"error\":\"No object found\"}"; + + //Type t = obj.GetType(); + + + //// get the properties and set them into a new collection of NameType wrappers + //var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); + //return JsonConvert.SerializeObject(props, Formatting.Indented); + } + + +} + +public class DeviceActionWrapper +{ + public string DeviceKey { get; set; } + public string MethodName { get; set; } + public object[] Params { get; set; } +} + +public class PropertyNameType +{ + private object Parent; + + [JsonIgnore] + public PropertyInfo PropInfo { get; private set; } + public string Name { get { return PropInfo.Name; } } + public string Type { get { return PropInfo.PropertyType.Name; } } + public string Value + { + get { - get + if (PropInfo.CanRead) { - return MethodInfo.GetParameters().Select(p => - new NameType { Name = p.Name, Type = p.ParameterType.Name }); + try + { + return PropInfo.GetValue(Parent, null).ToString(); + } + catch (Exception) + { + return null; + } } + else + return null; } + } - public MethodNameParams(MethodInfo info) + public bool CanRead { get { return PropInfo.CanRead; } } + public bool CanWrite { get { return PropInfo.CanWrite; } } + + + public PropertyNameType(PropertyInfo info, object parent) + { + PropInfo = info; + Parent = parent; + } +} + +public class MethodNameParams +{ + [JsonIgnore] + public MethodInfo MethodInfo { get; private set; } + + public string Name { get { return MethodInfo.Name; } } + public IEnumerable Params + { + get { - MethodInfo = info; + return MethodInfo.GetParameters().Select(p => + new NameType { Name = p.Name, Type = p.ParameterType.Name }); } } - public class NameType + public MethodNameParams(MethodInfo info) { - public string Name { get; set; } - public string Type { get; set; } + MethodInfo = info; } +} - [AttributeUsage(AttributeTargets.All)] - public class ApiAttribute : Attribute - { +public class NameType +{ + public string Name { get; set; } + public string Type { get; set; } +} + +[AttributeUsage(AttributeTargets.All)] +public class ApiAttribute : Attribute +{ - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs b/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs index a42239fc..90a2f516 100644 --- a/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs +++ b/src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Integers that represent the "source type number" for given sources. /// Primarily used by the UI to calculate subpage join offsets @@ -24,5 +24,4 @@ namespace PepperDash.Essentials.Core public const uint TypePc = 32; public const uint TypeNoControls = 49; - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs index 0812ca4e..23b06e9a 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs @@ -1,18 +1,17 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public abstract class EssentialsBridgeableDevice:EssentialsDevice, IBridgeAdvanced { - public abstract class EssentialsBridgeableDevice:EssentialsDevice, IBridgeAdvanced + protected EssentialsBridgeableDevice(string key) : base(key) { - protected EssentialsBridgeableDevice(string key) : base(key) - { - } - - protected EssentialsBridgeableDevice(string key, string name) : base(key, name) - { - } - - public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } + + protected EssentialsBridgeableDevice(string key, string name) : base(key, name) + { + } + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs index f23ac71d..34484a08 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs @@ -9,161 +9,178 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class +/// +[Description("The base Essentials Device Class")] +public abstract class EssentialsDevice : Device +{ + public event EventHandler Initialized; + + private bool _isInitialized; + public bool IsInitialized + { + get { return _isInitialized; } + private set + { + if (_isInitialized == value) return; + + _isInitialized = value; + + if (_isInitialized) + { + Initialized?.Invoke(this, new EventArgs()); + } + } + } + + protected EssentialsDevice(string key) + : base(key) + { + SubscribeToActivateComplete(); + } + + protected EssentialsDevice(string key, string name) + : base(key, name) + { + SubscribeToActivateComplete(); + } + + private void SubscribeToActivateComplete() + { + DeviceManager.AllDevicesActivated += DeviceManagerOnAllDevicesActivated; + } + + private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs) + { + CrestronInvoke.BeginInvoke((o) => + { + try + { + Initialize(); + + IsInitialized = true; + } + catch (Exception ex) + { + Debug.LogMessage(LogEventLevel.Error, this, "Exception initializing device: {0}", ex.Message); + Debug.LogMessage(LogEventLevel.Debug, this, "Stack Trace: {0}", ex.StackTrace); + } + }); + } + + public override bool CustomActivate() + { + CreateMobileControlMessengers(); + + return base.CustomActivate(); + } + + /// + /// Override this method to build and create custom Mobile Control Messengers during the Activation phase + /// + protected virtual void CreateMobileControlMessengers() + { + + } +} + +[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] +public class DescriptionAttribute : Attribute +{ + private string _Description; + + public DescriptionAttribute(string description) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description); + _Description = description; + } + + public string Description + { + get { return _Description; } + } +} + +[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] +public class ConfigSnippetAttribute : Attribute +{ + private string _ConfigSnippet; + + public ConfigSnippetAttribute(string configSnippet) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet); + _ConfigSnippet = configSnippet; + } + + public string ConfigSnippet + { + get { return _ConfigSnippet; } + } +} + +public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T: EssentialsDevice +{ + #region IProcessorExtensionDeviceFactory Members + + /// + /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device + /// + public List TypeNames { get; protected set; } + + /// + /// Loads an item to the ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods dictionary for each entry in the TypeNames list + /// + public void LoadFactories() + { + foreach (var typeName in TypeNames) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); + var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; + string description = descriptionAttribute[0].Description; + var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; + ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice); + } + } + + /// + /// The method that will build the device + /// + /// The device config + /// An instance of the device + public abstract EssentialsDevice BuildDevice(DeviceConfig dc); + + #endregion + +} + +/// +/// Devices the basic needs for a Device Factory +/// +public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice { /// - /// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class + /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") /// - [Description("The base Essentials Device Class")] - public abstract class EssentialsDevice : Device - { - public event EventHandler Initialized; - - private bool _isInitialized; - public bool IsInitialized - { - get { return _isInitialized; } - private set - { - if (_isInitialized == value) return; - - _isInitialized = value; - - if (_isInitialized) - { - Initialized?.Invoke(this, new EventArgs()); - } - } - } - - protected EssentialsDevice(string key) - : base(key) - { - SubscribeToActivateComplete(); - } - - protected EssentialsDevice(string key, string name) - : base(key, name) - { - SubscribeToActivateComplete(); - } - - private void SubscribeToActivateComplete() - { - DeviceManager.AllDevicesActivated += DeviceManagerOnAllDevicesActivated; - } - - private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs) - { - CrestronInvoke.BeginInvoke((o) => - { - try - { - Initialize(); - - IsInitialized = true; - } - catch (Exception ex) - { - Debug.LogMessage(LogEventLevel.Error, this, "Exception initializing device: {0}", ex.Message); - Debug.LogMessage(LogEventLevel.Debug, this, "Stack Trace: {0}", ex.StackTrace); - } - }); - } - - public override bool CustomActivate() - { - CreateMobileControlMessengers(); - - return base.CustomActivate(); - } - - /// - /// Override this method to build and create custom Mobile Control Messengers during the Activation phase - /// - protected virtual void CreateMobileControlMessengers() - { - - } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public class DescriptionAttribute : Attribute - { - private string _Description; - - public DescriptionAttribute(string description) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description); - _Description = description; - } - - public string Description - { - get { return _Description; } - } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public class ConfigSnippetAttribute : Attribute - { - private string _ConfigSnippet; - - public ConfigSnippetAttribute(string configSnippet) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet); - _ConfigSnippet = configSnippet; - } - - public string ConfigSnippet - { - get { return _ConfigSnippet; } - } - } - - public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T: EssentialsDevice - { - #region IProcessorExtensionDeviceFactory Members - - /// - /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device - /// - public List TypeNames { get; protected set; } - - /// - /// Loads an item to the ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods dictionary for each entry in the TypeNames list - /// - public void LoadFactories() - { - foreach (var typeName in TypeNames) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); - var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; - string description = descriptionAttribute[0].Description; - var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; - ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice); - } - } - - /// - /// The method that will build the device - /// - /// The device config - /// An instance of the device - public abstract EssentialsDevice BuildDevice(DeviceConfig dc); - - #endregion - - } - + public string MinimumEssentialsFrameworkVersion { get; protected set; } +} + +/// +/// Provides a base class for creating device factories specifically designed for plugin development in the Essentials +/// framework. +/// +/// This class is intended to be used by developers creating plugins for the Essentials framework. It +/// includes properties to specify the minimum required Essentials framework version and to track framework versions +/// used during development. +/// The type of device that this factory creates. Must derive from . +public abstract class EssentialsPluginDevelopmentDeviceFactory : EssentialsDeviceFactory, IPluginDevelopmentDeviceFactory where T : EssentialsDevice +{ /// - /// Devices the basic needs for a Device Factory + /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") /// - public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice - { - /// - /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") - /// - public string MinimumEssentialsFrameworkVersion { get; protected set; } - } + public string MinimumEssentialsFrameworkVersion { get; protected set; } + + public List DevelopmentEssentialsFrameworkVersions { get; protected set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs index 4b291f11..35651377 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs @@ -2,31 +2,29 @@ using System.Collections.Generic; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + +/// +/// Devices the basic needs for a Device Factory +/// +public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice +{ + #region IDeviceFactory Members + + /// + public Type FactoryType => typeof(T); + /// - /// Devices the basic needs for a Device Factory + /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device /// - public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice - { - #region IDeviceFactory Members + public List TypeNames { get; protected set; } - /// - public Type FactoryType => typeof(T); - - /// - /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device - /// - public List TypeNames { get; protected set; } - - /// - /// The method that will build the device - /// - /// The device config - /// An instance of the device - public abstract EssentialsDevice BuildDevice(DeviceConfig dc); - - #endregion - } + /// + /// The method that will build the device + /// + /// The device config + /// An instance of the device + public abstract EssentialsDevice BuildDevice(DeviceConfig dc); + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/FIND HOMES Interfaces.cs b/src/PepperDash.Essentials.Core/Devices/FIND HOMES Interfaces.cs index d4b09779..901304cb 100644 --- a/src/PepperDash.Essentials.Core/Devices/FIND HOMES Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/FIND HOMES Interfaces.cs @@ -1,8 +1,8 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public interface IOnline { BoolFeedback IsOnline { get; } @@ -28,5 +28,4 @@ namespace PepperDash.Essentials.Core { string DeviceMake { get; } string DeviceModel { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs b/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs index 26718ebf..e4265fc2 100644 --- a/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs +++ b/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs @@ -11,68 +11,68 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges.JoinMaps; using Serilog.Events; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +public class GenericIrController: EssentialsBridgeableDevice { - public class GenericIrController: EssentialsBridgeableDevice + //data storage for bridging + private BasicTriList _trilist; + private uint _joinStart; + private string _joinMapKey; + private EiscApiAdvanced _bridge; + + private readonly IrOutputPortController _port; + + public string[] IrCommands {get { return _port.IrFileCommands; }} + + public GenericIrController(string key, string name, IrOutputPortController irPort) : base(key, name) { - //data storage for bridging - private BasicTriList _trilist; - private uint _joinStart; - private string _joinMapKey; - private EiscApiAdvanced _bridge; - - private readonly IrOutputPortController _port; - - public string[] IrCommands {get { return _port.IrFileCommands; }} - - public GenericIrController(string key, string name, IrOutputPortController irPort) : base(key, name) + _port = irPort; + if (_port == null) { - _port = irPort; - if (_port == null) - { - Debug.LogMessage(LogEventLevel.Information, this, "IR Port is null, device will not function"); - return; - } - DeviceManager.AddDevice(_port); + Debug.LogMessage(LogEventLevel.Information, this, "IR Port is null, device will not function"); + return; + } + DeviceManager.AddDevice(_port); - _port.DriverLoaded.OutputChange += DriverLoadedOnOutputChange; + _port.DriverLoaded.OutputChange += DriverLoadedOnOutputChange; + } + + private void DriverLoadedOnOutputChange(object sender, FeedbackEventArgs args) + { + if (!args.BoolValue) + { + return; } - private void DriverLoadedOnOutputChange(object sender, FeedbackEventArgs args) + if (_trilist == null || _bridge == null) { - if (!args.BoolValue) - { - return; - } - - if (_trilist == null || _bridge == null) - { - return; - } - - LinkToApi(_trilist, _joinStart, _joinMapKey, _bridge); + return; } - #region Overrides of EssentialsBridgeableDevice + LinkToApi(_trilist, _joinStart, _joinMapKey, _bridge); + } - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + #region Overrides of EssentialsBridgeableDevice + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + //if driver isn't loaded yet, store the variables until it is loaded, then call the LinkToApi method again + if (!_port.DriverIsLoaded) { - //if driver isn't loaded yet, store the variables until it is loaded, then call the LinkToApi method again - if (!_port.DriverIsLoaded) - { - _trilist = trilist; - _joinStart = joinStart; - _joinMapKey = joinMapKey; - _bridge = bridge; - return; - } + _trilist = trilist; + _joinStart = joinStart; + _joinMapKey = joinMapKey; + _bridge = bridge; + return; + } - var joinMap = new GenericIrControllerJoinMap(joinStart); + var joinMap = new GenericIrControllerJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (_port.UseBridgeJoinMap) { @@ -134,43 +134,42 @@ Value.Metadata.Description-'{3}'", } } - joinMap.PrintJoinMapInfo(); + joinMap.PrintJoinMapInfo(); - 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."); - } - } - - #endregion - - public void Press(string command, bool pressRelease) + if (bridge != null) { - _port.PressRelease(command, pressRelease); + 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."); } } - public class GenericIrControllerFactory : EssentialsDeviceFactory + #endregion + + public void Press(string command, bool pressRelease) { - public GenericIrControllerFactory() - { - TypeNames = new List {"genericIrController"}; - } - #region Overrides of EssentialsDeviceFactory - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic IR Controller Device"); - - var irPort = IRPortHelper.GetIrOutputPortController(dc); - - return new GenericIrController(dc.Key, dc.Name, irPort); - } - - #endregion + _port.PressRelease(command, pressRelease); } +} + +public class GenericIrControllerFactory : EssentialsDeviceFactory +{ + public GenericIrControllerFactory() + { + TypeNames = new List {"genericIrController"}; + } + #region Overrides of EssentialsDeviceFactory + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic IR Controller Device"); + + var irPort = IRPortHelper.GetIrOutputPortController(dc); + + return new GenericIrController(dc.Key, dc.Name, irPort); + } + + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs b/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs index 8929edeb..08cfb47c 100644 --- a/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs @@ -8,8 +8,8 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Devices -{ +namespace PepperDash.Essentials.Core.Devices; + public class GenericCommunicationMonitoredDevice : Device, ICommunicationMonitor { IBasicCommunication Client; @@ -47,5 +47,4 @@ namespace PepperDash.Essentials.Core.Devices CommunicationMonitor.Stop(); return true; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs b/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs index e5218ee0..15f2068c 100644 --- a/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs +++ b/src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public static class IAttachVideoStatusExtensions { /// @@ -35,5 +35,4 @@ namespace PepperDash.Essentials.Core t.SourcePort.ParentDevice == attachedDev && t.DestinationPort is RoutingInputPortWithVideoStatuses) != null; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IDspPresets.cs b/src/PepperDash.Essentials.Core/Devices/IDspPresets.cs index 94bc3929..d6aad26b 100644 --- a/src/PepperDash.Essentials.Core/Devices/IDspPresets.cs +++ b/src/PepperDash.Essentials.Core/Devices/IDspPresets.cs @@ -1,12 +1,11 @@ using PepperDash.Core; using System.Collections.Generic; -namespace PepperDash.Essentials.Core -{ - public interface IDspPresets - { - Dictionary Presets { get; } +namespace PepperDash.Essentials.Core; - void RecallPreset(string key); - } +public interface IDspPresets +{ + Dictionary Presets { get; } + + void RecallPreset(string key); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs b/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs index 9943c738..e4bcd84a 100644 --- a/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs +++ b/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs @@ -4,8 +4,8 @@ using System.Linq; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public interface IHasFeedback : IKeyed { /// @@ -21,9 +21,9 @@ namespace PepperDash.Essentials.Core { public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates) { - Type t = source.GetType(); - // get the properties and set them into a new collection of NameType wrappers - var props = t.GetProperties().Select(p => new PropertyNameType(p, t)); + Type t = source.GetType(); + // get the properties and set them into a new collection of NameType wrappers + var props = t.GetProperties().Select(p => new PropertyNameType(p, t)); var feedbacks = source.Feedbacks; if (feedbacks != null) @@ -32,24 +32,24 @@ namespace PepperDash.Essentials.Core foreach (var f in feedbacks) { string val = ""; - string type = ""; + string type = ""; if (getCurrentStates) { - if (f is BoolFeedback) - { - val = f.BoolValue.ToString(); - type = "boolean"; - } - else if (f is IntFeedback) - { - val = f.IntValue.ToString(); - type = "integer"; - } - else if (f is StringFeedback) - { - val = f.StringValue; - type = "string"; - } + if (f is BoolFeedback) + { + val = f.BoolValue.ToString(); + type = "boolean"; + } + else if (f is IntFeedback) + { + val = f.IntValue.ToString(); + type = "integer"; + } + else if (f is StringFeedback) + { + val = f.StringValue; + type = "string"; + } } Debug.LogMessage(LogEventLevel.Information, "{0,-12} {1, -25} {2}", type, (string.IsNullOrEmpty(f.Key) ? "-no key-" : f.Key), val); @@ -58,5 +58,4 @@ namespace PepperDash.Essentials.Core else Debug.LogMessage(LogEventLevel.Information, source, "No available outputs:"); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs index c0cb33ed..97af2a39 100644 --- a/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs @@ -4,19 +4,18 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IBasicVideoMute { - public interface IBasicVideoMute - { - void VideoMuteToggle(); - } + void VideoMuteToggle(); +} - public interface IBasicVideoMuteWithFeedback : IBasicVideoMute - { - BoolFeedback VideoMuteIsOn { get; } +public interface IBasicVideoMuteWithFeedback : IBasicVideoMute +{ + BoolFeedback VideoMuteIsOn { get; } + + void VideoMuteOn(); + void VideoMuteOff(); - void VideoMuteOn(); - void VideoMuteOff(); - - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs b/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs index ab0e37c3..433d9628 100644 --- a/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs @@ -6,14 +6,13 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +public interface IReconfigurableDevice { - public interface IReconfigurableDevice - { - event EventHandler ConfigChanged; + event EventHandler ConfigChanged; - DeviceConfig Config { get; } + DeviceConfig Config { get; } - void SetConfig(DeviceConfig config); - } + void SetConfig(DeviceConfig config); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs b/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs index 968fa127..4a45f0cc 100644 --- a/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs +++ b/src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs @@ -6,100 +6,99 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IUsageTracking { - public interface IUsageTracking + UsageTracking UsageTracker { get; set; } +} + +//public static class IUsageTrackingExtensions +//{ +// public static void EnableUsageTracker(this IUsageTracking device) +// { +// device.UsageTracker = new UsageTracking(); +// } +//} + +public class UsageTracking +{ + public event EventHandler DeviceUsageEnded; + + public InUseTracking InUseTracker { get; protected set; } + + public bool UsageIsTracked { get; set; } + + public bool UsageTrackingStarted { get; protected set; } + public DateTime UsageStartTime { get; protected set; } + public DateTime UsageEndTime { get; protected set; } + + public Device Parent { get; private set; } + + public UsageTracking(Device parent) { - UsageTracking UsageTracker { get; set; } + Parent = parent; + + InUseTracker = new InUseTracking(); + + InUseTracker.InUseFeedback.OutputChange += InUseFeedback_OutputChange; //new EventHandler(); } - //public static class IUsageTrackingExtensions - //{ - // public static void EnableUsageTracker(this IUsageTracking device) - // { - // device.UsageTracker = new UsageTracking(); - // } - //} - - public class UsageTracking + void InUseFeedback_OutputChange(object sender, EventArgs e) { - public event EventHandler DeviceUsageEnded; - - public InUseTracking InUseTracker { get; protected set; } - - public bool UsageIsTracked { get; set; } - - public bool UsageTrackingStarted { get; protected set; } - public DateTime UsageStartTime { get; protected set; } - public DateTime UsageEndTime { get; protected set; } - - public Device Parent { get; private set; } - - public UsageTracking(Device parent) + if(InUseTracker.InUseFeedback.BoolValue) { - Parent = parent; - - InUseTracker = new InUseTracking(); - - InUseTracker.InUseFeedback.OutputChange += InUseFeedback_OutputChange; //new EventHandler(); + StartDeviceUsage(); } - - void InUseFeedback_OutputChange(object sender, EventArgs e) + else { - if(InUseTracker.InUseFeedback.BoolValue) - { - StartDeviceUsage(); - } - else - { - EndDeviceUsage(); - } + EndDeviceUsage(); } + } - /// - /// Stores the usage start time - /// - public void StartDeviceUsage() + /// + /// Stores the usage start time + /// + public void StartDeviceUsage() + { + UsageTrackingStarted = true; + UsageStartTime = DateTime.Now; + } + + /// + /// Calculates the difference between the usage start and end times, gets the total minutes used and fires an event to pass that info to a consumer + /// + public void EndDeviceUsage() + { + try { - UsageTrackingStarted = true; - UsageStartTime = DateTime.Now; - } + UsageTrackingStarted = false; - /// - /// Calculates the difference between the usage start and end times, gets the total minutes used and fires an event to pass that info to a consumer - /// - public void EndDeviceUsage() - { - try + UsageEndTime = DateTime.Now; + + if (UsageStartTime != null) { - UsageTrackingStarted = false; + var timeUsed = UsageEndTime - UsageStartTime; - UsageEndTime = DateTime.Now; + var handler = DeviceUsageEnded; - if (UsageStartTime != null) + if (handler != null) { - var timeUsed = UsageEndTime - UsageStartTime; - - var handler = DeviceUsageEnded; - - if (handler != null) - { - Debug.LogMessage(LogEventLevel.Debug, "Device Usage Ended for: {0} at {1}. In use for {2} minutes.", Parent.Name, UsageEndTime, timeUsed.Minutes); - handler(this, new DeviceUsageEventArgs() { UsageEndTime = UsageEndTime, MinutesUsed = timeUsed.Minutes }); - } + Debug.LogMessage(LogEventLevel.Debug, "Device Usage Ended for: {0} at {1}. In use for {2} minutes.", Parent.Name, UsageEndTime, timeUsed.Minutes); + handler(this, new DeviceUsageEventArgs() { UsageEndTime = UsageEndTime, MinutesUsed = timeUsed.Minutes }); } } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, "Error ending device usage: {0}", e); - } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, "Error ending device usage: {0}", e); } } +} - public class DeviceUsageEventArgs : EventArgs - { - public DateTime UsageEndTime { get; set; } - public int MinutesUsed { get; set; } - } +public class DeviceUsageEventArgs : EventArgs +{ + public DateTime UsageEndTime { get; set; } + public int MinutesUsed { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IVolumeAndAudioInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/IVolumeAndAudioInterfaces.cs index 5d8e0724..b0cd33c3 100644 --- a/src/PepperDash.Essentials.Core/Devices/IVolumeAndAudioInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/IVolumeAndAudioInterfaces.cs @@ -4,62 +4,62 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines minimal volume and mute control methods /// - public interface IBasicVolumeControls +public interface IBasicVolumeControls { void VolumeUp(bool pressRelease); void VolumeDown(bool pressRelease); void MuteToggle(); } - /// - /// Defines basic volume control methods - /// - public interface IHasVolumeControl - { - void VolumeUp(bool pressRelease); - void VolumeDown(bool pressRelease); - } +/// +/// Defines basic volume control methods +/// +public interface IHasVolumeControl +{ + void VolumeUp(bool pressRelease); + void VolumeDown(bool pressRelease); +} - /// - /// Defines volume control methods and properties with feedback - /// - public interface IHasVolumeControlWithFeedback : IHasVolumeControl - { - void SetVolume(ushort level); - IntFeedback VolumeLevelFeedback { get; } - } +/// +/// Defines volume control methods and properties with feedback +/// +public interface IHasVolumeControlWithFeedback : IHasVolumeControl +{ + void SetVolume(ushort level); + IntFeedback VolumeLevelFeedback { get; } +} - /// - /// Defines basic mute control methods - /// - public interface IHasMuteControl - { - void MuteToggle(); - } +/// +/// Defines basic mute control methods +/// +public interface IHasMuteControl +{ + void MuteToggle(); +} - /// - /// Defines mute control methods and properties with feedback - /// - public interface IHasMuteControlWithFeedback : IHasMuteControl - { - BoolFeedback MuteFeedback { get; } - void MuteOn(); - void MuteOff(); - } +/// +/// Defines mute control methods and properties with feedback +/// +public interface IHasMuteControlWithFeedback : IHasMuteControl +{ + BoolFeedback MuteFeedback { get; } + void MuteOn(); + void MuteOff(); +} /// /// Adds feedback and direct volume level set to IBasicVolumeControls /// - public interface IBasicVolumeWithFeedback : IBasicVolumeControls +public interface IBasicVolumeWithFeedback : IBasicVolumeControls { BoolFeedback MuteFeedback { get; } - void MuteOn(); - void MuteOff(); + void MuteOn(); + void MuteOff(); void SetVolume(ushort level); IntFeedback VolumeLevelFeedback { get; } } @@ -74,26 +74,26 @@ namespace PepperDash.Essentials.Core eVolumeLevelUnits Units { get; } } - public enum eVolumeLevelUnits - { - Decibels, - Percent, - Relative, - Absolute - } +public enum eVolumeLevelUnits +{ + Decibels, + Percent, + Relative, + Absolute +} - /// - /// A class that implements this contains a reference to a current IBasicVolumeControls device. - /// The class may have multiple IBasicVolumeControls. - /// - public interface IHasCurrentVolumeControls - { - IBasicVolumeControls CurrentVolumeControls { get; } +/// +/// A class that implements this contains a reference to a current IBasicVolumeControls device. +/// The class may have multiple IBasicVolumeControls. +/// +public interface IHasCurrentVolumeControls +{ + IBasicVolumeControls CurrentVolumeControls { get; } event EventHandler CurrentVolumeDeviceChange; - void SetDefaultLevels(); + void SetDefaultLevels(); - bool ZeroVolumeWhenSwtichingVolumeDevices { get; } + bool ZeroVolumeWhenSwtichingVolumeDevices { get; } } @@ -160,5 +160,4 @@ namespace PepperDash.Essentials.Core public interface IAudioZone : IBasicVolumeWithFeedback { void SelectInput(ushort input); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs b/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs index edcedfbb..ba639ceb 100644 --- a/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs +++ b/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs @@ -15,8 +15,8 @@ using Serilog.Events; using System.IO; using PepperDash.Core.Logging; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// IR port wrapper. May act standalone @@ -26,13 +26,13 @@ namespace PepperDash.Essentials.Core uint IrPortUid; IROutputPort IrPort; - public BoolFeedback DriverLoaded { get; private set; } + public BoolFeedback DriverLoaded { get; private set; } public ushort StandardIrPulseTime { get; set; } public string DriverFilepath { get; private set; } public bool DriverIsLoaded { get; private set; } - public string[] IrFileCommands { get { return IrPort.AvailableStandardIRCmds(IrPortUid); } } + public string[] IrFileCommands { get { return IrPort.AvailableStandardIRCmds(IrPortUid); } } public bool UseBridgeJoinMap { get; private set; } @@ -59,53 +59,53 @@ namespace PepperDash.Essentials.Core DeviceConfig config) : base(key) { - DriverLoaded = new BoolFeedback(() => DriverIsLoaded); + DriverLoaded = new BoolFeedback(() => DriverIsLoaded); UseBridgeJoinMap = config.Properties["control"].Value("useBridgeJoinMap"); - AddPostActivationAction(() => - { + AddPostActivationAction(() => + { IrPort = postActivationFunc(config); - if (IrPort == null) - { - Debug.LogMessage(LogEventLevel.Information, this, "WARNING No valid IR Port assigned to controller. IR will not function"); - return; - } - - // var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); + if (IrPort == null) + { + Debug.LogMessage(LogEventLevel.Information, this, "WARNING No valid IR Port assigned to controller. IR will not function"); + return; + } + + // var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); - var fileName = config.Properties["control"]["irFile"].Value(); + var fileName = config.Properties["control"]["irFile"].Value(); - var files = Directory.GetFiles(Global.FilePathPrefix, fileName, SearchOption.AllDirectories); + var files = Directory.GetFiles(Global.FilePathPrefix, fileName, SearchOption.AllDirectories); - if(files.Length == 0) - { - this.LogError("IR file {fileName} not found in {path}", fileName, Global.FilePathPrefix); - return; - } + if(files.Length == 0) + { + this.LogError("IR file {fileName} not found in {path}", fileName, Global.FilePathPrefix); + return; + } - if(files.Length > 1) - { - this.LogError("IR file {fileName} found in multiple locations: {files}", fileName, files); - return; - } + if(files.Length > 1) + { + this.LogError("IR file {fileName} found in multiple locations: {files}", fileName, files); + return; + } - var filePath = files[0]; + var filePath = files[0]; - Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath); + Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath); - LoadDriver(filePath); - + LoadDriver(filePath); + PrintAvailableCommands(); - }); + }); } public void PrintAvailableCommands() { - Debug.LogMessage(LogEventLevel.Verbose, this, "Available IR Commands in IR File {0}", IrPortUid); - foreach (var cmd in IrPort.AvailableIRCmds()) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", cmd); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Available IR Commands in IR File {0}", IrPortUid); + foreach (var cmd in IrPort.AvailableIRCmds()) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", cmd); + } } @@ -115,7 +115,7 @@ namespace PepperDash.Essentials.Core /// public void LoadDriver(string path) { - Debug.LogMessage(LogEventLevel.Verbose, this, "***Loading IR File***"); + Debug.LogMessage(LogEventLevel.Verbose, this, "***Loading IR File***"); if (string.IsNullOrEmpty(path)) path = DriverFilepath; try { @@ -124,14 +124,14 @@ namespace PepperDash.Essentials.Core StandardIrPulseTime = 200; DriverIsLoaded = true; - DriverLoaded.FireUpdate(); + DriverLoaded.FireUpdate(); } catch { DriverIsLoaded = false; var message = string.Format("WARNING IR Driver '{0}' failed to load", path); Debug.LogMessage(LogEventLevel.Information, this, message); - DriverLoaded.FireUpdate(); + DriverLoaded.FireUpdate(); } } @@ -192,5 +192,4 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Verbose, this, "Device {0}: IR Driver {1} does not contain command {2}", Key, IrPort.IRDriverFileNameByIRDriverId(IrPortUid), command); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs b/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs index 4c2e83e4..02769e28 100644 --- a/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs @@ -7,76 +7,75 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Devices; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class LevelControlListItem : AudioControlListItemBase { - public class LevelControlListItem : AudioControlListItemBase + + + [JsonIgnore] + public IBasicVolumeWithFeedback LevelControl { - - - [JsonIgnore] - public IBasicVolumeWithFeedback LevelControl + get { - get - { - if (_levelControl == null) - _levelControl = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IBasicVolumeWithFeedback; - return _levelControl; - } + if (_levelControl == null) + _levelControl = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IBasicVolumeWithFeedback; + return _levelControl; } - IBasicVolumeWithFeedback _levelControl; + } + IBasicVolumeWithFeedback _levelControl; - /// - /// Gets the name from the device if it implements IKeyName or else returns the Name property - /// - [JsonProperty("preferredName")] - public string PreferredName + /// + /// Gets the name from the device if it implements IKeyName or else returns the Name property + /// + [JsonProperty("preferredName")] + public string PreferredName + { + get { - get + if (!string.IsNullOrEmpty(Name)) return Name; + else { - if (!string.IsNullOrEmpty(Name)) return Name; - else + if (LevelControl is IKeyName namedLevelControl) { - if (LevelControl is IKeyName namedLevelControl) - { - if (namedLevelControl == null) - return "---"; - return namedLevelControl.Name; - } - else return "---"; + if (namedLevelControl == null) + return "---"; + return namedLevelControl.Name; } + else return "---"; } } - - /// - /// The key of the device in the DeviceManager for control - /// - [JsonProperty("deviceKey")] - public string DeviceKey - { - get - { - if(string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey; - else - { - return DeviceManager.AllDevices. - Where(d => d.Key.Contains(ParentDeviceKey) && d.Key.Contains(ItemKey)).FirstOrDefault()?.Key ?? $"{ParentDeviceKey}--{ItemKey}"; - } - } - } - - /// - /// Indicates if the item is a level, mute , or both - /// - [JsonProperty("type")] - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public eLevelControlType Type { get; set; } } - [Flags] - public enum eLevelControlType + /// + /// The key of the device in the DeviceManager for control + /// + [JsonProperty("deviceKey")] + public string DeviceKey { - Level = 1, - Mute = 2, - LevelAndMute = Level | Mute, + get + { + if(string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey; + else + { + return DeviceManager.AllDevices. + Where(d => d.Key.Contains(ParentDeviceKey) && d.Key.Contains(ItemKey)).FirstOrDefault()?.Key ?? $"{ParentDeviceKey}--{ItemKey}"; + } + } } + + /// + /// Indicates if the item is a level, mute , or both + /// + [JsonProperty("type")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public eLevelControlType Type { get; set; } +} + +[Flags] +public enum eLevelControlType +{ + Level = 1, + Mute = 2, + LevelAndMute = Level | Mute, } diff --git a/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs index 1c0431b5..5283907d 100644 --- a/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs @@ -4,33 +4,32 @@ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// Interface for any device that is able to control it'spower and has a configurable reboot time +/// +public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback { /// - /// Interface for any device that is able to control it'spower and has a configurable reboot time - /// - public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback - { - /// - /// Delay between power off and power on for reboot - /// - int PowerCycleTimeMs { get;} - - /// - /// Reboot outlet - /// - void PowerCycle(); - } + /// Delay between power off and power on for reboot + /// + int PowerCycleTimeMs { get;} /// - /// Interface for any device that contains a collection of IHasPowerReboot Devices - /// - public interface IHasControlledPowerOutlets : IKeyName - { - /// - /// Collection of IPduOutlets - /// - ReadOnlyDictionary PduOutlets { get; } + /// Reboot outlet + /// + void PowerCycle(); +} + +/// +/// Interface for any device that contains a collection of IHasPowerReboot Devices +/// +public interface IHasControlledPowerOutlets : IKeyName +{ + /// + /// Collection of IPduOutlets + /// + ReadOnlyDictionary PduOutlets { get; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs b/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs index 1fc6672a..443123dc 100644 --- a/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs +++ b/src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs @@ -1,87 +1,83 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Interface for any device that has a battery that can be monitored +/// +public interface IHasBatteryStats : IKeyName +{ + int BatteryPercentage { get; } + int BatteryCautionThresholdPercentage { get; } + int BatteryWarningThresholdPercentage { get; } + BoolFeedback BatteryIsWarningFeedback { get; } + BoolFeedback BatteryIsCautionFeedback { get; } + BoolFeedback BatteryIsOkFeedback { get; } + IntFeedback BatteryPercentageFeedback { get; } +} + +/// +/// Interface for any device that has a battery that can be monitored and the ability to charge and discharge +/// +public interface IHasBatteryCharging : IHasBatteryStats +{ + BoolFeedback BatteryIsCharging { get; } +} + +/// +/// Interface for any device that has multiple batteries that can be monitored +/// +public interface IHasBatteries : IKeyName +{ + ReadOnlyDictionary Batteries { get; } +} + +public interface IHasBatteryStatsExtended : IHasBatteryStats +{ + int InputVoltage { get; } + int OutputVoltage { get; } + int InptuCurrent { get; } + int OutputCurrent { get; } + + IntFeedback InputVoltageFeedback { get; } + IntFeedback OutputVoltageFeedback { get; } + IntFeedback InputCurrentFeedback { get; } + IntFeedback OutputCurrentFeedback { get; } +} + +/// +/// Interface for any device that is able to control its power, has a configurable reboot time, and has batteries that can be monitored +/// +public interface IHasPowerCycleWithBattery : IHasPowerCycle, IHasBatteryStats +{ + +} + +/// +/// Interface for any device that is able to control it's power and has a configurable reboot time +/// +public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback { /// - /// Interface for any device that has a battery that can be monitored + /// Delay between power off and power on for reboot /// - public interface IHasBatteryStats : IKeyName - { - int BatteryPercentage { get; } - int BatteryCautionThresholdPercentage { get; } - int BatteryWarningThresholdPercentage { get; } - BoolFeedback BatteryIsWarningFeedback { get; } - BoolFeedback BatteryIsCautionFeedback { get; } - BoolFeedback BatteryIsOkFeedback { get; } - IntFeedback BatteryPercentageFeedback { get; } - } + int PowerCycleTimeMs { get; } /// - /// Interface for any device that has a battery that can be monitored and the ability to charge and discharge + /// Reboot outlet /// - public interface IHasBatteryCharging : IHasBatteryStats - { - BoolFeedback BatteryIsCharging { get; } - } + void PowerCycle(); +} +/// +/// Interface for any device that contains a collection of IHasPowerReboot Devices +/// +public interface IHasControlledPowerOutlets : IKeyName +{ /// - /// Interface for any device that has multiple batteries that can be monitored + /// Collection of IPduOutlets /// - public interface IHasBatteries : IKeyName - { - ReadOnlyDictionary Batteries { get; } - } - - public interface IHasBatteryStatsExtended : IHasBatteryStats - { - int InputVoltage { get; } - int OutputVoltage { get; } - int InptuCurrent { get; } - int OutputCurrent { get; } - - IntFeedback InputVoltageFeedback { get; } - IntFeedback OutputVoltageFeedback { get; } - IntFeedback InputCurrentFeedback { get; } - IntFeedback OutputCurrentFeedback { get; } - } - - /// - /// Interface for any device that is able to control its power, has a configurable reboot time, and has batteries that can be monitored - /// - public interface IHasPowerCycleWithBattery : IHasPowerCycle, IHasBatteryStats - { - - } - - /// - /// Interface for any device that is able to control it's power and has a configurable reboot time - /// - public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback - { - /// - /// Delay between power off and power on for reboot - /// - int PowerCycleTimeMs { get; } - - /// - /// Reboot outlet - /// - void PowerCycle(); - } - - /// - /// Interface for any device that contains a collection of IHasPowerReboot Devices - /// - public interface IHasControlledPowerOutlets : IKeyName - { - /// - /// Collection of IPduOutlets - /// - ReadOnlyDictionary PduOutlets { get; } - - } - - + ReadOnlyDictionary PduOutlets { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs b/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs index 41555ae8..f2db9159 100644 --- a/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs +++ b/src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs @@ -7,10 +7,9 @@ using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.EthernetCommunication; using Crestron.SimplSharpPro.UI; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public enum PresentationSourceType { None, Dvd, Laptop, PC, SetTopBox, VCR - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs b/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs index f539d718..5865fc75 100644 --- a/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/PresetListItem.cs @@ -7,39 +7,38 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class PresetListItem : AudioControlListItemBase { - public class PresetListItem : AudioControlListItemBase + [JsonIgnore] + public IKeyName Preset { - [JsonIgnore] - public IKeyName Preset + get { - get + if (_preset == null) { - if (_preset == null) - { - var parent = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IDspPresets; - if (parent == null || !parent.Presets.ContainsKey(ItemKey)) - return null; - _preset = parent.Presets[ItemKey]; - } - return _preset; + var parent = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IDspPresets; + if (parent == null || !parent.Presets.ContainsKey(ItemKey)) + return null; + _preset = parent.Presets[ItemKey]; } + return _preset; } - private IKeyName _preset; + } + private IKeyName _preset; - /// - /// Gets the name from the device if it implements IKeyName or else returns the Name property - /// - [JsonProperty("preferredName")] - public string PreferredName + /// + /// Gets the name from the device if it implements IKeyName or else returns the Name property + /// + [JsonProperty("preferredName")] + public string PreferredName + { + get { - get - { - if (!string.IsNullOrEmpty(Name)) return Name; + if (!string.IsNullOrEmpty(Name)) return Name; - else return Preset.Name; - } + else return Preset.Name; } } } diff --git a/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs b/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs index 1da908a9..a7dc2af2 100644 --- a/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs @@ -12,68 +12,67 @@ using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace PepperDash.Essentials.Core.Devices +namespace PepperDash.Essentials.Core.Devices; + +/// +/// +/// +public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice { + public event EventHandler ConfigChanged; + + public DeviceConfig Config { get; private set; } + + protected ReconfigurableDevice(DeviceConfig config) + : base(config.Key) + { + SetNameHelper(config); + + Config = config; + } + /// - /// + /// Sets the Config, calls CustomSetConfig and fires the ConfigChanged event /// - public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice + /// + public void SetConfig(DeviceConfig config) { - public event EventHandler ConfigChanged; + Config = config; - public DeviceConfig Config { get; private set; } + SetNameHelper(config); - protected ReconfigurableDevice(DeviceConfig config) - : base(config.Key) + CustomSetConfig(config); + + var handler = ConfigChanged; + if (handler != null) { - SetNameHelper(config); - - Config = config; - } - - /// - /// Sets the Config, calls CustomSetConfig and fires the ConfigChanged event - /// - /// - public void SetConfig(DeviceConfig config) - { - Config = config; - - SetNameHelper(config); - - CustomSetConfig(config); - - var handler = ConfigChanged; - if (handler != null) - { - handler(this, new EventArgs()); - } - } - - void SetNameHelper(DeviceConfig config) - { - if (!string.IsNullOrEmpty(config.Name)) - Name = config.Name; - } - - - - /// - /// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc) - /// - /// - protected virtual void CustomSetConfig(DeviceConfig config) - { - ConfigWriter.UpdateDeviceConfig(config); + handler(this, new EventArgs()); } } - public abstract class ReconfigurableBridgableDevice : ReconfigurableDevice, IBridgeAdvanced + void SetNameHelper(DeviceConfig config) { - protected ReconfigurableBridgableDevice(DeviceConfig config) : base(config) - { - } - - public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); + if (!string.IsNullOrEmpty(config.Name)) + Name = config.Name; } + + + + /// + /// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc) + /// + /// + protected virtual void CustomSetConfig(DeviceConfig config) + { + ConfigWriter.UpdateDeviceConfig(config); + } +} + +public abstract class ReconfigurableBridgableDevice : ReconfigurableDevice, IBridgeAdvanced +{ + protected ReconfigurableBridgableDevice(DeviceConfig config) : base(config) + { + } + + public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs b/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs index 37e62036..95ef8e86 100644 --- a/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs +++ b/src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs @@ -1,11 +1,10 @@  -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class SmartObjectJoinOffsets { public const ushort Dpad = 1; public const ushort Numpad = 2; public const ushort PresetList = 6; - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index 6de2f35d..ed3f171a 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -3,195 +3,194 @@ using Newtonsoft.Json.Converters; using PepperDash.Core; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// +/// +public enum eSourceListItemType { + Route, Off, Other, SomethingAwesomerThanThese +} + +/// +/// Represents an item in a source list - can be deserialized into. +/// +public class SourceListItem +{ + [JsonProperty("sourceKey")] + public string SourceKey { get; set; } + /// - /// + /// Returns the source Device for this, if it exists in DeviceManager /// - public enum eSourceListItemType + [JsonIgnore] + public Device SourceDevice { - Route, Off, Other, SomethingAwesomerThanThese + get + { + if (_SourceDevice == null) + _SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device; + return _SourceDevice; + } + } + + private Device _SourceDevice; + + /// + /// Gets either the source's Name or this AlternateName property, if + /// defined. If source doesn't exist, returns "Missing source" + /// + [JsonProperty("preferredName")] + public string PreferredName + { + get + { + if (string.IsNullOrEmpty(Name)) + { + if (SourceDevice == null) + return "---"; + return SourceDevice.Name; + } + return Name; + } } /// - /// Represents an item in a source list - can be deserialized into. + /// A name that will override the source's name on the UI /// - public class SourceListItem - { - [JsonProperty("sourceKey")] - public string SourceKey { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - /// - /// Returns the source Device for this, if it exists in DeviceManager - /// - [JsonIgnore] - public Device SourceDevice - { - get - { - if (_SourceDevice == null) - _SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device; - return _SourceDevice; - } - } - - private Device _SourceDevice; - - /// - /// Gets either the source's Name or this AlternateName property, if - /// defined. If source doesn't exist, returns "Missing source" - /// - [JsonProperty("preferredName")] - public string PreferredName - { - get - { - if (string.IsNullOrEmpty(Name)) - { - if (SourceDevice == null) - return "---"; - return SourceDevice.Name; - } - return Name; - } - } - - /// - /// A name that will override the source's name on the UI - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Specifies and icon for the source list item - /// + /// + /// Specifies and icon for the source list item + /// [JsonProperty("icon")] - public string Icon { get; set; } - - /// - /// Alternate icon - /// - [JsonProperty("altIcon")] - public string AltIcon { get; set; } - - /// - /// Indicates if the item should be included in the source list - /// - [JsonProperty("includeInSourceList")] - public bool IncludeInSourceList { get; set; } - - /// - /// Used to specify the order of the items in the source list when displayed - /// - [JsonProperty("order")] - public int Order { get; set; } - - /// - /// The key of the device for volume control - /// - [JsonProperty("volumeControlKey")] - public string VolumeControlKey { get; set; } - - /// - /// The type of source list item - /// - [JsonProperty("type")] - [JsonConverter(typeof(StringEnumConverter))] - public eSourceListItemType Type { get; set; } - - /// - /// The list of routes to execute for this source list item - /// - [JsonProperty("routeList")] - public List RouteList { get; set; } - - /// - /// Indicates if this source should be disabled for sharing to the far end call participants via codec content - /// - [JsonProperty("disableCodecSharing")] - public bool DisableCodecSharing { get; set; } - - /// - /// Indicates if this source should be disabled for routing to a shared output - /// - [JsonProperty("disableRoutedSharing")] - public bool DisableRoutedSharing { get; set; } - - [JsonProperty("destinations")] - public List Destinations { get; set; } - /// - /// A means to reference a source list for this source item, in the event that this source has an input that can have sources routed to it - /// - [JsonProperty("sourceListKey")] - public string SourceListKey { get; set; } - - /// - /// Indicates if the device associated with this source is controllable - /// - [JsonProperty("isControllable")] - public bool IsControllable { get; set; } - - /// - /// Indicates that the device associated with this source has audio available - /// - [JsonProperty("isAudioSource")] - public bool IsAudioSource { get; set; } - - /// - /// Hide source on UI when Avanced Sharing is enabled - /// - [JsonProperty("disableAdvancedRouting")] - public bool DisableAdvancedRouting { get; set; } - - /// - /// Hide source on UI when Simpl Sharing is enabled - /// - [JsonProperty("disableSimpleRouting")] - public bool DisableSimpleRouting { get; set; } - - public SourceListItem() - { - Icon = "Blank"; - } - - public override string ToString() - { - return $"{SourceKey}:{Name}"; - } - } - - public class SourceRouteListItem - { - [JsonProperty("sourceKey")] - public string SourceKey { get; set; } - - [JsonProperty("sourcePortKey")] - public string SourcePortKey { get; set; } - - [JsonProperty("destinationKey")] - public string DestinationKey { get; set; } - - [JsonProperty("destinationPortKey")] - public string DestinationPortKey { get; set; } - - [JsonProperty("type")] - public eRoutingSignalType Type { get; set; } - } + public string Icon { get; set; } /// - /// Defines the valid destination types for SourceListItems in a room + /// Alternate icon /// - public enum eSourceListItemDestinationTypes + [JsonProperty("altIcon")] + public string AltIcon { get; set; } + + /// + /// Indicates if the item should be included in the source list + /// + [JsonProperty("includeInSourceList")] + public bool IncludeInSourceList { get; set; } + + /// + /// Used to specify the order of the items in the source list when displayed + /// + [JsonProperty("order")] + public int Order { get; set; } + + /// + /// The key of the device for volume control + /// + [JsonProperty("volumeControlKey")] + public string VolumeControlKey { get; set; } + + /// + /// The type of source list item + /// + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public eSourceListItemType Type { get; set; } + + /// + /// The list of routes to execute for this source list item + /// + [JsonProperty("routeList")] + public List RouteList { get; set; } + + /// + /// Indicates if this source should be disabled for sharing to the far end call participants via codec content + /// + [JsonProperty("disableCodecSharing")] + public bool DisableCodecSharing { get; set; } + + /// + /// Indicates if this source should be disabled for routing to a shared output + /// + [JsonProperty("disableRoutedSharing")] + public bool DisableRoutedSharing { get; set; } + + [JsonProperty("destinations")] + public List Destinations { get; set; } + /// + /// A means to reference a source list for this source item, in the event that this source has an input that can have sources routed to it + /// + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } + + /// + /// Indicates if the device associated with this source is controllable + /// + [JsonProperty("isControllable")] + public bool IsControllable { get; set; } + + /// + /// Indicates that the device associated with this source has audio available + /// + [JsonProperty("isAudioSource")] + public bool IsAudioSource { get; set; } + + /// + /// Hide source on UI when Avanced Sharing is enabled + /// + [JsonProperty("disableAdvancedRouting")] + public bool DisableAdvancedRouting { get; set; } + + /// + /// Hide source on UI when Simpl Sharing is enabled + /// + [JsonProperty("disableSimpleRouting")] + public bool DisableSimpleRouting { get; set; } + + public SourceListItem() { - defaultDisplay, - leftDisplay, - rightDisplay, - centerDisplay, - programAudio, - codecContent, - frontLeftDisplay, - frontRightDisplay, - rearLeftDisplay, - rearRightDisplay, + Icon = "Blank"; } + + public override string ToString() + { + return $"{SourceKey}:{Name}"; + } +} + +public class SourceRouteListItem +{ + [JsonProperty("sourceKey")] + public string SourceKey { get; set; } + + [JsonProperty("sourcePortKey")] + public string SourcePortKey { get; set; } + + [JsonProperty("destinationKey")] + public string DestinationKey { get; set; } + + [JsonProperty("destinationPortKey")] + public string DestinationPortKey { get; set; } + + [JsonProperty("type")] + public eRoutingSignalType Type { get; set; } +} + +/// +/// Defines the valid destination types for SourceListItems in a room +/// +public enum eSourceListItemDestinationTypes +{ + defaultDisplay, + leftDisplay, + rightDisplay, + centerDisplay, + programAudio, + codecContent, + frontLeftDisplay, + frontRightDisplay, + rearLeftDisplay, + rearRightDisplay, } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs b/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs index 2171cb73..931dc462 100644 --- a/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs @@ -7,8 +7,8 @@ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -32,5 +32,4 @@ namespace PepperDash.Essentials.Core public enum ChangeType { WillChange, DidChange - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs b/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs index cbdd0617..eb308cc5 100644 --- a/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs +++ b/src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.Ethernet -{ +namespace PepperDash.Essentials.Core.Ethernet; + public static class EthernetSettings { public static readonly BoolFeedback LinkActive = new BoolFeedback("LinkActive", @@ -29,5 +29,4 @@ namespace PepperDash.Essentials.Core.Ethernet public static readonly StringFeedback DefaultGateway0 = new StringFeedback("DefaultGateway0", () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0)); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs b/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs index 35ec1b8a..6da2211a 100644 --- a/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs +++ b/src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs @@ -5,82 +5,81 @@ using System.Net; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Extensions for IPAddress to provide additional functionality such as getting broadcast address, network address, and checking if two addresses are in the same subnet. +/// +public static class IPAddressExtensions { /// - /// Extensions for IPAddress to provide additional functionality such as getting broadcast address, network address, and checking if two addresses are in the same subnet. + /// Get the broadcast address for a given IP address and subnet mask. /// - public static class IPAddressExtensions + /// Address to check + /// Subnet mask in a.b.c.d format + /// Broadcast address + /// + /// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the broadcast address will be 192.168.1.255 + /// + /// + public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask) { - /// - /// Get the broadcast address for a given IP address and subnet mask. - /// - /// Address to check - /// Subnet mask in a.b.c.d format - /// Broadcast address - /// - /// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the broadcast address will be 192.168.1.255 - /// - /// - public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask) + byte[] ipAdressBytes = address.GetAddressBytes(); + byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); + + if (ipAdressBytes.Length != subnetMaskBytes.Length) + throw new ArgumentException("Lengths of IP address and subnet mask do not match."); + + byte[] broadcastAddress = new byte[ipAdressBytes.Length]; + for (int i = 0; i < broadcastAddress.Length; i++) { - byte[] ipAdressBytes = address.GetAddressBytes(); - byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); - - if (ipAdressBytes.Length != subnetMaskBytes.Length) - throw new ArgumentException("Lengths of IP address and subnet mask do not match."); - - byte[] broadcastAddress = new byte[ipAdressBytes.Length]; - for (int i = 0; i < broadcastAddress.Length; i++) - { - broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255)); - } - return new IPAddress(broadcastAddress); + broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255)); } + return new IPAddress(broadcastAddress); + } - /// - /// Get the network address for a given IP address and subnet mask. - /// - /// Address to check - /// Subnet mask in a.b.c.d - /// Network Address - /// /// - /// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the network address will be 192.168.1.0 - /// - /// - public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask) + /// + /// Get the network address for a given IP address and subnet mask. + /// + /// Address to check + /// Subnet mask in a.b.c.d + /// Network Address + /// /// + /// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the network address will be 192.168.1.0 + /// + /// + public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask) + { + byte[] ipAdressBytes = address.GetAddressBytes(); + byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); + + if (ipAdressBytes.Length != subnetMaskBytes.Length) + throw new ArgumentException("Lengths of IP address and subnet mask do not match."); + + byte[] broadcastAddress = new byte[ipAdressBytes.Length]; + for (int i = 0; i < broadcastAddress.Length; i++) { - byte[] ipAdressBytes = address.GetAddressBytes(); - byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); - - if (ipAdressBytes.Length != subnetMaskBytes.Length) - throw new ArgumentException("Lengths of IP address and subnet mask do not match."); - - byte[] broadcastAddress = new byte[ipAdressBytes.Length]; - for (int i = 0; i < broadcastAddress.Length; i++) - { - broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i])); - } - return new IPAddress(broadcastAddress); + broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i])); } + return new IPAddress(broadcastAddress); + } - /// - /// Determine if two IP addresses are in the same subnet. - /// - /// Address to check - /// Second address to check - /// Subnet mask to use to compare the 2 IP Address - /// True if addresses are in the same subnet - /// - /// If the input IP addresses are 192.168.1.100 and 192.168.1.200, and the subnet mask is 255.255.255.0, this will return true. - /// If the input IP addresses are 10.1.1.100 and 192.168.1.100, and the subnet mask is 255.255.255.0, this will return false. - /// - public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask) - { - IPAddress network1 = address.GetNetworkAddress(subnetMask); - IPAddress network2 = address2.GetNetworkAddress(subnetMask); + /// + /// Determine if two IP addresses are in the same subnet. + /// + /// Address to check + /// Second address to check + /// Subnet mask to use to compare the 2 IP Address + /// True if addresses are in the same subnet + /// + /// If the input IP addresses are 192.168.1.100 and 192.168.1.200, and the subnet mask is 255.255.255.0, this will return true. + /// If the input IP addresses are 10.1.1.100 and 192.168.1.100, and the subnet mask is 255.255.255.0, this will return false. + /// + public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask) + { + IPAddress network1 = address.GetNetworkAddress(subnetMask); + IPAddress network2 = address2.GetNetworkAddress(subnetMask); - return network1.Equals(network2); - } + return network1.Equals(network2); } } diff --git a/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs b/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs index 2d71c6bc..a25d9c89 100644 --- a/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs +++ b/src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs @@ -8,36 +8,35 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace PepperDash.Essentials.Core -{ - public static class JsonExtensions - { - public static List FindTokens(this JToken containerToken, string name) - { - List matches = new List(); - FindTokens(containerToken, name, matches); - return matches; - } +namespace PepperDash.Essentials.Core; - private static void FindTokens(JToken containerToken, string name, List matches) +public static class JsonExtensions +{ + public static List FindTokens(this JToken containerToken, string name) + { + List matches = new List(); + FindTokens(containerToken, name, matches); + return matches; + } + + private static void FindTokens(JToken containerToken, string name, List matches) + { + if (containerToken.Type == JTokenType.Object) { - if (containerToken.Type == JTokenType.Object) + foreach (JProperty child in containerToken.Children()) { - foreach (JProperty child in containerToken.Children()) + if (child.Name == name) { - if (child.Name == name) - { - matches.Add(child.Value); - } - FindTokens(child.Value, name, matches); + matches.Add(child.Value); } + FindTokens(child.Value, name, matches); } - else if (containerToken.Type == JTokenType.Array) + } + else if (containerToken.Type == JTokenType.Array) + { + foreach (JToken child in containerToken.Children()) { - foreach (JToken child in containerToken.Children()) - { - FindTokens(child, name, matches); - } + FindTokens(child, name, matches); } } } diff --git a/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs b/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs index 7bf8d5a5..3a863b15 100644 --- a/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs +++ b/src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs @@ -5,74 +5,73 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public static class StringExtensions { - public static class StringExtensions + /// + /// Returns null if a string is empty, otherwise returns the string + /// + /// string input + /// null if the string is emtpy, otherwise returns the string + public static string NullIfEmpty(this string s) { - /// - /// Returns null if a string is empty, otherwise returns the string - /// - /// string input - /// null if the string is emtpy, otherwise returns the string - public static string NullIfEmpty(this string s) - { - return string.IsNullOrEmpty(s) ? null : s; - } - - /// - /// Returns null if a string is empty or made of only whitespace characters, otherwise returns the string - /// - /// string input - /// null if the string is wempty or made of only whitespace characters, otherwise returns the string - public static string NullIfWhiteSpace(this string s) - { - return string.IsNullOrEmpty(s.Trim()) ? null : s; - } - - /// - /// Returns a replacement string if the input string is empty or made of only whitespace characters, otherwise returns the input string - /// - /// input string - /// string to replace with if input string is empty or whitespace - /// returns newString if s is null, emtpy, or made of whitespace characters, otherwise returns s - public static string ReplaceIfNullOrEmpty(this string s, string newString) - { - return string.IsNullOrEmpty(s) ? newString : s; - } - - /// - /// Overload for Contains that allows setting an explicit String Comparison - /// - /// Source String - /// String to check in Source String - /// Comparison parameters - /// true of string contains "toCheck" - public static bool Contains(this string source, string toCheck, StringComparison comp) - { - if (string.IsNullOrEmpty(source)) return false; - return source.IndexOf(toCheck, comp) >= 0; - } - - /// - /// Performs TrimStart() and TrimEnd() on source string - /// - /// String to Trim - /// Trimmed String - public static string TrimAll(this string source) - { - return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart().TrimEnd(); - } - - /// - /// Performs TrimStart(chars char[]) and TrimEnd(chars char[]) on source string. - /// - /// String to Trim - /// Char Array to trim from string - /// Trimmed String - public static string TrimAll(this string source, char[] chars) - { - return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart(chars).TrimEnd(chars); - } - + return string.IsNullOrEmpty(s) ? null : s; } + + /// + /// Returns null if a string is empty or made of only whitespace characters, otherwise returns the string + /// + /// string input + /// null if the string is wempty or made of only whitespace characters, otherwise returns the string + public static string NullIfWhiteSpace(this string s) + { + return string.IsNullOrEmpty(s.Trim()) ? null : s; + } + + /// + /// Returns a replacement string if the input string is empty or made of only whitespace characters, otherwise returns the input string + /// + /// input string + /// string to replace with if input string is empty or whitespace + /// returns newString if s is null, emtpy, or made of whitespace characters, otherwise returns s + public static string ReplaceIfNullOrEmpty(this string s, string newString) + { + return string.IsNullOrEmpty(s) ? newString : s; + } + + /// + /// Overload for Contains that allows setting an explicit String Comparison + /// + /// Source String + /// String to check in Source String + /// Comparison parameters + /// true of string contains "toCheck" + public static bool Contains(this string source, string toCheck, StringComparison comp) + { + if (string.IsNullOrEmpty(source)) return false; + return source.IndexOf(toCheck, comp) >= 0; + } + + /// + /// Performs TrimStart() and TrimEnd() on source string + /// + /// String to Trim + /// Trimmed String + public static string TrimAll(this string source) + { + return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart().TrimEnd(); + } + + /// + /// Performs TrimStart(chars char[]) and TrimEnd(chars char[]) on source string. + /// + /// String to Trim + /// Char Array to trim from string + /// Trimmed String + public static string TrimAll(this string source, char[] chars) + { + return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart(chars).TrimEnd(chars); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs index 9743aa43..affbc4f1 100644 --- a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs @@ -2,29 +2,28 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines a class that is capable of loading device types +/// +public interface IDeviceFactory { - /// - /// Defines a class that is capable of loading device types + /// + /// Gets the type of the factory associated with the current instance. /// - public interface IDeviceFactory - { - /// - /// Gets the type of the factory associated with the current instance. - /// - Type FactoryType { get; } + Type FactoryType { get; } - /// - /// Gets a list of type names associated with the current plugin. - /// - List TypeNames { get; } + /// + /// Gets a list of type names associated with the current plugin. + /// + List TypeNames { get; } - /// - /// Builds and returns an instance based on the provided configuration. - /// - /// The configuration settings used to initialize the device. This parameter cannot be null. - /// An instance configured according to the specified . - EssentialsDevice BuildDevice(DeviceConfig deviceConfig); - } + /// + /// Builds and returns an instance based on the provided configuration. + /// + /// The configuration settings used to initialize the device. This parameter cannot be null. + /// An instance configured according to the specified . + EssentialsDevice BuildDevice(DeviceConfig deviceConfig); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs index a50ab16d..5d016011 100644 --- a/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs @@ -4,13 +4,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IProcessorExtensionDeviceFactory { - public interface IProcessorExtensionDeviceFactory - { - /// - /// Loads all the extension factories to the ProcessorExtensionDeviceFactory - /// - void LoadFactories(); - } + /// + /// Loads all the extension factories to the ProcessorExtensionDeviceFactory + /// + void LoadFactories(); } diff --git a/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs index b67dcf5b..565a2a48 100644 --- a/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs @@ -7,8 +7,8 @@ using System; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class ProcessorExtensionDeviceFactory { @@ -147,8 +147,6 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace); return null; } - } - } } diff --git a/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs b/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs index 6ccc0600..f432734b 100644 --- a/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs @@ -5,21 +5,20 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class IsReadyEventArgs : EventArgs { - public class IsReadyEventArgs : EventArgs - { - public bool IsReady { get; set; } + public bool IsReady { get; set; } - public IsReadyEventArgs(bool data) - { - IsReady = data; - } - } - - public interface IHasReady + public IsReadyEventArgs(bool data) { - event EventHandler IsReadyEvent; - bool IsReady { get; } + IsReady = data; } } + +public interface IHasReady +{ + event EventHandler IsReadyEvent; + bool IsReady { get; } +} diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs index 055ed5b6..3aa75e22 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs @@ -5,167 +5,165 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// A Feedback whose output is derived from the return value of a provided Func. +/// +public class BoolFeedback : Feedback { /// - /// A Feedback whose output is derived from the return value of a provided Func. + /// Returns the current value of the feedback, derived from the ValueFunc. The ValueFunc is + /// evaluated whenever FireUpdate() is called /// - public class BoolFeedback : Feedback + public override bool BoolValue { get { return _BoolValue; } } + bool _BoolValue; + + /// + /// Fake value to be used in test mode + /// + public bool TestValue { get; private set; } + + /// + /// Func that evaluates on FireUpdate + /// + public Func ValueFunc { get; private set; } + + List LinkedInputSigs = new List(); + List LinkedComplementInputSigs = new List(); + + List LinkedCrestronFeedbacks = new List(); + + /// + /// Creates the feedback with the Func as described. + /// + /// + /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, + /// it will NOT reflect an actual value from a device until has been called + /// + /// Delegate to invoke when this feedback needs to be updated + public BoolFeedback(Func valueFunc) + : this(null, valueFunc) { - /// - /// Returns the current value of the feedback, derived from the ValueFunc. The ValueFunc is - /// evaluated whenever FireUpdate() is called - /// - public override bool BoolValue { get { return _BoolValue; } } - bool _BoolValue; + } - /// - /// Fake value to be used in test mode - /// - public bool TestValue { get; private set; } + /// + /// Creates the feedback with the Func as described. + /// + /// + /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, + /// it will NOT reflect an actual value from a device until has been called + /// + /// Key to find this Feedback + /// Delegate to invoke when this feedback needs to be updated + public BoolFeedback(string key, Func valueFunc) + : base(key) + { + ValueFunc = valueFunc; + } - /// - /// Func that evaluates on FireUpdate - /// - public Func ValueFunc { get; private set; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } - List LinkedInputSigs = new List(); - List LinkedComplementInputSigs = new List(); - - List LinkedCrestronFeedbacks = new List(); - - /// - /// Creates the feedback with the Func as described. - /// - /// - /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, - /// it will NOT reflect an actual value from a device until has been called - /// - /// Delegate to invoke when this feedback needs to be updated - public BoolFeedback(Func valueFunc) - : this(null, valueFunc) + public override void FireUpdate() + { + bool newValue = InTestMode ? TestValue : ValueFunc.Invoke(); + if (newValue != _BoolValue) { - } - - /// - /// Creates the feedback with the Func as described. - /// - /// - /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, - /// it will NOT reflect an actual value from a device until has been called - /// - /// Key to find this Feedback - /// Delegate to invoke when this feedback needs to be updated - public BoolFeedback(string key, Func valueFunc) - : base(key) - { - ValueFunc = valueFunc; - } - - public void SetValueFunc(Func newFunc) - { - ValueFunc = newFunc; - } - - public override void FireUpdate() - { - bool newValue = InTestMode ? TestValue : ValueFunc.Invoke(); - if (newValue != _BoolValue) - { - _BoolValue = newValue; - LinkedInputSigs.ForEach(s => UpdateSig(s)); - LinkedComplementInputSigs.ForEach(s => UpdateComplementSig(s)); - OnOutputChange(newValue); - } - } - - /// - /// Links an input sig - /// - /// - public void LinkInputSig(BoolInputSig sig) - { - LinkedInputSigs.Add(sig); - UpdateSig(sig); - } - - /// - /// Unlinks an inputs sig - /// - /// - public void UnlinkInputSig(BoolInputSig sig) - { - LinkedInputSigs.Remove(sig); - } - - /// - /// Links an input sig to the complement value - /// - /// - public void LinkComplementInputSig(BoolInputSig sig) - { - LinkedComplementInputSigs.Add(sig); - UpdateComplementSig(sig); - } - - /// - /// Unlinks an input sig to the complement value - /// - /// - public void UnlinkComplementInputSig(BoolInputSig sig) - { - LinkedComplementInputSigs.Remove(sig); - } - - /// - /// Links a Crestron Feedback object - /// - /// - public void LinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) - { - LinkedCrestronFeedbacks.Add(feedback); - UpdateCrestronFeedback(feedback); - } - - /// - /// - /// - /// - public void UnlinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) - { - LinkedCrestronFeedbacks.Remove(feedback); - } - - public override string ToString() - { - return (InTestMode ? "TEST -- " : "") + BoolValue.ToString(); - } - - /// - /// Puts this in test mode, sets the test value and fires an update. - /// - /// - public void SetTestValue(bool value) - { - TestValue = value; - InTestMode = true; - FireUpdate(); - } - - void UpdateSig(BoolInputSig sig) - { - sig.BoolValue = _BoolValue; - } - - void UpdateComplementSig(BoolInputSig sig) - { - sig.BoolValue = !_BoolValue; - } - - void UpdateCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) - { - feedback.State = _BoolValue; + _BoolValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s)); + LinkedComplementInputSigs.ForEach(s => UpdateComplementSig(s)); + OnOutputChange(newValue); } } + /// + /// Links an input sig + /// + /// + public void LinkInputSig(BoolInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } + + /// + /// Unlinks an inputs sig + /// + /// + public void UnlinkInputSig(BoolInputSig sig) + { + LinkedInputSigs.Remove(sig); + } + + /// + /// Links an input sig to the complement value + /// + /// + public void LinkComplementInputSig(BoolInputSig sig) + { + LinkedComplementInputSigs.Add(sig); + UpdateComplementSig(sig); + } + + /// + /// Unlinks an input sig to the complement value + /// + /// + public void UnlinkComplementInputSig(BoolInputSig sig) + { + LinkedComplementInputSigs.Remove(sig); + } + + /// + /// Links a Crestron Feedback object + /// + /// + public void LinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + LinkedCrestronFeedbacks.Add(feedback); + UpdateCrestronFeedback(feedback); + } + + /// + /// + /// + /// + public void UnlinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + LinkedCrestronFeedbacks.Remove(feedback); + } + + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + BoolValue.ToString(); + } + + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(bool value) + { + TestValue = value; + InTestMode = true; + FireUpdate(); + } + + void UpdateSig(BoolInputSig sig) + { + sig.BoolValue = _BoolValue; + } + + void UpdateComplementSig(BoolInputSig sig) + { + sig.BoolValue = !_BoolValue; + } + + void UpdateCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + feedback.State = _BoolValue; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs index cc183569..05d50a38 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class BoolFeedbackPulse { public uint TimeoutMs { get; set; } @@ -65,5 +65,4 @@ namespace PepperDash.Essentials.Core if(Timer != null) Timer.Reset(0); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs index 53a5e559..f4467411 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// A class that wraps a BoolFeedback with logic that extends it's true state for /// a time period after the value goes false. @@ -74,5 +74,4 @@ namespace PepperDash.Essentials.Core Feedback.FireUpdate(); Timer = null; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs b/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs index a8dae7b8..67ba435a 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs @@ -5,8 +5,8 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public abstract class BoolFeedbackLogic @@ -71,7 +71,7 @@ namespace PepperDash.Essentials.Core public void ClearOutputs() { OutputsIn.Clear(); - Evaluate(); + Evaluate(); } void AnyInput_OutputChange(object sender, EventArgs e) @@ -133,5 +133,4 @@ namespace PepperDash.Essentials.Core ComputedValue = newValue; Output.FireUpdate(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs index c3aac50b..90d9e014 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs @@ -7,18 +7,18 @@ using Crestron.SimplSharpPro; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public abstract class Feedback : IKeyed { public event EventHandler OutputChange; - public string Key { get; private set; } + public string Key { get; private set; } public virtual bool BoolValue { get { return false; } } public virtual int IntValue { get { return 0; } } public virtual string StringValue { get { return ""; } } - public virtual string SerialValue { get { return ""; } } + public virtual string SerialValue { get { return ""; } } /// /// Feedbacks can be put into test mode for simulation of events without real data. @@ -34,13 +34,13 @@ namespace PepperDash.Essentials.Core { } - protected Feedback(string key) - { - if (key == null) - Key = ""; - else - Key = key; - } + protected Feedback(string key) + { + if (key == null) + Key = ""; + else + Key = key; + } @@ -66,28 +66,27 @@ namespace PepperDash.Essentials.Core CrestronInvoke.BeginInvoke(o => FireUpdate()); } - ///// - ///// Helper method that fires event. Use this intstead of calling OutputChange - ///// - //protected void OnOutputChange() - //{ - // if (OutputChange != null) OutputChange(this, EventArgs.Empty); - //} + ///// + ///// Helper method that fires event. Use this intstead of calling OutputChange + ///// + //protected void OnOutputChange() + //{ + // if (OutputChange != null) OutputChange(this, EventArgs.Empty); + //} - protected void OnOutputChange(bool value) - { - if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); - } + protected void OnOutputChange(bool value) + { + if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); + } - protected void OnOutputChange(int value) - { - if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); - } + protected void OnOutputChange(int value) + { + if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); + } - protected void OnOutputChange(string value) - { - if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); - } - } -} \ No newline at end of file + protected void OnOutputChange(string value) + { + if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs index ed7517da..32b1abfb 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs @@ -4,22 +4,21 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Basically a List , with an indexer to find feedbacks by key name +/// +public class FeedbackCollection : List where T : Feedback { /// - /// Basically a List , with an indexer to find feedbacks by key name + /// Case-insensitive port lookup linked to feedbacks' keys /// - public class FeedbackCollection : List where T : Feedback + public T this[string key] { - /// - /// Case-insensitive port lookup linked to feedbacks' keys - /// - public T this[string key] + get { - get - { - return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - } + return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs index 9a7f5c29..8f8a5170 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs @@ -4,45 +4,44 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class FeedbackEventArgs : EventArgs { - public class FeedbackEventArgs : EventArgs + public bool BoolValue { get; private set; } + public int IntValue { get; private set; } + public ushort UShortValue { - public bool BoolValue { get; private set; } - public int IntValue { get; private set; } - public ushort UShortValue + get { - get - { - return (ushort)IntValue; - } - } - public string StringValue { get; private set; } - public eFeedbackEventType Type { get; private set; } - - public FeedbackEventArgs(bool value) - { - BoolValue = value; - Type = eFeedbackEventType.TypeBool; - } - - public FeedbackEventArgs(int value) - { - IntValue = value; - Type = eFeedbackEventType.TypeInt; - } - - public FeedbackEventArgs(string value) - { - StringValue = value; - Type = eFeedbackEventType.TypeString; + return (ushort)IntValue; } } + public string StringValue { get; private set; } + public eFeedbackEventType Type { get; private set; } - public enum eFeedbackEventType + public FeedbackEventArgs(bool value) { - TypeBool, - TypeInt, - TypeString + BoolValue = value; + Type = eFeedbackEventType.TypeBool; } + + public FeedbackEventArgs(int value) + { + IntValue = value; + Type = eFeedbackEventType.TypeInt; + } + + public FeedbackEventArgs(string value) + { + StringValue = value; + Type = eFeedbackEventType.TypeString; + } +} + +public enum eFeedbackEventType +{ + TypeBool, + TypeInt, + TypeString } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs index 53bae09a..1cf7a3bd 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs @@ -5,99 +5,98 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class IntFeedback : Feedback { - public class IntFeedback : Feedback + public override int IntValue { get { return _IntValue; } } // ValueFunc.Invoke(); } } + int _IntValue; + public ushort UShortValue { get { return (ushort)_IntValue; } } + + //public override eCueType Type { get { return eCueType.Int; } } + + public int TestValue { get; private set; } + + /// + /// Func evaluated on FireUpdate + /// + Func ValueFunc; + List LinkedInputSigs = new List(); + + /// + /// Creates the feedback with the Func as described. + /// + /// + /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, + /// it will NOT reflect an actual value from a device until has been called + /// + /// Delegate to invoke when this feedback needs to be updated + public IntFeedback(Func valueFunc) + : this(null, valueFunc) { - public override int IntValue { get { return _IntValue; } } // ValueFunc.Invoke(); } } - int _IntValue; - public ushort UShortValue { get { return (ushort)_IntValue; } } + } - //public override eCueType Type { get { return eCueType.Int; } } + /// + /// Creates the feedback with the Func as described. + /// + /// + /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, + /// it will NOT reflect an actual value from a device until has been called + /// + /// Key to find this Feedback + /// Delegate to invoke when this feedback needs to be updated + public IntFeedback(string key, Func valueFunc) + : base(key) + { + ValueFunc = valueFunc; + } - public int TestValue { get; private set; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } - /// - /// Func evaluated on FireUpdate - /// - Func ValueFunc; - List LinkedInputSigs = new List(); - /// - /// Creates the feedback with the Func as described. - /// - /// - /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, - /// it will NOT reflect an actual value from a device until has been called - /// - /// Delegate to invoke when this feedback needs to be updated - public IntFeedback(Func valueFunc) - : this(null, valueFunc) + public override void FireUpdate() + { + var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); + if (newValue != _IntValue) { - } - - /// - /// Creates the feedback with the Func as described. - /// - /// - /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, - /// it will NOT reflect an actual value from a device until has been called - /// - /// Key to find this Feedback - /// Delegate to invoke when this feedback needs to be updated - public IntFeedback(string key, Func valueFunc) - : base(key) - { - ValueFunc = valueFunc; - } - - public void SetValueFunc(Func newFunc) - { - ValueFunc = newFunc; - } - - - public override void FireUpdate() - { - var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); - if (newValue != _IntValue) - { - _IntValue = newValue; - LinkedInputSigs.ForEach(s => UpdateSig(s)); - OnOutputChange(newValue); - } - } - - public void LinkInputSig(UShortInputSig sig) - { - LinkedInputSigs.Add(sig); - UpdateSig(sig); - } - - public void UnlinkInputSig(UShortInputSig sig) - { - LinkedInputSigs.Remove(sig); - } - - public override string ToString() - { - return (InTestMode ? "TEST -- " : "") + IntValue.ToString(); - } - - /// - /// Puts this in test mode, sets the test value and fires an update. - /// - /// - public void SetTestValue(int value) - { - TestValue = value; - InTestMode = true; - FireUpdate(); - } - - void UpdateSig(UShortInputSig sig) - { - sig.UShortValue = UShortValue; + _IntValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s)); + OnOutputChange(newValue); } } + + public void LinkInputSig(UShortInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } + + public void UnlinkInputSig(UShortInputSig sig) + { + LinkedInputSigs.Remove(sig); + } + + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + IntValue.ToString(); + } + + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(int value) + { + TestValue = value; + InTestMode = true; + FireUpdate(); + } + + void UpdateSig(UShortInputSig sig) + { + sig.UShortValue = UShortValue; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs index bbf135dc..6fe0be62 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs @@ -5,82 +5,81 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// To be used for serial data feedback where the event chain / asynchronicity must be maintained +/// and calculating the value based on a Func when it is needed will not suffice. +/// +public class SerialFeedback : Feedback { + public override string SerialValue { get { return _SerialValue; } } + string _SerialValue; + + //public override eCueType Type { get { return eCueType.Serial; } } + /// - /// To be used for serial data feedback where the event chain / asynchronicity must be maintained - /// and calculating the value based on a Func when it is needed will not suffice. + /// Used in testing. Set/Clear functions /// - public class SerialFeedback : Feedback + public string TestValue { get; private set; } + + List LinkedInputSigs = new List(); + + public SerialFeedback() { - public override string SerialValue { get { return _SerialValue; } } - string _SerialValue; + } - //public override eCueType Type { get { return eCueType.Serial; } } + public SerialFeedback(string key) + : base(key) + { + } - /// - /// Used in testing. Set/Clear functions - /// - public string TestValue { get; private set; } + public override void FireUpdate() + { + throw new NotImplementedException("This feedback type does not use Funcs"); + } - List LinkedInputSigs = new List(); + public void FireUpdate(string newValue) + { + _SerialValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s, newValue)); + OnOutputChange(newValue); + } - public SerialFeedback() - { - } + public void LinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } - public SerialFeedback(string key) - : base(key) - { - } + public void UnlinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Remove(sig); + } - public override void FireUpdate() - { - throw new NotImplementedException("This feedback type does not use Funcs"); - } + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + SerialValue; + } - public void FireUpdate(string newValue) - { - _SerialValue = newValue; - LinkedInputSigs.ForEach(s => UpdateSig(s, newValue)); - OnOutputChange(newValue); - } + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(string value) + { + TestValue = value; + InTestMode = true; + FireUpdate(TestValue); + } - public void LinkInputSig(StringInputSig sig) - { - LinkedInputSigs.Add(sig); - UpdateSig(sig); - } + void UpdateSig(StringInputSig sig) + { + sig.StringValue = _SerialValue; + } - public void UnlinkInputSig(StringInputSig sig) - { - LinkedInputSigs.Remove(sig); - } - - public override string ToString() - { - return (InTestMode ? "TEST -- " : "") + SerialValue; - } - - /// - /// Puts this in test mode, sets the test value and fires an update. - /// - /// - public void SetTestValue(string value) - { - TestValue = value; - InTestMode = true; - FireUpdate(TestValue); - } - - void UpdateSig(StringInputSig sig) - { - sig.StringValue = _SerialValue; - } - - void UpdateSig(StringInputSig sig, string value) - { - sig.StringValue = value; - } + void UpdateSig(StringInputSig sig, string value) + { + sig.StringValue = value; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs b/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs index fb5cccb5..2eb18414 100644 --- a/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs +++ b/src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs @@ -5,99 +5,98 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +public class StringFeedback : Feedback { + public override string StringValue { get { return _StringValue; } } // ValueFunc.Invoke(); } } + string _StringValue; - public class StringFeedback : Feedback + /// + /// Used in testing. Set/Clear functions + /// + public string TestValue { get; private set; } + + /// + /// Evaluated on FireUpdate + /// + public Func ValueFunc { get; private set; } + List LinkedInputSigs = new List(); + + /// + /// Creates the feedback with the Func as described. + /// + /// + /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, + /// it will NOT reflect an actual value from a device until has been called + /// + /// Delegate to invoke when this feedback needs to be updated + public StringFeedback(Func valueFunc) + : this(null, valueFunc) { - public override string StringValue { get { return _StringValue; } } // ValueFunc.Invoke(); } } - string _StringValue; + } - /// - /// Used in testing. Set/Clear functions - /// - public string TestValue { get; private set; } + /// + /// Creates the feedback with the Func as described. + /// + /// + /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, + /// it will NOT reflect an actual value from a device until has been called + /// + /// Key to find this Feedback + /// Delegate to invoke when this feedback needs to be updated + public StringFeedback(string key, Func valueFunc) + : base(key) + { + ValueFunc = valueFunc; + } - /// - /// Evaluated on FireUpdate - /// - public Func ValueFunc { get; private set; } - List LinkedInputSigs = new List(); + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } - /// - /// Creates the feedback with the Func as described. - /// - /// - /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, - /// it will NOT reflect an actual value from a device until has been called - /// - /// Delegate to invoke when this feedback needs to be updated - public StringFeedback(Func valueFunc) - : this(null, valueFunc) + public override void FireUpdate() + { + var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); + if (newValue != _StringValue) { - } - - /// - /// Creates the feedback with the Func as described. - /// - /// - /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, - /// it will NOT reflect an actual value from a device until has been called - /// - /// Key to find this Feedback - /// Delegate to invoke when this feedback needs to be updated - public StringFeedback(string key, Func valueFunc) - : base(key) - { - ValueFunc = valueFunc; - } - - public void SetValueFunc(Func newFunc) - { - ValueFunc = newFunc; - } - - public override void FireUpdate() - { - var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); - if (newValue != _StringValue) - { - _StringValue = newValue; - LinkedInputSigs.ForEach(s => UpdateSig(s)); - OnOutputChange(newValue); - } - } - - public void LinkInputSig(StringInputSig sig) - { - LinkedInputSigs.Add(sig); - UpdateSig(sig); - } - - public void UnlinkInputSig(StringInputSig sig) - { - LinkedInputSigs.Remove(sig); - } - - public override string ToString() - { - return (InTestMode ? "TEST -- " : "") + StringValue; - } - - /// - /// Puts this in test mode, sets the test value and fires an update. - /// - /// - public void SetTestValue(string value) - { - TestValue = value; - InTestMode = true; - FireUpdate(); - } - - void UpdateSig(StringInputSig sig) - { - sig.StringValue = _StringValue; + _StringValue = newValue; + LinkedInputSigs.ForEach(s => UpdateSig(s)); + OnOutputChange(newValue); } } + + public void LinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Add(sig); + UpdateSig(sig); + } + + public void UnlinkInputSig(StringInputSig sig) + { + LinkedInputSigs.Remove(sig); + } + + public override string ToString() + { + return (InTestMode ? "TEST -- " : "") + StringValue; + } + + /// + /// Puts this in test mode, sets the test value and fires an update. + /// + /// + public void SetTestValue(string value) + { + TestValue = value; + InTestMode = true; + FireUpdate(); + } + + void UpdateSig(StringInputSig sig) + { + sig.StringValue = _StringValue; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/File/FileIO.cs b/src/PepperDash.Essentials.Core/File/FileIO.cs index 24bdf8d1..98ad787f 100644 --- a/src/PepperDash.Essentials.Core/File/FileIO.cs +++ b/src/PepperDash.Essentials.Core/File/FileIO.cs @@ -8,8 +8,8 @@ using PepperDash.Core; using Crestron.SimplSharpPro.CrestronThread; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public static class FileIO { @@ -22,37 +22,37 @@ namespace PepperDash.Essentials.Core /// /// /// - public static FileInfo[] GetFiles(string fileName) + public static FileInfo[] GetFiles(string fileName) + { + string fullFilePath = Global.FilePathPrefix + fileName; + DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath)); + var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath)); + Debug.LogMessage(LogEventLevel.Information, "FileIO found: {0}, {1}", files.Count(), fullFilePath); + if (files.Count() > 0) { - string fullFilePath = Global.FilePathPrefix + fileName; - DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath)); - var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath)); - Debug.LogMessage(LogEventLevel.Information, "FileIO found: {0}, {1}", files.Count(), fullFilePath); - if (files.Count() > 0) - { - return files; - } - else - { - return null; - } + return files; } + else + { + return null; + } + } - public static FileInfo GetFile(string fileName) + public static FileInfo GetFile(string fileName) + { + string fullFilePath = Global.FilePathPrefix + fileName; + DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath)); + var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath)); + Debug.LogMessage(LogEventLevel.Information, "FileIO found: {0}, {1}", files.Count(), fullFilePath); + if (files.Count() > 0) { - string fullFilePath = Global.FilePathPrefix + fileName; - DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath)); - var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath)); - Debug.LogMessage(LogEventLevel.Information, "FileIO found: {0}, {1}", files.Count(), fullFilePath); - if (files.Count() > 0) - { - return files.FirstOrDefault(); - } - else - { - return null; - } + return files.FirstOrDefault(); } + else + { + return null; + } + } /// @@ -73,12 +73,12 @@ namespace PepperDash.Essentials.Core } } - /// - /// Get the data with fileInfo object - /// - /// - /// - public static string ReadDataFromFile(FileInfo file) + /// + /// Get the data with fileInfo object + /// + /// + /// + public static string ReadDataFromFile(FileInfo file) { try { @@ -200,7 +200,7 @@ namespace PepperDash.Essentials.Core public static void WriteDataToFile(string data, string filePath) { Thread _WriteFileThread; - _WriteFileThread = new Thread((O) => _WriteFileMethod(data, Global.FilePathPrefix + "/" + filePath), null, Thread.eThreadStartOptions.CreateSuspended); + _WriteFileThread = new Thread((O) => _WriteFileMethod(data, Global.FilePathPrefix + "/" + filePath), null, Thread.eThreadStartOptions.CreateSuspended); _WriteFileThread.Priority = Thread.eThreadPriority.LowestPriority; _WriteFileThread.Start(); Debug.LogMessage(LogEventLevel.Information, "New WriteFile Thread"); @@ -216,7 +216,7 @@ namespace PepperDash.Essentials.Core if (fileLock.TryEnter()) { - using (StreamWriter sw = new StreamWriter(filePath)) + using (StreamWriter sw = new StreamWriter(filePath)) { sw.Write(data); sw.Flush(); @@ -273,5 +273,4 @@ namespace PepperDash.Essentials.Core public FileEventArgs(string data) { Data = data; } public string Data { get; private set; } // readonly - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 9a2667f0..2f0df0b6 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -16,1591 +16,1570 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider { - public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider + private readonly EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; + + private const string RemoteOccupancyXml = "Local{0}"; + private readonly bool _guidFileExists; + + private readonly Dictionary _sourceToFeedbackSigs = + new Dictionary(); + + protected StringSigData CurrentRoomSourceNameSig; + + private readonly FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge(); + protected FusionOccupancySensorAsset FusionOccSensor; + private readonly FusionRemoteOccupancySensor FusionRemoteOccSensor; + + protected FusionRoom FusionRoom; + protected Dictionary FusionStaticAssets; + private readonly long PushNotificationTimeout = 5000; + private readonly IEssentialsRoom Room; + private readonly long SchedulePollInterval = 300000; + + private Event _currentMeeting; + private RoomSchedule _currentSchedule; + private CTimer _dailyTimeRequestTimer; + private StatusMonitorCollection _errorMessageRollUp; + + private FusionRoomGuids _guiDs; + private uint _ipId; + + private bool _isRegisteredForSchedulePushNotifications; + private Event _nextMeeting; + + private CTimer _pollTimer; + + private CTimer _pushNotificationTimer; + + private string _roomOccupancyRemoteString; + + #region System Info Sigs + + //StringSigData SystemName; + //StringSigData Model; + //StringSigData SerialNumber; + //StringSigData Uptime; + + #endregion + + #region Processor Info Sigs + + private readonly StringSigData[] _program = new StringSigData[10]; + private StringSigData _dns1; + private StringSigData _dns2; + private StringSigData _domain; + private StringSigData _firmware; + private StringSigData _gateway; + private StringSigData _hostname; + private StringSigData _ip1; + private StringSigData _ip2; + private StringSigData _mac1; + private StringSigData _mac2; + private StringSigData _netMask1; + private StringSigData _netMask2; + + #endregion + + #region Default Display Source Sigs + + private readonly BooleanSigData[] _source = new BooleanSigData[10]; + + #endregion + + public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey) + : base(room.Key + "-fusion") { - private readonly EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; + try + { + JoinMap = new EssentialsHuddleSpaceRoomFusionRoomJoinMap(1); - private const string RemoteOccupancyXml = "Local{0}"; - private readonly bool _guidFileExists; + CrestronConsole.AddNewConsoleCommand((o) => JoinMap.PrintJoinMapInfo(), string.Format("ptjnmp-{0}", Key), "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator); - private readonly Dictionary _sourceToFeedbackSigs = - new Dictionary(); + if (!string.IsNullOrEmpty(joinMapKey)) + { + var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); + if (customJoins != null) + { + JoinMap.SetCustomJoinData(customJoins); + } + } + + Room = room; - protected StringSigData CurrentRoomSourceNameSig; + _ipId = ipId; - private readonly FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge(); - protected FusionOccupancySensorAsset FusionOccSensor; - private readonly FusionRemoteOccupancySensor FusionRemoteOccSensor; + FusionStaticAssets = new Dictionary(); - protected FusionRoom FusionRoom; - protected Dictionary FusionStaticAssets; - private readonly long PushNotificationTimeout = 5000; - private readonly IEssentialsRoom Room; - private readonly long SchedulePollInterval = 300000; + _guiDs = new FusionRoomGuids(); - private Event _currentMeeting; - private RoomSchedule _currentSchedule; - private CTimer _dailyTimeRequestTimer; - private StatusMonitorCollection _errorMessageRollUp; + var mac = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); - private FusionRoomGuids _guiDs; - private uint _ipId; + var slot = Global.ControlSystem.ProgramNumber; - private bool _isRegisteredForSchedulePushNotifications; - private Event _nextMeeting; + var guidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId); - private CTimer _pollTimer; + var oldGuidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); - private CTimer _pushNotificationTimer; + if (File.Exists(oldGuidFilePath)) + { + Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File"); - private string _roomOccupancyRemoteString; + File.Copy(oldGuidFilePath, guidFilePath); - #region System Info Sigs + File.Delete(oldGuidFilePath); + } - //StringSigData SystemName; - //StringSigData Model; - //StringSigData SerialNumber; - //StringSigData Uptime; + _guidFileExists = File.Exists(guidFilePath); - #endregion + // Check if file exists + if (!_guidFileExists) + { + // Does not exist. Create GUIDs + _guiDs = new FusionRoomGuids(Room.Name, ipId, _guiDs.GenerateNewRoomGuid(slot, mac), + FusionStaticAssets); + } + else + { + // Exists. Read GUIDs + ReadGuidFile(guidFilePath); + } - #region Processor Info Sigs - private readonly StringSigData[] _program = new StringSigData[10]; - private StringSigData _dns1; - private StringSigData _dns2; - private StringSigData _domain; - private StringSigData _firmware; - private StringSigData _gateway; - private StringSigData _hostname; - private StringSigData _ip1; - private StringSigData _ip2; - private StringSigData _mac1; - private StringSigData _mac2; - private StringSigData _netMask1; - private StringSigData _netMask2; + if (Room is IRoomOccupancy occupancyRoom) + { + if (occupancyRoom.RoomOccupancy != null) + { + if (occupancyRoom.OccupancyStatusProviderIsRemote) + { + SetUpRemoteOccupancy(); + } + else + { + SetUpLocalOccupancy(); + } + } + } - #endregion - #region Default Display Source Sigs + AddPostActivationAction(() => PostActivate(guidFilePath)); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Information, this, "Error Building Fusion System Controller: {0}", e); + } + } - private readonly BooleanSigData[] _source = new BooleanSigData[10]; + private void PostActivate(string guidFilePath) + { + CreateSymbolAndBasicSigs(_ipId); + SetUpSources(); + SetUpCommunitcationMonitors(); + SetUpDisplay(); + SetUpError(); + ExecuteCustomSteps(); - #endregion + FusionRVI.GenerateFileForAllFusionDevices(); - public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey) - : base(room.Key + "-fusion") + GenerateGuidFile(guidFilePath); + } + + protected string RoomGuid + { + get { return _guiDs.RoomGuid; } + } + + public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; } + + protected Func RoomIsOccupiedFeedbackFunc + { + get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; } + } + + #region IOccupancyStatusProvider Members + + public BoolFeedback RoomIsOccupiedFeedback { get; private set; } + + #endregion + + public event EventHandler ScheduleChange; + //public event EventHandler MeetingEndWarning; + //public event EventHandler NextMeetingBeginWarning; + + public event EventHandler RoomInfoChange; + + //ScheduleResponseEvent NextMeeting; + + /// + /// Used for extension classes to execute whatever steps are necessary before generating the RVI and GUID files + /// + protected virtual void ExecuteCustomSteps() + { + } + + /// + /// Generates the guid file in NVRAM. If the file already exists it will be overwritten. + /// + /// path for the file + private void GenerateGuidFile(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + { + Debug.LogMessage(LogEventLevel.Information, this, "Error writing guid file. No path specified."); + return; + } + + var fileLock = new CCriticalSection(); + + try + { + if (fileLock.Disposed) + { + return; + } + + fileLock.Enter(); + + Debug.LogMessage(LogEventLevel.Debug, this, "Writing GUIDs to file"); + + _guiDs = FusionOccSensor == null + ? new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets) + : new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets, FusionOccSensor); + + var json = JsonConvert.SerializeObject(_guiDs, Newtonsoft.Json.Formatting.Indented); + + using (var sw = new StreamWriter(filePath)) + { + sw.Write(json); + sw.Flush(); + } + + Debug.LogMessage(LogEventLevel.Debug, this, "Guids successfully written to file '{0}'", filePath); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Information, this, "Error writing guid file: {0}", e); + } + finally + { + if (!fileLock.Disposed) + { + fileLock.Leave(); + } + } + } + + /// + /// Reads the guid file from NVRAM + /// + /// path for te file + private void ReadGuidFile(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + { + Debug.LogMessage(LogEventLevel.Information, this, "Error reading guid file. No path specified."); + return; + } + + var fileLock = new CCriticalSection(); + + try + { + if (fileLock.Disposed) + { + return; + } + + fileLock.Enter(); + + if (File.Exists(filePath)) + { + var json = File.ReadToEnd(filePath, Encoding.ASCII); + + _guiDs = JsonConvert.DeserializeObject(json); + + _ipId = _guiDs.IpId; + + FusionStaticAssets = _guiDs.StaticAssets; + } + + Debug.LogMessage(LogEventLevel.Information, this, "Fusion Guids successfully read from file: {0}", + filePath); + + Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _ipId, RoomGuid); + + foreach (var item in FusionStaticAssets) + { + Debug.LogMessage(LogEventLevel.Debug, this, "\nAsset Name: {0}\nAsset No: {1}\n Guid: {2}", item.Value.Name, + item.Value.SlotNumber, item.Value.InstanceId); + } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Information, this, "Error reading guid file: {0}", e); + } + finally + { + if (!fileLock.Disposed) + { + fileLock.Leave(); + } + } + } + + protected virtual void CreateSymbolAndBasicSigs(uint ipId) + { + Debug.LogMessage(LogEventLevel.Information, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); + + FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); + FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); + FusionRoom.ExtenderFusionRoomDataReservedSigs.Use(); + + FusionRoom.Register(); + + FusionRoom.FusionStateChange += FusionRoom_FusionStateChange; + + FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += + FusionRoomSchedule_DeviceExtenderSigChange; + FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += + ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange; + FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange; + + CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", + "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", + "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(CreateAdHocMeeting, "FusCreateMeeting", + "Creates and Ad Hoc meeting for on hour or until the next meeting", + ConsoleAccessLevelEnum.AccessOperator); + + // Room to fusion room + Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig); + + // Moved to + CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(JoinMap.Display1CurrentSourceName.JoinNumber, JoinMap.Display1CurrentSourceName.AttributeName, + eSigIoMask.InputSigOnly); + // Don't think we need to get current status of this as nothing should be alive yet. + if (Room is IHasCurrentSourceInfoChange hasCurrentSourceInfoChange) + { + hasCurrentSourceInfoChange.CurrentSourceChange += Room_CurrentSourceInfoChange; + } + + + FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction(Room.PowerOnToDefaultOrLastSource); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => + { + if (Room is IRunRouteAction runRouteAction) + { + runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); + } + }); + // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); + FusionRoom.ErrorMessage.InputSig.StringValue = + "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; + + SetUpEthernetValues(); + + GetProcessorEthernetValues(); + + GetSystemInfo(); + + GetProcessorInfo(); + + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + } + + protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + { + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp) + { + GetProcessorEthernetValues(); + } + } + + protected void GetSystemInfo() + { + //SystemName.InputSig.StringValue = Room.Name; + //Model.InputSig.StringValue = InitialParametersClass.ControllerPromptName; + //SerialNumber.InputSig.StringValue = InitialParametersClass. + + var response = string.Empty; + + var systemReboot = FusionRoom.CreateOffsetBoolSig(JoinMap.ProcessorReboot.JoinNumber, JoinMap.ProcessorReboot.AttributeName, eSigIoMask.OutputSigOnly); + systemReboot.OutputSig.SetSigFalseAction( + () => CrestronConsole.SendControlSystemCommand("reboot", ref response)); + } + + protected void SetUpEthernetValues() + { + _ip1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp1.JoinNumber, JoinMap.ProcessorIp1.AttributeName, eSigIoMask.InputSigOnly); + _ip2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp2.JoinNumber, JoinMap.ProcessorIp2.AttributeName, eSigIoMask.InputSigOnly); + _gateway = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorGateway.JoinNumber, JoinMap.ProcessorGateway.AttributeName, eSigIoMask.InputSigOnly); + _hostname = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorHostname.JoinNumber, JoinMap.ProcessorHostname.AttributeName, eSigIoMask.InputSigOnly); + _domain = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDomain.JoinNumber, JoinMap.ProcessorDomain.AttributeName, eSigIoMask.InputSigOnly); + _dns1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDns1.JoinNumber, JoinMap.ProcessorDns1.AttributeName, eSigIoMask.InputSigOnly); + _dns2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDns2.JoinNumber, JoinMap.ProcessorDns2.AttributeName, eSigIoMask.InputSigOnly); + _mac1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorMac1.JoinNumber, JoinMap.ProcessorMac1.AttributeName, eSigIoMask.InputSigOnly); + _mac2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorMac2.JoinNumber, JoinMap.ProcessorMac2.AttributeName, eSigIoMask.InputSigOnly); + _netMask1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask1.JoinNumber, JoinMap.ProcessorNetMask1.AttributeName, eSigIoMask.InputSigOnly); + _netMask2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask2.JoinNumber, JoinMap.ProcessorNetMask2.AttributeName, eSigIoMask.InputSigOnly); + } + + protected void GetProcessorEthernetValues() + { + _ip1.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + _gateway.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); + _hostname.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + _domain.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); + + var dnsServers = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, 0).Split(','); + _dns1.InputSig.StringValue = dnsServers[0]; + if (dnsServers.Length > 1) + { + _dns2.InputSig.StringValue = dnsServers[1]; + } + + _mac1.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); + _netMask1.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0); + + // Interface 1 + + if (InitialParametersClass.NumberOfEthernetInterfaces > 1) + // Only get these values if the processor has more than 1 NIC + { + _ip2.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 1); + _mac2.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 1); + _netMask2.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 1); + } + } + + protected void GetProcessorInfo() + { + _firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly); + + if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) + { + for (var i = 0; i < Global.ControlSystem.NumProgramsSupported; i++) + { + var join = JoinMap.ProgramNameStart.JoinNumber + i; + var progNum = i + 1; + _program[i] = FusionRoom.CreateOffsetStringSig((uint) join, + string.Format("{0} {1}", JoinMap.ProgramNameStart.AttributeName, progNum), eSigIoMask.InputSigOnly); + } + } + + _firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; + } + + protected void GetCustomProperties() + { + if (FusionRoom.IsOnline) + { + const string fusionRoomCustomPropertiesRequest = + @"RoomConfigurationRequest"; + + FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigQuery.StringValue = + fusionRoomCustomPropertiesRequest; + } + } + + private void GetTouchpanelInfo() + { + // TODO: Get IP and Project Name from TP + } + + protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) + { + if (args.DeviceOnLine) + { + CrestronInvoke.BeginInvoke( (o) => + { + CrestronEnvironment.Sleep(200); + + // Send Push Notification Action request: + + const string requestId = "InitialPushRequest"; + + + var actionRequest = + string.Format("\n{0}\n", requestId) + + "RegisterPushModel\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n"; + + Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ActionRequest: \n{0}", actionRequest); + + FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = actionRequest; + + GetCustomProperties(); + + // Request current Fusion Server Time + RequestLocalDateTime(null); + + // Setup timer to request time daily + if (_dailyTimeRequestTimer != null && !_dailyTimeRequestTimer.Disposed) + { + _dailyTimeRequestTimer.Stop(); + _dailyTimeRequestTimer.Dispose(); + } + + _dailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000); + + _dailyTimeRequestTimer.Reset(86400000, 86400000); + }); + } + } + + /// + /// Requests the local date and time from the Fusion Server + /// + /// + public void RequestLocalDateTime(object callbackObject) + { + const string timeRequestId = "TimeRequest"; + + var timeRequest = string.Format("{0}", + timeRequestId); + + FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQuery.StringValue = timeRequest; + } + + /// + /// Generates a room schedule request for this room for the next 24 hours. + /// + public void RequestFullRoomSchedule(object callbackObject) + { + var now = DateTime.Today; + + var currentTime = now.ToString("s"); + + var requestTest = + string.Format( + "FullSchedleRequest{0}{1}24", + RoomGuid, currentTime); + + Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ScheduleQuery: \n{0}", requestTest); + + FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleQuery.StringValue = requestTest; + + if (_isRegisteredForSchedulePushNotifications) + { + _pushNotificationTimer.Stop(); + } + } + + /// + /// Wrapper method to allow console commands to modify the current meeting end time + /// + /// meetingID extendTime + public void ModifyMeetingEndTimeConsoleHelper(string command) + { + var extendMinutes = -1; + + const string requestId = "ModifyMeetingTest12345"; + + try + { + var tokens = command.Split(' '); + + extendMinutes = Int32.Parse(tokens[1]); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing console command: {0}", e); + } + + ModifyMeetingEndTime(requestId, extendMinutes); + } + + /// + /// Ends or Extends the current meeting by the specified number of minutes. + /// + /// + /// Number of minutes to extend the meeting. A value of 0 will end the meeting. + public void ModifyMeetingEndTime(string requestId, int extendMinutes) + { + if (_currentMeeting == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "No meeting in progress. Unable to modify end time."); + return; + } + + if (extendMinutes > -1) + { + if (extendMinutes > 0) + { + var extendTime = _currentMeeting.dtEnd - DateTime.Now; + var extendMinutesRaw = extendTime.TotalMinutes; + + extendMinutes += (int) Math.Round(extendMinutesRaw); + } + + + var requestTest = string.Format( + "{0}{1}MeetingChange" + , requestId, RoomGuid, _currentMeeting.MeetingID, extendMinutes); + + Debug.LogMessage(LogEventLevel.Debug, this, "Sending MeetingChange Request: \n{0}", requestTest); + + FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = requestTest; + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Invalid time specified"); + } + } + + /// + /// Creates and Ad Hoc meeting with a duration of 1 hour, or until the next meeting if in less than 1 hour. + /// + public void CreateAdHocMeeting(string command) + { + const string requestId = "CreateAdHocMeeting"; + + var now = DateTime.Now.AddMinutes(1); + + now.AddSeconds(-now.Second); + + // Assume 1 hour meeting if possible + var dtEnd = now.AddHours(1); + + // Check if room is available for 1 hour before next meeting + if (_nextMeeting != null) + { + var roomAvailable = _nextMeeting.dtEnd.Subtract(dtEnd); + + if (roomAvailable.TotalMinutes < 60) + { + // Room not available for full hour, book until next meeting starts + dtEnd = _nextMeeting.dtEnd; + } + } + + var createMeetingRequest = + "" + + string.Format("{0}", requestId) + + string.Format("{0}", RoomGuid) + + "" + + string.Format("{0}", now.ToString("s")) + + string.Format("{0}", dtEnd.ToString("s")) + + "AdHoc Meeting" + + "Room User" + + "Example Message" + + "" + + ""; + + Debug.LogMessage(LogEventLevel.Verbose, this, "Sending CreateMeeting Request: \n{0}", createMeetingRequest); + + FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = createMeetingRequest; + + //Debug.LogMessage(LogEventLevel.Debug, this, "Sending CreateMeeting Request: \n{0}", command); + + //FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = command; + } + + /// + /// Event handler method for Device Extender sig changes + /// + /// + /// + protected void ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, + SigEventArgs args) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, + args.Sig.StringValue); + + + if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQueryResponse) { try { - JoinMap = new EssentialsHuddleSpaceRoomFusionRoomJoinMap(1); + var message = new XmlDocument(); - CrestronConsole.AddNewConsoleCommand((o) => JoinMap.PrintJoinMapInfo(), string.Format("ptjnmp-{0}", Key), "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator); + message.LoadXml(args.Sig.StringValue); - if (!string.IsNullOrEmpty(joinMapKey)) + var actionResponse = message["ActionResponse"]; + + if (actionResponse == null) { - var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); - if (customJoins != null) + return; + } + + var requestId = actionResponse["RequestID"]; + + if (requestId.InnerText != "InitialPushRequest") + { + return; + } + + if (actionResponse["ActionID"].InnerText != "RegisterPushModel") + { + return; + } + + var parameters = actionResponse["Parameters"]; + + foreach (var isRegistered in from XmlElement parameter in parameters + where parameter.HasAttributes + select parameter.Attributes + into attributes + where attributes["ID"].Value == "Registered" + select Int32.Parse(attributes["Value"].Value)) + { + switch (isRegistered) { - JoinMap.SetCustomJoinData(customJoins); + case 1: + _isRegisteredForSchedulePushNotifications = true; + if (_pollTimer != null && !_pollTimer.Disposed) + { + _pollTimer.Stop(); + _pollTimer.Dispose(); + } + _pushNotificationTimer = new CTimer(RequestFullRoomSchedule, null, + PushNotificationTimeout, PushNotificationTimeout); + _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); + break; + case 0: + _isRegisteredForSchedulePushNotifications = false; + if (_pushNotificationTimer != null && !_pushNotificationTimer.Disposed) + { + _pushNotificationTimer.Stop(); + _pushNotificationTimer.Dispose(); + } + _pollTimer = new CTimer(RequestFullRoomSchedule, null, SchedulePollInterval, + SchedulePollInterval); + _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); + break; } } - - Room = room; + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing ActionQueryResponse: {0}", e); + } + } + else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQueryResponse) + { + try + { + var message = new XmlDocument(); - _ipId = ipId; + message.LoadXml(args.Sig.StringValue); - FusionStaticAssets = new Dictionary(); + var localDateTimeResponse = message["LocalTimeResponse"]; - _guiDs = new FusionRoomGuids(); - - var mac = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); - - var slot = Global.ControlSystem.ProgramNumber; - - var guidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId); - - var oldGuidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); - - if (File.Exists(oldGuidFilePath)) + if (localDateTimeResponse != null) { - Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File"); + var localDateTime = localDateTimeResponse["LocalDateTime"]; - File.Copy(oldGuidFilePath, guidFilePath); + if (localDateTime != null) + { + var tempLocalDateTime = localDateTime.InnerText; - File.Delete(oldGuidFilePath); + var currentTime = DateTime.Parse(tempLocalDateTime); + + Debug.LogMessage(LogEventLevel.Debug, this, "DateTime from Fusion Server: {0}", currentTime); + + // Parse time and date from response and insert values + CrestronEnvironment.SetTimeAndDate((ushort) currentTime.Hour, (ushort) currentTime.Minute, + (ushort) currentTime.Second, (ushort) currentTime.Month, (ushort) currentTime.Day, + (ushort) currentTime.Year); + + Debug.LogMessage(LogEventLevel.Debug, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime()); + } } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing LocalDateTimeQueryResponse: {0}", e); + } + } + else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigResponse) + { + // Room info response with custom properties - _guidFileExists = File.Exists(guidFilePath); + var roomConfigResponseArgs = args.Sig.StringValue.Replace("&", "and"); - // Check if file exists - if (!_guidFileExists) + Debug.LogMessage(LogEventLevel.Verbose, this, "Fusion Response: \n {0}", roomConfigResponseArgs); + + try + { + var roomConfigResponse = new XmlDocument(); + + roomConfigResponse.LoadXml(roomConfigResponseArgs); + + var requestRoomConfiguration = roomConfigResponse["RoomConfigurationResponse"]; + + if (requestRoomConfiguration != null) { - // Does not exist. Create GUIDs - _guiDs = new FusionRoomGuids(Room.Name, ipId, _guiDs.GenerateNewRoomGuid(slot, mac), - FusionStaticAssets); + var roomInformation = new RoomInformation(); + + foreach (XmlElement e in roomConfigResponse.FirstChild.ChildNodes) + { + if (e.Name == "RoomInformation") + { + var roomInfo = new XmlReader(e.OuterXml); + + roomInformation = CrestronXMLSerialization.DeSerializeObject(roomInfo); + } + else if (e.Name == "CustomFields") + { + foreach (XmlElement el in e) + { + var customProperty = new FusionCustomProperty(); + + if (el.Name == "CustomField") + { + customProperty.ID = el.Attributes["ID"].Value; + } + + foreach (XmlElement elm in el) + { + if (elm.Name == "CustomFieldName") + { + customProperty.CustomFieldName = elm.InnerText; + } + if (elm.Name == "CustomFieldType") + { + customProperty.CustomFieldType = elm.InnerText; + } + if (elm.Name == "CustomFieldValue") + { + customProperty.CustomFieldValue = elm.InnerText; + } + } + + roomInformation.FusionCustomProperties.Add(customProperty); + } + } + } + RoomInfoChange?.Invoke(this, new EventArgs()); + + CustomPropertiesBridge.EvaluateRoomInfo(Room.Key, roomInformation); + } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing Custom Properties response: {0}", e); + } + //PrintRoomInfo(); + //getRoomInfoBusy = false; + //_DynFusion.API.EISC.BooleanInput[Constants.GetRoomInfo].BoolValue = getRoomInfoBusy; + } + } + + /// + /// Event handler method for Device Extender sig changes + /// + /// + /// + protected void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, + SigEventArgs args) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Scehdule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, + args.Sig.Name, args.Sig.StringValue); + + + if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleResponse) + { + try + { + var scheduleResponse = new ScheduleResponse(); + + var message = new XmlDocument(); + + message.LoadXml(args.Sig.StringValue); + + var response = message["ScheduleResponse"]; + + if (response != null) + { + // Check for push notification + if (response["RequestID"].InnerText == "RVRequest") + { + var action = response["Action"]; + + if (action.OuterXml.IndexOf("RequestSchedule", StringComparison.Ordinal) > -1) + { + _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); + } + } + else // Not a push notification + { + _currentSchedule = new RoomSchedule(); // Clear Current Schedule + _currentMeeting = null; // Clear Current Meeting + _nextMeeting = null; // Clear Next Meeting + + var isNextMeeting = false; + + foreach (XmlElement element in message.FirstChild.ChildNodes) + { + if (element.Name == "RequestID") + { + scheduleResponse.RequestID = element.InnerText; + } + else if (element.Name == "RoomID") + { + scheduleResponse.RoomID = element.InnerText; + } + else if (element.Name == "RoomName") + { + scheduleResponse.RoomName = element.InnerText; + } + else if (element.Name == "Event") + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Event Found:\n{0}", element.OuterXml); + + var reader = new XmlReader(element.OuterXml); + + var tempEvent = CrestronXMLSerialization.DeSerializeObject(reader); + + scheduleResponse.Events.Add(tempEvent); + + // Check is this is the current event + if (tempEvent.dtStart <= DateTime.Now && tempEvent.dtEnd >= DateTime.Now) + { + _currentMeeting = tempEvent; // Set Current Meeting + isNextMeeting = true; // Flag that next element is next meeting + } + + if (isNextMeeting) + { + _nextMeeting = tempEvent; // Set Next Meeting + isNextMeeting = false; + } + + _currentSchedule.Meetings.Add(tempEvent); + } + } + + PrintTodaysSchedule(); + + if (!_isRegisteredForSchedulePushNotifications) + { + _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); + } + + // Fire Schedule Change Event + ScheduleChange?.Invoke(this, new ScheduleChangeEventArgs { Schedule = _currentSchedule }); + } + } + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing ScheduleResponse: {0}", e); + } + } + else if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateResponse) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Create Meeting Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, + args.Sig.Name, args.Sig.StringValue); + } + } + + /// + /// Prints today's schedule to console for debugging + /// + private void PrintTodaysSchedule() + { + if (Debug.Level > 1) + { + if (_currentSchedule.Meetings.Count > 0) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Today's Schedule for '{0}'\n", Room.Name); + + foreach (var e in _currentSchedule.Meetings) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Subject: {0}", e.Subject); + Debug.LogMessage(LogEventLevel.Debug, this, "Organizer: {0}", e.Organizer); + Debug.LogMessage(LogEventLevel.Debug, this, "MeetingID: {0}", e.MeetingID); + Debug.LogMessage(LogEventLevel.Debug, this, "Start Time: {0}", e.dtStart); + Debug.LogMessage(LogEventLevel.Debug, this, "End Time: {0}", e.dtEnd); + Debug.LogMessage(LogEventLevel.Debug, this, "Duration: {0}\n", e.DurationInMinutes); + } + } + } + } + + protected virtual void SetUpSources() + { + // Sources + var dict = ConfigReader.ConfigObject.GetSourceListForKey(Room.SourceListKey); + if (dict != null) + { + // NEW PROCESS: + // Make these lists and insert the fusion attributes by iterating these + var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls); + uint i = 1; + foreach (var kvp in setTopBoxes) + { + TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + i, JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); + i++; + if (i > JoinMap.Display1SetTopBoxSourceStart.JoinSpan) // We only have five spots + { + break; + } + } + + var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls); + i = 1; + foreach (var kvp in discPlayers) + { + TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + i, JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); + i++; + if (i > JoinMap.Display1DiscPlayerSourceStart.JoinSpan) // We only have five spots + { + break; + } + } + + var laptops = dict.Where(d => d.Value.SourceDevice is IRoutingSource); + i = 1; + foreach (var kvp in laptops) + { + TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + i, JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); + i++; + if (i > JoinMap.Display1LaptopSourceStart.JoinSpan) // We only have ten spots??? + { + break; + } + } + + foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType()) + { + usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) {UsageIsTracked = true}; + usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; + } + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Config source list '{0}' not found for room '{1}'", + Room.SourceListKey, Room.Key); + } + } + + /// + /// Collects usage data from source and sends to Fusion + /// + /// + /// + protected void UsageTracker_DeviceUsageEnded(object sender, DeviceUsageEventArgs e) + { + if (!(sender is UsageTracking deviceTracker)) + { + return; + } + + var group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); + + var currentMeetingId = "-"; + + if (_currentMeeting != null) + { + currentMeetingId = _currentMeeting.MeetingID; + } + + //String Format: "USAGE||[Date YYYY-MM-DD]||[Time HH-mm-ss]||TIME||[Asset_Type]||[Asset_Name]||[Minutes_used]||[Asset_ID]||[Meeting_ID]" + // [Asset_ID] property does not appear to be used in Crestron SSI examples. They are sending "-" instead so that's what is replicated here + var deviceUsage = string.Format("USAGE||{0}||{1}||TIME||{2}||{3}||-||{4}||-||{5}||{6}||\r\n", + e.UsageEndTime.ToString("yyyy-MM-dd"), e.UsageEndTime.ToString("HH:mm:ss"), + @group, deviceTracker.Parent.Name, e.MinutesUsed, "-", currentMeetingId); + + Debug.LogMessage(LogEventLevel.Debug, this, "Device usage for: {0} ended at {1}. In use for {2} minutes", + deviceTracker.Parent.Name, e.UsageEndTime, e.MinutesUsed); + + FusionRoom.DeviceUsage.InputSig.StringValue = deviceUsage; + + Debug.LogMessage(LogEventLevel.Debug, this, "Device usage string: {0}", deviceUsage); + } + + + protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Creating attribute '{0}' with join {1} for source {2}", + attrName, attrNum, pSrc.Key); + try + { + var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig); + // Need feedback when this source is selected + // Event handler, added below, will compare source changes with this sig dict + _sourceToFeedbackSigs.Add(pSrc, sigD.InputSig); + + // And respond to selection in Fusion + sigD.OutputSig.SetSigFalseAction(() => + { + if (Room is IRunRouteAction runRouteAction) + { + runRouteAction.RunRouteAction(routeKey, Room.SourceListKey); + } + }); + } + catch (Exception) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", + attrNum, attrName, pSrc.Key); + } + } + + /// + /// + /// + private void SetUpCommunitcationMonitors() + { + uint displayNum = 0; + uint touchpanelNum = 0; + uint xpanelNum = 0; + + // Attach to all room's devices with monitors. + //foreach (var dev in DeviceManager.Devices) + foreach (var dev in DeviceManager.GetDevices()) + { + if (!(dev is ICommunicationMonitor)) + { + continue; + } + + string attrName = null; + uint attrNum = 1; + + //var keyNum = ExtractNumberFromKey(dev.Key); + //if (keyNum == -1) + //{ + // Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Cannot link device '{0}' to numbered Fusion monitoring attributes", + // dev.Key); + // continue; + //} + //uint attrNum = Convert.ToUInt32(keyNum); + + // Check for UI devices + if (dev is IHasBasicTriListWithSmartObject uiDev) + { + if (uiDev.Panel is Crestron.SimplSharpPro.UI.XpanelForSmartGraphics) + { + attrNum += touchpanelNum; + + if (attrNum > JoinMap.XpanelOnlineStart.JoinSpan) + { + continue; + } + attrName = JoinMap.XpanelOnlineStart.AttributeName + " " + attrNum; + attrNum += JoinMap.XpanelOnlineStart.JoinNumber; + + touchpanelNum++; } else { - // Exists. Read GUIDs - ReadGuidFile(guidFilePath); - } + attrNum += xpanelNum; - - if (Room is IRoomOccupancy occupancyRoom) - { - if (occupancyRoom.RoomOccupancy != null) + if (attrNum > JoinMap.TouchpanelOnlineStart.JoinSpan) { - if (occupancyRoom.OccupancyStatusProviderIsRemote) - { - SetUpRemoteOccupancy(); - } - else - { - SetUpLocalOccupancy(); - } + continue; } + attrName = JoinMap.TouchpanelOnlineStart.AttributeName + " " + attrNum; + attrNum += JoinMap.TouchpanelOnlineStart.JoinNumber; + + xpanelNum++; } - - - AddPostActivationAction(() => PostActivate(guidFilePath)); } - catch (Exception e) + + //else + if (dev is IDisplay) { - Debug.LogMessage(LogEventLevel.Information, this, "Error Building Fusion System Controller: {0}", e); + attrNum += displayNum; + if (attrNum > JoinMap.DisplayOnlineStart.JoinSpan) + { + continue; + } + attrName = JoinMap.DisplayOnlineStart.AttributeName + " " + attrNum; + attrNum += JoinMap.DisplayOnlineStart.JoinNumber; + + displayNum++; + } + //else if (dev is DvdDeviceBase) + //{ + // if (attrNum > 5) + // continue; + // attrName = "Device Ok - DVD " + attrNum; + // attrNum += 260; + //} + // add set top box + + // add Cresnet roll-up + + // add DM-devices roll-up + + if (attrName != null) + { + // Link comm status to sig and update + var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); + var smd = dev as ICommunicationMonitor; + sigD.InputSig.BoolValue = smd.CommunicationMonitor.Status == MonitorStatus.IsOk; + smd.CommunicationMonitor.StatusChange += + (o, a) => { sigD.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; + Debug.LogMessage(LogEventLevel.Information, this, "Linking '{0}' communication monitor to Fusion '{1}'", dev.Key, attrName); } } + } - private void PostActivate(string guidFilePath) + protected virtual void SetUpDisplay() + { + try { - CreateSymbolAndBasicSigs(_ipId); - SetUpSources(); - SetUpCommunitcationMonitors(); - SetUpDisplay(); - SetUpError(); - ExecuteCustomSteps(); + //Setup Display Usage Monitoring - FusionRVI.GenerateFileForAllFusionDevices(); + var displays = DeviceManager.AllDevices.Where(d => d is IDisplay); - GenerateGuidFile(guidFilePath); - } + // Consider updating this in multiple display systems - protected string RoomGuid - { - get { return _guiDs.RoomGuid; } - } - - public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; } - - protected Func RoomIsOccupiedFeedbackFunc - { - get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; } - } - - #region IOccupancyStatusProvider Members - - public BoolFeedback RoomIsOccupiedFeedback { get; private set; } - - #endregion - - public event EventHandler ScheduleChange; - //public event EventHandler MeetingEndWarning; - //public event EventHandler NextMeetingBeginWarning; - - public event EventHandler RoomInfoChange; - - //ScheduleResponseEvent NextMeeting; - - /// - /// Used for extension classes to execute whatever steps are necessary before generating the RVI and GUID files - /// - protected virtual void ExecuteCustomSteps() - { - } - - /// - /// Generates the guid file in NVRAM. If the file already exists it will be overwritten. - /// - /// path for the file - private void GenerateGuidFile(string filePath) - { - if (string.IsNullOrEmpty(filePath)) + foreach (var display in displays.Cast()) { - Debug.LogMessage(LogEventLevel.Information, this, "Error writing guid file. No path specified."); + display.UsageTracker = new UsageTracking(display as Device) {UsageIsTracked = true}; + display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; + } + + if (!(Room is IHasDefaultDisplay hasDefaultDisplay)) + { + return; + } + if (!(hasDefaultDisplay.DefaultDisplay is IDisplay defaultDisplay)) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Cannot link null display to Fusion because default display is null"); return; } - var fileLock = new CCriticalSection(); - - try + var dispPowerOnAction = new Action(b => { - if (fileLock.Disposed) + if (!b) { - return; + defaultDisplay.PowerOn(); + } + }); + var dispPowerOffAction = new Action(b => + { + if (!b) + { + defaultDisplay.PowerOff(); + } + }); + + // Display to fusion room sigs + FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; + FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; + + MapDisplayToRoomJoins(1, JoinMap.Display1Start.JoinNumber, defaultDisplay); + + + var deviceConfig = + ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); + + //Check for existing asset in GUIDs collection + + FusionAsset tempAsset; + + if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) + { + tempAsset = FusionStaticAssets[deviceConfig.Uid]; + } + else + { + // Create a new asset + tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), + defaultDisplay.Name, "Display", ""); + FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); + } + + var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", + tempAsset.InstanceId); + dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; + dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; + + if (defaultDisplay is IHasPowerControlWithFeedback defaultTwoWayDisplay) + { + defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); + if (defaultDisplay is IDisplayUsage) + { + (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); } - fileLock.Enter(); - - Debug.LogMessage(LogEventLevel.Debug, this, "Writing GUIDs to file"); - - _guiDs = FusionOccSensor == null - ? new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets) - : new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets, FusionOccSensor); - - var json = JsonConvert.SerializeObject(_guiDs, Newtonsoft.Json.Formatting.Indented); - - using (var sw = new StreamWriter(filePath)) - { - sw.Write(json); - sw.Flush(); - } - - Debug.LogMessage(LogEventLevel.Debug, this, "Guids successfully written to file '{0}'", filePath); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Information, this, "Error writing guid file: {0}", e); - } - finally - { - if (!fileLock.Disposed) - { - fileLock.Leave(); - } + defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); } + + // Use extension methods + dispAsset.TrySetMakeModel(defaultDisplay as Device); + dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay as Device); } - - /// - /// Reads the guid file from NVRAM - /// - /// path for te file - private void ReadGuidFile(string filePath) + catch (Exception e) { - if (string.IsNullOrEmpty(filePath)) + Debug.LogMessage(LogEventLevel.Debug, this, "Error setting up display in Fusion: {0}", e); + } + } + + /// + /// Maps room attributes to a display at a specified index + /// + /// + /// + /// + /// a + protected virtual void MapDisplayToRoomJoins(int displayIndex, uint joinOffset, IDisplay display) + { + var displayName = string.Format("Display {0} - ", displayIndex); + + + if (!(Room is IHasDefaultDisplay hasDefaultDisplay) || display != hasDefaultDisplay.DefaultDisplay) + { + return; + } + // Display volume + var defaultDisplayVolume = FusionRoom.CreateOffsetUshortSig(JoinMap.VolumeFader1.JoinNumber, JoinMap.VolumeFader1.AttributeName, + eSigIoMask.InputOutputSig); + defaultDisplayVolume.OutputSig.UserObject = new Action(b => + { + if (!(display is IBasicVolumeWithFeedback basicVolumeWithFeedback)) { - Debug.LogMessage(LogEventLevel.Information, this, "Error reading guid file. No path specified."); return; } - var fileLock = new CCriticalSection(); + basicVolumeWithFeedback.SetVolume(b); + basicVolumeWithFeedback.VolumeLevelFeedback.LinkInputSig(defaultDisplayVolume.InputSig); + }); - try + + // Power on + var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On", + eSigIoMask.InputOutputSig); + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) { - if (fileLock.Disposed) - { - return; - } - - fileLock.Enter(); - - if (File.Exists(filePath)) - { - var json = File.ReadToEnd(filePath, Encoding.ASCII); - - _guiDs = JsonConvert.DeserializeObject(json); - - _ipId = _guiDs.IpId; - - FusionStaticAssets = _guiDs.StaticAssets; - } - - Debug.LogMessage(LogEventLevel.Information, this, "Fusion Guids successfully read from file: {0}", - filePath); - - Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _ipId, RoomGuid); - - foreach (var item in FusionStaticAssets) - { - Debug.LogMessage(LogEventLevel.Debug, this, "\nAsset Name: {0}\nAsset No: {1}\n Guid: {2}", item.Value.Name, - item.Value.SlotNumber, item.Value.InstanceId); - } + display.PowerOn(); } - catch (Exception e) + }); + + // Power Off + var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1, displayName + "Power Off", + eSigIoMask.InputOutputSig); + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) { - Debug.LogMessage(LogEventLevel.Information, this, "Error reading guid file: {0}", e); - } - finally - { - if (!fileLock.Disposed) - { - fileLock.Leave(); - } + display.PowerOff(); } + }); + + + if (display is IHasPowerControlWithFeedback defaultTwoWayDisplay) + { + defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); + defaultTwoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(defaultDisplayPowerOff.InputSig); } - protected virtual void CreateSymbolAndBasicSigs(uint ipId) + // Current Source + var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8, + displayName + "Source None", eSigIoMask.InputOutputSig); + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { - Debug.LogMessage(LogEventLevel.Information, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); - - FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); - FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); - FusionRoom.ExtenderFusionRoomDataReservedSigs.Use(); - - FusionRoom.Register(); - - FusionRoom.FusionStateChange += FusionRoom_FusionStateChange; - - FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += - FusionRoomSchedule_DeviceExtenderSigChange; - FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += - ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange; - FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange; - - CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", - "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", - "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(CreateAdHocMeeting, "FusCreateMeeting", - "Creates and Ad Hoc meeting for on hour or until the next meeting", - ConsoleAccessLevelEnum.AccessOperator); - - // Room to fusion room - Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig); - - // Moved to - CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(JoinMap.Display1CurrentSourceName.JoinNumber, JoinMap.Display1CurrentSourceName.AttributeName, - eSigIoMask.InputSigOnly); - // Don't think we need to get current status of this as nothing should be alive yet. - if (Room is IHasCurrentSourceInfoChange hasCurrentSourceInfoChange) - { - hasCurrentSourceInfoChange.CurrentSourceChange += Room_CurrentSourceInfoChange; - } - - - FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction(Room.PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => + if (!b) { if (Room is IRunRouteAction runRouteAction) { runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); } - }); - // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); - FusionRoom.ErrorMessage.InputSig.StringValue = - "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; + } + }); + } - SetUpEthernetValues(); - - GetProcessorEthernetValues(); - - GetSystemInfo(); - - GetProcessorInfo(); - - CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; - } - - protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + private void SetUpError() + { + // Roll up ALL device errors + _errorMessageRollUp = new StatusMonitorCollection(this); + foreach (var dev in DeviceManager.GetDevices()) { - if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp) + if (dev is ICommunicationMonitor md) { - GetProcessorEthernetValues(); + _errorMessageRollUp.AddMonitor(md.CommunicationMonitor); + Debug.LogMessage(LogEventLevel.Verbose, this, "Adding '{0}' to room's overall error monitor", + md.CommunicationMonitor.Parent.Key); } } + _errorMessageRollUp.Start(); + FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; + _errorMessageRollUp.StatusChange += + (o, a) => { FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; }; + } - protected void GetSystemInfo() + /// + /// Sets up a local occupancy sensor, such as one attached to a Fusion Scheduling panel. The occupancy status of the room will be read from Fusion + /// + private void SetUpLocalOccupancy() + { + RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); + + FusionRoom.FusionAssetStateChange += FusionRoom_FusionAssetStateChange; + + // Build Occupancy Asset? + // Link sigs? + + //Room.SetRoomOccupancy(this as IOccupancyStatusProvider, 0); + } + + private void FusionRoom_FusionAssetStateChange(FusionBase device, FusionAssetStateEventArgs args) + { + if (args.EventId == FusionAssetEventId.RoomOccupiedReceivedEventId || + args.EventId == FusionAssetEventId.RoomUnoccupiedReceivedEventId) { - //SystemName.InputSig.StringValue = Room.Name; - //Model.InputSig.StringValue = InitialParametersClass.ControllerPromptName; - //SerialNumber.InputSig.StringValue = InitialParametersClass. + RoomIsOccupiedFeedback.FireUpdate(); + } + } - var response = string.Empty; + /// + /// Sets up remote occupancy that will relay the occupancy status determined by local system devices to Fusion + /// + private void SetUpRemoteOccupancy() + { + // Need to have the room occupancy object first and somehow determine the slot number of the Occupancy asset but will not be able to use the UID from config likely. + // Consider defining an object just for Room Occupancy (either eAssetType.Occupancy Sensor (local) or eAssetType.RemoteOccupancySensor (from Fusion sched. panel)) and reserving slot 4 for that asset (statics would start at 5) - var systemReboot = FusionRoom.CreateOffsetBoolSig(JoinMap.ProcessorReboot.JoinNumber, JoinMap.ProcessorReboot.AttributeName, eSigIoMask.OutputSigOnly); - systemReboot.OutputSig.SetSigFalseAction( - () => CrestronConsole.SendControlSystemCommand("reboot", ref response)); + //if (Room.OccupancyObj != null) + //{ + + var tempOccAsset = _guiDs.OccupancyAsset; + + if (tempOccAsset == null) + { + FusionOccSensor = new FusionOccupancySensorAsset(eAssetType.OccupancySensor); + tempOccAsset = FusionOccSensor; } - protected void SetUpEthernetValues() + var occSensorAsset = FusionRoom.CreateOccupancySensorAsset(tempOccAsset.SlotNumber, tempOccAsset.Name, + "Occupancy Sensor", tempOccAsset.InstanceId); + + occSensorAsset.RoomOccupied.AddSigToRVIFile = true; + + //var occSensorShutdownMinutes = FusionRoom.CreateOffsetUshortSig(70, "Occ Shutdown - Minutes", eSigIoMask.InputOutputSig); + + // Tie to method on occupancy object + //occSensorShutdownMinutes.OutputSig.UserObject(new Action(ushort)(b => Room.OccupancyObj.SetShutdownMinutes(b)); + + + if (Room is IRoomOccupancy occRoom) { - _ip1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp1.JoinNumber, JoinMap.ProcessorIp1.AttributeName, eSigIoMask.InputSigOnly); - _ip2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp2.JoinNumber, JoinMap.ProcessorIp2.AttributeName, eSigIoMask.InputSigOnly); - _gateway = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorGateway.JoinNumber, JoinMap.ProcessorGateway.AttributeName, eSigIoMask.InputSigOnly); - _hostname = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorHostname.JoinNumber, JoinMap.ProcessorHostname.AttributeName, eSigIoMask.InputSigOnly); - _domain = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDomain.JoinNumber, JoinMap.ProcessorDomain.AttributeName, eSigIoMask.InputSigOnly); - _dns1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDns1.JoinNumber, JoinMap.ProcessorDns1.AttributeName, eSigIoMask.InputSigOnly); - _dns2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDns2.JoinNumber, JoinMap.ProcessorDns2.AttributeName, eSigIoMask.InputSigOnly); - _mac1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorMac1.JoinNumber, JoinMap.ProcessorMac1.AttributeName, eSigIoMask.InputSigOnly); - _mac2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorMac2.JoinNumber, JoinMap.ProcessorMac2.AttributeName, eSigIoMask.InputSigOnly); - _netMask1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask1.JoinNumber, JoinMap.ProcessorNetMask1.AttributeName, eSigIoMask.InputSigOnly); - _netMask2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask2.JoinNumber, JoinMap.ProcessorNetMask2.AttributeName, eSigIoMask.InputSigOnly); + occRoom.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig); + occRoom.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; + } + RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); + + RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); + + //} + } + + private void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + _roomOccupancyRemoteString = String.Format(RemoteOccupancyXml, e.BoolValue ? "Occupied" : "Unoccupied"); + RoomOccupancyRemoteStringFeedback.FireUpdate(); + } + + /// + /// Helper to get the number from the end of a device's key string + /// + /// -1 if no number matched + private int ExtractNumberFromKey(string key) + { + var capture = System.Text.RegularExpressions.Regex.Match(key, @"\b(\d+)"); + if (!capture.Success) + { + return -1; + } + return Convert.ToInt32(capture.Groups[1].Value); + } + + /// + /// Event handler for when room source changes + /// + protected void Room_CurrentSourceInfoChange(SourceListItem info, ChangeType type) + { + // Handle null. Nothing to do when switching from or to null + if (info == null || info.SourceDevice == null) + { + return; } - protected void GetProcessorEthernetValues() + var dev = info.SourceDevice; + if (type == ChangeType.WillChange) { - _ip1.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - _gateway.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); - _hostname.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - _domain.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); - - var dnsServers = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, 0).Split(','); - _dns1.InputSig.StringValue = dnsServers[0]; - if (dnsServers.Length > 1) + if (_sourceToFeedbackSigs.ContainsKey(dev)) { - _dns2.InputSig.StringValue = dnsServers[1]; - } - - _mac1.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); - _netMask1.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0); - - // Interface 1 - - if (InitialParametersClass.NumberOfEthernetInterfaces > 1) - // Only get these values if the processor has more than 1 NIC - { - _ip2.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 1); - _mac2.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 1); - _netMask2.InputSig.StringValue = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 1); + _sourceToFeedbackSigs[dev].BoolValue = false; } } - - protected void GetProcessorInfo() + else { - _firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly); - - if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) + if (_sourceToFeedbackSigs.ContainsKey(dev)) { - for (var i = 0; i < Global.ControlSystem.NumProgramsSupported; i++) - { - var join = JoinMap.ProgramNameStart.JoinNumber + i; - var progNum = i + 1; - _program[i] = FusionRoom.CreateOffsetStringSig((uint) join, - string.Format("{0} {1}", JoinMap.ProgramNameStart.AttributeName, progNum), eSigIoMask.InputSigOnly); - } + _sourceToFeedbackSigs[dev].BoolValue = true; } - - _firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; + //var name = (room == null ? "" : room.Name); + CurrentRoomSourceNameSig.InputSig.StringValue = info.SourceDevice.Name; } + } - protected void GetCustomProperties() + protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) + { + // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, + // even though they all contain sigs. + + + BoolOutputSig outSig; + if (args.UserConfiguredSigDetail is BooleanSigDataFixedName sigData) { - if (FusionRoom.IsOnline) - { - const string fusionRoomCustomPropertiesRequest = - @"RoomConfigurationRequest"; - - FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigQuery.StringValue = - fusionRoomCustomPropertiesRequest; - } - } - - private void GetTouchpanelInfo() - { - // TODO: Get IP and Project Name from TP - } - - protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) - { - if (args.DeviceOnLine) - { - CrestronInvoke.BeginInvoke( (o) => - { - CrestronEnvironment.Sleep(200); - - // Send Push Notification Action request: - - const string requestId = "InitialPushRequest"; - - - var actionRequest = - string.Format("\n{0}\n", requestId) + - "RegisterPushModel\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n"; - - Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ActionRequest: \n{0}", actionRequest); - - FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = actionRequest; - - GetCustomProperties(); - - // Request current Fusion Server Time - RequestLocalDateTime(null); - - // Setup timer to request time daily - if (_dailyTimeRequestTimer != null && !_dailyTimeRequestTimer.Disposed) - { - _dailyTimeRequestTimer.Stop(); - _dailyTimeRequestTimer.Dispose(); - } - - _dailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000); - - _dailyTimeRequestTimer.Reset(86400000, 86400000); - }); - } - } - - /// - /// Requests the local date and time from the Fusion Server - /// - /// - public void RequestLocalDateTime(object callbackObject) - { - const string timeRequestId = "TimeRequest"; - - var timeRequest = string.Format("{0}", - timeRequestId); - - FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQuery.StringValue = timeRequest; - } - - /// - /// Generates a room schedule request for this room for the next 24 hours. - /// - public void RequestFullRoomSchedule(object callbackObject) - { - var now = DateTime.Today; - - var currentTime = now.ToString("s"); - - var requestTest = - string.Format( - "FullSchedleRequest{0}{1}24", - RoomGuid, currentTime); - - Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ScheduleQuery: \n{0}", requestTest); - - FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleQuery.StringValue = requestTest; - - if (_isRegisteredForSchedulePushNotifications) - { - _pushNotificationTimer.Stop(); - } - } - - /// - /// Wrapper method to allow console commands to modify the current meeting end time - /// - /// meetingID extendTime - public void ModifyMeetingEndTimeConsoleHelper(string command) - { - var extendMinutes = -1; - - const string requestId = "ModifyMeetingTest12345"; - - try - { - var tokens = command.Split(' '); - - extendMinutes = Int32.Parse(tokens[1]); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing console command: {0}", e); - } - - ModifyMeetingEndTime(requestId, extendMinutes); - } - - /// - /// Ends or Extends the current meeting by the specified number of minutes. - /// - /// - /// Number of minutes to extend the meeting. A value of 0 will end the meeting. - public void ModifyMeetingEndTime(string requestId, int extendMinutes) - { - if (_currentMeeting == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "No meeting in progress. Unable to modify end time."); - return; - } - - if (extendMinutes > -1) - { - if (extendMinutes > 0) - { - var extendTime = _currentMeeting.dtEnd - DateTime.Now; - var extendMinutesRaw = extendTime.TotalMinutes; - - extendMinutes += (int) Math.Round(extendMinutesRaw); - } - - - var requestTest = string.Format( - "{0}{1}MeetingChange" - , requestId, RoomGuid, _currentMeeting.MeetingID, extendMinutes); - - Debug.LogMessage(LogEventLevel.Debug, this, "Sending MeetingChange Request: \n{0}", requestTest); - - FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = requestTest; - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Invalid time specified"); - } - } - - /// - /// Creates and Ad Hoc meeting with a duration of 1 hour, or until the next meeting if in less than 1 hour. - /// - public void CreateAdHocMeeting(string command) - { - const string requestId = "CreateAdHocMeeting"; - - var now = DateTime.Now.AddMinutes(1); - - now.AddSeconds(-now.Second); - - // Assume 1 hour meeting if possible - var dtEnd = now.AddHours(1); - - // Check if room is available for 1 hour before next meeting - if (_nextMeeting != null) - { - var roomAvailable = _nextMeeting.dtEnd.Subtract(dtEnd); - - if (roomAvailable.TotalMinutes < 60) - { - // Room not available for full hour, book until next meeting starts - dtEnd = _nextMeeting.dtEnd; - } - } - - var createMeetingRequest = - "" + - string.Format("{0}", requestId) + - string.Format("{0}", RoomGuid) + - "" + - string.Format("{0}", now.ToString("s")) + - string.Format("{0}", dtEnd.ToString("s")) + - "AdHoc Meeting" + - "Room User" + - "Example Message" + - "" + - ""; - - Debug.LogMessage(LogEventLevel.Verbose, this, "Sending CreateMeeting Request: \n{0}", createMeetingRequest); - - FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = createMeetingRequest; - - //Debug.LogMessage(LogEventLevel.Debug, this, "Sending CreateMeeting Request: \n{0}", command); - - //FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = command; - } - - /// - /// Event handler method for Device Extender sig changes - /// - /// - /// - protected void ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, - SigEventArgs args) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, - args.Sig.StringValue); - - - if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQueryResponse) - { - try - { - var message = new XmlDocument(); - - message.LoadXml(args.Sig.StringValue); - - var actionResponse = message["ActionResponse"]; - - if (actionResponse == null) - { - return; - } - - var requestId = actionResponse["RequestID"]; - - if (requestId.InnerText != "InitialPushRequest") - { - return; - } - - if (actionResponse["ActionID"].InnerText != "RegisterPushModel") - { - return; - } - - var parameters = actionResponse["Parameters"]; - - foreach (var isRegistered in from XmlElement parameter in parameters - where parameter.HasAttributes - select parameter.Attributes - into attributes - where attributes["ID"].Value == "Registered" - select Int32.Parse(attributes["Value"].Value)) - { - switch (isRegistered) - { - case 1: - _isRegisteredForSchedulePushNotifications = true; - if (_pollTimer != null && !_pollTimer.Disposed) - { - _pollTimer.Stop(); - _pollTimer.Dispose(); - } - _pushNotificationTimer = new CTimer(RequestFullRoomSchedule, null, - PushNotificationTimeout, PushNotificationTimeout); - _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); - break; - case 0: - _isRegisteredForSchedulePushNotifications = false; - if (_pushNotificationTimer != null && !_pushNotificationTimer.Disposed) - { - _pushNotificationTimer.Stop(); - _pushNotificationTimer.Dispose(); - } - _pollTimer = new CTimer(RequestFullRoomSchedule, null, SchedulePollInterval, - SchedulePollInterval); - _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); - break; - } - } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing ActionQueryResponse: {0}", e); - } - } - else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQueryResponse) - { - try - { - var message = new XmlDocument(); - - message.LoadXml(args.Sig.StringValue); - - var localDateTimeResponse = message["LocalTimeResponse"]; - - if (localDateTimeResponse != null) - { - var localDateTime = localDateTimeResponse["LocalDateTime"]; - - if (localDateTime != null) - { - var tempLocalDateTime = localDateTime.InnerText; - - var currentTime = DateTime.Parse(tempLocalDateTime); - - Debug.LogMessage(LogEventLevel.Debug, this, "DateTime from Fusion Server: {0}", currentTime); - - // Parse time and date from response and insert values - CrestronEnvironment.SetTimeAndDate((ushort) currentTime.Hour, (ushort) currentTime.Minute, - (ushort) currentTime.Second, (ushort) currentTime.Month, (ushort) currentTime.Day, - (ushort) currentTime.Year); - - Debug.LogMessage(LogEventLevel.Debug, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime()); - } - } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing LocalDateTimeQueryResponse: {0}", e); - } - } - else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigResponse) - { - // Room info response with custom properties - - var roomConfigResponseArgs = args.Sig.StringValue.Replace("&", "and"); - - Debug.LogMessage(LogEventLevel.Verbose, this, "Fusion Response: \n {0}", roomConfigResponseArgs); - - try - { - var roomConfigResponse = new XmlDocument(); - - roomConfigResponse.LoadXml(roomConfigResponseArgs); - - var requestRoomConfiguration = roomConfigResponse["RoomConfigurationResponse"]; - - if (requestRoomConfiguration != null) - { - var roomInformation = new RoomInformation(); - - foreach (XmlElement e in roomConfigResponse.FirstChild.ChildNodes) - { - if (e.Name == "RoomInformation") - { - var roomInfo = new XmlReader(e.OuterXml); - - roomInformation = CrestronXMLSerialization.DeSerializeObject(roomInfo); - } - else if (e.Name == "CustomFields") - { - foreach (XmlElement el in e) - { - var customProperty = new FusionCustomProperty(); - - if (el.Name == "CustomField") - { - customProperty.ID = el.Attributes["ID"].Value; - } - - foreach (XmlElement elm in el) - { - if (elm.Name == "CustomFieldName") - { - customProperty.CustomFieldName = elm.InnerText; - } - if (elm.Name == "CustomFieldType") - { - customProperty.CustomFieldType = elm.InnerText; - } - if (elm.Name == "CustomFieldValue") - { - customProperty.CustomFieldValue = elm.InnerText; - } - } - - roomInformation.FusionCustomProperties.Add(customProperty); - } - } - } - RoomInfoChange?.Invoke(this, new EventArgs()); - - CustomPropertiesBridge.EvaluateRoomInfo(Room.Key, roomInformation); - } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing Custom Properties response: {0}", e); - } - //PrintRoomInfo(); - //getRoomInfoBusy = false; - //_DynFusion.API.EISC.BooleanInput[Constants.GetRoomInfo].BoolValue = getRoomInfoBusy; - } - } - - /// - /// Event handler method for Device Extender sig changes - /// - /// - /// - protected void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, - SigEventArgs args) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Scehdule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, - args.Sig.Name, args.Sig.StringValue); - - - if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleResponse) - { - try - { - var scheduleResponse = new ScheduleResponse(); - - var message = new XmlDocument(); - - message.LoadXml(args.Sig.StringValue); - - var response = message["ScheduleResponse"]; - - if (response != null) - { - // Check for push notification - if (response["RequestID"].InnerText == "RVRequest") - { - var action = response["Action"]; - - if (action.OuterXml.IndexOf("RequestSchedule", StringComparison.Ordinal) > -1) - { - _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); - } - } - else // Not a push notification - { - _currentSchedule = new RoomSchedule(); // Clear Current Schedule - _currentMeeting = null; // Clear Current Meeting - _nextMeeting = null; // Clear Next Meeting - - var isNextMeeting = false; - - foreach (XmlElement element in message.FirstChild.ChildNodes) - { - if (element.Name == "RequestID") - { - scheduleResponse.RequestID = element.InnerText; - } - else if (element.Name == "RoomID") - { - scheduleResponse.RoomID = element.InnerText; - } - else if (element.Name == "RoomName") - { - scheduleResponse.RoomName = element.InnerText; - } - else if (element.Name == "Event") - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Event Found:\n{0}", element.OuterXml); - - var reader = new XmlReader(element.OuterXml); - - var tempEvent = CrestronXMLSerialization.DeSerializeObject(reader); - - scheduleResponse.Events.Add(tempEvent); - - // Check is this is the current event - if (tempEvent.dtStart <= DateTime.Now && tempEvent.dtEnd >= DateTime.Now) - { - _currentMeeting = tempEvent; // Set Current Meeting - isNextMeeting = true; // Flag that next element is next meeting - } - - if (isNextMeeting) - { - _nextMeeting = tempEvent; // Set Next Meeting - isNextMeeting = false; - } - - _currentSchedule.Meetings.Add(tempEvent); - } - } - - PrintTodaysSchedule(); - - if (!_isRegisteredForSchedulePushNotifications) - { - _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); - } - - // Fire Schedule Change Event - ScheduleChange?.Invoke(this, new ScheduleChangeEventArgs { Schedule = _currentSchedule }); - } - } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing ScheduleResponse: {0}", e); - } - } - else if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateResponse) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Create Meeting Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, - args.Sig.Name, args.Sig.StringValue); - } - } - - /// - /// Prints today's schedule to console for debugging - /// - private void PrintTodaysSchedule() - { - if (Debug.Level > 1) - { - if (_currentSchedule.Meetings.Count > 0) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Today's Schedule for '{0}'\n", Room.Name); - - foreach (var e in _currentSchedule.Meetings) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Subject: {0}", e.Subject); - Debug.LogMessage(LogEventLevel.Debug, this, "Organizer: {0}", e.Organizer); - Debug.LogMessage(LogEventLevel.Debug, this, "MeetingID: {0}", e.MeetingID); - Debug.LogMessage(LogEventLevel.Debug, this, "Start Time: {0}", e.dtStart); - Debug.LogMessage(LogEventLevel.Debug, this, "End Time: {0}", e.dtEnd); - Debug.LogMessage(LogEventLevel.Debug, this, "Duration: {0}\n", e.DurationInMinutes); - } - } - } - } - - protected virtual void SetUpSources() - { - // Sources - var dict = ConfigReader.ConfigObject.GetSourceListForKey(Room.SourceListKey); - if (dict != null) - { - // NEW PROCESS: - // Make these lists and insert the fusion attributes by iterating these - var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls); - uint i = 1; - foreach (var kvp in setTopBoxes) - { - TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + i, JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); - i++; - if (i > JoinMap.Display1SetTopBoxSourceStart.JoinSpan) // We only have five spots - { - break; - } - } - - var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls); - i = 1; - foreach (var kvp in discPlayers) - { - TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + i, JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); - i++; - if (i > JoinMap.Display1DiscPlayerSourceStart.JoinSpan) // We only have five spots - { - break; - } - } - - var laptops = dict.Where(d => d.Value.SourceDevice is IRoutingSource); - i = 1; - foreach (var kvp in laptops) - { - TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + i, JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); - i++; - if (i > JoinMap.Display1LaptopSourceStart.JoinSpan) // We only have ten spots??? - { - break; - } - } - - foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType()) - { - usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) {UsageIsTracked = true}; - usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; - } - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Config source list '{0}' not found for room '{1}'", - Room.SourceListKey, Room.Key); - } - } - - /// - /// Collects usage data from source and sends to Fusion - /// - /// - /// - protected void UsageTracker_DeviceUsageEnded(object sender, DeviceUsageEventArgs e) - { - if (!(sender is UsageTracking deviceTracker)) - { - return; - } - - var group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); - - var currentMeetingId = "-"; - - if (_currentMeeting != null) - { - currentMeetingId = _currentMeeting.MeetingID; - } - - //String Format: "USAGE||[Date YYYY-MM-DD]||[Time HH-mm-ss]||TIME||[Asset_Type]||[Asset_Name]||[Minutes_used]||[Asset_ID]||[Meeting_ID]" - // [Asset_ID] property does not appear to be used in Crestron SSI examples. They are sending "-" instead so that's what is replicated here - var deviceUsage = string.Format("USAGE||{0}||{1}||TIME||{2}||{3}||-||{4}||-||{5}||{6}||\r\n", - e.UsageEndTime.ToString("yyyy-MM-dd"), e.UsageEndTime.ToString("HH:mm:ss"), - @group, deviceTracker.Parent.Name, e.MinutesUsed, "-", currentMeetingId); - - Debug.LogMessage(LogEventLevel.Debug, this, "Device usage for: {0} ended at {1}. In use for {2} minutes", - deviceTracker.Parent.Name, e.UsageEndTime, e.MinutesUsed); - - FusionRoom.DeviceUsage.InputSig.StringValue = deviceUsage; - - Debug.LogMessage(LogEventLevel.Debug, this, "Device usage string: {0}", deviceUsage); - } - - - protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Creating attribute '{0}' with join {1} for source {2}", - attrName, attrNum, pSrc.Key); - try - { - var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig); - // Need feedback when this source is selected - // Event handler, added below, will compare source changes with this sig dict - _sourceToFeedbackSigs.Add(pSrc, sigD.InputSig); - - // And respond to selection in Fusion - sigD.OutputSig.SetSigFalseAction(() => - { - if (Room is IRunRouteAction runRouteAction) - { - runRouteAction.RunRouteAction(routeKey, Room.SourceListKey); - } - }); - } - catch (Exception) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", - attrNum, attrName, pSrc.Key); - } - } - - /// - /// - /// - private void SetUpCommunitcationMonitors() - { - uint displayNum = 0; - uint touchpanelNum = 0; - uint xpanelNum = 0; - - // Attach to all room's devices with monitors. - //foreach (var dev in DeviceManager.Devices) - foreach (var dev in DeviceManager.GetDevices()) - { - if (!(dev is ICommunicationMonitor)) - { - continue; - } - - string attrName = null; - uint attrNum = 1; - - //var keyNum = ExtractNumberFromKey(dev.Key); - //if (keyNum == -1) - //{ - // Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Cannot link device '{0}' to numbered Fusion monitoring attributes", - // dev.Key); - // continue; - //} - //uint attrNum = Convert.ToUInt32(keyNum); - - // Check for UI devices - if (dev is IHasBasicTriListWithSmartObject uiDev) - { - if (uiDev.Panel is Crestron.SimplSharpPro.UI.XpanelForSmartGraphics) - { - attrNum += touchpanelNum; - - if (attrNum > JoinMap.XpanelOnlineStart.JoinSpan) - { - continue; - } - attrName = JoinMap.XpanelOnlineStart.AttributeName + " " + attrNum; - attrNum += JoinMap.XpanelOnlineStart.JoinNumber; - - touchpanelNum++; - } - else - { - attrNum += xpanelNum; - - if (attrNum > JoinMap.TouchpanelOnlineStart.JoinSpan) - { - continue; - } - attrName = JoinMap.TouchpanelOnlineStart.AttributeName + " " + attrNum; - attrNum += JoinMap.TouchpanelOnlineStart.JoinNumber; - - xpanelNum++; - } - } - - //else - if (dev is IDisplay) - { - attrNum += displayNum; - if (attrNum > JoinMap.DisplayOnlineStart.JoinSpan) - { - continue; - } - attrName = JoinMap.DisplayOnlineStart.AttributeName + " " + attrNum; - attrNum += JoinMap.DisplayOnlineStart.JoinNumber; - - displayNum++; - } - //else if (dev is DvdDeviceBase) - //{ - // if (attrNum > 5) - // continue; - // attrName = "Device Ok - DVD " + attrNum; - // attrNum += 260; - //} - // add set top box - - // add Cresnet roll-up - - // add DM-devices roll-up - - if (attrName != null) - { - // Link comm status to sig and update - var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); - var smd = dev as ICommunicationMonitor; - sigD.InputSig.BoolValue = smd.CommunicationMonitor.Status == MonitorStatus.IsOk; - smd.CommunicationMonitor.StatusChange += - (o, a) => { sigD.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; - Debug.LogMessage(LogEventLevel.Information, this, "Linking '{0}' communication monitor to Fusion '{1}'", dev.Key, attrName); - } - } - } - - protected virtual void SetUpDisplay() - { - try - { - //Setup Display Usage Monitoring - - var displays = DeviceManager.AllDevices.Where(d => d is IDisplay); - - // Consider updating this in multiple display systems - - foreach (var display in displays.Cast()) - { - display.UsageTracker = new UsageTracking(display as Device) {UsageIsTracked = true}; - display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; - } - - if (!(Room is IHasDefaultDisplay hasDefaultDisplay)) - { - return; - } - if (!(hasDefaultDisplay.DefaultDisplay is IDisplay defaultDisplay)) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Cannot link null display to Fusion because default display is null"); - return; - } - - var dispPowerOnAction = new Action(b => - { - if (!b) - { - defaultDisplay.PowerOn(); - } - }); - var dispPowerOffAction = new Action(b => - { - if (!b) - { - defaultDisplay.PowerOff(); - } - }); - - // Display to fusion room sigs - FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; - FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; - - MapDisplayToRoomJoins(1, JoinMap.Display1Start.JoinNumber, defaultDisplay); - - - var deviceConfig = - ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); - - //Check for existing asset in GUIDs collection - - FusionAsset tempAsset; - - if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) - { - tempAsset = FusionStaticAssets[deviceConfig.Uid]; - } - else - { - // Create a new asset - tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), - defaultDisplay.Name, "Display", ""); - FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); - } - - var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", - tempAsset.InstanceId); - dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; - dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; - - if (defaultDisplay is IHasPowerControlWithFeedback defaultTwoWayDisplay) - { - defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); - if (defaultDisplay is IDisplayUsage) - { - (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); - } - - defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); - } - - // Use extension methods - dispAsset.TrySetMakeModel(defaultDisplay as Device); - dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay as Device); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error setting up display in Fusion: {0}", e); - } - } - - /// - /// Maps room attributes to a display at a specified index - /// - /// - /// - /// - /// a - protected virtual void MapDisplayToRoomJoins(int displayIndex, uint joinOffset, IDisplay display) - { - var displayName = string.Format("Display {0} - ", displayIndex); - - - if (!(Room is IHasDefaultDisplay hasDefaultDisplay) || display != hasDefaultDisplay.DefaultDisplay) - { - return; - } - // Display volume - var defaultDisplayVolume = FusionRoom.CreateOffsetUshortSig(JoinMap.VolumeFader1.JoinNumber, JoinMap.VolumeFader1.AttributeName, - eSigIoMask.InputOutputSig); - defaultDisplayVolume.OutputSig.UserObject = new Action(b => - { - if (!(display is IBasicVolumeWithFeedback basicVolumeWithFeedback)) - { - return; - } - - basicVolumeWithFeedback.SetVolume(b); - basicVolumeWithFeedback.VolumeLevelFeedback.LinkInputSig(defaultDisplayVolume.InputSig); - }); - - - // Power on - var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On", - eSigIoMask.InputOutputSig); - defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => - { - if (!b) - { - display.PowerOn(); - } - }); - - // Power Off - var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1, displayName + "Power Off", - eSigIoMask.InputOutputSig); - defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => - { - if (!b) - { - display.PowerOff(); - } - }); - - - if (display is IHasPowerControlWithFeedback defaultTwoWayDisplay) - { - defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); - defaultTwoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(defaultDisplayPowerOff.InputSig); - } - - // Current Source - var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8, - displayName + "Source None", eSigIoMask.InputOutputSig); - defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => - { - if (!b) - { - if (Room is IRunRouteAction runRouteAction) - { - runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); - } - } - }); - } - - private void SetUpError() - { - // Roll up ALL device errors - _errorMessageRollUp = new StatusMonitorCollection(this); - foreach (var dev in DeviceManager.GetDevices()) - { - if (dev is ICommunicationMonitor md) - { - _errorMessageRollUp.AddMonitor(md.CommunicationMonitor); - Debug.LogMessage(LogEventLevel.Verbose, this, "Adding '{0}' to room's overall error monitor", - md.CommunicationMonitor.Parent.Key); - } - } - _errorMessageRollUp.Start(); - FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; - _errorMessageRollUp.StatusChange += - (o, a) => { FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; }; - } - - /// - /// Sets up a local occupancy sensor, such as one attached to a Fusion Scheduling panel. The occupancy status of the room will be read from Fusion - /// - private void SetUpLocalOccupancy() - { - RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); - - FusionRoom.FusionAssetStateChange += FusionRoom_FusionAssetStateChange; - - // Build Occupancy Asset? - // Link sigs? - - //Room.SetRoomOccupancy(this as IOccupancyStatusProvider, 0); - } - - private void FusionRoom_FusionAssetStateChange(FusionBase device, FusionAssetStateEventArgs args) - { - if (args.EventId == FusionAssetEventId.RoomOccupiedReceivedEventId || - args.EventId == FusionAssetEventId.RoomUnoccupiedReceivedEventId) - { - RoomIsOccupiedFeedback.FireUpdate(); - } - } - - /// - /// Sets up remote occupancy that will relay the occupancy status determined by local system devices to Fusion - /// - private void SetUpRemoteOccupancy() - { - // Need to have the room occupancy object first and somehow determine the slot number of the Occupancy asset but will not be able to use the UID from config likely. - // Consider defining an object just for Room Occupancy (either eAssetType.Occupancy Sensor (local) or eAssetType.RemoteOccupancySensor (from Fusion sched. panel)) and reserving slot 4 for that asset (statics would start at 5) - - //if (Room.OccupancyObj != null) - //{ - - var tempOccAsset = _guiDs.OccupancyAsset; - - if (tempOccAsset == null) - { - FusionOccSensor = new FusionOccupancySensorAsset(eAssetType.OccupancySensor); - tempOccAsset = FusionOccSensor; - } - - var occSensorAsset = FusionRoom.CreateOccupancySensorAsset(tempOccAsset.SlotNumber, tempOccAsset.Name, - "Occupancy Sensor", tempOccAsset.InstanceId); - - occSensorAsset.RoomOccupied.AddSigToRVIFile = true; - - //var occSensorShutdownMinutes = FusionRoom.CreateOffsetUshortSig(70, "Occ Shutdown - Minutes", eSigIoMask.InputOutputSig); - - // Tie to method on occupancy object - //occSensorShutdownMinutes.OutputSig.UserObject(new Action(ushort)(b => Room.OccupancyObj.SetShutdownMinutes(b)); - - - if (Room is IRoomOccupancy occRoom) - { - occRoom.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig); - occRoom.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; - } - RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); - - RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); - - //} - } - - private void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - _roomOccupancyRemoteString = String.Format(RemoteOccupancyXml, e.BoolValue ? "Occupied" : "Unoccupied"); - RoomOccupancyRemoteStringFeedback.FireUpdate(); - } - - /// - /// Helper to get the number from the end of a device's key string - /// - /// -1 if no number matched - private int ExtractNumberFromKey(string key) - { - var capture = System.Text.RegularExpressions.Regex.Match(key, @"\b(\d+)"); - if (!capture.Success) - { - return -1; - } - return Convert.ToInt32(capture.Groups[1].Value); - } - - /// - /// Event handler for when room source changes - /// - protected void Room_CurrentSourceInfoChange(SourceListItem info, ChangeType type) - { - // Handle null. Nothing to do when switching from or to null - if (info == null || info.SourceDevice == null) - { - return; - } - - var dev = info.SourceDevice; - if (type == ChangeType.WillChange) - { - if (_sourceToFeedbackSigs.ContainsKey(dev)) - { - _sourceToFeedbackSigs[dev].BoolValue = false; - } - } - else - { - if (_sourceToFeedbackSigs.ContainsKey(dev)) - { - _sourceToFeedbackSigs[dev].BoolValue = true; - } - //var name = (room == null ? "" : room.Name); - CurrentRoomSourceNameSig.InputSig.StringValue = info.SourceDevice.Name; - } - } - - protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) - { - // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, - // even though they all contain sigs. - - - BoolOutputSig outSig; - if (args.UserConfiguredSigDetail is BooleanSigDataFixedName sigData) - { - outSig = sigData.OutputSig; - if (outSig.UserObject is Action) - { - (outSig.UserObject as Action).Invoke(outSig.BoolValue); - } - else if (outSig.UserObject is Action) - { - (outSig.UserObject as Action).Invoke(outSig.UShortValue); - } - else if (outSig.UserObject is Action) - { - (outSig.UserObject as Action).Invoke(outSig.StringValue); - } - return; - } - - var attrData = (args.UserConfiguredSigDetail as BooleanSigData); - if (attrData == null) - { - return; - } - outSig = attrData.OutputSig; + outSig = sigData.OutputSig; if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.BoolValue); @@ -1613,191 +1592,211 @@ namespace PepperDash.Essentials.Core.Fusion { (outSig.UserObject as Action).Invoke(outSig.StringValue); } + return; + } + + var attrData = (args.UserConfiguredSigDetail as BooleanSigData); + if (attrData == null) + { + return; + } + outSig = attrData.OutputSig; + if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.BoolValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.UShortValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.StringValue); } } +} - public static class FusionRoomExtensions - { - /// - /// Creates and returns a fusion attribute. The join number will match the established Simpl - /// standard of 50+, and will generate a 50+ join in the RVI. It calls - /// FusionRoom.AddSig with join number - 49 - /// - /// The new attribute - public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) - { - if (number < 50) - { - throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); - } - number -= 49; - fr.AddSig(eSigType.Bool, number, name, mask); - return fr.UserDefinedBooleanSigDetails[number]; - } - - /// - /// Creates and returns a fusion attribute. The join number will match the established Simpl - /// standard of 50+, and will generate a 50+ join in the RVI. It calls - /// FusionRoom.AddSig with join number - 49 - /// - /// The new attribute - public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) - { - if (number < 50) - { - throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); - } - number -= 49; - fr.AddSig(eSigType.UShort, number, name, mask); - return fr.UserDefinedUShortSigDetails[number]; - } - - /// - /// Creates and returns a fusion attribute. The join number will match the established Simpl - /// standard of 50+, and will generate a 50+ join in the RVI. It calls - /// FusionRoom.AddSig with join number - 49 - /// - /// The new attribute - public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) - { - if (number < 50) - { - throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); - } - number -= 49; - fr.AddSig(eSigType.String, number, name, mask); - return fr.UserDefinedStringSigDetails[number]; - } - - /// - /// Creates and returns a static asset - /// - /// the new asset - public static FusionStaticAsset CreateStaticAsset(this FusionRoom fr, uint number, string name, string type, - string instanceId) - { - try - { - Debug.LogMessage(LogEventLevel.Information, "Adding Fusion Static Asset '{0}' to slot {1} with GUID: '{2}'", name, number, instanceId); - - fr.AddAsset(eAssetType.StaticAsset, number, name, type, instanceId); - return fr.UserConfigurableAssetDetails[number].Asset as FusionStaticAsset; - } - catch (InvalidOperationException ex) - { - Debug.LogMessage(LogEventLevel.Information, "Error creating Static Asset for device: '{0}'. Check that multiple devices don't have missing or duplicate uid properties in configuration. /r/nError: {1}", name, ex); - return null; - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, "Error creating Static Asset: {0}", e); - return null; - } - } - - public static FusionOccupancySensor CreateOccupancySensorAsset(this FusionRoom fr, uint number, string name, - string type, string instanceId) - { - try - { - Debug.LogMessage(LogEventLevel.Information, "Adding Fusion Occupancy Sensor Asset '{0}' to slot {1} with GUID: '{2}'", name, number, - instanceId); - - fr.AddAsset(eAssetType.OccupancySensor, number, name, type, instanceId); - return fr.UserConfigurableAssetDetails[number].Asset as FusionOccupancySensor; - } - catch (InvalidOperationException ex) - { - Debug.LogMessage(LogEventLevel.Information, "Error creating Static Asset for device: '{0}'. Check that multiple devices don't have missing or duplicate uid properties in configuration. Error: {1}", name, ex); - return null; - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Error, "Error creating Static Asset: {0}", e); - return null; - } - } - } - - //************************************************************************************************ +public static class FusionRoomExtensions +{ /// - /// Extensions to enhance Fusion room, asset and signal creation. + /// Creates and returns a fusion attribute. The join number will match the established Simpl + /// standard of 50+, and will generate a 50+ join in the RVI. It calls + /// FusionRoom.AddSig with join number - 49 /// - public static class FusionStaticAssetExtensions + /// The new attribute + public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { - /// - /// Tries to set a Fusion asset with the make and model of a device. - /// If the provided Device is IMakeModel, will set the corresponding parameters on the fusion static asset. - /// Otherwise, does nothing. - /// - public static void TrySetMakeModel(this FusionStaticAsset asset, Device device) + if (number < 50) { - if (device is IMakeModel mm) + throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); + } + number -= 49; + fr.AddSig(eSigType.Bool, number, name, mask); + return fr.UserDefinedBooleanSigDetails[number]; + } + + /// + /// Creates and returns a fusion attribute. The join number will match the established Simpl + /// standard of 50+, and will generate a 50+ join in the RVI. It calls + /// FusionRoom.AddSig with join number - 49 + /// + /// The new attribute + public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) + { + if (number < 50) + { + throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); + } + number -= 49; + fr.AddSig(eSigType.UShort, number, name, mask); + return fr.UserDefinedUShortSigDetails[number]; + } + + /// + /// Creates and returns a fusion attribute. The join number will match the established Simpl + /// standard of 50+, and will generate a 50+ join in the RVI. It calls + /// FusionRoom.AddSig with join number - 49 + /// + /// The new attribute + public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) + { + if (number < 50) + { + throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); + } + number -= 49; + fr.AddSig(eSigType.String, number, name, mask); + return fr.UserDefinedStringSigDetails[number]; + } + + /// + /// Creates and returns a static asset + /// + /// the new asset + public static FusionStaticAsset CreateStaticAsset(this FusionRoom fr, uint number, string name, string type, + string instanceId) + { + try + { + Debug.LogMessage(LogEventLevel.Information, "Adding Fusion Static Asset '{0}' to slot {1} with GUID: '{2}'", name, number, instanceId); + + fr.AddAsset(eAssetType.StaticAsset, number, name, type, instanceId); + return fr.UserConfigurableAssetDetails[number].Asset as FusionStaticAsset; + } + catch (InvalidOperationException ex) + { + Debug.LogMessage(LogEventLevel.Information, "Error creating Static Asset for device: '{0}'. Check that multiple devices don't have missing or duplicate uid properties in configuration. /r/nError: {1}", name, ex); + return null; + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, "Error creating Static Asset: {0}", e); + return null; + } + } + + public static FusionOccupancySensor CreateOccupancySensorAsset(this FusionRoom fr, uint number, string name, + string type, string instanceId) + { + try + { + Debug.LogMessage(LogEventLevel.Information, "Adding Fusion Occupancy Sensor Asset '{0}' to slot {1} with GUID: '{2}'", name, number, + instanceId); + + fr.AddAsset(eAssetType.OccupancySensor, number, name, type, instanceId); + return fr.UserConfigurableAssetDetails[number].Asset as FusionOccupancySensor; + } + catch (InvalidOperationException ex) + { + Debug.LogMessage(LogEventLevel.Information, "Error creating Static Asset for device: '{0}'. Check that multiple devices don't have missing or duplicate uid properties in configuration. Error: {1}", name, ex); + return null; + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Error, "Error creating Static Asset: {0}", e); + return null; + } + } +} + +//************************************************************************************************ +/// +/// Extensions to enhance Fusion room, asset and signal creation. +/// +public static class FusionStaticAssetExtensions +{ + /// + /// Tries to set a Fusion asset with the make and model of a device. + /// If the provided Device is IMakeModel, will set the corresponding parameters on the fusion static asset. + /// Otherwise, does nothing. + /// + public static void TrySetMakeModel(this FusionStaticAsset asset, Device device) + { + if (device is IMakeModel mm) + { + asset.ParamMake.Value = mm.DeviceMake; + asset.ParamModel.Value = mm.DeviceModel; + } + } + + /// + /// Tries to attach the AssetError input on a Fusion asset to a Device's + /// CommunicationMonitor.StatusChange event. Does nothing if the device is not + /// IStatusMonitor + /// + /// + /// + public static void TryLinkAssetErrorToCommunication(this FusionStaticAsset asset, Device device) + { + if (device is ICommunicationMonitor) + { + var monitor = (device as ICommunicationMonitor).CommunicationMonitor; + monitor.StatusChange += (o, a) => { - asset.ParamMake.Value = mm.DeviceMake; - asset.ParamModel.Value = mm.DeviceModel; - } - } - - /// - /// Tries to attach the AssetError input on a Fusion asset to a Device's - /// CommunicationMonitor.StatusChange event. Does nothing if the device is not - /// IStatusMonitor - /// - /// - /// - public static void TryLinkAssetErrorToCommunication(this FusionStaticAsset asset, Device device) - { - if (device is ICommunicationMonitor) - { - var monitor = (device as ICommunicationMonitor).CommunicationMonitor; - monitor.StatusChange += (o, a) => - { - // Link connected and error inputs on asset - asset.Connected.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; - asset.AssetError.InputSig.StringValue = a.Status.ToString(); - }; - // set current value - asset.Connected.InputSig.BoolValue = monitor.Status == MonitorStatus.IsOk; - asset.AssetError.InputSig.StringValue = monitor.Status.ToString(); - } + // Link connected and error inputs on asset + asset.Connected.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; + asset.AssetError.InputSig.StringValue = a.Status.ToString(); + }; + // set current value + asset.Connected.InputSig.BoolValue = monitor.Status == MonitorStatus.IsOk; + asset.AssetError.InputSig.StringValue = monitor.Status.ToString(); } } +} - public class RoomInformation +public class RoomInformation +{ + public RoomInformation() { - public RoomInformation() - { - FusionCustomProperties = new List(); - } - - public string ID { get; set; } - public string Name { get; set; } - public string Location { get; set; } - public string Description { get; set; } - public string TimeZone { get; set; } - public string WebcamURL { get; set; } - public string BacklogMsg { get; set; } - public string SubErrorMsg { get; set; } - public string EmailInfo { get; set; } - public List FusionCustomProperties { get; set; } + FusionCustomProperties = new List(); } - public class FusionCustomProperty + public string ID { get; set; } + public string Name { get; set; } + public string Location { get; set; } + public string Description { get; set; } + public string TimeZone { get; set; } + public string WebcamURL { get; set; } + public string BacklogMsg { get; set; } + public string SubErrorMsg { get; set; } + public string EmailInfo { get; set; } + public List FusionCustomProperties { get; set; } +} + +public class FusionCustomProperty +{ + public FusionCustomProperty() { - public FusionCustomProperty() - { - } - - public FusionCustomProperty(string id) - { - ID = id; - } - - public string ID { get; set; } - public string CustomFieldName { get; set; } - public string CustomFieldType { get; set; } - public string CustomFieldValue { get; set; } } + + public FusionCustomProperty(string id) + { + ID = id; + } + + public string ID { get; set; } + public string CustomFieldName { get; set; } + public string CustomFieldType { get; set; } + public string CustomFieldValue { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs index 33f2fe1b..37d1e6a5 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs @@ -7,144 +7,143 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +public class EssentialsHuddleSpaceRoomFusionRoomJoinMap : JoinMapBaseAdvanced { - public class EssentialsHuddleSpaceRoomFusionRoomJoinMap : JoinMapBaseAdvanced + + // Processor Attributes + [JoinName("ProcessorIp1")] + public JoinDataComplete ProcessorIp1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Info - Processor - IP 1" }, + new JoinMetadata { Description = "Info - Processor - IP 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorIp2")] + public JoinDataComplete ProcessorIp2 = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1, AttributeName = "Info - Processor - IP 2" }, + new JoinMetadata { Description = "Info - Processor - IP 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorGateway")] + public JoinDataComplete ProcessorGateway = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1, AttributeName = "Info - Processor - Gateway" }, + new JoinMetadata { Description = "Info - Processor - Gateway", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorHostname")] + public JoinDataComplete ProcessorHostname = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1, AttributeName = "Info - Processor - Hostname" }, + new JoinMetadata { Description = "Info - Processor - Hostname", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorDomain")] + public JoinDataComplete ProcessorDomain = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1, AttributeName = "Info - Processor - Domain" }, + new JoinMetadata { Description = "Info - Processor - Domain", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorDns1")] + public JoinDataComplete ProcessorDns1 = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1, AttributeName = "Info - Processor - DNS 1" }, + new JoinMetadata { Description = "Info - Processor - DNS 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorDns2")] + public JoinDataComplete ProcessorDns2 = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1, AttributeName = "Info - Processor - DNS 2" }, + new JoinMetadata { Description = "Info - Processor - DNS 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorMac1")] + public JoinDataComplete ProcessorMac1 = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1, AttributeName = "Info - Processor - MAC 1" }, + new JoinMetadata { Description = "Info - Processor - MAC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorMac2")] + public JoinDataComplete ProcessorMac2 = new JoinDataComplete(new JoinData { JoinNumber = 58, JoinSpan = 1, AttributeName = "Info - Processor - MAC 2" }, + new JoinMetadata { Description = "Info - Processor - MAC 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorNetMask1")] + public JoinDataComplete ProcessorNetMask1 = new JoinDataComplete(new JoinData { JoinNumber = 59, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 1" }, + new JoinMetadata { Description = "Info - Processor - Net Mask 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorNetMask2")] + public JoinDataComplete ProcessorNetMask2 = new JoinDataComplete(new JoinData { JoinNumber = 60, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 2" }, + new JoinMetadata { Description = "Info - Processor - Net Mask 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorFirmware")] + public JoinDataComplete ProcessorFirmware = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1, AttributeName = "Info - Processor - Firmware" }, + new JoinMetadata { Description = "Info - Processor - Firmware", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProgramNameStart")] + public JoinDataComplete ProgramNameStart = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 10, AttributeName = "Info - Processor - Program" }, + new JoinMetadata { Description = "Info - Processor - Program", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("ProcessorReboot")] + public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 74, JoinSpan = 1, AttributeName = "Processor - Reboot" }, + new JoinMetadata { Description = "Processor - Reboot", JoinCapabilities = eJoinCapabilities.FromFusion, JoinType = eJoinType.Digital }); + + // Volume Controls + [JoinName("VolumeFader1")] + public JoinDataComplete VolumeFader1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Volume - Fader01" }, + new JoinMetadata { Description = "Volume - Fader01", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Analog }); + + // Codec Info + [JoinName("VcCodecInCall")] + public JoinDataComplete VcCodecInCall = new JoinDataComplete(new JoinData { JoinNumber = 69, JoinSpan = 1, AttributeName = "Conf - VC 1 In Call" }, + new JoinMetadata { Description = "Conf - VC 1 In Call", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + + [JoinName("VcCodecOnline")] + public JoinDataComplete VcCodecOnline = new JoinDataComplete(new JoinData { JoinNumber = 122, JoinSpan = 1, AttributeName = "Online - VC 1" }, + new JoinMetadata { Description = "Online - VC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + + [JoinName("VcCodecIpAddress")] + public JoinDataComplete VcCodecIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 121, JoinSpan = 1, AttributeName = "IP Address - VC" }, + new JoinMetadata { Description = "IP Address - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + [JoinName("VcCodecIpPort")] + public JoinDataComplete VcCodecIpPort = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 1, AttributeName = "IP Port - VC" }, + new JoinMetadata { Description = "IP Port - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + // Source Attributes + [JoinName("Display1CurrentSourceName")] + public JoinDataComplete Display1CurrentSourceName = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1, AttributeName = "Display 1 - Current Source" }, + new JoinMetadata { Description = "Display 1 - Current Source", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + + + // Device Online Status + [JoinName("TouchpanelOnlineStart")] + public JoinDataComplete TouchpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 10, AttributeName = "Online - Touch Panel" }, + new JoinMetadata { Description = "Online - Touch Panel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + + [JoinName("XpanelOnlineStart")] + public JoinDataComplete XpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 160, JoinSpan = 5, AttributeName = "Online - XPanel" }, + new JoinMetadata { Description = "Online - XPanel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + + [JoinName("DisplayOnlineStart")] + public JoinDataComplete DisplayOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 170, JoinSpan = 10, AttributeName = "Online - Display" }, + new JoinMetadata { Description = "Online - Display", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + + [JoinName("Display1LaptopSourceStart")] + public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 166, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" }, + new JoinMetadata { Description = "Display 1 - Source Laptop", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); + + [JoinName("Display1DiscPlayerSourceStart")] + public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 181, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" }, + new JoinMetadata { Description = "Display 1 - Source Disc Player", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); + + [JoinName("Display1SetTopBoxSourceStart")] + public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 188, JoinSpan = 5, AttributeName = "Display 1 - Source TV" }, + new JoinMetadata { Description = "Display 1 - Source TV", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); + + // Display 1 + [JoinName("Display1Start")] + public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 158, JoinSpan = 1 }, + new JoinMetadata { Description = "Display 1 Start", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); + + + /// + /// Constructor to use when instantiating this Join Map without inheriting from it + /// + /// Join this join map will start at + public EssentialsHuddleSpaceRoomFusionRoomJoinMap(uint joinStart) + : base(joinStart, typeof(EssentialsHuddleSpaceRoomFusionRoomJoinMap)) { - // Processor Attributes - [JoinName("ProcessorIp1")] - public JoinDataComplete ProcessorIp1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Info - Processor - IP 1" }, - new JoinMetadata { Description = "Info - Processor - IP 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + } - [JoinName("ProcessorIp2")] - public JoinDataComplete ProcessorIp2 = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1, AttributeName = "Info - Processor - IP 2" }, - new JoinMetadata { Description = "Info - Processor - IP 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorGateway")] - public JoinDataComplete ProcessorGateway = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1, AttributeName = "Info - Processor - Gateway" }, - new JoinMetadata { Description = "Info - Processor - Gateway", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorHostname")] - public JoinDataComplete ProcessorHostname = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1, AttributeName = "Info - Processor - Hostname" }, - new JoinMetadata { Description = "Info - Processor - Hostname", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorDomain")] - public JoinDataComplete ProcessorDomain = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1, AttributeName = "Info - Processor - Domain" }, - new JoinMetadata { Description = "Info - Processor - Domain", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorDns1")] - public JoinDataComplete ProcessorDns1 = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1, AttributeName = "Info - Processor - DNS 1" }, - new JoinMetadata { Description = "Info - Processor - DNS 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorDns2")] - public JoinDataComplete ProcessorDns2 = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1, AttributeName = "Info - Processor - DNS 2" }, - new JoinMetadata { Description = "Info - Processor - DNS 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorMac1")] - public JoinDataComplete ProcessorMac1 = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1, AttributeName = "Info - Processor - MAC 1" }, - new JoinMetadata { Description = "Info - Processor - MAC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorMac2")] - public JoinDataComplete ProcessorMac2 = new JoinDataComplete(new JoinData { JoinNumber = 58, JoinSpan = 1, AttributeName = "Info - Processor - MAC 2" }, - new JoinMetadata { Description = "Info - Processor - MAC 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorNetMask1")] - public JoinDataComplete ProcessorNetMask1 = new JoinDataComplete(new JoinData { JoinNumber = 59, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 1" }, - new JoinMetadata { Description = "Info - Processor - Net Mask 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorNetMask2")] - public JoinDataComplete ProcessorNetMask2 = new JoinDataComplete(new JoinData { JoinNumber = 60, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 2" }, - new JoinMetadata { Description = "Info - Processor - Net Mask 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorFirmware")] - public JoinDataComplete ProcessorFirmware = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1, AttributeName = "Info - Processor - Firmware" }, - new JoinMetadata { Description = "Info - Processor - Firmware", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProgramNameStart")] - public JoinDataComplete ProgramNameStart = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 10, AttributeName = "Info - Processor - Program" }, - new JoinMetadata { Description = "Info - Processor - Program", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("ProcessorReboot")] - public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 74, JoinSpan = 1, AttributeName = "Processor - Reboot" }, - new JoinMetadata { Description = "Processor - Reboot", JoinCapabilities = eJoinCapabilities.FromFusion, JoinType = eJoinType.Digital }); - - // Volume Controls - [JoinName("VolumeFader1")] - public JoinDataComplete VolumeFader1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Volume - Fader01" }, - new JoinMetadata { Description = "Volume - Fader01", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Analog }); - - // Codec Info - [JoinName("VcCodecInCall")] - public JoinDataComplete VcCodecInCall = new JoinDataComplete(new JoinData { JoinNumber = 69, JoinSpan = 1, AttributeName = "Conf - VC 1 In Call" }, - new JoinMetadata { Description = "Conf - VC 1 In Call", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); - - [JoinName("VcCodecOnline")] - public JoinDataComplete VcCodecOnline = new JoinDataComplete(new JoinData { JoinNumber = 122, JoinSpan = 1, AttributeName = "Online - VC 1" }, - new JoinMetadata { Description = "Online - VC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); - - [JoinName("VcCodecIpAddress")] - public JoinDataComplete VcCodecIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 121, JoinSpan = 1, AttributeName = "IP Address - VC" }, - new JoinMetadata { Description = "IP Address - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - [JoinName("VcCodecIpPort")] - public JoinDataComplete VcCodecIpPort = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 1, AttributeName = "IP Port - VC" }, - new JoinMetadata { Description = "IP Port - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - // Source Attributes - [JoinName("Display1CurrentSourceName")] - public JoinDataComplete Display1CurrentSourceName = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1, AttributeName = "Display 1 - Current Source" }, - new JoinMetadata { Description = "Display 1 - Current Source", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); - - - // Device Online Status - [JoinName("TouchpanelOnlineStart")] - public JoinDataComplete TouchpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 10, AttributeName = "Online - Touch Panel" }, - new JoinMetadata { Description = "Online - Touch Panel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); - - [JoinName("XpanelOnlineStart")] - public JoinDataComplete XpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 160, JoinSpan = 5, AttributeName = "Online - XPanel" }, - new JoinMetadata { Description = "Online - XPanel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); - - [JoinName("DisplayOnlineStart")] - public JoinDataComplete DisplayOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 170, JoinSpan = 10, AttributeName = "Online - Display" }, - new JoinMetadata { Description = "Online - Display", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); - - [JoinName("Display1LaptopSourceStart")] - public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 166, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" }, - new JoinMetadata { Description = "Display 1 - Source Laptop", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); - - [JoinName("Display1DiscPlayerSourceStart")] - public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 181, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" }, - new JoinMetadata { Description = "Display 1 - Source Disc Player", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); - - [JoinName("Display1SetTopBoxSourceStart")] - public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 188, JoinSpan = 5, AttributeName = "Display 1 - Source TV" }, - new JoinMetadata { Description = "Display 1 - Source TV", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); - - // Display 1 - [JoinName("Display1Start")] - public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 158, JoinSpan = 1 }, - new JoinMetadata { Description = "Display 1 Start", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); - - - /// - /// Constructor to use when instantiating this Join Map without inheriting from it - /// - /// Join this join map will start at - public EssentialsHuddleSpaceRoomFusionRoomJoinMap(uint joinStart) - : base(joinStart, typeof(EssentialsHuddleSpaceRoomFusionRoomJoinMap)) - { - - } - - /// - /// Constructor to use when extending this Join map - /// - /// Join this join map will start at - /// Type of the child join map - public EssentialsHuddleSpaceRoomFusionRoomJoinMap(uint joinStart, Type type) : base(joinStart, type) - { - } - } -} \ No newline at end of file + /// + /// Constructor to use when extending this Join map + /// + /// Join this join map will start at + /// Type of the child join map + public EssentialsHuddleSpaceRoomFusionRoomJoinMap(uint joinStart, Type type) : base(joinStart, type) + { + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs b/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs index a0cd8e6e..c7864f12 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs @@ -14,108 +14,107 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using Serilog.Events; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +/// +/// Handles mapping Fusion Custom Property values to system properties +/// +public class FusionCustomPropertiesBridge { + /// - /// Handles mapping Fusion Custom Property values to system properties + /// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed /// - public class FusionCustomPropertiesBridge + /// + public void EvaluateRoomInfo(string roomKey, RoomInformation roomInfo) { - - /// - /// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed - /// - /// - public void EvaluateRoomInfo(string roomKey, RoomInformation roomInfo) + try { - try + var reconfigurableDevices = DeviceManager.AllDevices.Where(d => d is ReconfigurableDevice); + + foreach (var device in reconfigurableDevices) { - var reconfigurableDevices = DeviceManager.AllDevices.Where(d => d is ReconfigurableDevice); + // Get the current device config so new values can be overwritten over existing + var deviceConfig = (device as ReconfigurableDevice).Config; - foreach (var device in reconfigurableDevices) + if (device is RoomOnToDefaultSourceWhenOccupied) { - // Get the current device config so new values can be overwritten over existing - var deviceConfig = (device as ReconfigurableDevice).Config; + Debug.LogMessage(LogEventLevel.Debug, "Mapping Room on via Occupancy values from Fusion"); - if (device is RoomOnToDefaultSourceWhenOccupied) + var devProps = JsonConvert.DeserializeObject(deviceConfig.Properties.ToString()); + + var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied")); + if (enableFeature != null) + devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue); + + var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime")); + if (enableTime != null) + devProps.OccupancyStartTime = enableTime.CustomFieldValue; + + var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime")); + if (disableTime != null) + devProps.OccupancyEndTime = disableTime.CustomFieldValue; + + var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun")); + if (enableSunday != null) + devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue); + + var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon")); + if (enableMonday != null) + devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue); + + var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue")); + if (enableTuesday != null) + devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue); + + var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed")); + if (enableWednesday != null) + devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue); + + var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu")); + if (enableThursday != null) + devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue); + + var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri")); + if (enableFriday != null) + devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue); + + var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat")); + if (enableSaturday != null) + devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue); + + deviceConfig.Properties = JToken.FromObject(devProps); + } + else if (device is IEssentialsRoom) + { + // Set the room name + if (!string.IsNullOrEmpty(roomInfo.Name)) { - Debug.LogMessage(LogEventLevel.Debug, "Mapping Room on via Occupancy values from Fusion"); + Debug.LogMessage(LogEventLevel.Debug, "Current Room Name: {0}. New Room Name: {1}", deviceConfig.Name, roomInfo.Name); + // Set the name in config + deviceConfig.Name = roomInfo.Name; - var devProps = JsonConvert.DeserializeObject(deviceConfig.Properties.ToString()); - - var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied")); - if (enableFeature != null) - devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue); - - var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime")); - if (enableTime != null) - devProps.OccupancyStartTime = enableTime.CustomFieldValue; - - var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime")); - if (disableTime != null) - devProps.OccupancyEndTime = disableTime.CustomFieldValue; - - var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun")); - if (enableSunday != null) - devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue); - - var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon")); - if (enableMonday != null) - devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue); - - var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue")); - if (enableTuesday != null) - devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue); - - var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed")); - if (enableWednesday != null) - devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue); - - var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu")); - if (enableThursday != null) - devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue); - - var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri")); - if (enableFriday != null) - devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue); - - var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat")); - if (enableSaturday != null) - devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue); - - deviceConfig.Properties = JToken.FromObject(devProps); - } - else if (device is IEssentialsRoom) - { - // Set the room name - if (!string.IsNullOrEmpty(roomInfo.Name)) - { - Debug.LogMessage(LogEventLevel.Debug, "Current Room Name: {0}. New Room Name: {1}", deviceConfig.Name, roomInfo.Name); - // Set the name in config - deviceConfig.Name = roomInfo.Name; - - Debug.LogMessage(LogEventLevel.Debug, "Room Name Successfully Changed."); - } - - // Set the help message - var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage")); - if (helpMessage != null) - { - //Debug.LogMessage(LogEventLevel.Debug, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value(ToString()), helpMessage.CustomFieldValue); - deviceConfig.Properties["helpMessage"] = (string)helpMessage.CustomFieldValue; - } + Debug.LogMessage(LogEventLevel.Debug, "Room Name Successfully Changed."); } - // Set the config on the device - (device as ReconfigurableDevice).SetConfig(deviceConfig); + // Set the help message + var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage")); + if (helpMessage != null) + { + //Debug.LogMessage(LogEventLevel.Debug, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value(ToString()), helpMessage.CustomFieldValue); + deviceConfig.Properties["helpMessage"] = (string)helpMessage.CustomFieldValue; + } } + // Set the config on the device + (device as ReconfigurableDevice).SetConfig(deviceConfig); + } - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, "FusionCustomPropetiesBridge: Error mapping properties: {0}", e); - } + + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Debug, "FusionCustomPropetiesBridge: Error mapping properties: {0}", e); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs b/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs index 26647a96..dc0c3822 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs @@ -4,15 +4,14 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core.Fusion -{ - public class ScheduleChangeEventArgs : EventArgs - { - public RoomSchedule Schedule { get; set; } - } +namespace PepperDash.Essentials.Core.Fusion; - public class MeetingChangeEventArgs : EventArgs - { - public Event Meeting { get; set; } - } +public class ScheduleChangeEventArgs : EventArgs +{ + public RoomSchedule Schedule { get; set; } +} + +public class MeetingChangeEventArgs : EventArgs +{ + public Event Meeting { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs b/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs index cdf1dfa8..ea44f98a 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs @@ -6,58 +6,57 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Fusion -{ - /// - /// When created, runs progcomments on every slot and stores the program names in a list - /// - public class ProcessorProgReg - { - //public static Dictionary Programs { get; private set; } +namespace PepperDash.Essentials.Core.Fusion; - public static Dictionary GetProcessorProgReg() +/// +/// When created, runs progcomments on every slot and stores the program names in a list +/// +public class ProcessorProgReg +{ + //public static Dictionary Programs { get; private set; } + + public static Dictionary GetProcessorProgReg() + { + var programs = new Dictionary(); + for (int i = 1; i <= Global.ControlSystem.NumProgramsSupported; i++) { - var programs = new Dictionary(); - for (int i = 1; i <= Global.ControlSystem.NumProgramsSupported; i++) + string response = null; + var success = CrestronConsole.SendControlSystemCommand("progcomments:" + i, ref response); + var item = new ProcessorProgramItem(); + if (!success) + item.Name = "Error: PROGCOMMENTS failed"; + else { - string response = null; - var success = CrestronConsole.SendControlSystemCommand("progcomments:" + i, ref response); - var item = new ProcessorProgramItem(); - if (!success) - item.Name = "Error: PROGCOMMENTS failed"; + if (response.ToLower().Contains("bad or incomplete")) + item.Name = ""; else { - if (response.ToLower().Contains("bad or incomplete")) - item.Name = ""; - else + var startPos = response.IndexOf("Program File"); + var colonPos = response.IndexOf(":", startPos) + 1; + var endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos); + item.Name = response.Substring(colonPos, endPos - colonPos).Trim(); + item.Exists = true; + if (item.Name.Contains(".dll")) { - var startPos = response.IndexOf("Program File"); - var colonPos = response.IndexOf(":", startPos) + 1; - var endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos); - item.Name = response.Substring(colonPos, endPos - colonPos).Trim(); - item.Exists = true; - if (item.Name.Contains(".dll")) - { - startPos = response.IndexOf("Compiler Revision"); - colonPos = response.IndexOf(":", startPos) + 1; - endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos); - item.Name = item.Name + "_v" + response.Substring(colonPos, endPos - colonPos).Trim(); - } + startPos = response.IndexOf("Compiler Revision"); + colonPos = response.IndexOf(":", startPos) + 1; + endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos); + item.Name = item.Name + "_v" + response.Substring(colonPos, endPos - colonPos).Trim(); } } - programs[i] = item; - Debug.LogMessage(LogEventLevel.Debug, "Program {0}: {1}", i, item.Name); } - return programs; + programs[i] = item; + Debug.LogMessage(LogEventLevel.Debug, "Program {0}: {1}", i, item.Name); } + return programs; } +} - /// - /// Used in ProcessorProgReg - /// - public class ProcessorProgramItem - { - public bool Exists { get; set; } - public string Name { get; set; } - } +/// +/// Used in ProcessorProgReg +/// +public class ProcessorProgramItem +{ + public bool Exists { get; set; } + public string Name { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs b/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs index 1ac5dbde..ba53564a 100644 --- a/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs +++ b/src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs @@ -8,493 +8,492 @@ using Crestron.SimplSharpPro.Fusion; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Fusion +namespace PepperDash.Essentials.Core.Fusion; + +// Helper Classes for GUIDs + +/// +/// Stores GUIDs to be written to a file in NVRAM +/// +public class FusionRoomGuids { - // Helper Classes for GUIDs + public string RoomName { get; set; } + public uint IpId { get; set; } + public string RoomGuid { get; set; } + public FusionOccupancySensorAsset OccupancyAsset { get; set; } + public Dictionary StaticAssets { get; set; } + + public FusionRoomGuids() + { + StaticAssets = new Dictionary(); + OccupancyAsset = new FusionOccupancySensorAsset(); + } + + public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets) + { + RoomName = roomName; + IpId = ipId; + RoomGuid = roomGuid; + + StaticAssets = staticAssets; + OccupancyAsset = new FusionOccupancySensorAsset(); + } + + public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets, FusionOccupancySensorAsset occAsset) + { + RoomName = roomName; + IpId = ipId; + RoomGuid = roomGuid; + + StaticAssets = staticAssets; + OccupancyAsset = occAsset; + } /// - /// Stores GUIDs to be written to a file in NVRAM + /// Generates a new room GUID prefixed by the program slot number and NIC MAC address /// - public class FusionRoomGuids + /// + /// + public string GenerateNewRoomGuid(uint progSlot, string mac) { - public string RoomName { get; set; } - public uint IpId { get; set; } - public string RoomGuid { get; set; } - public FusionOccupancySensorAsset OccupancyAsset { get; set; } - public Dictionary StaticAssets { get; set; } + Guid roomGuid = Guid.NewGuid(); - public FusionRoomGuids() + return string.Format("{0}-{1}-{2}", progSlot, mac, roomGuid.ToString()); + } + + + /// + /// Adds an asset to the StaticAssets collection and returns the new asset + /// + /// + /// + /// + /// + /// + /// + public FusionAsset AddStaticAsset(FusionRoom room, int uid, string assetName, string type, string instanceId) + { + var slotNum = GetNextAvailableAssetNumber(room); + + Debug.LogMessage(LogEventLevel.Verbose, "Adding Fusion Asset: {0} of Type: {1} at Slot Number: {2} with GUID: {3}", assetName, type, slotNum, instanceId); + + var tempAsset = new FusionAsset(slotNum, assetName, type, instanceId); + + StaticAssets.Add(uid, tempAsset); + + return tempAsset; + } + + /// + /// Returns the next available slot number in the Fusion UserConfigurableAssetDetails collection + /// + /// + /// + public static uint GetNextAvailableAssetNumber(FusionRoom room) + { + uint slotNum = 0; + + foreach (var item in room.UserConfigurableAssetDetails) { - StaticAssets = new Dictionary(); - OccupancyAsset = new FusionOccupancySensorAsset(); + if(item.Number > slotNum) + slotNum = item.Number; } - public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets) + if (slotNum < 5) { - RoomName = roomName; - IpId = ipId; - RoomGuid = roomGuid; - - StaticAssets = staticAssets; - OccupancyAsset = new FusionOccupancySensorAsset(); + slotNum = 5; } + else + slotNum = slotNum + 1; - public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets, FusionOccupancySensorAsset occAsset) - { - RoomName = roomName; - IpId = ipId; - RoomGuid = roomGuid; + Debug.LogMessage(LogEventLevel.Verbose, "#Next available fusion asset number is: {0}", slotNum); - StaticAssets = staticAssets; - OccupancyAsset = occAsset; - } + return slotNum; + } - /// - /// Generates a new room GUID prefixed by the program slot number and NIC MAC address - /// - /// - /// - public string GenerateNewRoomGuid(uint progSlot, string mac) - { - Guid roomGuid = Guid.NewGuid(); +} - return string.Format("{0}-{1}-{2}", progSlot, mac, roomGuid.ToString()); - } +public class FusionOccupancySensorAsset +{ + // SlotNumber fixed at 4 + public uint SlotNumber { get { return 4; } } + public string Name { get { return "Occupancy Sensor"; } } + public eAssetType Type { get; set; } + public string InstanceId { get; set; } - /// - /// Adds an asset to the StaticAssets collection and returns the new asset - /// - /// - /// - /// - /// - /// - /// - public FusionAsset AddStaticAsset(FusionRoom room, int uid, string assetName, string type, string instanceId) - { - var slotNum = GetNextAvailableAssetNumber(room); + public FusionOccupancySensorAsset() + { + } - Debug.LogMessage(LogEventLevel.Verbose, "Adding Fusion Asset: {0} of Type: {1} at Slot Number: {2} with GUID: {3}", assetName, type, slotNum, instanceId); + public FusionOccupancySensorAsset(eAssetType type) + { + Type = type; - var tempAsset = new FusionAsset(slotNum, assetName, type, instanceId); + InstanceId = Guid.NewGuid().ToString(); + } +} - StaticAssets.Add(uid, tempAsset); +public class FusionAsset +{ + public uint SlotNumber { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public string InstanceId { get;set; } - return tempAsset; - } - - /// - /// Returns the next available slot number in the Fusion UserConfigurableAssetDetails collection - /// - /// - /// - public static uint GetNextAvailableAssetNumber(FusionRoom room) - { - uint slotNum = 0; - - foreach (var item in room.UserConfigurableAssetDetails) - { - if(item.Number > slotNum) - slotNum = item.Number; - } - - if (slotNum < 5) - { - slotNum = 5; - } - else - slotNum = slotNum + 1; - - Debug.LogMessage(LogEventLevel.Verbose, "#Next available fusion asset number is: {0}", slotNum); - - return slotNum; - } + public FusionAsset() + { } - public class FusionOccupancySensorAsset + public FusionAsset(uint slotNum, string assetName, string type, string instanceId) { - // SlotNumber fixed at 4 - - public uint SlotNumber { get { return 4; } } - public string Name { get { return "Occupancy Sensor"; } } - public eAssetType Type { get; set; } - public string InstanceId { get; set; } - - public FusionOccupancySensorAsset() + SlotNumber = slotNum; + Name = assetName; + Type = type; + if (string.IsNullOrEmpty(instanceId)) { - } - - public FusionOccupancySensorAsset(eAssetType type) - { - Type = type; - InstanceId = Guid.NewGuid().ToString(); } - } - - public class FusionAsset - { - public uint SlotNumber { get; set; } - public string Name { get; set; } - public string Type { get; set; } - public string InstanceId { get;set; } - - public FusionAsset() + else { - + InstanceId = instanceId; } + } +} - public FusionAsset(uint slotNum, string assetName, string type, string instanceId) +//*************************************************************************************************** + +public class RoomSchedule +{ + public List Meetings { get; set; } + + public RoomSchedule() + { + Meetings = new List(); + } +} + +//**************************************************************************************************** +// Helper Classes for XML API + +/// +/// Data needed to request the local time from the Fusion server +/// +public class LocalTimeRequest +{ + public string RequestID { get; set; } +} + +/// +/// All the data needed for a full schedule request in a room +/// +/// //[XmlRoot(ElementName = "RequestSchedule")] +public class RequestSchedule +{ + //[XmlElement(ElementName = "RequestID")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "RoomID")] + public string RoomID { get; set; } + //[XmlElement(ElementName = "Start")] + public DateTime Start { get; set; } + //[XmlElement(ElementName = "HourSpan")] + public double HourSpan { get; set; } + + public RequestSchedule(string requestID, string roomID) + { + RequestID = requestID; + RoomID = roomID; + Start = DateTime.Now; + HourSpan = 24; + } +} + + +//[XmlRoot(ElementName = "RequestAction")] +public class RequestAction +{ + //[XmlElement(ElementName = "RequestID")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "RoomID")] + public string RoomID { get; set; } + //[XmlElement(ElementName = "ActionID")] + public string ActionID { get; set; } + //[XmlElement(ElementName = "Parameters")] + public List Parameters { get; set; } + + public RequestAction(string roomID, string actionID, List parameters) + { + RoomID = roomID; + ActionID = actionID; + Parameters = parameters; + } +} + +//[XmlRoot(ElementName = "ActionResponse")] +public class ActionResponse +{ + //[XmlElement(ElementName = "RequestID")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "ActionID")] + public string ActionID { get; set; } + //[XmlElement(ElementName = "Parameters")] + public List Parameters { get; set; } +} + +//[XmlRoot(ElementName = "Parameter")] +public class Parameter +{ + //[XmlAttribute(AttributeName = "ID")] + public string ID { get; set; } + //[XmlAttribute(AttributeName = "Value")] + public string Value { get; set; } +} + +////[XmlRoot(ElementName = "Parameters")] +//public class Parameters +//{ +// //[XmlElement(ElementName = "Parameter")] +// public List Parameter { get; set; } +//} + +/// +/// Data structure for a ScheduleResponse from Fusion +/// +/// //[XmlRoot(ElementName = "ScheduleResponse")] +public class ScheduleResponse +{ + //[XmlElement(ElementName = "RequestID")] + public string RequestID { get; set; } + //[XmlElement(ElementName = "RoomID")] + public string RoomID { get; set; } + //[XmlElement(ElementName = "RoomName")] + public string RoomName { get; set; } + //[XmlElement("Event")] + public List Events { get; set; } + + public ScheduleResponse() + { + Events = new List(); + } +} + +//[XmlRoot(ElementName = "Event")] +public class Event +{ + //[XmlElement(ElementName = "MeetingID")] + public string MeetingID { get; set; } + //[XmlElement(ElementName = "RVMeetingID")] + public string RVMeetingID { get; set; } + //[XmlElement(ElementName = "Recurring")] + public string Recurring { get; set; } + //[XmlElement(ElementName = "InstanceID")] + public string InstanceID { get; set; } + //[XmlElement(ElementName = "dtStart")] + public DateTime dtStart { get; set; } + //[XmlElement(ElementName = "dtEnd")] + public DateTime dtEnd { get; set; } + //[XmlElement(ElementName = "Organizer")] + public string Organizer { get; set; } + //[XmlElement(ElementName = "Attendees")] + public Attendees Attendees { get; set; } + //[XmlElement(ElementName = "Resources")] + public Resources Resources { get; set; } + //[XmlElement(ElementName = "IsEvent")] + public string IsEvent { get; set; } + //[XmlElement(ElementName = "IsRoomViewMeeting")] + public string IsRoomViewMeeting { get; set; } + //[XmlElement(ElementName = "IsPrivate")] + public string IsPrivate { get; set; } + //[XmlElement(ElementName = "IsExchangePrivate")] + public string IsExchangePrivate { get; set; } + //[XmlElement(ElementName = "MeetingTypes")] + public MeetingTypes MeetingTypes { get; set; } + //[XmlElement(ElementName = "ParticipantCode")] + public string ParticipantCode { get; set; } + //[XmlElement(ElementName = "PhoneNo")] + public string PhoneNo { get; set; } + //[XmlElement(ElementName = "WelcomeMsg")] + public string WelcomeMsg { get; set; } + //[XmlElement(ElementName = "Subject")] + public string Subject { get; set; } + //[XmlElement(ElementName = "LiveMeeting")] + public LiveMeeting LiveMeeting { get; set; } + //[XmlElement(ElementName = "ShareDocPath")] + public string ShareDocPath { get; set; } + //[XmlElement(ElementName = "HaveAttendees")] + public string HaveAttendees { get; set; } + //[XmlElement(ElementName = "HaveResources")] + public string HaveResources { get; set; } + + /// + /// Gets the duration of the meeting + /// + public string DurationInMinutes + { + get { - SlotNumber = slotNum; - Name = assetName; - Type = type; - if (string.IsNullOrEmpty(instanceId)) + string duration; + + var timeSpan = dtEnd.Subtract(dtStart); + int hours = timeSpan.Hours; + double minutes = timeSpan.Minutes; + double roundedMinutes = Math.Round(minutes); + if (hours > 0) { - InstanceId = Guid.NewGuid().ToString(); + duration = string.Format("{0} hours {1} minutes", hours, roundedMinutes); } else { - InstanceId = instanceId; + duration = string.Format("{0} minutes", roundedMinutes); } + + return duration; } } - //*************************************************************************************************** - - public class RoomSchedule - { - public List Meetings { get; set; } - - public RoomSchedule() - { - Meetings = new List(); - } - } - - //**************************************************************************************************** - // Helper Classes for XML API - - /// - /// Data needed to request the local time from the Fusion server - /// - public class LocalTimeRequest - { - public string RequestID { get; set; } - } - /// - /// All the data needed for a full schedule request in a room + /// Gets the remaining time in the meeting. Returns null if the meeting is not currently in progress. /// - /// //[XmlRoot(ElementName = "RequestSchedule")] - public class RequestSchedule + public string RemainingTime { - //[XmlElement(ElementName = "RequestID")] - public string RequestID { get; set; } - //[XmlElement(ElementName = "RoomID")] - public string RoomID { get; set; } - //[XmlElement(ElementName = "Start")] - public DateTime Start { get; set; } - //[XmlElement(ElementName = "HourSpan")] - public double HourSpan { get; set; } - - public RequestSchedule(string requestID, string roomID) + get { - RequestID = requestID; - RoomID = roomID; - Start = DateTime.Now; - HourSpan = 24; - } - } + var now = DateTime.Now; + string remainingTime; - //[XmlRoot(ElementName = "RequestAction")] - public class RequestAction - { - //[XmlElement(ElementName = "RequestID")] - public string RequestID { get; set; } - //[XmlElement(ElementName = "RoomID")] - public string RoomID { get; set; } - //[XmlElement(ElementName = "ActionID")] - public string ActionID { get; set; } - //[XmlElement(ElementName = "Parameters")] - public List Parameters { get; set; } - - public RequestAction(string roomID, string actionID, List parameters) - { - RoomID = roomID; - ActionID = actionID; - Parameters = parameters; - } - } - - //[XmlRoot(ElementName = "ActionResponse")] - public class ActionResponse - { - //[XmlElement(ElementName = "RequestID")] - public string RequestID { get; set; } - //[XmlElement(ElementName = "ActionID")] - public string ActionID { get; set; } - //[XmlElement(ElementName = "Parameters")] - public List Parameters { get; set; } - } - - //[XmlRoot(ElementName = "Parameter")] - public class Parameter - { - //[XmlAttribute(AttributeName = "ID")] - public string ID { get; set; } - //[XmlAttribute(AttributeName = "Value")] - public string Value { get; set; } - } - - ////[XmlRoot(ElementName = "Parameters")] - //public class Parameters - //{ - // //[XmlElement(ElementName = "Parameter")] - // public List Parameter { get; set; } - //} - - /// - /// Data structure for a ScheduleResponse from Fusion - /// - /// //[XmlRoot(ElementName = "ScheduleResponse")] - public class ScheduleResponse - { - //[XmlElement(ElementName = "RequestID")] - public string RequestID { get; set; } - //[XmlElement(ElementName = "RoomID")] - public string RoomID { get; set; } - //[XmlElement(ElementName = "RoomName")] - public string RoomName { get; set; } - //[XmlElement("Event")] - public List Events { get; set; } - - public ScheduleResponse() - { - Events = new List(); - } - } - - //[XmlRoot(ElementName = "Event")] - public class Event - { - //[XmlElement(ElementName = "MeetingID")] - public string MeetingID { get; set; } - //[XmlElement(ElementName = "RVMeetingID")] - public string RVMeetingID { get; set; } - //[XmlElement(ElementName = "Recurring")] - public string Recurring { get; set; } - //[XmlElement(ElementName = "InstanceID")] - public string InstanceID { get; set; } - //[XmlElement(ElementName = "dtStart")] - public DateTime dtStart { get; set; } - //[XmlElement(ElementName = "dtEnd")] - public DateTime dtEnd { get; set; } - //[XmlElement(ElementName = "Organizer")] - public string Organizer { get; set; } - //[XmlElement(ElementName = "Attendees")] - public Attendees Attendees { get; set; } - //[XmlElement(ElementName = "Resources")] - public Resources Resources { get; set; } - //[XmlElement(ElementName = "IsEvent")] - public string IsEvent { get; set; } - //[XmlElement(ElementName = "IsRoomViewMeeting")] - public string IsRoomViewMeeting { get; set; } - //[XmlElement(ElementName = "IsPrivate")] - public string IsPrivate { get; set; } - //[XmlElement(ElementName = "IsExchangePrivate")] - public string IsExchangePrivate { get; set; } - //[XmlElement(ElementName = "MeetingTypes")] - public MeetingTypes MeetingTypes { get; set; } - //[XmlElement(ElementName = "ParticipantCode")] - public string ParticipantCode { get; set; } - //[XmlElement(ElementName = "PhoneNo")] - public string PhoneNo { get; set; } - //[XmlElement(ElementName = "WelcomeMsg")] - public string WelcomeMsg { get; set; } - //[XmlElement(ElementName = "Subject")] - public string Subject { get; set; } - //[XmlElement(ElementName = "LiveMeeting")] - public LiveMeeting LiveMeeting { get; set; } - //[XmlElement(ElementName = "ShareDocPath")] - public string ShareDocPath { get; set; } - //[XmlElement(ElementName = "HaveAttendees")] - public string HaveAttendees { get; set; } - //[XmlElement(ElementName = "HaveResources")] - public string HaveResources { get; set; } - - /// - /// Gets the duration of the meeting - /// - public string DurationInMinutes - { - get + if (GetInProgress()) { - string duration; - - var timeSpan = dtEnd.Subtract(dtStart); + var timeSpan = dtEnd.Subtract(now); int hours = timeSpan.Hours; double minutes = timeSpan.Minutes; double roundedMinutes = Math.Round(minutes); if (hours > 0) { - duration = string.Format("{0} hours {1} minutes", hours, roundedMinutes); + remainingTime = string.Format("{0} hours {1} minutes", hours, roundedMinutes); } else { - duration = string.Format("{0} minutes", roundedMinutes); + remainingTime = string.Format("{0} minutes", roundedMinutes); } - return duration; - } - } - - /// - /// Gets the remaining time in the meeting. Returns null if the meeting is not currently in progress. - /// - public string RemainingTime - { - get - { - var now = DateTime.Now; - - string remainingTime; - - if (GetInProgress()) - { - var timeSpan = dtEnd.Subtract(now); - int hours = timeSpan.Hours; - double minutes = timeSpan.Minutes; - double roundedMinutes = Math.Round(minutes); - if (hours > 0) - { - remainingTime = string.Format("{0} hours {1} minutes", hours, roundedMinutes); - } - else - { - remainingTime = string.Format("{0} minutes", roundedMinutes); - } - - return remainingTime; - } - else - return null; - } - - } - - /// - /// Indicates that the meeting is in progress - /// - public bool isInProgress - { - get - { - return GetInProgress(); - } - } - - /// - /// Determines if the meeting is in progress - /// - /// Returns true if in progress - bool GetInProgress() - { - var now = DateTime.Now; - - if (now > dtStart && now < dtEnd) - { - return true; + return remainingTime; } else - return false; + return null; + } + + } + + /// + /// Indicates that the meeting is in progress + /// + public bool isInProgress + { + get + { + return GetInProgress(); } } - //[XmlRoot(ElementName = "Resources")] - public class Resources + /// + /// Determines if the meeting is in progress + /// + /// Returns true if in progress + bool GetInProgress() { - //[XmlElement(ElementName = "Rooms")] - public Rooms Rooms { get; set; } - } + var now = DateTime.Now; - //[XmlRoot(ElementName = "Rooms")] - public class Rooms - { - //[XmlElement(ElementName = "Room")] - public List Room { get; set; } + if (now > dtStart && now < dtEnd) + { + return true; + } + else + return false; } +} - //[XmlRoot(ElementName = "Room")] - public class Room - { - //[XmlElement(ElementName = "Name")] - public string Name { get; set; } - //[XmlElement(ElementName = "ID")] - public string ID { get; set; } - //[XmlElement(ElementName = "MPType")] - public string MPType { get; set; } - } +//[XmlRoot(ElementName = "Resources")] +public class Resources +{ + //[XmlElement(ElementName = "Rooms")] + public Rooms Rooms { get; set; } +} - //[XmlRoot(ElementName = "Attendees")] - public class Attendees - { - //[XmlElement(ElementName = "Required")] - public Required Required { get; set; } - //[XmlElement(ElementName = "Optional")] - public Optional Optional { get; set; } - } +//[XmlRoot(ElementName = "Rooms")] +public class Rooms +{ + //[XmlElement(ElementName = "Room")] + public List Room { get; set; } +} - //[XmlRoot(ElementName = "Required")] - public class Required - { - //[XmlElement(ElementName = "Attendee")] - public List Attendee { get; set; } - } +//[XmlRoot(ElementName = "Room")] +public class Room +{ + //[XmlElement(ElementName = "Name")] + public string Name { get; set; } + //[XmlElement(ElementName = "ID")] + public string ID { get; set; } + //[XmlElement(ElementName = "MPType")] + public string MPType { get; set; } +} - //[XmlRoot(ElementName = "Optional")] - public class Optional - { - //[XmlElement(ElementName = "Attendee")] - public List Attendee { get; set; } - } +//[XmlRoot(ElementName = "Attendees")] +public class Attendees +{ + //[XmlElement(ElementName = "Required")] + public Required Required { get; set; } + //[XmlElement(ElementName = "Optional")] + public Optional Optional { get; set; } +} - //[XmlRoot(ElementName = "MeetingType")] - public class MeetingType - { - //[XmlAttribute(AttributeName = "ID")] - public string ID { get; set; } - //[XmlAttribute(AttributeName = "Value")] - public string Value { get; set; } - } +//[XmlRoot(ElementName = "Required")] +public class Required +{ + //[XmlElement(ElementName = "Attendee")] + public List Attendee { get; set; } +} - //[XmlRoot(ElementName = "MeetingTypes")] - public class MeetingTypes - { - //[XmlElement(ElementName = "MeetingType")] - public List MeetingType { get; set; } - } +//[XmlRoot(ElementName = "Optional")] +public class Optional +{ + //[XmlElement(ElementName = "Attendee")] + public List Attendee { get; set; } +} - //[XmlRoot(ElementName = "LiveMeeting")] - public class LiveMeeting - { - //[XmlElement(ElementName = "URL")] - public string URL { get; set; } - //[XmlElement(ElementName = "ID")] - public string ID { get; set; } - //[XmlElement(ElementName = "Key")] - public string Key { get; set; } - //[XmlElement(ElementName = "Subject")] - public string Subject { get; set; } - } +//[XmlRoot(ElementName = "MeetingType")] +public class MeetingType +{ + //[XmlAttribute(AttributeName = "ID")] + public string ID { get; set; } + //[XmlAttribute(AttributeName = "Value")] + public string Value { get; set; } +} - //[XmlRoot(ElementName = "LiveMeetingURL")] - public class LiveMeetingURL - { - //[XmlElement(ElementName = "LiveMeeting")] - public LiveMeeting LiveMeeting { get; set; } - } +//[XmlRoot(ElementName = "MeetingTypes")] +public class MeetingTypes +{ + //[XmlElement(ElementName = "MeetingType")] + public List MeetingType { get; set; } +} + +//[XmlRoot(ElementName = "LiveMeeting")] +public class LiveMeeting +{ + //[XmlElement(ElementName = "URL")] + public string URL { get; set; } + //[XmlElement(ElementName = "ID")] + public string ID { get; set; } + //[XmlElement(ElementName = "Key")] + public string Key { get; set; } + //[XmlElement(ElementName = "Subject")] + public string Subject { get; set; } +} + +//[XmlRoot(ElementName = "LiveMeetingURL")] +public class LiveMeetingURL +{ + //[XmlElement(ElementName = "LiveMeeting")] + public LiveMeeting LiveMeeting { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs b/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs index c21df098..ec33512c 100644 --- a/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs +++ b/src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs @@ -4,20 +4,19 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class EthernetAdapterInfo { - public class EthernetAdapterInfo - { - public EthernetAdapterType Type { get; set; } - public bool DhcpIsOn { get; set; } - public string Hostname { get; set; } - public string MacAddress { get; set; } - public string IpAddress { get; set; } - public string Subnet { get; set; } - public string Gateway { get; set; } - public string Dns1 { get; set; } - public string Dns2 { get; set; } - public string Dns3 { get; set; } - public string Domain { get; set; } - } + public EthernetAdapterType Type { get; set; } + public bool DhcpIsOn { get; set; } + public string Hostname { get; set; } + public string MacAddress { get; set; } + public string IpAddress { get; set; } + public string Subnet { get; set; } + public string Gateway { get; set; } + public string Dns1 { get; set; } + public string Dns2 { get; set; } + public string Dns3 { get; set; } + public string Domain { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Global/Global.cs b/src/PepperDash.Essentials.Core/Global/Global.cs index 6b2841c8..5bde3e06 100644 --- a/src/PepperDash.Essentials.Core/Global/Global.cs +++ b/src/PepperDash.Essentials.Core/Global/Global.cs @@ -18,170 +18,170 @@ using Newtonsoft.Json.Schema; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public static class Global { public static CrestronControlSystem ControlSystem { get; set; } - public static eDevicePlatform Platform { get { return CrestronEnvironment.DevicePlatform; } } + public static eDevicePlatform Platform { get { return CrestronEnvironment.DevicePlatform; } } - public static Dictionary EthernetAdapterInfoCollection { get; private set; } + public static Dictionary EthernetAdapterInfoCollection { get; private set; } public static LicenseManager LicenseManager { get; set; } - public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } } + public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } } - // TODO: consider making this configurable later - public static IFormatProvider Culture = CultureInfo.InvariantCulture; + // TODO: consider making this configurable later + public static IFormatProvider Culture = CultureInfo.InvariantCulture; - /// - /// True when the processor type is a DMPS variant - /// - public static bool ControlSystemIsDmpsType + /// + /// True when the processor type is a DMPS variant + /// + public static bool ControlSystemIsDmpsType + { + get { - get + if(ControlSystem.SystemControl != null) { - if(ControlSystem.SystemControl != null) + if(ControlSystem.SystemControl.SystemControlType > 0) { - if(ControlSystem.SystemControl.SystemControlType > 0) - { - return true; - } - } - return false; + return true; + } } + return false; } + } - /// - /// True when the processor type is a DMPS 4K variant - /// - public static bool ControlSystemIsDmps4kType + /// + /// True when the processor type is a DMPS 4K variant + /// + public static bool ControlSystemIsDmps4kType + { + get { - get + if(ControlSystem.SystemControl != null) { - if(ControlSystem.SystemControl != null) + if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K150CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl) { - if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K150CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl) - { - return true; - } - } - return false; + return true; + } } + return false; } + } - /// - /// True when the processor type is a DMPS 4K 200/300/250/350 variant - /// - public static bool ControlSystemIsDmps4k3xxType + /// + /// True when the processor type is a DMPS 4K 200/300/250/350 variant + /// + public static bool ControlSystemIsDmps4k3xxType + { + get { - get + if(ControlSystem.SystemControl != null) { - if(ControlSystem.SystemControl != null) + if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl || + ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl) { - if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl || - ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl) - { - return true; - } - } - return false; + return true; + } } + return false; } + } - /// - /// The file path prefix to the folder containing configuration files - /// - public static string FilePathPrefix { get; private set; } + /// + /// The file path prefix to the folder containing configuration files + /// + public static string FilePathPrefix { get; private set; } - /// - /// The file path prefix to the applciation directory - /// - public static string ApplicationDirectoryPathPrefix + /// + /// The file path prefix to the applciation directory + /// + public static string ApplicationDirectoryPathPrefix + { + get { - get - { - return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); - } + return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); } + } - /// - /// Returns the directory separator character based on the running OS - /// - public static char DirectorySeparator + /// + /// Returns the directory separator character based on the running OS + /// + public static char DirectorySeparator + { + get { - get - { - return System.IO.Path.DirectorySeparatorChar; - } + return System.IO.Path.DirectorySeparatorChar; } + } - /// - /// Wildcarded config file name for global reference - /// - public const string ConfigFileName = "*configurationFile*.json"; + /// + /// Wildcarded config file name for global reference + /// + public const string ConfigFileName = "*configurationFile*.json"; - /// - /// Sets the file path prefix - /// - /// - public static void SetFilePathPrefix(string prefix) + /// + /// Sets the file path prefix + /// + /// + public static void SetFilePathPrefix(string prefix) + { + FilePathPrefix = prefix; + Debug.LogMessage(LogEventLevel.Information, "File Path Prefix set to '{0}'", FilePathPrefix); + } + + static string _AssemblyVersion; + + /// + /// Gets the Assembly Version of Essentials + /// + /// The Assembly Version at Runtime + public static string AssemblyVersion + { + get { - FilePathPrefix = prefix; - Debug.LogMessage(LogEventLevel.Information, "File Path Prefix set to '{0}'", FilePathPrefix); + return _AssemblyVersion; } - - static string _AssemblyVersion; - - /// - /// Gets the Assembly Version of Essentials - /// - /// The Assembly Version at Runtime - public static string AssemblyVersion + private set { - get - { - return _AssemblyVersion; - } - private set - { - _AssemblyVersion = value; - } + _AssemblyVersion = value; } + } - /// - /// Sets the Assembly version to the version of the Essentials Library - /// - /// - public static void SetAssemblyVersion(string assemblyVersion) - { - AssemblyVersion = assemblyVersion; - } + /// + /// Sets the Assembly version to the version of the Essentials Library + /// + /// + public static void SetAssemblyVersion(string assemblyVersion) + { + AssemblyVersion = assemblyVersion; + } public static bool IsRunningDevelopmentVersion(List developmentVersions, string minimumVersion) { if (Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*").Groups[1].Value == "0") { - Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); - return true; + Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); + return true; } if (developmentVersions == null) { Debug.LogMessage(LogEventLevel.Information, - "Development Plugin does not specify a list of versions. Loading plugin may not work as expected. Checking Minumum version"); - return IsRunningMinimumVersionOrHigher(minimumVersion); + "Development Plugin does not specify a list of versions. Loading plugin may not work as expected. Checking Minumum version"); + return IsRunningMinimumVersionOrHigher(minimumVersion); } - Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum versions '{1}'", AssemblyVersion, developmentVersions); + Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum versions '{1}'", AssemblyVersion, developmentVersions); var versionMatch = developmentVersions.FirstOrDefault(x => x == AssemblyVersion); @@ -191,83 +191,83 @@ namespace PepperDash.Essentials.Core return false; } - Debug.LogMessage(LogEventLevel.Verbose, "Essentials Build {0} matches list of development builds", AssemblyVersion); + Debug.LogMessage(LogEventLevel.Verbose, "Essentials Build {0} matches list of development builds", AssemblyVersion); return IsRunningMinimumVersionOrHigher(minimumVersion); } - /// - /// Checks to see if the running version meets or exceed the minimum specified version. For beta versions (0.xx.yy), will always return true. - /// - /// Minimum specified version in format of xx.yy.zz - /// Returns true if the running version meets or exceeds the minimum specified version - public static bool IsRunningMinimumVersionOrHigher(string minimumVersion) + /// + /// Checks to see if the running version meets or exceed the minimum specified version. For beta versions (0.xx.yy), will always return true. + /// + /// Minimum specified version in format of xx.yy.zz + /// Returns true if the running version meets or exceeds the minimum specified version + public static bool IsRunningMinimumVersionOrHigher(string minimumVersion) + { + Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum version '{1}'", AssemblyVersion, minimumVersion); + + if (String.IsNullOrEmpty(minimumVersion)) { - Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum version '{1}'", AssemblyVersion, minimumVersion); - - if (String.IsNullOrEmpty(minimumVersion)) - { - Debug.LogMessage(LogEventLevel.Information,"Plugin does not specify a minimum version. Loading plugin may not work as expected. Proceeding with loading plugin"); - return true; - } - - var runtimeVersion = Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*"); - - var runtimeVersionMajor = Int16.Parse(runtimeVersion.Groups[1].Value); - var runtimeVersionMinor = Int16.Parse(runtimeVersion.Groups[2].Value); - var runtimeVersionBuild = Int16.Parse(runtimeVersion.Groups[3].Value); - - var runtimeVer = new Version(runtimeVersionMajor, runtimeVersionMinor, runtimeVersionBuild); - - Version minimumVer; - try - { - minimumVer = new Version(minimumVersion); - } - catch - { - Debug.LogMessage(LogEventLevel.Verbose, "unable to parse minimum version {0}. Bypassing plugin load.", minimumVersion); - return false; - } - - - // Check for beta build version - if (runtimeVer.Major != 0) - { - return runtimeVer.CompareTo(minimumVer) >= 0; - } - - Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); + Debug.LogMessage(LogEventLevel.Information,"Plugin does not specify a minimum version. Loading plugin may not work as expected. Proceeding with loading plugin"); return true; - - /* - var minVersion = Regex.Match(minimumVersion, @"^(\d*).(\d*).(\d*)$"); - - if(!minVersion.Success) - { - - } - - var minVersionMajor = Int16.Parse(minVersion.Groups[1].Value); - var minVersionMinor = Int16.Parse(minVersion.Groups[2].Value); - var minVersionBuild = Int16.Parse(minVersion.Groups[3].Value); - - - - if (minVersionMajor > runtimeVersionMajor) - return false; - - if (minVersionMinor > runtimeVersionMinor) - return false; - - if (minVersionBuild > runtimeVersionBuild) - return false; - - return true; - */ } + + var runtimeVersion = Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*"); + + var runtimeVersionMajor = Int16.Parse(runtimeVersion.Groups[1].Value); + var runtimeVersionMinor = Int16.Parse(runtimeVersion.Groups[2].Value); + var runtimeVersionBuild = Int16.Parse(runtimeVersion.Groups[3].Value); + + var runtimeVer = new Version(runtimeVersionMajor, runtimeVersionMinor, runtimeVersionBuild); + + Version minimumVer; + try + { + minimumVer = new Version(minimumVersion); + } + catch + { + Debug.LogMessage(LogEventLevel.Verbose, "unable to parse minimum version {0}. Bypassing plugin load.", minimumVersion); + return false; + } + + + // Check for beta build version + if (runtimeVer.Major != 0) + { + return runtimeVer.CompareTo(minimumVer) >= 0; + } + + Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); + return true; + + /* + var minVersion = Regex.Match(minimumVersion, @"^(\d*).(\d*).(\d*)$"); + + if(!minVersion.Success) + { + + } + + var minVersionMajor = Int16.Parse(minVersion.Groups[1].Value); + var minVersionMinor = Int16.Parse(minVersion.Groups[2].Value); + var minVersionBuild = Int16.Parse(minVersion.Groups[3].Value); + + + + if (minVersionMajor > runtimeVersionMajor) + return false; + + if (minVersionMinor > runtimeVersionMinor) + return false; + + if (minVersionBuild > runtimeVersionBuild) + return false; + + return true; + */ + } static Global() { @@ -279,18 +279,17 @@ namespace PepperDash.Essentials.Core return; } - try - { - CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("en"); - CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en"); - } - catch (CultureNotFoundException) - { - // If specific culture fails, fall back to invariant - CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; - CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; - } + try + { + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("en"); + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en"); + } + catch (CultureNotFoundException) + { + // If specific culture fails, fall back to invariant + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; + } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Global/JobTimer.cs b/src/PepperDash.Essentials.Core/Global/JobTimer.cs index 83159c12..c79fa53d 100644 --- a/src/PepperDash.Essentials.Core/Global/JobTimer.cs +++ b/src/PepperDash.Essentials.Core/Global/JobTimer.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public static class JobTimer { static CTimer MinuteTimer; @@ -72,9 +72,8 @@ namespace PepperDash.Essentials.Core public enum eJobTimerCycleTypes { - RunEveryDay, + RunEveryDay, RunEveryHour, RunEveryHalfHour, RunEveryMinute - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Global/Scheduler.cs b/src/PepperDash.Essentials.Core/Global/Scheduler.cs index 64350916..55a2116d 100644 --- a/src/PepperDash.Essentials.Core/Global/Scheduler.cs +++ b/src/PepperDash.Essentials.Core/Global/Scheduler.cs @@ -10,94 +10,94 @@ using PepperDash.Essentials.Room.Config; using Serilog.Events; using Activator = System.Activator; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Global Scheduler for the system +/// +public static class Scheduler { - /// - /// Global Scheduler for the system - /// - public static class Scheduler + private static readonly Dictionary EventGroups = new Dictionary(); + + static Scheduler() { - private static readonly Dictionary EventGroups = new Dictionary(); + CrestronConsole.AddNewConsoleCommand(DeleteEventGroup, "DeleteEventGroup", "Deletes the event group by key", ConsoleAccessLevelEnum.AccessOperator); - static Scheduler() + CrestronConsole.AddNewConsoleCommand(ClearEventsFromGroup, "ClearAllEvents", "Clears all scheduled events for this group", ConsoleAccessLevelEnum.AccessOperator); + + CrestronConsole.AddNewConsoleCommand(ListAllEventGroups, "ListAllEventGroups", "Lists all the event groups by key", ConsoleAccessLevelEnum.AccessOperator); + + CrestronConsole.AddNewConsoleCommand(ListAllEventsForGroup, "ListEventsForGroup", + "Lists all events for the given group", ConsoleAccessLevelEnum.AccessOperator); + } + + + static void DeleteEventGroup(string groupName) + { + if (EventGroups.ContainsKey(groupName)) { - CrestronConsole.AddNewConsoleCommand(DeleteEventGroup, "DeleteEventGroup", "Deletes the event group by key", ConsoleAccessLevelEnum.AccessOperator); - - CrestronConsole.AddNewConsoleCommand(ClearEventsFromGroup, "ClearAllEvents", "Clears all scheduled events for this group", ConsoleAccessLevelEnum.AccessOperator); - - CrestronConsole.AddNewConsoleCommand(ListAllEventGroups, "ListAllEventGroups", "Lists all the event groups by key", ConsoleAccessLevelEnum.AccessOperator); - - CrestronConsole.AddNewConsoleCommand(ListAllEventsForGroup, "ListEventsForGroup", - "Lists all events for the given group", ConsoleAccessLevelEnum.AccessOperator); - } - - - static void DeleteEventGroup(string groupName) - { - if (EventGroups.ContainsKey(groupName)) - { - var group = EventGroups[groupName]; - - EventGroups.Remove(groupName); - - group.Dispose(); - - group = null; - } - } - - /// - /// Clears (deletes) all events from a group - /// - /// - static void ClearEventsFromGroup(string groupName) - { - if (!EventGroups.ContainsKey(groupName)) - { - Debug.LogMessage(LogEventLevel.Information, - "[Scheduler]: Unable to delete events from group '{0}'. Group not found in EventGroups dictionary.", null, - groupName); - return; - } - var group = EventGroups[groupName]; + + EventGroups.Remove(groupName); - if (group != null) - { - group.ClearAllEvents(); + group.Dispose(); - Debug.LogMessage(LogEventLevel.Information, "[Scheduler]: All events deleted from group '{0}'", null, groupName); - } - else - Debug.LogMessage(LogEventLevel.Information, - "[Scheduler]: Unable to delete events from group '{0}'. Group not found in EventGroups dictionary.", null, - groupName); + group = null; + } + } + + /// + /// Clears (deletes) all events from a group + /// + /// + static void ClearEventsFromGroup(string groupName) + { + if (!EventGroups.ContainsKey(groupName)) + { + Debug.LogMessage(LogEventLevel.Information, + "[Scheduler]: Unable to delete events from group '{0}'. Group not found in EventGroups dictionary.", null, + groupName); + return; } - static void ListAllEventGroups(string command) + var group = EventGroups[groupName]; + + if (group != null) { - CrestronConsole.ConsoleCommandResponse("Event Groups:"); - foreach (var group in EventGroups) - { - CrestronConsole.ConsoleCommandResponse($"{group.Key}"); - } + group.ClearAllEvents(); + + Debug.LogMessage(LogEventLevel.Information, "[Scheduler]: All events deleted from group '{0}'", null, groupName); + } + else + Debug.LogMessage(LogEventLevel.Information, + "[Scheduler]: Unable to delete events from group '{0}'. Group not found in EventGroups dictionary.", null, + groupName); + } + + static void ListAllEventGroups(string command) + { + CrestronConsole.ConsoleCommandResponse("Event Groups:"); + foreach (var group in EventGroups) + { + CrestronConsole.ConsoleCommandResponse($"{group.Key}"); + } + } + + static void ListAllEventsForGroup(string args) + { + Debug.LogMessage(LogEventLevel.Information, "Getting events for group {0}...", null, args); + + ScheduledEventGroup group; + + if (!EventGroups.TryGetValue(args, out group)) + { + Debug.LogMessage(LogEventLevel.Information, "Unabled to get event group for key {0}", null, args); + return; } - static void ListAllEventsForGroup(string args) + foreach (var evt in group.ScheduledEvents) { - Debug.LogMessage(LogEventLevel.Information, "Getting events for group {0}...", null, args); - - ScheduledEventGroup group; - - if (!EventGroups.TryGetValue(args, out group)) - { - Debug.LogMessage(LogEventLevel.Information, "Unabled to get event group for key {0}", null, args); - return; - } - - foreach (var evt in group.ScheduledEvents) - { - CrestronConsole.ConsoleCommandResponse( + CrestronConsole.ConsoleCommandResponse( $@" ****Event key {evt.Key}**** Event state: {evt.Value.EventState} @@ -107,198 +107,197 @@ Acknowlegable: {evt.Value.Acknowledgeable} Recurrence: {evt.Value.Recurrence.Recurrence} Recurrence Days: {evt.Value.Recurrence.RecurrenceDays} ********************"); - } - } - - /// - /// Adds the event group to the global list - /// - /// - public static void AddEventGroup(ScheduledEventGroup eventGroup) - { - // Add this group to the global collection - if (!EventGroups.ContainsKey(eventGroup.Name)) - EventGroups.Add(eventGroup.Name, eventGroup); - } - - /// - /// Removes the event group from the global list - /// - /// - public static void RemoveEventGroup(ScheduledEventGroup eventGroup) - { - if(!EventGroups.ContainsKey(eventGroup.Name)) - EventGroups.Remove(eventGroup.Name); - } - - public static ScheduledEventGroup GetEventGroup(string key) - { - ScheduledEventGroup returnValue; - - return EventGroups.TryGetValue(key, out returnValue) ? returnValue : null; } } - public static class SchedulerUtilities + /// + /// Adds the event group to the global list + /// + /// + public static void AddEventGroup(ScheduledEventGroup eventGroup) { - /// - /// Checks the day of week in eventTime to see if it matches the weekdays defined in the recurrence enum. - /// - /// - /// - /// - public static bool CheckIfDayOfWeekMatchesRecurrenceDays(DateTime eventTime, ScheduledEventCommon.eWeekDays recurrence) - { - bool isMatch = false; + // Add this group to the global collection + if (!EventGroups.ContainsKey(eventGroup.Name)) + EventGroups.Add(eventGroup.Name, eventGroup); + } - var dayOfWeek = eventTime.DayOfWeek; + /// + /// Removes the event group from the global list + /// + /// + public static void RemoveEventGroup(ScheduledEventGroup eventGroup) + { + if(!EventGroups.ContainsKey(eventGroup.Name)) + EventGroups.Remove(eventGroup.Name); + } - Debug.LogMessage(LogEventLevel.Debug, "[Scheduler]: eventTime day of week is: {0}",null, dayOfWeek); - switch (dayOfWeek) - { - case DayOfWeek.Sunday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Sunday) == ScheduledEventCommon.eWeekDays.Sunday) - isMatch = true; - break; - } - case DayOfWeek.Monday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Monday) == ScheduledEventCommon.eWeekDays.Monday) - isMatch = true; - break; - } - case DayOfWeek.Tuesday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Tuesday) == ScheduledEventCommon.eWeekDays.Tuesday) - isMatch = true; - break; - } - case DayOfWeek.Wednesday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Wednesday) == ScheduledEventCommon.eWeekDays.Wednesday) - isMatch = true; - break; - } - case DayOfWeek.Thursday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Thursday) == ScheduledEventCommon.eWeekDays.Thursday) - isMatch = true; - break; - } - case DayOfWeek.Friday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Friday) == ScheduledEventCommon.eWeekDays.Friday) - isMatch = true; - break; - } - case DayOfWeek.Saturday: - { - if ((recurrence & ScheduledEventCommon.eWeekDays.Saturday) == ScheduledEventCommon.eWeekDays.Saturday) - isMatch = true; - break; - } - } + public static ScheduledEventGroup GetEventGroup(string key) + { + ScheduledEventGroup returnValue; - Debug.LogMessage(LogEventLevel.Debug, "[Scheduler]: eventTime day of week matches recurrence days: {0}", isMatch); + return EventGroups.TryGetValue(key, out returnValue) ? returnValue : null; + } +} - return isMatch; +public static class SchedulerUtilities +{ + /// + /// Checks the day of week in eventTime to see if it matches the weekdays defined in the recurrence enum. + /// + /// + /// + /// + public static bool CheckIfDayOfWeekMatchesRecurrenceDays(DateTime eventTime, ScheduledEventCommon.eWeekDays recurrence) + { + bool isMatch = false; + + var dayOfWeek = eventTime.DayOfWeek; + + Debug.LogMessage(LogEventLevel.Debug, "[Scheduler]: eventTime day of week is: {0}",null, dayOfWeek); + switch (dayOfWeek) + { + case DayOfWeek.Sunday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Sunday) == ScheduledEventCommon.eWeekDays.Sunday) + isMatch = true; + break; + } + case DayOfWeek.Monday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Monday) == ScheduledEventCommon.eWeekDays.Monday) + isMatch = true; + break; + } + case DayOfWeek.Tuesday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Tuesday) == ScheduledEventCommon.eWeekDays.Tuesday) + isMatch = true; + break; + } + case DayOfWeek.Wednesday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Wednesday) == ScheduledEventCommon.eWeekDays.Wednesday) + isMatch = true; + break; + } + case DayOfWeek.Thursday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Thursday) == ScheduledEventCommon.eWeekDays.Thursday) + isMatch = true; + break; + } + case DayOfWeek.Friday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Friday) == ScheduledEventCommon.eWeekDays.Friday) + isMatch = true; + break; + } + case DayOfWeek.Saturday: + { + if ((recurrence & ScheduledEventCommon.eWeekDays.Saturday) == ScheduledEventCommon.eWeekDays.Saturday) + isMatch = true; + break; + } } - public static bool CheckEventTimeForMatch(ScheduledEvent evnt, DateTime time) - { - return evnt.DateAndTime.Hour == time.Hour && evnt.DateAndTime.Minute == time.Minute; - } + Debug.LogMessage(LogEventLevel.Debug, "[Scheduler]: eventTime day of week matches recurrence days: {0}", isMatch); - public static bool CheckEventRecurrenceForMatch(ScheduledEvent evnt, ScheduledEventCommon.eWeekDays days) - { - return evnt.Recurrence.RecurrenceDays == days; - } + return isMatch; + } - public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group, ScheduledEvent.UserEventCallBack handler) + public static bool CheckEventTimeForMatch(ScheduledEvent evnt, DateTime time) + { + return evnt.DateAndTime.Hour == time.Hour && evnt.DateAndTime.Minute == time.Minute; + } + + public static bool CheckEventRecurrenceForMatch(ScheduledEvent evnt, ScheduledEventCommon.eWeekDays days) + { + return evnt.Recurrence.RecurrenceDays == days; + } + + public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group, ScheduledEvent.UserEventCallBack handler) + { + try { - try + if (group == null) { - if (group == null) - { - Debug.LogMessage(LogEventLevel.Information, "Unable to create event. Group is null", null, null); - return; - } - var scheduledEvent = new ScheduledEvent(config.Key, group) - { - Acknowledgeable = config.Acknowledgeable, - Persistent = config.Persistent - }; - - scheduledEvent.UserCallBack += handler; - - scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); - - var eventTime = DateTime.Parse(config.Time); - - if (DateTime.Now > eventTime) - { - eventTime = eventTime.AddDays(1); - } - - Debug.LogMessage(LogEventLevel.Verbose, "[Scheduler] Current Date day of week: {0} recurrence days: {1}", null, eventTime.DayOfWeek, - config.Days); - - var dayOfWeekConverted = ConvertDayOfWeek(eventTime); - - Debug.LogMessage(LogEventLevel.Debug, "[Scheduler] eventTime Day: {0}", null, dayOfWeekConverted); - - while (!dayOfWeekConverted.IsFlagSet(config.Days)) - { - eventTime = eventTime.AddDays(1); - - dayOfWeekConverted = ConvertDayOfWeek(eventTime); - } - - scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); - - scheduledEvent.Recurrence.Weekly(config.Days); - - Debug.LogMessage(LogEventLevel.Verbose, $"[Scheduler] Event State: {scheduledEvent.EventState}", null, null); - - if (config.Enable && scheduledEvent.EventState != ScheduledEventCommon.eEventState.Enabled) - { - scheduledEvent.Enable(); - } - else if (!config.Enable && scheduledEvent.EventState != ScheduledEventCommon.eEventState.Disabled) - { - scheduledEvent.Disable(); - } - + Debug.LogMessage(LogEventLevel.Information, "Unable to create event. Group is null", null, null); + return; } - catch (Exception e) + var scheduledEvent = new ScheduledEvent(config.Key, group) { + Acknowledgeable = config.Acknowledgeable, + Persistent = config.Persistent + }; - Debug.LogMessage(LogEventLevel.Error, "Error creating scheduled event: {0}", null, e); + scheduledEvent.UserCallBack += handler; + + scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); + + var eventTime = DateTime.Parse(config.Time); + + if (DateTime.Now > eventTime) + { + eventTime = eventTime.AddDays(1); } - } - private static ScheduledEventCommon.eWeekDays ConvertDayOfWeek(DateTime eventTime) + Debug.LogMessage(LogEventLevel.Verbose, "[Scheduler] Current Date day of week: {0} recurrence days: {1}", null, eventTime.DayOfWeek, + config.Days); + + var dayOfWeekConverted = ConvertDayOfWeek(eventTime); + + Debug.LogMessage(LogEventLevel.Debug, "[Scheduler] eventTime Day: {0}", null, dayOfWeekConverted); + + while (!dayOfWeekConverted.IsFlagSet(config.Days)) + { + eventTime = eventTime.AddDays(1); + + dayOfWeekConverted = ConvertDayOfWeek(eventTime); + } + + scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); + + scheduledEvent.Recurrence.Weekly(config.Days); + + Debug.LogMessage(LogEventLevel.Verbose, $"[Scheduler] Event State: {scheduledEvent.EventState}", null, null); + + if (config.Enable && scheduledEvent.EventState != ScheduledEventCommon.eEventState.Enabled) + { + scheduledEvent.Enable(); + } + else if (!config.Enable && scheduledEvent.EventState != ScheduledEventCommon.eEventState.Disabled) + { + scheduledEvent.Disable(); + } + + } + catch (Exception e) { - return (ScheduledEventCommon.eWeekDays) Enum.Parse(typeof(ScheduledEventCommon.eWeekDays), eventTime.DayOfWeek.ToString(), true); + + Debug.LogMessage(LogEventLevel.Error, "Error creating scheduled event: {0}", null, e); } + } - private static bool IsFlagSet(this T value, T flag) where T : struct - { - CheckIsEnum(true); + private static ScheduledEventCommon.eWeekDays ConvertDayOfWeek(DateTime eventTime) + { + return (ScheduledEventCommon.eWeekDays) Enum.Parse(typeof(ScheduledEventCommon.eWeekDays), eventTime.DayOfWeek.ToString(), true); + } - var lValue = Convert.ToInt64(value); - var lFlag = Convert.ToInt64(flag); + private static bool IsFlagSet(this T value, T flag) where T : struct + { + CheckIsEnum(true); - return (lValue & lFlag) != 0; - } + var lValue = Convert.ToInt64(value); + var lFlag = Convert.ToInt64(flag); - private static void CheckIsEnum(bool withFlags) - { - if (!typeof(T).IsEnum) - throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName)); - if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute))) - throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName)); - } + return (lValue & lFlag) != 0; + } + + private static void CheckIsEnum(bool withFlags) + { + if (!typeof(T).IsEnum) + throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName)); + if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute))) + throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName)); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs b/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs index 97a7c7f6..404c52af 100644 --- a/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs +++ b/src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs @@ -4,13 +4,12 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines a class that uses an InUseTracker /// public interface IInUseTracking { InUseTracking InUseTracker { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs b/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs index 4bf1a551..3015171c 100644 --- a/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs +++ b/src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Provides in use tracking. Objects can register with this. InUseFeedback can provide /// events when usage changes. @@ -96,5 +96,4 @@ namespace PepperDash.Essentials.Core // Tracker = tracker; // EventType = eventType; // } - //} -} \ No newline at end of file + //} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs b/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs index 4f48e278..fbf46abb 100644 --- a/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs +++ b/src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs @@ -5,13 +5,12 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Interfaces -{ +namespace PepperDash.Essentials.Core.Interfaces; + public interface ILogStrings : IKeyed { /// /// Defines a class that is capable of logging a string /// void SendToLog(IKeyed device, string logMessage); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs b/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs index 47c3674e..2768d283 100644 --- a/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs +++ b/src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs @@ -5,14 +5,12 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Interfaces -{ +namespace PepperDash.Essentials.Core.Interfaces; + public interface ILogStringsWithLevel : IKeyed { /// /// Defines a class that is capable of logging a string with an int level /// void SendToLog(IKeyed device, Debug.ErrorLogLevel level,string logMessage); - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs b/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs index 37760e09..9cd6776e 100644 --- a/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs +++ b/src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs @@ -15,527 +15,526 @@ using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public static class JoinMapHelper { - public static class JoinMapHelper + /// + /// Attempts to get the serialized join map from config + /// + /// + /// + public static string GetSerializedJoinMapForDevice(string joinMapKey) { - /// - /// Attempts to get the serialized join map from config - /// - /// - /// - public static string GetSerializedJoinMapForDevice(string joinMapKey) + if (string.IsNullOrEmpty(joinMapKey)) + return null; + + var joinMap = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; + + return joinMap.ToString(); + } + + /// + /// Attempts to get the serialized join map from config + /// + /// + /// + public static string GetJoinMapForDevice(string joinMapKey) + { + return GetSerializedJoinMapForDevice(joinMapKey); + } + + /// + /// Attempts to find a custom join map by key and returns it deserialized if found + /// + /// + /// + public static Dictionary TryGetJoinMapAdvancedForDevice(string joinMapKey) + { + try { if (string.IsNullOrEmpty(joinMapKey)) return null; - var joinMap = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; - - return joinMap.ToString(); - } - - /// - /// Attempts to get the serialized join map from config - /// - /// - /// - public static string GetJoinMapForDevice(string joinMapKey) - { - return GetSerializedJoinMapForDevice(joinMapKey); - } - - /// - /// Attempts to find a custom join map by key and returns it deserialized if found - /// - /// - /// - public static Dictionary TryGetJoinMapAdvancedForDevice(string joinMapKey) - { - try + if (!ConfigReader.ConfigObject.JoinMaps.ContainsKey(joinMapKey)) { - if (string.IsNullOrEmpty(joinMapKey)) - return null; - - if (!ConfigReader.ConfigObject.JoinMaps.ContainsKey(joinMapKey)) - { - Debug.LogMessage(LogEventLevel.Verbose, "No Join Map found in config with key: '{0}'", joinMapKey); - return null; - } - - Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load custom join map with key: {0}", joinMapKey); - - var joinMapJToken = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; - - if (joinMapJToken == null) - return null; - - var joinMapData = joinMapJToken.ToObject>(); - - return joinMapData; - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, "Error getting join map for key: '{0}'. Error: {1}", joinMapKey, e); + Debug.LogMessage(LogEventLevel.Verbose, "No Join Map found in config with key: '{0}'", joinMapKey); return null; } - } + Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load custom join map with key: {0}", joinMapKey); + + var joinMapJToken = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; + + if (joinMapJToken == null) + return null; + + var joinMapData = joinMapJToken.ToObject>(); + + return joinMapData; + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, "Error getting join map for key: '{0}'. Error: {1}", joinMapKey, e); + return null; + } } +} + +/// +/// Base class for join maps +/// +public abstract class JoinMapBaseAdvanced +{ + protected uint JoinOffset; + /// - /// Base class for join maps + /// The collection of joins and associated metadata /// - public abstract class JoinMapBaseAdvanced + public Dictionary Joins { get; private set; } + + protected JoinMapBaseAdvanced(uint joinStart) { - protected uint JoinOffset; + Joins = new Dictionary(); - /// - /// The collection of joins and associated metadata - /// - public Dictionary Joins { get; private set; } + JoinOffset = joinStart - 1; + } - protected JoinMapBaseAdvanced(uint joinStart) + protected JoinMapBaseAdvanced(uint joinStart, Type type):this(joinStart) + { + AddJoins(type); + } + + protected void AddJoins(Type type) + { + var fields = + type.GetFields(BindingFlags.Public | BindingFlags.Instance) + .Where(f => f.IsDefined(typeof (JoinNameAttribute), true)).ToList(); + + Debug.LogMessage(LogEventLevel.Debug, "Got {fields} with JoinNameAttribute", fields.Count); + + foreach (var field in fields) { - Joins = new Dictionary(); + var childClass = Convert.ChangeType(this, type, null); - JoinOffset = joinStart - 1; - } + //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields. - protected JoinMapBaseAdvanced(uint joinStart, Type type):this(joinStart) - { - AddJoins(type); - } - - protected void AddJoins(Type type) - { - var fields = - type.GetFields(BindingFlags.Public | BindingFlags.Instance) - .Where(f => f.IsDefined(typeof (JoinNameAttribute), true)).ToList(); - - Debug.LogMessage(LogEventLevel.Debug, "Got {fields} with JoinNameAttribute", fields.Count); - - foreach (var field in fields) + if (!(field.GetValue(childClass) is JoinDataComplete value)) { - var childClass = Convert.ChangeType(this, type, null); - - //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields. - - if (!(field.GetValue(childClass) is JoinDataComplete value)) - { - Debug.LogMessage(LogEventLevel.Information, "Unable to cast base class to {0}", type.Name); - continue; - } - - value.SetJoinOffset(JoinOffset); - - var joinName = value.GetNameAttribute(field); - - if (string.IsNullOrEmpty(joinName)) continue; - - Joins.Add(joinName, value); + Debug.LogMessage(LogEventLevel.Information, "Unable to cast base class to {0}", type.Name); + continue; } + value.SetJoinOffset(JoinOffset); - if (Debug.Level > 0) - { - PrintJoinMapInfo(); - } - } + var joinName = value.GetNameAttribute(field); - /// - /// Prints the join information to console - /// - public void PrintJoinMapInfo() - { - var sb = JoinmapStringBuilder(); + if (string.IsNullOrEmpty(joinName)) continue; - CrestronConsole.ConsoleCommandResponse(sb.ToString()); - } - - private StringBuilder JoinmapStringBuilder() - { - var sb = new StringBuilder(); - - var lineEnding = "\r\n"; - - var digitals = - Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Digital)) - .ToDictionary(j => j.Key, j => j.Value); - - var analogs = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Analog)) - .ToDictionary(j => j.Key, j => j.Value); - - var serials = - Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Serial)) - .ToDictionary(j => j.Key, j => j.Value); - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Digital join count {digitalCount} Analog join count {analogCount} Serial join count {serialCount}", null, digitals.Count, analogs.Count, serials.Count); - - // Get the joins of each type and print them - sb.Append($"# {GetType().Name}\r\n"); - sb.Append(lineEnding); - sb.Append($"## Digitals{lineEnding}"); - sb.Append(lineEnding); - // Get the joins of each type and print them - - var digitalSb = AppendJoinList(GetSortedJoins(digitals)); - digitalSb.Append($"## Analogs{lineEnding}"); - digitalSb.Append(lineEnding); - - var analogSb = AppendJoinList(GetSortedJoins(analogs)); - analogSb.Append($"## Serials{lineEnding}"); - analogSb.Append(lineEnding); - - - var serialSb = AppendJoinList(GetSortedJoins(serials)); - - sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length); - sb.Append(digitalSb).Append(analogSb).Append(serialSb); - return sb; - } - - /// - /// Prints the join information to console - /// - public void MarkdownJoinMapInfo(string deviceKey, string bridgeKey) - { - var pluginType = GetType().Name; - - CrestronConsole.ConsoleCommandResponse("{0}:\n", pluginType); - - - - WriteJoinmapMarkdown(JoinmapStringBuilder(), pluginType, bridgeKey, deviceKey); - - } - - private static void WriteJoinmapMarkdown(StringBuilder stringBuilder, string pluginType, string bridgeKey, string deviceKey) - { - var fileName = string.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey); - - using (var sw = new StreamWriter(fileName)) - { - sw.WriteLine(stringBuilder.ToString()); - CrestronConsole.ConsoleCommandResponse("Joinmap Readme generated and written to {0}", fileName); - } - - } - - /// - /// Returns a sorted list by JoinNumber - /// - /// - /// - static List> GetSortedJoins(Dictionary joins) - { - var sortedJoins = joins.ToList(); - - sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber)); - - return sortedJoins; + Joins.Add(joinName, value); } - static StringBuilder AppendJoinList(List> joins) + if (Debug.Level > 0) { - var sb = new StringBuilder(); - const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |\r\n"; - const int joinNumberLen = 11; - const int joinSpanLen = 9; - const int typeLen = 19; - const int capabilitiesLen = 12; - var descriptionLen = (from @join in joins select @join.Value into j select j.Metadata.Description.Length).Concat(new[] {11}).Max(); - - //build header - sb.Append(string.Format(stringFormatter, - string.Format("Join Number").PadRight(joinNumberLen, ' '), - string.Format("Join Span").PadRight(joinSpanLen, ' '), - string.Format("Description").PadRight(descriptionLen, ' '), - string.Format("Type").PadRight(typeLen, ' '), - string.Format("Capabilities").PadRight(capabilitiesLen, ' '))); - //build table seperator - sb.Append(string.Format(stringFormatter, - new string('-', joinNumberLen), - new string('-', joinSpanLen), - new string('-', descriptionLen), - new string('-', typeLen), - new string('-', capabilitiesLen))); - - foreach (var join in joins) - { - sb.Append(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen)); - } - sb.Append("\r\n"); - return sb; - } - - /// - /// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom - /// - /// - public void SetCustomJoinData(Dictionary joinData) - { - foreach (var customJoinData in joinData) - { - JoinDataComplete join; - - if (!Joins.TryGetValue(customJoinData.Key, out join)) - { - Debug.LogMessage(LogEventLevel.Verbose, "No matching key found in join map for: '{0}'", customJoinData.Key); - continue; - } - - if (join != null) - { - join.SetCustomJoinData(customJoinData.Value); - } - } - PrintJoinMapInfo(); } - - ///// - ///// Returns the join number for the join with the specified key - ///// - ///// - ///// - //public uint GetJoinForKey(string key) - //{ - // return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0; - //} - - - ///// - ///// Returns the join span for the join with the specified key - ///// - ///// - ///// - //public uint GetJoinSpanForKey(string key) - //{ - // return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0; - //} } /// - /// Read = Provides feedback to SIMPL - /// Write = Responds to sig values from SIMPL + /// Prints the join information to console /// - [Flags] - public enum eJoinCapabilities + public void PrintJoinMapInfo() { - None = 0, - ToSIMPL = 1, - FromSIMPL = 2, - ToFromSIMPL = ToSIMPL | FromSIMPL, - ToFusion = 4, - FromFusion = 8, - ToFromFusion = ToFusion | FromFusion, + var sb = JoinmapStringBuilder(); + + CrestronConsole.ConsoleCommandResponse(sb.ToString()); } - [Flags] - public enum eJoinType + private StringBuilder JoinmapStringBuilder() { - None = 0, - Digital = 1, - Analog = 2, - Serial = 4, - DigitalAnalog = Digital | Analog, - DigitalSerial = Digital | Serial, - AnalogSerial = Analog | Serial, - DigitalAnalogSerial = Digital | Analog | Serial, + var sb = new StringBuilder(); + + var lineEnding = "\r\n"; + + var digitals = + Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Digital)) + .ToDictionary(j => j.Key, j => j.Value); + + var analogs = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Analog)) + .ToDictionary(j => j.Key, j => j.Value); + + var serials = + Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Serial)) + .ToDictionary(j => j.Key, j => j.Value); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Digital join count {digitalCount} Analog join count {analogCount} Serial join count {serialCount}", null, digitals.Count, analogs.Count, serials.Count); + + // Get the joins of each type and print them + sb.Append($"# {GetType().Name}\r\n"); + sb.Append(lineEnding); + sb.Append($"## Digitals{lineEnding}"); + sb.Append(lineEnding); + // Get the joins of each type and print them + + var digitalSb = AppendJoinList(GetSortedJoins(digitals)); + digitalSb.Append($"## Analogs{lineEnding}"); + digitalSb.Append(lineEnding); + + var analogSb = AppendJoinList(GetSortedJoins(analogs)); + analogSb.Append($"## Serials{lineEnding}"); + analogSb.Append(lineEnding); + + + var serialSb = AppendJoinList(GetSortedJoins(serials)); + + sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length); + sb.Append(digitalSb).Append(analogSb).Append(serialSb); + return sb; } /// - /// Metadata describing the join + /// Prints the join information to console /// - public class JoinMetadata + public void MarkdownJoinMapInfo(string deviceKey, string bridgeKey) { - private string _description; - /// - /// A description for the join to better describe its usage - /// - [JsonProperty("description")] - public string Description { get { return _description; } set { _description = value; } } - /// - /// Signal type(s) - /// - [JsonProperty("joinType")] - public eJoinType JoinType { get; set; } - /// - /// Indicates whether the join is read and/or write - /// - [JsonProperty("joinCapabilities")] - public eJoinCapabilities JoinCapabilities { get; set; } - /// - /// Indicates a set of valid values (particularly if this translates to an enum - /// - [JsonProperty("validValues")] - public string[] ValidValues { get; set; } + var pluginType = GetType().Name; + + CrestronConsole.ConsoleCommandResponse("{0}:\n", pluginType); + + + + WriteJoinmapMarkdown(JoinmapStringBuilder(), pluginType, bridgeKey, deviceKey); } - /// - /// Data describing the join. Can be overridden from configuratino - /// - public class JoinData + private static void WriteJoinmapMarkdown(StringBuilder stringBuilder, string pluginType, string bridgeKey, string deviceKey) { - /// - /// Join number (based on join offset value) - /// - [JsonProperty("joinNumber")] - public uint JoinNumber { get; set; } - /// - /// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range - /// - [JsonProperty("joinSpan")] - public uint JoinSpan { get; set; } - /// - /// Fusion Attribute Name (optional) - /// - [JsonProperty("attributeName")] - public string AttributeName { get; set; } - } + var fileName = string.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey); - /// - /// A class to aggregate the JoinData and JoinMetadata for a join - /// - public class JoinDataComplete - { - private uint _joinOffset; - - private JoinData _data; - public JoinMetadata Metadata { get; set; } - /// - /// To store some future information as you please - /// - public object UserObject { get; private set; } - - public JoinDataComplete(JoinData data, JoinMetadata metadata) + using (var sw = new StreamWriter(fileName)) { - _data = data; - Metadata = metadata; + sw.WriteLine(stringBuilder.ToString()); + CrestronConsole.ConsoleCommandResponse("Joinmap Readme generated and written to {0}", fileName); } - public string GetMarkdownFormattedData(string stringFormatter, int descriptionLen) + } + + /// + /// Returns a sorted list by JoinNumber + /// + /// + /// + static List> GetSortedJoins(Dictionary joins) + { + var sortedJoins = joins.ToList(); + + sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber)); + + return sortedJoins; + } + + + static StringBuilder AppendJoinList(List> joins) + { + var sb = new StringBuilder(); + const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |\r\n"; + const int joinNumberLen = 11; + const int joinSpanLen = 9; + const int typeLen = 19; + const int capabilitiesLen = 12; + var descriptionLen = (from @join in joins select @join.Value into j select j.Metadata.Description.Length).Concat(new[] {11}).Max(); + + //build header + sb.Append(string.Format(stringFormatter, + string.Format("Join Number").PadRight(joinNumberLen, ' '), + string.Format("Join Span").PadRight(joinSpanLen, ' '), + string.Format("Description").PadRight(descriptionLen, ' '), + string.Format("Type").PadRight(typeLen, ' '), + string.Format("Capabilities").PadRight(capabilitiesLen, ' '))); + //build table seperator + sb.Append(string.Format(stringFormatter, + new string('-', joinNumberLen), + new string('-', joinSpanLen), + new string('-', descriptionLen), + new string('-', typeLen), + new string('-', capabilitiesLen))); + + foreach (var join in joins) { + sb.Append(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen)); + } + sb.Append("\r\n"); + return sb; + } - //Fixed Width Headers - var joinNumberLen = string.Format("Join Number").Length; - var joinSpanLen = string.Format("Join Span").Length; - var typeLen = string.Format("AnalogDigitalSerial").Length; - var capabilitiesLen = string.Format("ToFromFusion").Length; + /// + /// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom + /// + /// + public void SetCustomJoinData(Dictionary joinData) + { + foreach (var customJoinData in joinData) + { + JoinDataComplete join; - //Track which one failed, if it did - const string placeholder = "unknown"; - var dataArray = new Dictionary + if (!Joins.TryGetValue(customJoinData.Key, out join)) { - {"joinNumber", placeholder.PadRight(joinNumberLen, ' ')}, - {"joinSpan", placeholder.PadRight(joinSpanLen, ' ')}, - {"description", placeholder.PadRight(descriptionLen, ' ')}, - {"joinType", placeholder.PadRight(typeLen, ' ')}, - {"capabilities", placeholder.PadRight(capabilitiesLen, ' ')} - }; - - - try - { - dataArray["joinNumber"] = string.Format("{0}", JoinNumber.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinNumberLen, ' '); - dataArray["joinSpan"] = string.Format("{0}", JoinSpan.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinSpanLen, ' '); - dataArray["description"] = string.Format("{0}", Metadata.Description.ReplaceIfNullOrEmpty(placeholder)).PadRight(descriptionLen, ' '); - dataArray["joinType"] = string.Format("{0}", Metadata.JoinType.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(typeLen, ' '); - dataArray["capabilities"] = string.Format("{0}", Metadata.JoinCapabilities.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(capabilitiesLen, ' '); - - return string.Format(stringFormatter, - dataArray["joinNumber"], - dataArray["joinSpan"], - dataArray["description"], - dataArray["joinType"], - dataArray["capabilities"]); - + Debug.LogMessage(LogEventLevel.Verbose, "No matching key found in join map for: '{0}'", customJoinData.Key); + continue; } - catch (Exception e) + + if (join != null) { - //Don't Throw - we don't want to kill the system if this falls over - it's not mission critical. Print the error, use placeholder data - var errorKey = string.Empty; - foreach (var item in dataArray) - { - if (item.Value.TrimEnd() == placeholder) continue; - errorKey = item.Key; - break; - } - Debug.LogMessage(LogEventLevel.Information, "Unable to decode join metadata {1}- {0}", e.Message, !string.IsNullOrEmpty(errorKey) ? (' ' + errorKey) : string.Empty); - return string.Format(stringFormatter, - dataArray["joinNumber"], - dataArray["joinSpan"], - dataArray["description"], - dataArray["joinType"], - dataArray["capabilities"]); + join.SetCustomJoinData(customJoinData.Value); } } + PrintJoinMapInfo(); + } - /// - /// Sets the join offset value - /// - /// - public void SetJoinOffset(uint joinOffset) + ///// + ///// Returns the join number for the join with the specified key + ///// + ///// + ///// + //public uint GetJoinForKey(string key) + //{ + // return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0; + //} + + + ///// + ///// Returns the join span for the join with the specified key + ///// + ///// + ///// + //public uint GetJoinSpanForKey(string key) + //{ + // return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0; + //} +} + +/// +/// Read = Provides feedback to SIMPL +/// Write = Responds to sig values from SIMPL +/// +[Flags] +public enum eJoinCapabilities +{ + None = 0, + ToSIMPL = 1, + FromSIMPL = 2, + ToFromSIMPL = ToSIMPL | FromSIMPL, + ToFusion = 4, + FromFusion = 8, + ToFromFusion = ToFusion | FromFusion, +} + +[Flags] +public enum eJoinType +{ + None = 0, + Digital = 1, + Analog = 2, + Serial = 4, + DigitalAnalog = Digital | Analog, + DigitalSerial = Digital | Serial, + AnalogSerial = Analog | Serial, + DigitalAnalogSerial = Digital | Analog | Serial, +} + +/// +/// Metadata describing the join +/// +public class JoinMetadata +{ + private string _description; + /// + /// A description for the join to better describe its usage + /// + [JsonProperty("description")] + public string Description { get { return _description; } set { _description = value; } } + /// + /// Signal type(s) + /// + [JsonProperty("joinType")] + public eJoinType JoinType { get; set; } + /// + /// Indicates whether the join is read and/or write + /// + [JsonProperty("joinCapabilities")] + public eJoinCapabilities JoinCapabilities { get; set; } + /// + /// Indicates a set of valid values (particularly if this translates to an enum + /// + [JsonProperty("validValues")] + public string[] ValidValues { get; set; } + +} + +/// +/// Data describing the join. Can be overridden from configuratino +/// +public class JoinData +{ + /// + /// Join number (based on join offset value) + /// + [JsonProperty("joinNumber")] + public uint JoinNumber { get; set; } + /// + /// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range + /// + [JsonProperty("joinSpan")] + public uint JoinSpan { get; set; } + /// + /// Fusion Attribute Name (optional) + /// + [JsonProperty("attributeName")] + public string AttributeName { get; set; } +} + +/// +/// A class to aggregate the JoinData and JoinMetadata for a join +/// +public class JoinDataComplete +{ + private uint _joinOffset; + + private JoinData _data; + public JoinMetadata Metadata { get; set; } + /// + /// To store some future information as you please + /// + public object UserObject { get; private set; } + + public JoinDataComplete(JoinData data, JoinMetadata metadata) + { + _data = data; + Metadata = metadata; + } + + public string GetMarkdownFormattedData(string stringFormatter, int descriptionLen) + { + + //Fixed Width Headers + var joinNumberLen = string.Format("Join Number").Length; + var joinSpanLen = string.Format("Join Span").Length; + var typeLen = string.Format("AnalogDigitalSerial").Length; + var capabilitiesLen = string.Format("ToFromFusion").Length; + + //Track which one failed, if it did + const string placeholder = "unknown"; + var dataArray = new Dictionary { - _joinOffset = joinOffset; + {"joinNumber", placeholder.PadRight(joinNumberLen, ' ')}, + {"joinSpan", placeholder.PadRight(joinSpanLen, ' ')}, + {"description", placeholder.PadRight(descriptionLen, ' ')}, + {"joinType", placeholder.PadRight(typeLen, ' ')}, + {"capabilities", placeholder.PadRight(capabilitiesLen, ' ')} + }; + + + try + { + dataArray["joinNumber"] = string.Format("{0}", JoinNumber.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinNumberLen, ' '); + dataArray["joinSpan"] = string.Format("{0}", JoinSpan.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinSpanLen, ' '); + dataArray["description"] = string.Format("{0}", Metadata.Description.ReplaceIfNullOrEmpty(placeholder)).PadRight(descriptionLen, ' '); + dataArray["joinType"] = string.Format("{0}", Metadata.JoinType.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(typeLen, ' '); + dataArray["capabilities"] = string.Format("{0}", Metadata.JoinCapabilities.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(capabilitiesLen, ' '); + + return string.Format(stringFormatter, + dataArray["joinNumber"], + dataArray["joinSpan"], + dataArray["description"], + dataArray["joinType"], + dataArray["capabilities"]); + } - - /// - /// The join number (including the offset) - /// - public uint JoinNumber + catch (Exception e) { - get { return _data.JoinNumber+ _joinOffset; } - set { _data.JoinNumber = value; } - } - - public uint JoinSpan - { - get { return _data.JoinSpan; } - } - - public string AttributeName - { - get { return _data.AttributeName; } - } - - public void SetCustomJoinData(JoinData customJoinData) - { - _data = customJoinData; - } - - public string GetNameAttribute(MemberInfo memberInfo) - { - var name = string.Empty; - var attribute = (JoinNameAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute)); - - if (attribute == null) return name; - - name = attribute.Name; - Debug.LogMessage(LogEventLevel.Verbose, "JoinName Attribute value: {0}", name); - return name; + //Don't Throw - we don't want to kill the system if this falls over - it's not mission critical. Print the error, use placeholder data + var errorKey = string.Empty; + foreach (var item in dataArray) + { + if (item.Value.TrimEnd() == placeholder) continue; + errorKey = item.Key; + break; + } + Debug.LogMessage(LogEventLevel.Information, "Unable to decode join metadata {1}- {0}", e.Message, !string.IsNullOrEmpty(errorKey) ? (' ' + errorKey) : string.Empty); + return string.Format(stringFormatter, + dataArray["joinNumber"], + dataArray["joinSpan"], + dataArray["description"], + dataArray["joinType"], + dataArray["capabilities"]); } } - - [AttributeUsage(AttributeTargets.All)] - public class JoinNameAttribute : Attribute + /// + /// Sets the join offset value + /// + /// + public void SetJoinOffset(uint joinOffset) { - private string _Name; + _joinOffset = joinOffset; + } - public JoinNameAttribute(string name) - { - Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}",null, name); - _Name = name; - } + /// + /// The join number (including the offset) + /// + public uint JoinNumber + { + get { return _data.JoinNumber+ _joinOffset; } + set { _data.JoinNumber = value; } + } - public string Name - { - get { return _Name; } - } + public uint JoinSpan + { + get { return _data.JoinSpan; } + } + + public string AttributeName + { + get { return _data.AttributeName; } + } + + public void SetCustomJoinData(JoinData customJoinData) + { + _data = customJoinData; + } + + public string GetNameAttribute(MemberInfo memberInfo) + { + var name = string.Empty; + var attribute = (JoinNameAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute)); + + if (attribute == null) return name; + + name = attribute.Name; + Debug.LogMessage(LogEventLevel.Verbose, "JoinName Attribute value: {0}", name); + return name; + } +} + + + +[AttributeUsage(AttributeTargets.All)] +public class JoinNameAttribute : Attribute +{ + private string _Name; + + public JoinNameAttribute(string name) + { + Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}",null, name); + _Name = name; + } + + public string Name + { + get { return _Name; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs b/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs index a242591e..4c2df0c3 100644 --- a/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs +++ b/src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs @@ -11,8 +11,8 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.License -{ +namespace PepperDash.Essentials.License; + public abstract class LicenseManager { public BoolFeedback LicenseIsValid { get; protected set; } @@ -83,5 +83,4 @@ namespace PepperDash.Essentials.License { return string.Format("License Status: {0}", IsValid ? "Valid" : "Not Valid"); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs b/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs index c762147c..8cc9e815 100644 --- a/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs @@ -1,59 +1,57 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Lighting +namespace PepperDash.Essentials.Core.Lighting; + +/// +/// Requirements for a device that implements lighting scene control +/// +public interface ILightingScenes { - /// - /// Requirements for a device that implements lighting scene control - /// - public interface ILightingScenes + event EventHandler LightingSceneChange; + + List LightingScenes { get; } + + void SelectScene(LightingScene scene); + + LightingScene CurrentLightingScene { get; } + +} + +public interface ILightingScenesDynamic : ILightingScenes +{ + event EventHandler LightingScenesUpdated; +} + +/// +/// Requirements for a device that implements master raise/lower +/// +public interface ILightingMasterRaiseLower +{ + void MasterRaise(); + void MasterLower(); + void MasterRaiseLowerStop(); +} + +/// +/// Requiremnts for controlling a lighting load +/// +public interface ILightingLoad +{ + void SetLoadLevel(int level); + void Raise(); + void Lower(); + + IntFeedback LoadLevelFeedback { get; } + BoolFeedback LoadIsOnFeedback { get; } +} + +public class LightingSceneChangeEventArgs : EventArgs +{ + public LightingScene CurrentLightingScene { get; private set; } + + public LightingSceneChangeEventArgs(LightingScene scene) { - event EventHandler LightingSceneChange; - - List LightingScenes { get; } - - void SelectScene(LightingScene scene); - - LightingScene CurrentLightingScene { get; } - + CurrentLightingScene = scene; } - - public interface ILightingScenesDynamic : ILightingScenes - { - event EventHandler LightingScenesUpdated; - } - - /// - /// Requirements for a device that implements master raise/lower - /// - public interface ILightingMasterRaiseLower - { - void MasterRaise(); - void MasterLower(); - void MasterRaiseLowerStop(); - } - - /// - /// Requiremnts for controlling a lighting load - /// - public interface ILightingLoad - { - void SetLoadLevel(int level); - void Raise(); - void Lower(); - - IntFeedback LoadLevelFeedback { get; } - BoolFeedback LoadIsOnFeedback { get; } - } - - public class LightingSceneChangeEventArgs : EventArgs - { - public LightingScene CurrentLightingScene { get; private set; } - - public LightingSceneChangeEventArgs(LightingScene scene) - { - CurrentLightingScene = scene; - } - } - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Lighting/LightingScene.cs b/src/PepperDash.Essentials.Core/Lighting/LightingScene.cs index b0e0ddbe..c9d93ef7 100644 --- a/src/PepperDash.Essentials.Core/Lighting/LightingScene.cs +++ b/src/PepperDash.Essentials.Core/Lighting/LightingScene.cs @@ -3,38 +3,37 @@ using System; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Lighting +namespace PepperDash.Essentials.Core.Lighting; + +public class LightingScene { - public class LightingScene + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string ID { get; set; } + bool _IsActive; + [JsonProperty("isActive", NullValueHandling = NullValueHandling.Ignore)] + public bool IsActive { - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string Name { get; set; } - [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] - public string ID { get; set; } - bool _IsActive; - [JsonProperty("isActive", NullValueHandling = NullValueHandling.Ignore)] - public bool IsActive + get { - get - { - return _IsActive; - } - set - { - _IsActive = value; - IsActiveFeedback.FireUpdate(); - } + return _IsActive; } - - [JsonProperty("sortOrder", NullValueHandling = NullValueHandling.Ignore)] - public int SortOrder { get; set; } - - [JsonIgnore] - public BoolFeedback IsActiveFeedback { get; set; } - - public LightingScene() + set { - IsActiveFeedback = new BoolFeedback(new Func(() => IsActive)); + _IsActive = value; + IsActiveFeedback.FireUpdate(); } } + + [JsonProperty("sortOrder", NullValueHandling = NullValueHandling.Ignore)] + public int SortOrder { get; set; } + + [JsonIgnore] + public BoolFeedback IsActiveFeedback { get; set; } + + public LightingScene() + { + IsActiveFeedback = new BoolFeedback(new Func(() => IsActive)); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs index 653e2b18..c34ac0d6 100644 --- a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs +++ b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs @@ -11,245 +11,243 @@ using PepperDash.Essentials.Core.CrestronIO; using Serilog.Events; -namespace PepperDash.Essentials.Core.Privacy +namespace PepperDash.Essentials.Core.Privacy; + +/// +/// Used for applications where one or more microphones with momentary contact closure outputs are used to +/// toggle the privacy state of the room. Privacy state feedback is represented +/// +public class MicrophonePrivacyController : EssentialsDevice { - /// - /// Used for applications where one or more microphones with momentary contact closure outputs are used to - /// toggle the privacy state of the room. Privacy state feedback is represented - /// - public class MicrophonePrivacyController : EssentialsDevice + MicrophonePrivacyControllerConfig Config; + + bool initialized; + + public bool EnableLeds { - MicrophonePrivacyControllerConfig Config; - - bool initialized; - - public bool EnableLeds + get { - get - { - return _enableLeds; - } - set - { - _enableLeds = value; + return _enableLeds; + } + set + { + _enableLeds = value; - if (initialized) + if (initialized) + { + if (value) { - if (value) - { - CheckPrivacyMode(); - SetLedStates(); - } - else - TurnOffAllLeds(); + CheckPrivacyMode(); + SetLedStates(); } - } - } - bool _enableLeds; - - public List Inputs { get; private set; } - - public GenericRelayDevice RedLedRelay { get; private set; } - bool _redLedRelayState; - - public GenericRelayDevice GreenLedRelay { get; private set; } - bool _greenLedRelayState; - - public IPrivacy PrivacyDevice { get; private set; } - - public MicrophonePrivacyController(string key, MicrophonePrivacyControllerConfig config) : - base(key) - { - Config = config; - - Inputs = new List(); - } - - public override bool CustomActivate() - { - foreach (var i in Config.Inputs) - { - var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput; - - if(input != null) - AddInput(input); - } - - var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice; - - if (greenLed != null) - GreenLedRelay = greenLed; - else - Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Green LED device"); - - var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice; - - if (redLed != null) - RedLedRelay = redLed; - else - Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Red LED device"); - - AddPostActivationAction(() => { - PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; - PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; - }); - - initialized = true; - - return base.CustomActivate(); - } - - #region Overrides of Device - - public override void Initialize() - { - CheckPrivacyMode(); - } - - #endregion - - public void SetPrivacyDevice(IPrivacy privacyDevice) - { - PrivacyDevice = privacyDevice; - } - - void PrivacyModeIsOnFeedback_OutputChange(object sender, EventArgs e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Privacy mode change: {0}", sender as BoolFeedback); - CheckPrivacyMode(); - } - - void CheckPrivacyMode() - { - if (PrivacyDevice != null) - { - var privacyState = PrivacyDevice.PrivacyModeIsOnFeedback.BoolValue; - - if (privacyState) - TurnOnRedLeds(); else - TurnOnGreenLeds(); + TurnOffAllLeds(); } } + } + bool _enableLeds; - void AddInput(IDigitalInput input) + public List Inputs { get; private set; } + + public GenericRelayDevice RedLedRelay { get; private set; } + bool _redLedRelayState; + + public GenericRelayDevice GreenLedRelay { get; private set; } + bool _greenLedRelayState; + + public IPrivacy PrivacyDevice { get; private set; } + + public MicrophonePrivacyController(string key, MicrophonePrivacyControllerConfig config) : + base(key) + { + Config = config; + + Inputs = new List(); + } + + public override bool CustomActivate() + { + foreach (var i in Config.Inputs) { - Inputs.Add(input); + var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput; - input.InputStateFeedback.OutputChange += InputStateFeedback_OutputChange; + if(input != null) + AddInput(input); } - void RemoveInput(IDigitalInput input) + var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice; + + if (greenLed != null) + GreenLedRelay = greenLed; + else + Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Green LED device"); + + var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice; + + if (redLed != null) + RedLedRelay = redLed; + else + Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Red LED device"); + + AddPostActivationAction(() => { + PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; + PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; + }); + + initialized = true; + + return base.CustomActivate(); + } + + #region Overrides of Device + + public override void Initialize() + { + CheckPrivacyMode(); + } + + #endregion + + public void SetPrivacyDevice(IPrivacy privacyDevice) + { + PrivacyDevice = privacyDevice; + } + + void PrivacyModeIsOnFeedback_OutputChange(object sender, EventArgs e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Privacy mode change: {0}", sender as BoolFeedback); + CheckPrivacyMode(); + } + + void CheckPrivacyMode() + { + if (PrivacyDevice != null) { - var tempInput = Inputs.FirstOrDefault(i => i.Equals(input)); + var privacyState = PrivacyDevice.PrivacyModeIsOnFeedback.BoolValue; - if (tempInput != null) - tempInput.InputStateFeedback.OutputChange -= InputStateFeedback_OutputChange; - - Inputs.Remove(input); - } - - void SetRedLedRelay(GenericRelayDevice relay) - { - RedLedRelay = relay; - } - - void SetGreenLedRelay(GenericRelayDevice relay) - { - GreenLedRelay = relay; - } - - /// - /// Check the state of the input change and handle accordingly - /// - /// - /// - void InputStateFeedback_OutputChange(object sender, EventArgs e) - { - if ((sender as BoolFeedback).BoolValue == true) - TogglePrivacyMute(); - } - - /// - /// Toggles the state of the privacy mute - /// - public void TogglePrivacyMute() - { - PrivacyDevice.PrivacyModeToggle(); - } - - void TurnOnRedLeds() - { - _greenLedRelayState = false; - _redLedRelayState = true; - SetLedStates(); - } - - void TurnOnGreenLeds() - { - _redLedRelayState = false; - _greenLedRelayState = true; - SetLedStates(); - } - - /// - /// If enabled, sets the actual state of the relays - /// - void SetLedStates() - { - if (_enableLeds) - { - SetRelayStates(); - } + if (privacyState) + TurnOnRedLeds(); else - TurnOffAllLeds(); + TurnOnGreenLeds(); } + } - /// - /// Turns off all LEDs - /// - void TurnOffAllLeds() + void AddInput(IDigitalInput input) + { + Inputs.Add(input); + + input.InputStateFeedback.OutputChange += InputStateFeedback_OutputChange; + } + + void RemoveInput(IDigitalInput input) + { + var tempInput = Inputs.FirstOrDefault(i => i.Equals(input)); + + if (tempInput != null) + tempInput.InputStateFeedback.OutputChange -= InputStateFeedback_OutputChange; + + Inputs.Remove(input); + } + + void SetRedLedRelay(GenericRelayDevice relay) + { + RedLedRelay = relay; + } + + void SetGreenLedRelay(GenericRelayDevice relay) + { + GreenLedRelay = relay; + } + + /// + /// Check the state of the input change and handle accordingly + /// + /// + /// + void InputStateFeedback_OutputChange(object sender, EventArgs e) + { + if ((sender as BoolFeedback).BoolValue == true) + TogglePrivacyMute(); + } + + /// + /// Toggles the state of the privacy mute + /// + public void TogglePrivacyMute() + { + PrivacyDevice.PrivacyModeToggle(); + } + + void TurnOnRedLeds() + { + _greenLedRelayState = false; + _redLedRelayState = true; + SetLedStates(); + } + + void TurnOnGreenLeds() + { + _redLedRelayState = false; + _greenLedRelayState = true; + SetLedStates(); + } + + /// + /// If enabled, sets the actual state of the relays + /// + void SetLedStates() + { + if (_enableLeds) { - _redLedRelayState = false; - _greenLedRelayState = false; - SetRelayStates(); } - - void SetRelayStates() - { - if (RedLedRelay != null) - { - if (_redLedRelayState) - RedLedRelay.CloseRelay(); - else - RedLedRelay.OpenRelay(); - } - - if(GreenLedRelay != null) - { - if (_greenLedRelayState) - GreenLedRelay.CloseRelay(); - else - GreenLedRelay.OpenRelay(); - } - } + else + TurnOffAllLeds(); } - public class MicrophonePrivacyControllerFactory : EssentialsDeviceFactory + /// + /// Turns off all LEDs + /// + void TurnOffAllLeds() { - public MicrophonePrivacyControllerFactory() - { - TypeNames = new List() { "microphoneprivacycontroller" }; - } + _redLedRelayState = false; + _greenLedRelayState = false; - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MIcrophonePrivacyController Device"); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); - - return new Core.Privacy.MicrophonePrivacyController(dc.Key, props); - } + SetRelayStates(); } + void SetRelayStates() + { + if (RedLedRelay != null) + { + if (_redLedRelayState) + RedLedRelay.CloseRelay(); + else + RedLedRelay.OpenRelay(); + } + + if(GreenLedRelay != null) + { + if (_greenLedRelayState) + GreenLedRelay.CloseRelay(); + else + GreenLedRelay.OpenRelay(); + } + } +} + +public class MicrophonePrivacyControllerFactory : EssentialsDeviceFactory +{ + public MicrophonePrivacyControllerFactory() + { + TypeNames = new List() { "microphoneprivacycontroller" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MIcrophonePrivacyController Device"); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); + + return new Core.Privacy.MicrophonePrivacyController(dc.Key, props); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs index 1c172090..25ade531 100644 --- a/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs +++ b/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs @@ -6,17 +6,16 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core.CrestronIO; -namespace PepperDash.Essentials.Core.Privacy -{ - public class MicrophonePrivacyControllerConfig - { - public List Inputs { get; set; } - public KeyedDevice GreenLedRelay { get; set; } - public KeyedDevice RedLedRelay { get; set; } - } +namespace PepperDash.Essentials.Core.Privacy; - public class KeyedDevice - { - public string DeviceKey { get; set; } - } +public class MicrophonePrivacyControllerConfig +{ + public List Inputs { get; set; } + public KeyedDevice GreenLedRelay { get; set; } + public KeyedDevice RedLedRelay { get; set; } +} + +public class KeyedDevice +{ + public string DeviceKey { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs b/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs index bd57b70a..22d0f0b4 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs @@ -11,8 +11,8 @@ using System.ComponentModel; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -53,5 +53,4 @@ namespace PepperDash.Essentials.Core else StartErrorTimers(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs b/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs index a3a427f1..46691909 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs @@ -3,48 +3,48 @@ using PepperDash.Core; using System.Threading; using PepperDash.Core.Logging; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Used for monitoring comms that are IBasicCommunication. Will send a poll string and provide an event when /// statuses change. - /// Default monitoring uses TextReceived event on Client. +/// Default monitoring uses TextReceived event on Client. /// public class GenericCommunicationMonitor : StatusMonitorBase { public IBasicCommunication Client { get; private set; } - /// - /// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived - /// - public bool MonitorBytesReceived { get; private set; } + /// + /// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived + /// + public bool MonitorBytesReceived { get; private set; } - /// - /// Return true if the Client is ISocketStatus - /// - public bool IsSocket => Client is ISocketStatus; + /// + /// Return true if the Client is ISocketStatus + /// + public bool IsSocket => Client is ISocketStatus; - private readonly string PollString; - private readonly Action PollAction; - private readonly long PollTime; + private readonly string PollString; + private readonly Action PollAction; + private readonly long PollTime; private Timer PollTimer; - private SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); + private SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); - /// - /// GenericCommunicationMonitor constructor - /// - /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected - /// - /// Parent device - /// Communications Client - /// Time in MS for polling - /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning - /// Error time in MS. If a message is not received before this elapsed time the status will be Error - /// string to send for polling - /// Poll time must be less than warning and error time - public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + /// + /// GenericCommunicationMonitor constructor + /// + /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected + /// + /// Parent device + /// Communications Client + /// Time in MS for polling + /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning + /// Error time in MS. If a message is not received before this elapsed time the status will be Error + /// string to send for polling + /// Poll time must be less than warning and error time + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, long warningTime, long errorTime, string pollString) : base(parent, warningTime, errorTime) { @@ -55,212 +55,212 @@ namespace PepperDash.Essentials.Core PollTime = pollTime; PollString = pollString; - if (IsSocket) - { - (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; - } + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; + } } - /// - /// GenericCommunicationMonitor constructor with a bool to specify whether to monitor BytesReceived - /// - /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected - /// - /// Parent device - /// Communications Client - /// Time in MS for polling - /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning - /// Error time in MS. If a message is not received before this elapsed time the status will be Error - /// string to send for polling - /// Use bytesReceived event instead of textReceived when true - public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, - long warningTime, long errorTime, string pollString, bool monitorBytesReceived) : - this(parent, client, pollTime, warningTime, errorTime, pollString) + /// + /// GenericCommunicationMonitor constructor with a bool to specify whether to monitor BytesReceived + /// + /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected + /// + /// Parent device + /// Communications Client + /// Time in MS for polling + /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning + /// Error time in MS. If a message is not received before this elapsed time the status will be Error + /// string to send for polling + /// Use bytesReceived event instead of textReceived when true + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, string pollString, bool monitorBytesReceived) : + this(parent, client, pollTime, warningTime, errorTime, pollString) + { + MonitorBytesReceived = monitorBytesReceived; + } + + /// + /// GenericCommunicationMonitor constructor with a poll action instead of a poll string + /// + /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected + /// + /// Parent device + /// Communications Client + /// Time in MS for polling + /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning + /// Error time in MS. If a message is not received before this elapsed time the status will be Error + /// Action to execute for polling + /// Poll time must be less than warning and error time + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, Action pollAction) : + base(parent, warningTime, errorTime) + { + if (pollTime > warningTime || pollTime > errorTime) + throw new ArgumentException("pollTime must be less than warning or errorTime"); + //if (pollTime < 5000) + // throw new ArgumentException("pollTime cannot be less than 5000 ms"); + + Client = client; + PollTime = pollTime; + PollAction = pollAction; + + if (IsSocket) { - MonitorBytesReceived = monitorBytesReceived; + (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; } - /// - /// GenericCommunicationMonitor constructor with a poll action instead of a poll string - /// - /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected - /// - /// Parent device - /// Communications Client - /// Time in MS for polling - /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning - /// Error time in MS. If a message is not received before this elapsed time the status will be Error - /// Action to execute for polling - /// Poll time must be less than warning and error time - public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, - long warningTime, long errorTime, Action pollAction) : - base(parent, warningTime, errorTime) - { - if (pollTime > warningTime || pollTime > errorTime) - throw new ArgumentException("pollTime must be less than warning or errorTime"); - //if (pollTime < 5000) - // throw new ArgumentException("pollTime cannot be less than 5000 ms"); + } - Client = client; - PollTime = pollTime; - PollAction = pollAction; - - if (IsSocket) - { - (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; - } - - } - - /// - /// GenericCommunicationMonitor constructor with a poll action instead of a poll string and a bool to specify whether to monitor BytesReceived - /// - /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected - /// - /// Parent device - /// Communications Client - /// Time in MS for polling - /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning - /// Error time in MS. If a message is not received before this elapsed time the status will be Error - /// Action to execute for polling - /// Use bytesReceived event instead of textReceived when true - public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, - long warningTime, long errorTime, Action pollAction, bool monitorBytesReceived) : - this(parent, client, pollTime, warningTime, errorTime, pollAction) - { - MonitorBytesReceived = monitorBytesReceived; - } + /// + /// GenericCommunicationMonitor constructor with a poll action instead of a poll string and a bool to specify whether to monitor BytesReceived + /// + /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected + /// + /// Parent device + /// Communications Client + /// Time in MS for polling + /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning + /// Error time in MS. If a message is not received before this elapsed time the status will be Error + /// Action to execute for polling + /// Use bytesReceived event instead of textReceived when true + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, + long warningTime, long errorTime, Action pollAction, bool monitorBytesReceived) : + this(parent, client, pollTime, warningTime, errorTime, pollAction) + { + MonitorBytesReceived = monitorBytesReceived; + } - /// - /// GenericCommunicationMonitor constructor with a config object - /// - /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected - /// - /// Parent Device - /// Communications Client - /// Communication Monitor Config object - public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, + /// + /// GenericCommunicationMonitor constructor with a config object + /// + /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected + /// + /// Parent Device + /// Communications Client + /// Communication Monitor Config object + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props) : this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) { - if (IsSocket) - { - (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; - } + if (IsSocket) + { + (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; + } } - /// - /// GenericCommunicationMonitor constructor with a config object and a bool to specify whether to monitor BytesReceived - /// - /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected - /// - /// Parent Device - /// Communications Client - /// Communication Monitor Config object - /// Use bytesReceived event instead of textReceived when true - public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props, bool monitorBytesReceived) : - this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) - { - MonitorBytesReceived = monitorBytesReceived; - } + /// + /// GenericCommunicationMonitor constructor with a config object and a bool to specify whether to monitor BytesReceived + /// + /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected + /// + /// Parent Device + /// Communications Client + /// Communication Monitor Config object + /// Use bytesReceived event instead of textReceived when true + public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props, bool monitorBytesReceived) : + this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) + { + MonitorBytesReceived = monitorBytesReceived; + } - /// - /// Start the poll cycle - /// + /// + /// Start the poll cycle + /// public override void Start() { - if (MonitorBytesReceived) - { + if (MonitorBytesReceived) + { Client.BytesReceived -= Client_BytesReceived; - Client.BytesReceived += Client_BytesReceived; - } - else - { - Client.TextReceived -= Client_TextReceived; - Client.TextReceived += Client_TextReceived; - } + Client.BytesReceived += Client_BytesReceived; + } + else + { + Client.TextReceived -= Client_TextReceived; + Client.TextReceived += Client_TextReceived; + } - BeginPolling(); + BeginPolling(); } - private void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + private void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + { + if (!e.Client.IsConnected) { - if (!e.Client.IsConnected) - { - // Immediately stop polling and notify that device is offline - Stop(); - Status = MonitorStatus.InError; - ResetErrorTimers(); - } - else - { - // Start polling and set status to unknow and let poll result update the status to IsOk when a response is received - Status = MonitorStatus.StatusUnknown; - Start(); - } + // Immediately stop polling and notify that device is offline + Stop(); + Status = MonitorStatus.InError; + ResetErrorTimers(); } - - private void BeginPolling() + else { - try + // Start polling and set status to unknow and let poll result update the status to IsOk when a response is received + Status = MonitorStatus.StatusUnknown; + Start(); + } + } + + private void BeginPolling() + { + try + { + semaphore.Wait(); { - semaphore.Wait(); + if (PollTimer != null) { - if (PollTimer != null) - { - return; - } - - PollTimer = new Timer(o => Poll(), null, 0, PollTime); + return; } - } - finally - { - semaphore.Release(); + + PollTimer = new Timer(o => Poll(), null, 0, PollTime); } } + finally + { + semaphore.Release(); + } + } - /// - /// Stop the poll cycle - /// + /// + /// Stop the poll cycle + /// public override void Stop() { - if(MonitorBytesReceived) - { + if(MonitorBytesReceived) + { Client.BytesReceived -= Client_BytesReceived; - } - else - { - Client.TextReceived -= Client_TextReceived; - } + } + else + { + Client.TextReceived -= Client_TextReceived; + } - StopErrorTimers(); + StopErrorTimers(); - if (PollTimer == null) - { - return; - } - - PollTimer.Dispose(); - PollTimer = null; + if (PollTimer == null) + { + return; + } + + PollTimer.Dispose(); + PollTimer = null; } - private void Client_TextReceived(object sender, GenericCommMethodReceiveTextArgs e) - { - DataReceived(); - } + private void Client_TextReceived(object sender, GenericCommMethodReceiveTextArgs e) + { + DataReceived(); + } private void Client_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) { - DataReceived(); - } + DataReceived(); + } - private void DataReceived() - { - Status = MonitorStatus.IsOk; - ResetErrorTimers(); - } + private void DataReceived() + { + Status = MonitorStatus.IsOk; + ResetErrorTimers(); + } private void Poll() { @@ -268,10 +268,10 @@ namespace PepperDash.Essentials.Core if (Client.IsConnected) { //Debug.LogMessage(LogEventLevel.Verbose, this, "Polling"); - if(PollAction != null) - PollAction.Invoke(); - else - Client.SendText(PollString); + if(PollAction != null) + PollAction.Invoke(); + else + Client.SendText(PollString); } else { @@ -280,9 +280,9 @@ namespace PepperDash.Essentials.Core } } - /// - /// Communication Monitor Configuration from Essentials Configuration - /// +/// +/// Communication Monitor Configuration from Essentials Configuration +/// public class CommunicationMonitorConfig { public int PollInterval { get; set; } @@ -290,9 +290,9 @@ namespace PepperDash.Essentials.Core public int TimeToError { get; set; } public string PollString { get; set; } - /// - /// Default constructor. Sets pollInterval to 30s, TimeToWarning to 120s, and TimeToError to 300s - /// + /// + /// Default constructor. Sets pollInterval to 30s, TimeToWarning to 120s, and TimeToError to 300s + /// public CommunicationMonitorConfig() { PollInterval = 30000; @@ -300,5 +300,4 @@ namespace PepperDash.Essentials.Core TimeToError = 300000; PollString = ""; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/Interfaces.cs b/src/PepperDash.Essentials.Core/Monitoring/Interfaces.cs index 6e4a847e..b9cc8c6b 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/Interfaces.cs @@ -4,8 +4,8 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public interface IStatusMonitor { IKeyed Parent { get; } @@ -31,10 +31,10 @@ namespace PepperDash.Essentials.Core /// public enum MonitorStatus { - StatusUnknown = 0, + StatusUnknown = 0, IsOk = 1, - InWarning = 2, - InError = 3 + InWarning = 2, + InError = 3 } public class MonitorStatusChangeEventArgs : EventArgs @@ -53,5 +53,4 @@ namespace PepperDash.Essentials.Core Status = status; Message = message; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs index 4abb930f..6c392317 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs @@ -11,18 +11,18 @@ using System.ComponentModel; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public abstract class StatusMonitorBase : IStatusMonitor, IKeyName { public event EventHandler StatusChange; - /// - /// Format returned: "parentdevkey-comMonitor" - /// - public string Key { get { return Parent.Key + "-comMonitor"; } } + /// + /// Format returned: "parentdevkey-comMonitor" + /// + public string Key { get { return Parent.Key + "-comMonitor"; } } - public string Name { get { return "Comm. monitor"; } } + public string Name { get { return "Comm. monitor"; } } public IKeyed Parent { get; private set; } @@ -118,13 +118,12 @@ namespace PepperDash.Essentials.Core ErrorTimer = null; } - protected void ResetErrorTimers() - { - if(WarningTimer != null) - WarningTimer.Reset(WarningTime, WarningTime); - if(ErrorTimer != null) - ErrorTimer.Reset(ErrorTime, ErrorTime); + protected void ResetErrorTimers() + { + if(WarningTimer != null) + WarningTimer.Reset(WarningTime, WarningTime); + if(ErrorTimer != null) + ErrorTimer.Reset(ErrorTime, ErrorTime); - } - } -} \ No newline at end of file + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs index 7f985fe0..9f3a5b3c 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs @@ -11,8 +11,8 @@ using System.ComponentModel; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// /// @@ -70,28 +70,28 @@ namespace PepperDash.Essentials.Core initialStatus = MonitorStatus.StatusUnknown; // Build the error message string - if (InError.Count() > 0 || InWarning.Count() > 0) + if (InError.Count() > 0 || InWarning.Count() > 0) + { + StringBuilder sb = new StringBuilder(prefix); + if (InError.Count() > 0) { - StringBuilder sb = new StringBuilder(prefix); - if (InError.Count() > 0) - { - // Do string splits and joins - sb.Append(string.Format("{0} Errors:", InError.Count())); - foreach (var mon in InError) - sb.Append(string.Format("{0}, ", mon.Parent.Key)); - } - if (InWarning.Count() > 0) - { - sb.Append(string.Format("{0} Warnings:", InWarning.Count())); - foreach (var mon in InWarning) - sb.Append(string.Format("{0}, ", mon.Parent.Key)); - } - Message = sb.ToString(); + // Do string splits and joins + sb.Append(string.Format("{0} Errors:", InError.Count())); + foreach (var mon in InError) + sb.Append(string.Format("{0}, ", mon.Parent.Key)); } - else + if (InWarning.Count() > 0) { - Message = "Room Ok."; + sb.Append(string.Format("{0} Warnings:", InWarning.Count())); + foreach (var mon in InWarning) + sb.Append(string.Format("{0}, ", mon.Parent.Key)); } + Message = sb.ToString(); + } + else + { + Message = "Room Ok."; + } // Want to fire even if status doesn't change because the message may. Status = initialStatus; @@ -124,5 +124,4 @@ namespace PepperDash.Essentials.Core if (handler != null) handler(this, new MonitorStatusChangeEventArgs(status, message)); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs b/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs index 06a4fbd9..99a58ec6 100644 --- a/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs +++ b/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs @@ -12,39 +12,39 @@ using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; -namespace PepperDash.Essentials.Core.Monitoring +namespace PepperDash.Essentials.Core.Monitoring; + +/// +/// Wrapper for the static SystemMonitor class to extend functionality and provide external access +/// to SystemMonitor via APIs +/// +public class SystemMonitorController : EssentialsBridgeableDevice { - /// - /// Wrapper for the static SystemMonitor class to extend functionality and provide external access - /// to SystemMonitor via APIs - /// - public class SystemMonitorController : EssentialsBridgeableDevice - { - private const long UptimePollTime = 300000; - private CTimer _uptimePollTimer; + private const long UptimePollTime = 300000; + private CTimer _uptimePollTimer; - private string _uptime; - private string _lastStart; + private string _uptime; + private string _lastStart; - public event EventHandler SystemMonitorPropertiesChanged; + public event EventHandler SystemMonitorPropertiesChanged; - public Dictionary ProgramStatusFeedbackCollection; - public Dictionary EthernetStatusFeedbackCollection; + public Dictionary ProgramStatusFeedbackCollection; + public Dictionary EthernetStatusFeedbackCollection; - public IntFeedback TimeZoneFeedback { get; protected set; } - public StringFeedback TimeZoneTextFeedback { get; protected set; } + public IntFeedback TimeZoneFeedback { get; protected set; } + public StringFeedback TimeZoneTextFeedback { get; protected set; } - public StringFeedback IoControllerVersionFeedback { get; protected set; } - public StringFeedback SnmpVersionFeedback { get; protected set; } - public StringFeedback BaCnetAppVersionFeedback { get; protected set; } - public StringFeedback ControllerVersionFeedback { get; protected set; } + public StringFeedback IoControllerVersionFeedback { get; protected set; } + public StringFeedback SnmpVersionFeedback { get; protected set; } + public StringFeedback BaCnetAppVersionFeedback { get; protected set; } + public StringFeedback ControllerVersionFeedback { get; protected set; } - //new feedbacks. Issue #50 - public StringFeedback SerialNumberFeedback { get; protected set; } - public StringFeedback ModelFeedback { get; set; } + //new feedbacks. Issue #50 + public StringFeedback SerialNumberFeedback { get; protected set; } + public StringFeedback ModelFeedback { get; set; } - public StringFeedback UptimeFeedback { get; set; } - public StringFeedback LastStartFeedback { get; set; } + public StringFeedback UptimeFeedback { get; set; } + public StringFeedback LastStartFeedback { get; set; } public BoolFeedback IsApplianceFeedback { get; protected set; } private bool _isApplianceFb @@ -60,104 +60,104 @@ namespace PepperDash.Essentials.Core.Monitoring public SystemMonitorController(string key) - : base(key) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Adding SystemMonitorController."); + : base(key) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Adding SystemMonitorController."); - SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true; + SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true; - TimeZoneFeedback = new IntFeedback(() => SystemMonitor.TimeZoneInformation.TimeZoneNumber); - TimeZoneTextFeedback = new StringFeedback(() => SystemMonitor.TimeZoneInformation.TimeZoneName); + TimeZoneFeedback = new IntFeedback(() => SystemMonitor.TimeZoneInformation.TimeZoneNumber); + TimeZoneTextFeedback = new StringFeedback(() => SystemMonitor.TimeZoneInformation.TimeZoneName); - IoControllerVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.IOPVersion); - SnmpVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.SNMPVersion); - BaCnetAppVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.BACNetVersion); - ControllerVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.ControlSystemVersion); + IoControllerVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.IOPVersion); + SnmpVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.SNMPVersion); + BaCnetAppVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.BACNetVersion); + ControllerVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.ControlSystemVersion); - SerialNumberFeedback = new StringFeedback(() => CrestronEnvironment.SystemInfo.SerialNumber); - ModelFeedback = new StringFeedback(() => InitialParametersClass.ControllerPromptName); - UptimeFeedback = new StringFeedback(() => _uptime); - LastStartFeedback = new StringFeedback(()=> _lastStart); + SerialNumberFeedback = new StringFeedback(() => CrestronEnvironment.SystemInfo.SerialNumber); + ModelFeedback = new StringFeedback(() => InitialParametersClass.ControllerPromptName); + UptimeFeedback = new StringFeedback(() => _uptime); + LastStartFeedback = new StringFeedback(()=> _lastStart); IsApplianceFeedback = new BoolFeedback(() => _isApplianceFb); IsServerFeedback = new BoolFeedback(() => _isServerFb); - ProgramStatusFeedbackCollection = new Dictionary(); + ProgramStatusFeedbackCollection = new Dictionary(); - foreach (var prog in SystemMonitor.ProgramCollection) - { - var program = new ProgramStatusFeedbacks(prog); - ProgramStatusFeedbackCollection.Add(prog.Number, program); - } - - CreateEthernetStatusFeedbacks(); - UpdateEthernetStatusFeeedbacks(); - - _uptimePollTimer = new CTimer(PollUptime,null,0, UptimePollTime); - - SystemMonitor.ProgramChange += SystemMonitor_ProgramChange; - SystemMonitor.TimeZoneInformation.TimeZoneChange += TimeZoneInformation_TimeZoneChange; - CrestronEnvironment.EthernetEventHandler += CrestronEnvironmentOnEthernetEventHandler; - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironmentOnProgramStatusEventHandler; - } - - private void CrestronEnvironmentOnProgramStatusEventHandler(eProgramStatusEventType programEventType) + foreach (var prog in SystemMonitor.ProgramCollection) { - if (programEventType != eProgramStatusEventType.Stopping) return; - - _uptimePollTimer.Stop(); - _uptimePollTimer.Dispose(); - _uptimePollTimer = null; + var program = new ProgramStatusFeedbacks(prog); + ProgramStatusFeedbackCollection.Add(prog.Number, program); } - public void PollUptime(object obj) + CreateEthernetStatusFeedbacks(); + UpdateEthernetStatusFeeedbacks(); + + _uptimePollTimer = new CTimer(PollUptime,null,0, UptimePollTime); + + SystemMonitor.ProgramChange += SystemMonitor_ProgramChange; + SystemMonitor.TimeZoneInformation.TimeZoneChange += TimeZoneInformation_TimeZoneChange; + CrestronEnvironment.EthernetEventHandler += CrestronEnvironmentOnEthernetEventHandler; + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironmentOnProgramStatusEventHandler; + } + + private void CrestronEnvironmentOnProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType != eProgramStatusEventType.Stopping) return; + + _uptimePollTimer.Stop(); + _uptimePollTimer.Dispose(); + _uptimePollTimer = null; + } + + public void PollUptime(object obj) + { + var consoleResponse = string.Empty; + + CrestronConsole.SendControlSystemCommand("uptime", ref consoleResponse); + + ParseUptime(consoleResponse); + + UptimeFeedback.FireUpdate(); + LastStartFeedback.FireUpdate(); + } + + private void ParseUptime(string response) + { + var splitString = response.Trim().Split('\r', '\n'); + + var lastStartRaw = splitString.FirstOrDefault(o => o.Contains("started")); + var uptimeRaw = splitString.FirstOrDefault(o => o.Contains("running")); + + if (!String.IsNullOrEmpty(lastStartRaw)) { - var consoleResponse = string.Empty; - - CrestronConsole.SendControlSystemCommand("uptime", ref consoleResponse); - - ParseUptime(consoleResponse); - - UptimeFeedback.FireUpdate(); - LastStartFeedback.FireUpdate(); + var lastStartIndex = lastStartRaw.IndexOf(':'); + _lastStart = lastStartRaw.Substring(lastStartIndex + 1).Trim(); } - private void ParseUptime(string response) - { - var splitString = response.Trim().Split('\r', '\n'); + if (String.IsNullOrEmpty(uptimeRaw)) return; + var forIndex = uptimeRaw.IndexOf("for", StringComparison.Ordinal); - var lastStartRaw = splitString.FirstOrDefault(o => o.Contains("started")); - var uptimeRaw = splitString.FirstOrDefault(o => o.Contains("running")); - - if (!String.IsNullOrEmpty(lastStartRaw)) - { - var lastStartIndex = lastStartRaw.IndexOf(':'); - _lastStart = lastStartRaw.Substring(lastStartIndex + 1).Trim(); - } - - if (String.IsNullOrEmpty(uptimeRaw)) return; - var forIndex = uptimeRaw.IndexOf("for", StringComparison.Ordinal); - - //4 => "for " to get what's on the right - _uptime = uptimeRaw.Substring(forIndex + 4); - } + //4 => "for " to get what's on the right + _uptime = uptimeRaw.Substring(forIndex + 4); + } public static void ProcessorReboot() { if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return; - Debug.LogMessage(LogEventLevel.Information, "Rebooting..."); + Debug.LogMessage(LogEventLevel.Information, "Rebooting..."); - var response = string.Empty; + var response = string.Empty; CrestronConsole.SendControlSystemCommand("reboot", ref response); } public static void ProgramReset(uint index) { if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return; - Debug.LogMessage(LogEventLevel.Information, "Resetting Program {0}...", index); + Debug.LogMessage(LogEventLevel.Information, "Resetting Program {0}...", index); - if (index <= 0 || index > 10) return; + if (index <= 0 || index > 10) return; var cmd = string.Format("progreset -p:{0}", index); @@ -165,493 +165,493 @@ namespace PepperDash.Essentials.Core.Monitoring CrestronConsole.SendControlSystemCommand(cmd, ref response); } - private void CrestronEnvironmentOnEthernetEventHandler(EthernetEventArgs ethernetEventArgs) - { - if (ethernetEventArgs.EthernetEventType != eEthernetEventType.LinkUp) return; + private void CrestronEnvironmentOnEthernetEventHandler(EthernetEventArgs ethernetEventArgs) + { + if (ethernetEventArgs.EthernetEventType != eEthernetEventType.LinkUp) return; - foreach (var fb in EthernetStatusFeedbackCollection) - { - fb.Value.UpdateEthernetStatus(); - } + foreach (var fb in EthernetStatusFeedbackCollection) + { + fb.Value.UpdateEthernetStatus(); } + } - private void CreateEthernetStatusFeedbacks() + private void CreateEthernetStatusFeedbacks() + { + EthernetStatusFeedbackCollection = new Dictionary(); + + Debug.LogMessage(LogEventLevel.Verbose, "Creating {0} EthernetStatusFeedbacks", InitialParametersClass.NumberOfEthernetInterfaces); + + for (short i = 0; i < InitialParametersClass.NumberOfEthernetInterfaces; i++) { - EthernetStatusFeedbackCollection = new Dictionary(); - - Debug.LogMessage(LogEventLevel.Verbose, "Creating {0} EthernetStatusFeedbacks", InitialParametersClass.NumberOfEthernetInterfaces); - - for (short i = 0; i < InitialParametersClass.NumberOfEthernetInterfaces; i++) - { - Debug.LogMessage(LogEventLevel.Verbose, "Creating EthernetStatusFeedback for Interface {0}", i); - var ethernetInterface = new EthernetStatusFeedbacks(i); - EthernetStatusFeedbackCollection.Add(i, ethernetInterface); - } + Debug.LogMessage(LogEventLevel.Verbose, "Creating EthernetStatusFeedback for Interface {0}", i); + var ethernetInterface = new EthernetStatusFeedbacks(i); + EthernetStatusFeedbackCollection.Add(i, ethernetInterface); } + } - private void UpdateEthernetStatusFeeedbacks() + private void UpdateEthernetStatusFeeedbacks() + { + foreach (var iface in EthernetStatusFeedbackCollection) { - foreach (var iface in EthernetStatusFeedbackCollection) - { - iface.Value.CurrentIpAddressFeedback.FireUpdate(); - iface.Value.CurrentSubnetMaskFeedback.FireUpdate(); - iface.Value.CurrentDefaultGatewayFeedback.FireUpdate(); - iface.Value.StaticIpAddressFeedback.FireUpdate(); - iface.Value.StaticSubnetMaskFeedback.FireUpdate(); - iface.Value.StaticDefaultGatewayFeedback.FireUpdate(); - iface.Value.HostNameFeedback.FireUpdate(); - iface.Value.DnsServerFeedback.FireUpdate(); - iface.Value.DomainFeedback.FireUpdate(); - iface.Value.DhcpStatusFeedback.FireUpdate(); - iface.Value.MacAddressFeedback.FireUpdate(); - } + iface.Value.CurrentIpAddressFeedback.FireUpdate(); + iface.Value.CurrentSubnetMaskFeedback.FireUpdate(); + iface.Value.CurrentDefaultGatewayFeedback.FireUpdate(); + iface.Value.StaticIpAddressFeedback.FireUpdate(); + iface.Value.StaticSubnetMaskFeedback.FireUpdate(); + iface.Value.StaticDefaultGatewayFeedback.FireUpdate(); + iface.Value.HostNameFeedback.FireUpdate(); + iface.Value.DnsServerFeedback.FireUpdate(); + iface.Value.DomainFeedback.FireUpdate(); + iface.Value.DhcpStatusFeedback.FireUpdate(); + iface.Value.MacAddressFeedback.FireUpdate(); } + } - /// - /// Gets data in separate thread - /// - private void RefreshSystemMonitorData() - { - // this takes a while, launch a new thread - CrestronInvoke.BeginInvoke(UpdateFeedback); - } + /// + /// Gets data in separate thread + /// + private void RefreshSystemMonitorData() + { + // this takes a while, launch a new thread + CrestronInvoke.BeginInvoke(UpdateFeedback); + } - private void UpdateFeedback(object o) - { - TimeZoneFeedback.FireUpdate(); - TimeZoneTextFeedback.FireUpdate(); - IoControllerVersionFeedback.FireUpdate(); - SnmpVersionFeedback.FireUpdate(); - BaCnetAppVersionFeedback.FireUpdate(); - ControllerVersionFeedback.FireUpdate(); - SerialNumberFeedback.FireUpdate(); - ModelFeedback.FireUpdate(); + private void UpdateFeedback(object o) + { + TimeZoneFeedback.FireUpdate(); + TimeZoneTextFeedback.FireUpdate(); + IoControllerVersionFeedback.FireUpdate(); + SnmpVersionFeedback.FireUpdate(); + BaCnetAppVersionFeedback.FireUpdate(); + ControllerVersionFeedback.FireUpdate(); + SerialNumberFeedback.FireUpdate(); + ModelFeedback.FireUpdate(); IsApplianceFeedback.FireUpdate(); IsServerFeedback.FireUpdate(); - OnSystemMonitorPropertiesChanged(); + OnSystemMonitorPropertiesChanged(); + } + + private void OnSystemMonitorPropertiesChanged() + { + var handler = SystemMonitorPropertiesChanged; + if (handler != null) + { + handler(this, new EventArgs()); + } + } + + public override bool CustomActivate() + { + RefreshSystemMonitorData(); + + return base.CustomActivate(); + } + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new SystemMonitorJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); } - private void OnSystemMonitorPropertiesChanged() - { - var handler = SystemMonitorPropertiesChanged; - if (handler != null) - { - handler(this, new EventArgs()); - } - } + Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + Debug.LogMessage(LogEventLevel.Verbose, this, "Linking API starting at join: {0}", joinStart); - public override bool CustomActivate() - { - RefreshSystemMonitorData(); + TimeZoneFeedback.LinkInputSig(trilist.UShortInput[joinMap.TimeZone.JoinNumber]); + TimeZoneTextFeedback.LinkInputSig(trilist.StringInput[joinMap.TimeZoneName.JoinNumber]); - return base.CustomActivate(); - } - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new SystemMonitorJoinMap(joinStart); - - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(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."); - } - - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - Debug.LogMessage(LogEventLevel.Verbose, this, "Linking API starting at join: {0}", joinStart); - - TimeZoneFeedback.LinkInputSig(trilist.UShortInput[joinMap.TimeZone.JoinNumber]); - TimeZoneTextFeedback.LinkInputSig(trilist.StringInput[joinMap.TimeZoneName.JoinNumber]); - - IoControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.IOControllerVersion.JoinNumber]); - SnmpVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.SnmpAppVersion.JoinNumber]); - BaCnetAppVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.BACnetAppVersion.JoinNumber]); - ControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.ControllerVersion.JoinNumber]); - SerialNumberFeedback.LinkInputSig(trilist.StringInput[joinMap.SerialNumber.JoinNumber]); - ModelFeedback.LinkInputSig(trilist.StringInput[joinMap.Model.JoinNumber]); - UptimeFeedback.LinkInputSig(trilist.StringInput[joinMap.Uptime.JoinNumber]); - LastStartFeedback.LinkInputSig(trilist.StringInput[joinMap.LastBoot.JoinNumber]); + IoControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.IOControllerVersion.JoinNumber]); + SnmpVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.SnmpAppVersion.JoinNumber]); + BaCnetAppVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.BACnetAppVersion.JoinNumber]); + ControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.ControllerVersion.JoinNumber]); + SerialNumberFeedback.LinkInputSig(trilist.StringInput[joinMap.SerialNumber.JoinNumber]); + ModelFeedback.LinkInputSig(trilist.StringInput[joinMap.Model.JoinNumber]); + UptimeFeedback.LinkInputSig(trilist.StringInput[joinMap.Uptime.JoinNumber]); + LastStartFeedback.LinkInputSig(trilist.StringInput[joinMap.LastBoot.JoinNumber]); trilist.SetSigHeldAction(joinMap.ProcessorReboot.JoinNumber, 10000, ProcessorReboot); IsApplianceFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsAppliance.JoinNumber]); IsServerFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsServer.JoinNumber]); - // iterate the program status feedback collection and map all the joins - LinkProgramInfoJoins(this, trilist, joinMap); + // iterate the program status feedback collection and map all the joins + LinkProgramInfoJoins(this, trilist, joinMap); - LinkEthernetInfoJoins(this, trilist, joinMap); - } + LinkEthernetInfoJoins(this, trilist, joinMap); + } - private static void LinkEthernetInfoJoins(SystemMonitorController systemMonitorController, BasicTriList trilist, SystemMonitorJoinMap joinMap) + private static void LinkEthernetInfoJoins(SystemMonitorController systemMonitorController, BasicTriList trilist, SystemMonitorJoinMap joinMap) + { + uint ethernetSlotJoinStart = 0; + foreach (var fb in systemMonitorController.EthernetStatusFeedbackCollection) { - uint ethernetSlotJoinStart = 0; - foreach (var fb in systemMonitorController.EthernetStatusFeedbackCollection) - { - fb.Value.CurrentIpAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentIpAddress.JoinNumber]); - fb.Value.CurrentSubnetMaskFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentSubnetMask.JoinNumber]); - fb.Value.CurrentDefaultGatewayFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentDefaultGateway.JoinNumber]); - fb.Value.StaticIpAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticIpAddress.JoinNumber]); - fb.Value.StaticSubnetMaskFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticSubnetMask.JoinNumber]); - fb.Value.StaticDefaultGatewayFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticDefaultGateway.JoinNumber]); - fb.Value.HostNameFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.HostName.JoinNumber]); - fb.Value.MacAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.MacAddress.JoinNumber]); - fb.Value.DomainFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.Domain.JoinNumber]); - fb.Value.DnsServerFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.DnsServer.JoinNumber]); - fb.Value.DhcpStatusFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.DhcpStatus.JoinNumber]); + fb.Value.CurrentIpAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentIpAddress.JoinNumber]); + fb.Value.CurrentSubnetMaskFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentSubnetMask.JoinNumber]); + fb.Value.CurrentDefaultGatewayFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentDefaultGateway.JoinNumber]); + fb.Value.StaticIpAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticIpAddress.JoinNumber]); + fb.Value.StaticSubnetMaskFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticSubnetMask.JoinNumber]); + fb.Value.StaticDefaultGatewayFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticDefaultGateway.JoinNumber]); + fb.Value.HostNameFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.HostName.JoinNumber]); + fb.Value.MacAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.MacAddress.JoinNumber]); + fb.Value.DomainFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.Domain.JoinNumber]); + fb.Value.DnsServerFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.DnsServer.JoinNumber]); + fb.Value.DhcpStatusFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.DhcpStatus.JoinNumber]); - ethernetSlotJoinStart += joinMap.EthernetOffsetJoin.JoinNumber; - } + ethernetSlotJoinStart += joinMap.EthernetOffsetJoin.JoinNumber; } + } - private static void LinkProgramInfoJoins(SystemMonitorController systemMonitorController, BasicTriList trilist, - SystemMonitorJoinMap joinMap) + private static void LinkProgramInfoJoins(SystemMonitorController systemMonitorController, BasicTriList trilist, + SystemMonitorJoinMap joinMap) + { + uint programSlotJoinStart = 0; + + foreach (var p in systemMonitorController.ProgramStatusFeedbackCollection) { - uint programSlotJoinStart = 0; + var programNumber = p.Value.Program.Number; - foreach (var p in systemMonitorController.ProgramStatusFeedbackCollection) - { - var programNumber = p.Value.Program.Number; + trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStart.JoinNumber, + b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Start); + p.Value.ProgramStartedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStart.JoinNumber]); - trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStart.JoinNumber, - b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Start); - p.Value.ProgramStartedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStart.JoinNumber]); + trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStop.JoinNumber, + b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Stop); + p.Value.ProgramStoppedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStop.JoinNumber]); - trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStop.JoinNumber, - b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Stop); - p.Value.ProgramStoppedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStop.JoinNumber]); + trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramRegister.JoinNumber, + b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Register); + p.Value.ProgramRegisteredFeedback.LinkInputSig( + trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramRegister.JoinNumber]); - trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramRegister.JoinNumber, - b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Register); - p.Value.ProgramRegisteredFeedback.LinkInputSig( - trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramRegister.JoinNumber]); + trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramUnregister.JoinNumber, + b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Unregister); + p.Value.ProgramUnregisteredFeedback.LinkInputSig( + trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramUnregister.JoinNumber]); - trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramUnregister.JoinNumber, - b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Unregister); - p.Value.ProgramUnregisteredFeedback.LinkInputSig( - trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramUnregister.JoinNumber]); - - p.Value.ProgramNameFeedback.LinkInputSig(trilist.StringInput[programSlotJoinStart + joinMap.ProgramName.JoinNumber]); - p.Value.ProgramCompileTimeFeedback.LinkInputSig( - trilist.StringInput[programSlotJoinStart + joinMap.ProgramCompiledTime.JoinNumber]); - p.Value.CrestronDataBaseVersionFeedback.LinkInputSig( - trilist.StringInput[programSlotJoinStart + joinMap.ProgramCrestronDatabaseVersion.JoinNumber]); - p.Value.EnvironmentVersionFeedback.LinkInputSig( - trilist.StringInput[programSlotJoinStart + joinMap.ProgramEnvironmentVersion.JoinNumber]); - p.Value.AggregatedProgramInfoFeedback.LinkInputSig( - trilist.StringInput[programSlotJoinStart + joinMap.AggregatedProgramInfo.JoinNumber]); + p.Value.ProgramNameFeedback.LinkInputSig(trilist.StringInput[programSlotJoinStart + joinMap.ProgramName.JoinNumber]); + p.Value.ProgramCompileTimeFeedback.LinkInputSig( + trilist.StringInput[programSlotJoinStart + joinMap.ProgramCompiledTime.JoinNumber]); + p.Value.CrestronDataBaseVersionFeedback.LinkInputSig( + trilist.StringInput[programSlotJoinStart + joinMap.ProgramCrestronDatabaseVersion.JoinNumber]); + p.Value.EnvironmentVersionFeedback.LinkInputSig( + trilist.StringInput[programSlotJoinStart + joinMap.ProgramEnvironmentVersion.JoinNumber]); + p.Value.AggregatedProgramInfoFeedback.LinkInputSig( + trilist.StringInput[programSlotJoinStart + joinMap.AggregatedProgramInfo.JoinNumber]); trilist.SetSigHeldAction(programSlotJoinStart + joinMap.ProgramReset.JoinNumber, 10000, () => ProgramReset(programNumber)); - programSlotJoinStart = programSlotJoinStart + joinMap.ProgramOffsetJoin.JoinSpan; - } - } + programSlotJoinStart = programSlotJoinStart + joinMap.ProgramOffsetJoin.JoinSpan; + } + } //// Sets the time zone - //public void SetTimeZone(int timeZone) - //{ - // SystemMonitor.TimeZoneInformation.TimeZoneNumber = timeZone; - //} + //public void SetTimeZone(int timeZone) + //{ + // SystemMonitor.TimeZoneInformation.TimeZoneNumber = timeZone; + //} - /// - /// Responds to program change events and triggers the appropriate feedbacks to update - /// - /// - /// - private void SystemMonitor_ProgramChange(Program sender, ProgramEventArgs args) + /// + /// Responds to program change events and triggers the appropriate feedbacks to update + /// + /// + /// + private void SystemMonitor_ProgramChange(Program sender, ProgramEventArgs args) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Program Change Detected for slot: {0}", sender.Number); + Debug.LogMessage(LogEventLevel.Verbose, this, "Event Type: {0}", args.EventType); + + var program = ProgramStatusFeedbackCollection[sender.Number]; + + switch (args.EventType) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Program Change Detected for slot: {0}", sender.Number); - Debug.LogMessage(LogEventLevel.Verbose, this, "Event Type: {0}", args.EventType); - - var program = ProgramStatusFeedbackCollection[sender.Number]; - - switch (args.EventType) - { - case eProgramChangeEventType.OperatingState: - program.ProgramStartedFeedback.FireUpdate(); - program.ProgramStoppedFeedback.FireUpdate(); - program.ProgramInfo.OperatingState = args.OperatingState; - if (args.OperatingState == eProgramOperatingState.Start) - program.GetProgramInfo(); - else - { - program.AggregatedProgramInfoFeedback.FireUpdate(); - program.OnProgramInfoChanged(); - } - break; - case eProgramChangeEventType.RegistrationState: - program.ProgramRegisteredFeedback.FireUpdate(); - program.ProgramUnregisteredFeedback.FireUpdate(); - program.ProgramInfo.RegistrationState = args.RegistrationState; + case eProgramChangeEventType.OperatingState: + program.ProgramStartedFeedback.FireUpdate(); + program.ProgramStoppedFeedback.FireUpdate(); + program.ProgramInfo.OperatingState = args.OperatingState; + if (args.OperatingState == eProgramOperatingState.Start) program.GetProgramInfo(); - break; - } + else + { + program.AggregatedProgramInfoFeedback.FireUpdate(); + program.OnProgramInfoChanged(); + } + break; + case eProgramChangeEventType.RegistrationState: + program.ProgramRegisteredFeedback.FireUpdate(); + program.ProgramUnregisteredFeedback.FireUpdate(); + program.ProgramInfo.RegistrationState = args.RegistrationState; + program.GetProgramInfo(); + break; } + } - /// - /// Responds to time zone changes and updates the appropriate feedbacks - /// - /// - private void TimeZoneInformation_TimeZoneChange(TimeZoneEventArgs args) + /// + /// Responds to time zone changes and updates the appropriate feedbacks + /// + /// + private void TimeZoneInformation_TimeZoneChange(TimeZoneEventArgs args) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Time Zone Change Detected."); + TimeZoneFeedback.FireUpdate(); + TimeZoneTextFeedback.FireUpdate(); + + OnSystemMonitorPropertiesChanged(); + } + + public class EthernetStatusFeedbacks + { + public StringFeedback HostNameFeedback { get; protected set; } + public StringFeedback DnsServerFeedback { get; protected set; } + public StringFeedback DomainFeedback { get; protected set; } + public StringFeedback MacAddressFeedback { get; protected set; } + public StringFeedback DhcpStatusFeedback { get; protected set; } + + public StringFeedback CurrentIpAddressFeedback { get; protected set; } + public StringFeedback CurrentSubnetMaskFeedback { get; protected set; } + public StringFeedback CurrentDefaultGatewayFeedback { get; protected set; } + + public StringFeedback StaticIpAddressFeedback { get; protected set; } + public StringFeedback StaticSubnetMaskFeedback { get; protected set; } + public StringFeedback StaticDefaultGatewayFeedback { get; protected set; } + + public EthernetStatusFeedbacks(short adapterIndex) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Time Zone Change Detected."); - TimeZoneFeedback.FireUpdate(); - TimeZoneTextFeedback.FireUpdate(); - - OnSystemMonitorPropertiesChanged(); - } - - public class EthernetStatusFeedbacks - { - public StringFeedback HostNameFeedback { get; protected set; } - public StringFeedback DnsServerFeedback { get; protected set; } - public StringFeedback DomainFeedback { get; protected set; } - public StringFeedback MacAddressFeedback { get; protected set; } - public StringFeedback DhcpStatusFeedback { get; protected set; } - - public StringFeedback CurrentIpAddressFeedback { get; protected set; } - public StringFeedback CurrentSubnetMaskFeedback { get; protected set; } - public StringFeedback CurrentDefaultGatewayFeedback { get; protected set; } - - public StringFeedback StaticIpAddressFeedback { get; protected set; } - public StringFeedback StaticSubnetMaskFeedback { get; protected set; } - public StringFeedback StaticDefaultGatewayFeedback { get; protected set; } - - public EthernetStatusFeedbacks(short adapterIndex) - { - Debug.LogMessage(LogEventLevel.Verbose, "Ethernet Information for interface {0}", adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Hostname: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current IP Address: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current Subnet Mask: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current Router: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static IP Address: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_IPADDRESS, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static Subnet Mask: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_IPMASK, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static Router: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_ROUTER, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} DNS Servers: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} DHCP State: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Domain Name: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterIndex), adapterIndex); - Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} MAC Address: {0}", CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterIndex), adapterIndex); - HostNameFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex)); - - CurrentIpAddressFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex)); - CurrentDefaultGatewayFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex)); - CurrentSubnetMaskFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex)); - StaticIpAddressFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex)); - StaticDefaultGatewayFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex)); - StaticSubnetMaskFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex)); - DomainFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterIndex)); - DnsServerFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterIndex)); - MacAddressFeedback = - new StringFeedback( - () => - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterIndex)); - - DhcpStatusFeedback = new StringFeedback( + Debug.LogMessage(LogEventLevel.Verbose, "Ethernet Information for interface {0}", adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Hostname: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current IP Address: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current Subnet Mask: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current Router: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static IP Address: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_IPADDRESS, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static Subnet Mask: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_IPMASK, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static Router: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_ROUTER, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} DNS Servers: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} DHCP State: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Domain Name: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterIndex), adapterIndex); + Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} MAC Address: {0}", CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterIndex), adapterIndex); + HostNameFeedback = + new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterIndex)); - } + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex)); - public void UpdateEthernetStatus() - { - HostNameFeedback.FireUpdate(); - CurrentIpAddressFeedback.FireUpdate(); - CurrentSubnetMaskFeedback.FireUpdate(); - CurrentDefaultGatewayFeedback.FireUpdate(); - StaticIpAddressFeedback.FireUpdate(); - StaticSubnetMaskFeedback.FireUpdate(); - StaticDefaultGatewayFeedback.FireUpdate(); - DomainFeedback.FireUpdate(); - DnsServerFeedback.FireUpdate(); - MacAddressFeedback.FireUpdate(); - DhcpStatusFeedback.FireUpdate(); - } + CurrentIpAddressFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex)); + CurrentDefaultGatewayFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex)); + CurrentSubnetMaskFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex)); + StaticIpAddressFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex)); + StaticDefaultGatewayFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex)); + StaticSubnetMaskFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex)); + DomainFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterIndex)); + DnsServerFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterIndex)); + MacAddressFeedback = + new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterIndex)); + + DhcpStatusFeedback = new StringFeedback( + () => + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterIndex)); } - - public class ProgramStatusFeedbacks + public void UpdateEthernetStatus() { - public event EventHandler ProgramInfoChanged; + HostNameFeedback.FireUpdate(); + CurrentIpAddressFeedback.FireUpdate(); + CurrentSubnetMaskFeedback.FireUpdate(); + CurrentDefaultGatewayFeedback.FireUpdate(); + StaticIpAddressFeedback.FireUpdate(); + StaticSubnetMaskFeedback.FireUpdate(); + StaticDefaultGatewayFeedback.FireUpdate(); + DomainFeedback.FireUpdate(); + DnsServerFeedback.FireUpdate(); + MacAddressFeedback.FireUpdate(); + DhcpStatusFeedback.FireUpdate(); + } + } - public Program Program; - public ProgramInfo ProgramInfo { get; set; } + public class ProgramStatusFeedbacks + { + public event EventHandler ProgramInfoChanged; - public BoolFeedback ProgramStartedFeedback; - public BoolFeedback ProgramStoppedFeedback; - public BoolFeedback ProgramRegisteredFeedback; - public BoolFeedback ProgramUnregisteredFeedback; + public Program Program; - public StringFeedback ProgramNameFeedback; - public StringFeedback ProgramCompileTimeFeedback; - public StringFeedback CrestronDataBaseVersionFeedback; - // SIMPL windows version - public StringFeedback EnvironmentVersionFeedback; - public StringFeedback AggregatedProgramInfoFeedback; + public ProgramInfo ProgramInfo { get; set; } - public ProgramStatusFeedbacks(Program program) - { - ProgramInfo = new ProgramInfo(program.Number); + public BoolFeedback ProgramStartedFeedback; + public BoolFeedback ProgramStoppedFeedback; + public BoolFeedback ProgramRegisteredFeedback; + public BoolFeedback ProgramUnregisteredFeedback; - Program = program; + public StringFeedback ProgramNameFeedback; + public StringFeedback ProgramCompileTimeFeedback; + public StringFeedback CrestronDataBaseVersionFeedback; + // SIMPL windows version + public StringFeedback EnvironmentVersionFeedback; + public StringFeedback AggregatedProgramInfoFeedback; - ProgramInfo.OperatingState = Program.OperatingState; - ProgramInfo.RegistrationState = Program.RegistrationState; + public ProgramStatusFeedbacks(Program program) + { + ProgramInfo = new ProgramInfo(program.Number); - ProgramStartedFeedback = new BoolFeedback(() => Program.OperatingState == eProgramOperatingState.Start); - ProgramStartedFeedback.FireUpdate(); + Program = program; - ProgramStoppedFeedback = new BoolFeedback(() => Program.OperatingState == eProgramOperatingState.Stop); - ProgramStoppedFeedback.FireUpdate(); + ProgramInfo.OperatingState = Program.OperatingState; + ProgramInfo.RegistrationState = Program.RegistrationState; - ProgramRegisteredFeedback = - new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Register); - ProgramRegisteredFeedback.FireUpdate(); + ProgramStartedFeedback = new BoolFeedback(() => Program.OperatingState == eProgramOperatingState.Start); + ProgramStartedFeedback.FireUpdate(); - ProgramUnregisteredFeedback = - new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Unregister); - ProgramUnregisteredFeedback.FireUpdate(); + ProgramStoppedFeedback = new BoolFeedback(() => Program.OperatingState == eProgramOperatingState.Stop); + ProgramStoppedFeedback.FireUpdate(); + + ProgramRegisteredFeedback = + new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Register); + ProgramRegisteredFeedback.FireUpdate(); + + ProgramUnregisteredFeedback = + new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Unregister); + ProgramUnregisteredFeedback.FireUpdate(); ProgramNameFeedback = new StringFeedback(() => ProgramInfo.ProgramFile); CrestronDataBaseVersionFeedback = new StringFeedback(() => ProgramInfo.CrestronDb); EnvironmentVersionFeedback = new StringFeedback(() => ProgramInfo.Environment); - ProgramCompileTimeFeedback = new StringFeedback(() => ProgramInfo.CompileTime); - AggregatedProgramInfoFeedback = new StringFeedback(() => JsonConvert.SerializeObject(ProgramInfo)); + ProgramCompileTimeFeedback = new StringFeedback(() => ProgramInfo.CompileTime); + AggregatedProgramInfoFeedback = new StringFeedback(() => JsonConvert.SerializeObject(ProgramInfo)); - GetProgramInfo(); + GetProgramInfo(); + } + + /// + /// Retrieves information about a running program + /// + public void GetProgramInfo() + { + CrestronInvoke.BeginInvoke(GetProgramInfo); + } + + private void GetProgramInfo(object o) + { + Debug.LogMessage(LogEventLevel.Verbose, "Attempting to get program info for slot: {0}", Program.Number); + + string response = null; + + if (Program.RegistrationState == eProgramRegistrationState.Unregister || Program.OperatingState == eProgramOperatingState.Stop) + { + Debug.LogMessage(LogEventLevel.Verbose, "Program {0} not registered. Setting default values for program information.", + Program.Number); + + ProgramInfo = new ProgramInfo(Program.Number) + { + OperatingState = Program.OperatingState, + RegistrationState = Program.RegistrationState + }; + + return; } - /// - /// Retrieves information about a running program - /// - public void GetProgramInfo() + var success = CrestronConsole.SendControlSystemCommand( + string.Format("progcomments:{0}", Program.Number), ref response); + + if (!success) { - CrestronInvoke.BeginInvoke(GetProgramInfo); + Debug.LogMessage(LogEventLevel.Verbose, "Progcomments Attempt Unsuccessful for slot: {0}", Program.Number); + UpdateFeedbacks(); + return; } - private void GetProgramInfo(object o) + if (response.ToLower().Contains("bad or incomplete")) { - Debug.LogMessage(LogEventLevel.Verbose, "Attempting to get program info for slot: {0}", Program.Number); + Debug.LogMessage(LogEventLevel.Verbose, + "Program in slot {0} not running. Setting default ProgramInfo for slot: {0}", + Program.Number); - string response = null; - - if (Program.RegistrationState == eProgramRegistrationState.Unregister || Program.OperatingState == eProgramOperatingState.Stop) + // Assume no valid program info. Constructing a new object will wipe all properties + ProgramInfo = new ProgramInfo(Program.Number) { - Debug.LogMessage(LogEventLevel.Verbose, "Program {0} not registered. Setting default values for program information.", - Program.Number); - - ProgramInfo = new ProgramInfo(Program.Number) - { - OperatingState = Program.OperatingState, - RegistrationState = Program.RegistrationState - }; - - return; - } - - var success = CrestronConsole.SendControlSystemCommand( - string.Format("progcomments:{0}", Program.Number), ref response); - - if (!success) - { - Debug.LogMessage(LogEventLevel.Verbose, "Progcomments Attempt Unsuccessful for slot: {0}", Program.Number); - UpdateFeedbacks(); - return; - } - - if (response.ToLower().Contains("bad or incomplete")) - { - Debug.LogMessage(LogEventLevel.Verbose, - "Program in slot {0} not running. Setting default ProgramInfo for slot: {0}", - Program.Number); - - // Assume no valid program info. Constructing a new object will wipe all properties - ProgramInfo = new ProgramInfo(Program.Number) - { OperatingState = Program.OperatingState, - RegistrationState = Program.RegistrationState - }; + RegistrationState = Program.RegistrationState + }; - UpdateFeedbacks(); + UpdateFeedbacks(); - return; - } + return; + } - // Shared properteis - ProgramInfo.ProgramFile = ParseConsoleData(response, "Program File", ": ", "\n"); - ProgramInfo.CompilerRevision = ParseConsoleData(response, "Compiler Rev", ": ", "\n"); - ProgramInfo.CompileTime = ParseConsoleData(response, "Compiled On", ": ", "\n"); - ProgramInfo.Include4Dat = ParseConsoleData(response, "Include4.dat", ": ", "\n"); + // Shared properteis + ProgramInfo.ProgramFile = ParseConsoleData(response, "Program File", ": ", "\n"); + ProgramInfo.CompilerRevision = ParseConsoleData(response, "Compiler Rev", ": ", "\n"); + ProgramInfo.CompileTime = ParseConsoleData(response, "Compiled On", ": ", "\n"); + ProgramInfo.Include4Dat = ParseConsoleData(response, "Include4.dat", ": ", "\n"); - if (ProgramInfo.ProgramFile.Contains(".dll")) - { - // SSP Program - ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ": ", "\n"); - ProgramInfo.ApplicationName = ParseConsoleData(response, "Application Name", ": ", "\n"); - ProgramInfo.ProgramTool = ParseConsoleData(response, "Program Tool", ": ", "\n"); - ProgramInfo.MinFirmwareVersion = ParseConsoleData(response, "Min Firmware Version", ": ", - "\n"); - ProgramInfo.PlugInVersion = ParseConsoleData(response, "PlugInVersion", ": ", "\n"); + if (ProgramInfo.ProgramFile.Contains(".dll")) + { + // SSP Program + ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ": ", "\n"); + ProgramInfo.ApplicationName = ParseConsoleData(response, "Application Name", ": ", "\n"); + ProgramInfo.ProgramTool = ParseConsoleData(response, "Program Tool", ": ", "\n"); + ProgramInfo.MinFirmwareVersion = ParseConsoleData(response, "Min Firmware Version", ": ", + "\n"); + ProgramInfo.PlugInVersion = ParseConsoleData(response, "PlugInVersion", ": ", "\n"); ProgramInfo.ProgramFile += string.Format(" {0}.{1}.{2}", ProgramInfo.CompilerRevisionInfo.Major, @@ -659,101 +659,101 @@ namespace PepperDash.Essentials.Core.Monitoring ProgramInfo.CompilerRevisionInfo.Build); ProgramInfo.Environment = ProgramInfo.ProgramTool; - } - else if (ProgramInfo.ProgramFile.Contains(".smw")) - { - // SIMPL Windows Program - ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ":", "\n"); - ProgramInfo.SystemName = ParseConsoleData(response, "System Name", ": ", "\n"); - ProgramInfo.CrestronDb = ParseConsoleData(response, "CrestronDB", ": ", "\n"); - ProgramInfo.Environment = ParseConsoleData(response, "Source Env", ": ", "\n"); - ProgramInfo.Programmer = ParseConsoleData(response, "Programmer", ": ", "\n"); - } - Debug.LogMessage(LogEventLevel.Verbose, "Program info for slot {0} successfully updated", Program.Number); - - UpdateFeedbacks(); } - - private void UpdateFeedbacks() + else if (ProgramInfo.ProgramFile.Contains(".smw")) { - ProgramNameFeedback.FireUpdate(); - ProgramCompileTimeFeedback.FireUpdate(); - CrestronDataBaseVersionFeedback.FireUpdate(); - EnvironmentVersionFeedback.FireUpdate(); - - AggregatedProgramInfoFeedback.FireUpdate(); - - OnProgramInfoChanged(); + // SIMPL Windows Program + ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ":", "\n"); + ProgramInfo.SystemName = ParseConsoleData(response, "System Name", ": ", "\n"); + ProgramInfo.CrestronDb = ParseConsoleData(response, "CrestronDB", ": ", "\n"); + ProgramInfo.Environment = ParseConsoleData(response, "Source Env", ": ", "\n"); + ProgramInfo.Programmer = ParseConsoleData(response, "Programmer", ": ", "\n"); } + Debug.LogMessage(LogEventLevel.Verbose, "Program info for slot {0} successfully updated", Program.Number); - public void OnProgramInfoChanged() + UpdateFeedbacks(); + } + + private void UpdateFeedbacks() + { + ProgramNameFeedback.FireUpdate(); + ProgramCompileTimeFeedback.FireUpdate(); + CrestronDataBaseVersionFeedback.FireUpdate(); + EnvironmentVersionFeedback.FireUpdate(); + + AggregatedProgramInfoFeedback.FireUpdate(); + + OnProgramInfoChanged(); + } + + public void OnProgramInfoChanged() + { + //Debug.LogMessage(LogEventLevel.Debug, "Firing ProgramInfoChanged for slot: {0}", Program.Number); + var handler = ProgramInfoChanged; + if (handler != null) { - //Debug.LogMessage(LogEventLevel.Debug, "Firing ProgramInfoChanged for slot: {0}", Program.Number); - var handler = ProgramInfoChanged; - if (handler != null) - { - handler(this, new ProgramInfoEventArgs(ProgramInfo)); - } - } - - private string ParseConsoleData(string data, string line, string startString, string endString) - { - var outputData = ""; - - if (data.Length <= 0) return outputData; - - if (!data.Contains(line)) - { - return outputData; - } - - try - { - //Debug.LogMessage(LogEventLevel.Verbose, "ParseConsoleData Data: {0}, Line {1}, startStirng {2}, endString {3}", data, line, startString, endString); - var linePosition = data.IndexOf(line, StringComparison.Ordinal); - var startPosition = data.IndexOf(startString, linePosition, StringComparison.Ordinal) + - startString.Length; - var endPosition = data.IndexOf(endString, startPosition, StringComparison.Ordinal); - outputData = data.Substring(startPosition, endPosition - startPosition).Trim(); - //Debug.LogMessage(LogEventLevel.Verbose, "ParseConsoleData Return: {0}", outputData); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Error, "Error Parsing Console Data: {0}", e); - Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", e.StackTrace); - } - - return outputData; + handler(this, new ProgramInfoEventArgs(ProgramInfo)); } } + + private string ParseConsoleData(string data, string line, string startString, string endString) + { + var outputData = ""; + + if (data.Length <= 0) return outputData; + + if (!data.Contains(line)) + { + return outputData; + } + + try + { + //Debug.LogMessage(LogEventLevel.Verbose, "ParseConsoleData Data: {0}, Line {1}, startStirng {2}, endString {3}", data, line, startString, endString); + var linePosition = data.IndexOf(line, StringComparison.Ordinal); + var startPosition = data.IndexOf(startString, linePosition, StringComparison.Ordinal) + + startString.Length; + var endPosition = data.IndexOf(endString, startPosition, StringComparison.Ordinal); + outputData = data.Substring(startPosition, endPosition - startPosition).Trim(); + //Debug.LogMessage(LogEventLevel.Verbose, "ParseConsoleData Return: {0}", outputData); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Error, "Error Parsing Console Data: {0}", e); + Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", e.StackTrace); + } + + return outputData; + } } +} - /// - /// Class for serializing program slot information - /// - public class ProgramInfo - { - // Shared properties +/// +/// Class for serializing program slot information +/// +public class ProgramInfo +{ + // Shared properties - [JsonProperty("programNumber")] - public uint ProgramNumber { get; private set; } + [JsonProperty("programNumber")] + public uint ProgramNumber { get; private set; } - [JsonConverter(typeof (StringEnumConverter))] - [JsonProperty("operatingState")] - public eProgramOperatingState OperatingState { get; set; } + [JsonConverter(typeof (StringEnumConverter))] + [JsonProperty("operatingState")] + public eProgramOperatingState OperatingState { get; set; } - [JsonConverter(typeof (StringEnumConverter))] - [JsonProperty("registrationState")] - public eProgramRegistrationState RegistrationState { get; set; } + [JsonConverter(typeof (StringEnumConverter))] + [JsonProperty("registrationState")] + public eProgramRegistrationState RegistrationState { get; set; } - [JsonProperty("programFile")] - public string ProgramFile { get; set; } + [JsonProperty("programFile")] + public string ProgramFile { get; set; } - [JsonProperty("friendlyName")] - public string FriendlyName { get; set; } + [JsonProperty("friendlyName")] + public string FriendlyName { get; set; } - [JsonProperty("compilerRevision")] - public string CompilerRevision { get; set; } + [JsonProperty("compilerRevision")] + public string CompilerRevision { get; set; } [JsonIgnore] public Version CompilerRevisionInfo @@ -764,68 +764,67 @@ namespace PepperDash.Essentials.Core.Monitoring } } - [JsonProperty("compileTime")] - public string CompileTime { get; set; } + [JsonProperty("compileTime")] + public string CompileTime { get; set; } - [JsonProperty("include4Dat")] - public string Include4Dat { get; set; } + [JsonProperty("include4Dat")] + public string Include4Dat { get; set; } - // SIMPL Windows properties - [JsonProperty("systemName")] - public string SystemName { get; set; } + // SIMPL Windows properties + [JsonProperty("systemName")] + public string SystemName { get; set; } - [JsonProperty("crestronDb")] - public string CrestronDb { get; set; } + [JsonProperty("crestronDb")] + public string CrestronDb { get; set; } - [JsonProperty("environment")] - public string Environment { get; set; } + [JsonProperty("environment")] + public string Environment { get; set; } - [JsonProperty("programmer")] - public string Programmer { get; set; } + [JsonProperty("programmer")] + public string Programmer { get; set; } - // SSP Properties - [JsonProperty("applicationName")] - public string ApplicationName { get; set; } + // SSP Properties + [JsonProperty("applicationName")] + public string ApplicationName { get; set; } - [JsonProperty("programTool")] - public string ProgramTool { get; set; } + [JsonProperty("programTool")] + public string ProgramTool { get; set; } - [JsonProperty("minFirmwareVersion")] - public string MinFirmwareVersion { get; set; } + [JsonProperty("minFirmwareVersion")] + public string MinFirmwareVersion { get; set; } - [JsonProperty("plugInVersion")] - public string PlugInVersion { get; set; } + [JsonProperty("plugInVersion")] + public string PlugInVersion { get; set; } - public ProgramInfo(uint number) - { - ProgramNumber = number; - - ProgramFile = ""; - FriendlyName = ""; - CompilerRevision = ""; - CompileTime = ""; - Include4Dat = ""; - - SystemName = ""; - CrestronDb = ""; - Environment = ""; - Programmer = ""; - - ApplicationName = ""; - ProgramTool = ""; - MinFirmwareVersion = ""; - PlugInVersion = ""; - } - } - - public class ProgramInfoEventArgs : EventArgs + public ProgramInfo(uint number) { - public ProgramInfo ProgramInfo; + ProgramNumber = number; - public ProgramInfoEventArgs(ProgramInfo progInfo) - { - ProgramInfo = progInfo; - } + ProgramFile = ""; + FriendlyName = ""; + CompilerRevision = ""; + CompileTime = ""; + Include4Dat = ""; + + SystemName = ""; + CrestronDb = ""; + Environment = ""; + Programmer = ""; + + ApplicationName = ""; + ProgramTool = ""; + MinFirmwareVersion = ""; + PlugInVersion = ""; + } +} + +public class ProgramInfoEventArgs : EventArgs +{ + public ProgramInfo ProgramInfo; + + public ProgramInfoEventArgs(ProgramInfo progInfo) + { + ProgramInfo = progInfo; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs b/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs index aca4f008..352d7cef 100644 --- a/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs +++ b/src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs @@ -1,187 +1,186 @@ using PepperDash.Core; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents an abstract controller device for a partition dividing rooms that are combinable +/// +/// In Auto mode, it can use a partition sensor to automatically determine whether the partition is present. +/// +/// In Manual mode it accepts user input to tell it whether the partition is present. +/// +public class EssentialsPartitionController : IPartitionController { - /// - /// Represents an abstract controller device for a partition dividing rooms that are combinable - /// - /// In Auto mode, it can use a partition sensor to automatically determine whether the partition is present. - /// - /// In Manual mode it accepts user input to tell it whether the partition is present. - /// - public class EssentialsPartitionController : IPartitionController + private IPartitionStateProvider _partitionSensor; + + public bool IsInAutoMode { get; private set; } + + private bool _partitionPresent; + + public bool PartitionPresent { - private IPartitionStateProvider _partitionSensor; - - public bool IsInAutoMode { get; private set; } - - private bool _partitionPresent; - - public bool PartitionPresent + get { - get + if (IsInAutoMode) { - if (IsInAutoMode) - { - return _partitionSensor.PartitionPresentFeedback.BoolValue; - } - - return _partitionPresent; + return _partitionSensor.PartitionPresentFeedback.BoolValue; } - set + + return _partitionPresent; + } + set + { + if (_partitionPresent == value) { - if (_partitionPresent == value) - { - return; - } + return; + } - _partitionPresent = value; + _partitionPresent = value; - if (PartitionPresentFeedback != null) - { - PartitionPresentFeedback.FireUpdate(); - } + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.FireUpdate(); } } + } - public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List adjacentRoomKeys) + public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List adjacentRoomKeys) + { + Key = key; + + Name = name; + + AdjacentRoomKeys = adjacentRoomKeys; + + if (sensor != null) { - Key = key; + _partitionSensor = sensor; - Name = name; - - AdjacentRoomKeys = adjacentRoomKeys; - - if (sensor != null) + if (!defaultToManualMode) { - _partitionSensor = sensor; - - if (!defaultToManualMode) - { - SetAutoMode(); - } - else - { - SetManualMode(); - } + SetAutoMode(); } else { SetManualMode(); } - - PartitionPresentFeedback.FireUpdate(); } - - private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + else { - if (IsInAutoMode) - { - PartitionPresent = e.BoolValue; - } + SetManualMode(); } - #region IPartitionController Members - - public List AdjacentRoomKeys { get; private set; } - - public void SetAutoMode() - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Auto Mode", this); - - IsInAutoMode = true; - if (PartitionPresentFeedback != null) - { - PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue); - } - else - { - PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionPresentFeedback.BoolValue); - } - - if (_partitionSensor != null) - { - _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; - _partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; - PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue; - } - - PartitionPresentFeedback.FireUpdate(); - } - - public void SetManualMode() - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Manual Mode", this); - - IsInAutoMode = false; - if (PartitionPresentFeedback != null) - { - PartitionPresentFeedback.SetValueFunc(() => _partitionPresent); - } - else - { - PartitionPresentFeedback = new BoolFeedback(() => _partitionPresent); - } - - if (_partitionSensor != null) - { - _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; - PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue; - } - - PartitionPresentFeedback.FireUpdate(); - } - - - public void SetPartitionStatePresent() - { - if (!IsInAutoMode) - { - PartitionPresent = true; - PartitionPresentFeedback.FireUpdate(); - } - } - - public void SetPartitionStateNotPresent() - { - if (!IsInAutoMode) - { - PartitionPresent = false; - PartitionPresentFeedback.FireUpdate(); - } - } - - public void ToggglePartitionState() - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Toggling Partition State for {Key}", this); - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"IsInAutoMode: {IsInAutoMode}", this); - - if (!IsInAutoMode) - { - PartitionPresent = !PartitionPresent; - PartitionPresentFeedback.FireUpdate(); - } - } - - #endregion - - #region IPartitionStateProvider Members - - public BoolFeedback PartitionPresentFeedback { get; private set; } - - #endregion - - #region IKeyName Members - - public string Name { get; private set; } - - #endregion - - #region IKeyed Members - - public string Key { get; private set; } - - #endregion + PartitionPresentFeedback.FireUpdate(); } + + private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + if (IsInAutoMode) + { + PartitionPresent = e.BoolValue; + } + } + + #region IPartitionController Members + + public List AdjacentRoomKeys { get; private set; } + + public void SetAutoMode() + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Auto Mode", this); + + IsInAutoMode = true; + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue); + } + else + { + PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionPresentFeedback.BoolValue); + } + + if (_partitionSensor != null) + { + _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; + _partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; + PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue; + } + + PartitionPresentFeedback.FireUpdate(); + } + + public void SetManualMode() + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Manual Mode", this); + + IsInAutoMode = false; + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.SetValueFunc(() => _partitionPresent); + } + else + { + PartitionPresentFeedback = new BoolFeedback(() => _partitionPresent); + } + + if (_partitionSensor != null) + { + _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; + PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue; + } + + PartitionPresentFeedback.FireUpdate(); + } + + + public void SetPartitionStatePresent() + { + if (!IsInAutoMode) + { + PartitionPresent = true; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void SetPartitionStateNotPresent() + { + if (!IsInAutoMode) + { + PartitionPresent = false; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void ToggglePartitionState() + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Toggling Partition State for {Key}", this); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"IsInAutoMode: {IsInAutoMode}", this); + + if (!IsInAutoMode) + { + PartitionPresent = !PartitionPresent; + PartitionPresentFeedback.FireUpdate(); + } + } + + #endregion + + #region IPartitionStateProvider Members + + public BoolFeedback PartitionPresentFeedback { get; private set; } + + #endregion + + #region IKeyName Members + + public string Name { get; private set; } + + #endregion + + #region IKeyed Members + + public string Key { get; private set; } + + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs b/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs index 418da80c..47c04a4d 100644 --- a/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs +++ b/src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs @@ -2,39 +2,38 @@ using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Describes the functionality of a device that senses and provides partition state +/// +public interface IPartitionStateProvider : IKeyName { - /// - /// Describes the functionality of a device that senses and provides partition state - /// - public interface IPartitionStateProvider : IKeyName - { - [JsonIgnore] - BoolFeedback PartitionPresentFeedback { get; } + [JsonIgnore] + BoolFeedback PartitionPresentFeedback { get; } - [JsonProperty("partitionPresent")] - bool PartitionPresent { get; } - } + [JsonProperty("partitionPresent")] + bool PartitionPresent { get; } +} - /// - /// Describes the functionality of a device that can provide partition state either manually via user input or optionally via a sensor state - /// - public interface IPartitionController : IPartitionStateProvider - { - [JsonProperty("adjacentRoomKeys")] - List AdjacentRoomKeys { get; } +/// +/// Describes the functionality of a device that can provide partition state either manually via user input or optionally via a sensor state +/// +public interface IPartitionController : IPartitionStateProvider +{ + [JsonProperty("adjacentRoomKeys")] + List AdjacentRoomKeys { get; } - [JsonProperty("isInAutoMode")] - bool IsInAutoMode { get; } + [JsonProperty("isInAutoMode")] + bool IsInAutoMode { get; } - void SetPartitionStatePresent(); + void SetPartitionStatePresent(); - void SetPartitionStateNotPresent(); + void SetPartitionStateNotPresent(); - void ToggglePartitionState(); + void ToggglePartitionState(); - void SetManualMode(); + void SetManualMode(); - void SetAutoMode(); - } + void SetAutoMode(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs index caee2dcd..116c4aa1 100644 --- a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs @@ -2,18 +2,28 @@ using PepperDash.Essentials.Core.Config; using System.Collections.Generic; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + +/// +/// Defines a class that is capable of loading custom plugin device types +/// +public interface IPluginDeviceFactory : IDeviceFactory +{ /// - /// Defines a class that is capable of loading custom plugin device types + /// Required to define the minimum version for Essentials in the format xx.yy.zz /// - public interface IPluginDeviceFactory : IDeviceFactory - { - /// - /// Required to define the minimum version for Essentials in the format xx.yy.zz - /// - string MinimumEssentialsFrameworkVersion { get; } - } + string MinimumEssentialsFrameworkVersion { get; } } - +/// +/// Defines a factory for creating plugin development devices, including support for specific framework versions. +/// +/// This interface extends to provide additional functionality +/// specific to plugin development, such as access to supported framework versions. +public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory +{ + /// + /// Gets a list of framework versions that are essential for development. + /// + List DevelopmentEssentialsFrameworkVersions { get; } +} diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs index bf273678..2f0839da 100644 --- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs +++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs @@ -181,7 +181,7 @@ public static class PluginLoader /// this method updates its associated assembly. If no matching name is found, the method does nothing. /// The name used to identify the assembly. This value is case-sensitive and must not be null or empty. /// The assembly to associate with the specified name. This value must not be null. - public static void SetEssentialsAssembly(string name, Assembly assembly) + public static void AddLoadedAssembly(string name, Assembly assembly) { var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name)); @@ -717,22 +717,23 @@ public static class PluginLoader foreach (var type in types) { try - { - if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract) - { - var plugin = - (IPluginDeviceFactory)Activator.CreateInstance(type); - LoadCustomPlugin(plugin, loadedAssembly); - } - } + { + if (!typeof(IPluginDeviceFactory).IsAssignableFrom(type) || type.IsAbstract) + { + continue; + } + + var plugin = (IPluginDeviceFactory)Activator.CreateInstance(type); + LoadCustomPlugin(plugin, loadedAssembly); + } catch (NotSupportedException) { //this happens for dlls that aren't PD dlls, like ports of Mono classes into S#. Swallowing. } - catch (Exception e) + catch (Exception ex) { - Debug.LogMessage(LogEventLevel.Error, "Load Plugin not found. {0}.{2} is not a plugin factory. Exception: {1}", - loadedAssembly.Name, e.Message, type.Name); + Debug.LogError("Load Plugin not found. {assemblyName}.{typeName} is not a plugin factory. Exception: {exception}", + loadedAssembly.Name, type.Name, ex.Message); continue; } } @@ -814,7 +815,11 @@ public static class PluginLoader /// The assembly associated with the plugin being loaded. This is used for logging and tracking purposes. private static void LoadCustomPlugin(IPluginDeviceFactory deviceFactory, LoadedAssembly loadedAssembly) { - var passed = Global.IsRunningMinimumVersionOrHigher(deviceFactory.MinimumEssentialsFrameworkVersion); + var developmentDeviceFactory = deviceFactory as IPluginDevelopmentDeviceFactory; + + var passed = developmentDeviceFactory != null ? Global.IsRunningDevelopmentVersion + (developmentDeviceFactory.DevelopmentEssentialsFrameworkVersions, developmentDeviceFactory.MinimumEssentialsFrameworkVersion) + : Global.IsRunningMinimumVersionOrHigher(deviceFactory.MinimumEssentialsFrameworkVersion); if (!passed) { diff --git a/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs b/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs index 42059c78..7346981b 100644 --- a/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs +++ b/src/PepperDash.Essentials.Core/Presets/DevicePresets.cs @@ -12,203 +12,40 @@ using PepperDash.Core; using PepperDash.Core.WebApi.Presets; using Serilog.Events; -namespace PepperDash.Essentials.Core.Presets +namespace PepperDash.Essentials.Core.Presets; + +/// +/// Class that represents the model behind presets display +/// +public class DevicePresetsModel : Device { + public delegate void PresetRecalledCallback(ISetTopBoxNumericKeypad device, string channel); + + public delegate void PresetsSavedCallback(List presets); + + private readonly CCriticalSection _fileOps = new CCriticalSection(); + private readonly bool _initSuccess; + + private readonly ISetTopBoxNumericKeypad _setTopBox; + /// - /// Class that represents the model behind presets display + /// The methods on the STB device to call when dialing /// - public class DevicePresetsModel : Device + private Dictionary> _dialFunctions; + + private bool _dialIsRunning; + private Action _enterFunction; + private string _filePath; + + public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) + : this(key, fileName) { - public delegate void PresetRecalledCallback(ISetTopBoxNumericKeypad device, string channel); - - public delegate void PresetsSavedCallback(List presets); - - private readonly CCriticalSection _fileOps = new CCriticalSection(); - private readonly bool _initSuccess; - - private readonly ISetTopBoxNumericKeypad _setTopBox; - - /// - /// The methods on the STB device to call when dialing - /// - private Dictionary> _dialFunctions; - - private bool _dialIsRunning; - private Action _enterFunction; - private string _filePath; - - public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) - : this(key, fileName) + try { - try - { - _setTopBox = setTopBox; + _setTopBox = setTopBox; - // Grab the digit functions from the device - // If any fail, the whole thing fails peacefully - _dialFunctions = new Dictionary>(10) - { - {'1', setTopBox.Digit1}, - {'2', setTopBox.Digit2}, - {'3', setTopBox.Digit3}, - {'4', setTopBox.Digit4}, - {'5', setTopBox.Digit5}, - {'6', setTopBox.Digit6}, - {'7', setTopBox.Digit7}, - {'8', setTopBox.Digit8}, - {'9', setTopBox.Digit9}, - {'0', setTopBox.Digit0}, - {'-', setTopBox.Dash} - }; - } - catch - { - Debug.LogMessage(LogEventLevel.Information, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); - _dialFunctions = null; - return; - } - - _enterFunction = setTopBox.KeypadEnter; - } - - public DevicePresetsModel(string key, string fileName) : base(key) - { - PulseTime = 150; - DigitSpacingMs = 150; - - UseLocalImageStorage = true; - - ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - ImagesPathPrefix = @"/presets/images.zip/"; - ListPathPrefix = @"/html/presets/lists/"; - - SetFileName(fileName); - - _initSuccess = true; - } - - public event PresetRecalledCallback PresetRecalled; - public event PresetsSavedCallback PresetsSaved; - - public int PulseTime { get; set; } - public int DigitSpacingMs { get; set; } - public bool PresetsAreLoaded { get; private set; } - - public List PresetsList { get; private set; } - - public int Count - { - get { return PresetsList != null ? PresetsList.Count : 0; } - } - - public bool UseLocalImageStorage { get; set; } - public string ImagesLocalHostPrefix { get; set; } - public string ImagesPathPrefix { get; set; } - public string ListPathPrefix { get; set; } - public event EventHandler PresetsLoaded; - - - public void SetFileName(string path) - { - _filePath = ListPathPrefix + path; - - Debug.LogMessage(LogEventLevel.Verbose, this, "Setting presets file path to {0}", _filePath); - LoadChannels(); - } - - public void LoadChannels() - { - try - { - _fileOps.Enter(); - - Debug.LogMessage(LogEventLevel.Verbose, this, "Loading presets from {0}", _filePath); - PresetsAreLoaded = false; - try - { - var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); - Name = pl.Name; - PresetsList = pl.Channels; - - Debug.LogMessage(LogEventLevel.Verbose, this, "Loaded {0} presets", PresetsList.Count); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, - "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", - _filePath, e.Message); - // Just save a default empty list - PresetsList = new List(); - } - PresetsAreLoaded = true; - - var handler = PresetsLoaded; - if (handler != null) - { - handler(this, EventArgs.Empty); - } - } - finally - { - _fileOps.Leave(); - } - } - - public void Dial(int presetNum) - { - if (presetNum <= PresetsList.Count) - { - Dial(PresetsList[presetNum - 1].Channel); - } - } - - public void Dial(string chanNum) - { - if (_dialIsRunning || !_initSuccess) - { - return; - } - if (_dialFunctions == null) - { - Debug.LogMessage(LogEventLevel.Debug, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key); - return; - } - - _dialIsRunning = true; - CrestronInvoke.BeginInvoke(o => - { - foreach (var c in chanNum.ToCharArray()) - { - if (_dialFunctions.ContainsKey(c)) - { - Pulse(_dialFunctions[c]); - } - CrestronEnvironment.Sleep(DigitSpacingMs); - } - - if (_enterFunction != null) - { - Pulse(_enterFunction); - } - _dialIsRunning = false; - }); - - if (_setTopBox == null) return; - - OnPresetRecalled(_setTopBox, chanNum); - } - - public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) - { - if (presetNum <= PresetsList.Count) - { - Dial(PresetsList[presetNum - 1].Channel, setTopBox); - } - } - - public void Dial(string chanNum, ISetTopBoxNumericKeypad setTopBox) - { + // Grab the digit functions from the device + // If any fail, the whole thing fails peacefully _dialFunctions = new Dictionary>(10) { {'1', setTopBox.Digit1}, @@ -223,83 +60,245 @@ namespace PepperDash.Essentials.Core.Presets {'0', setTopBox.Digit0}, {'-', setTopBox.Dash} }; - - _enterFunction = setTopBox.KeypadEnter; - - OnPresetRecalled(setTopBox, chanNum); - - Dial(chanNum); + } + catch + { + Debug.LogMessage(LogEventLevel.Information, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); + _dialFunctions = null; + return; } - private void OnPresetRecalled(ISetTopBoxNumericKeypad setTopBox, string channel) + _enterFunction = setTopBox.KeypadEnter; + } + + public DevicePresetsModel(string key, string fileName) : base(key) + { + PulseTime = 150; + DigitSpacingMs = 150; + + UseLocalImageStorage = true; + + ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + ImagesPathPrefix = @"/presets/images.zip/"; + ListPathPrefix = @"/html/presets/lists/"; + + SetFileName(fileName); + + _initSuccess = true; + } + + public event PresetRecalledCallback PresetRecalled; + public event PresetsSavedCallback PresetsSaved; + + public int PulseTime { get; set; } + public int DigitSpacingMs { get; set; } + public bool PresetsAreLoaded { get; private set; } + + public List PresetsList { get; private set; } + + public int Count + { + get { return PresetsList != null ? PresetsList.Count : 0; } + } + + public bool UseLocalImageStorage { get; set; } + public string ImagesLocalHostPrefix { get; set; } + public string ImagesPathPrefix { get; set; } + public string ListPathPrefix { get; set; } + public event EventHandler PresetsLoaded; + + + public void SetFileName(string path) + { + _filePath = ListPathPrefix + path; + + Debug.LogMessage(LogEventLevel.Verbose, this, "Setting presets file path to {0}", _filePath); + LoadChannels(); + } + + public void LoadChannels() + { + try { - var handler = PresetRecalled; + _fileOps.Enter(); - if (handler == null) - { - return; - } - - handler(setTopBox, channel); - } - - public void UpdatePreset(int index, PresetChannel preset) - { - if (index >= PresetsList.Count) - { - return; - } - - PresetsList[index] = preset; - - SavePresets(); - - OnPresetsSaved(); - } - - public void UpdatePresets(List presets) - { - PresetsList = presets; - - SavePresets(); - - OnPresetsSaved(); - } - - private void SavePresets() - { + Debug.LogMessage(LogEventLevel.Verbose, this, "Loading presets from {0}", _filePath); + PresetsAreLoaded = false; try { - _fileOps.Enter(); - var pl = new PresetsList {Channels = PresetsList, Name = Name}; - var json = JsonConvert.SerializeObject(pl, Formatting.Indented); + var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); + Name = pl.Name; + PresetsList = pl.Channels; - using (var file = File.Open(_filePath, FileMode.Truncate)) - { - file.Write(json, Encoding.UTF8); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Loaded {0} presets", PresetsList.Count); } - finally + catch (Exception e) { - _fileOps.Leave(); + Debug.LogMessage(LogEventLevel.Verbose, this, + "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", + _filePath, e.Message); + // Just save a default empty list + PresetsList = new List(); + } + PresetsAreLoaded = true; + + var handler = PresetsLoaded; + if (handler != null) + { + handler(this, EventArgs.Empty); } - } - - private void OnPresetsSaved() + finally { - var handler = PresetsSaved; - - if (handler == null) return; - - handler(PresetsList); - } - - private void Pulse(Action act) - { - act(true); - CrestronEnvironment.Sleep(PulseTime); - act(false); + _fileOps.Leave(); } } + + public void Dial(int presetNum) + { + if (presetNum <= PresetsList.Count) + { + Dial(PresetsList[presetNum - 1].Channel); + } + } + + public void Dial(string chanNum) + { + if (_dialIsRunning || !_initSuccess) + { + return; + } + if (_dialFunctions == null) + { + Debug.LogMessage(LogEventLevel.Debug, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key); + return; + } + + _dialIsRunning = true; + CrestronInvoke.BeginInvoke(o => + { + foreach (var c in chanNum.ToCharArray()) + { + if (_dialFunctions.ContainsKey(c)) + { + Pulse(_dialFunctions[c]); + } + CrestronEnvironment.Sleep(DigitSpacingMs); + } + + if (_enterFunction != null) + { + Pulse(_enterFunction); + } + _dialIsRunning = false; + }); + + if (_setTopBox == null) return; + + OnPresetRecalled(_setTopBox, chanNum); + } + + public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) + { + if (presetNum <= PresetsList.Count) + { + Dial(PresetsList[presetNum - 1].Channel, setTopBox); + } + } + + public void Dial(string chanNum, ISetTopBoxNumericKeypad setTopBox) + { + _dialFunctions = new Dictionary>(10) + { + {'1', setTopBox.Digit1}, + {'2', setTopBox.Digit2}, + {'3', setTopBox.Digit3}, + {'4', setTopBox.Digit4}, + {'5', setTopBox.Digit5}, + {'6', setTopBox.Digit6}, + {'7', setTopBox.Digit7}, + {'8', setTopBox.Digit8}, + {'9', setTopBox.Digit9}, + {'0', setTopBox.Digit0}, + {'-', setTopBox.Dash} + }; + + _enterFunction = setTopBox.KeypadEnter; + + OnPresetRecalled(setTopBox, chanNum); + + Dial(chanNum); + } + + private void OnPresetRecalled(ISetTopBoxNumericKeypad setTopBox, string channel) + { + var handler = PresetRecalled; + + if (handler == null) + { + return; + } + + handler(setTopBox, channel); + } + + public void UpdatePreset(int index, PresetChannel preset) + { + if (index >= PresetsList.Count) + { + return; + } + + PresetsList[index] = preset; + + SavePresets(); + + OnPresetsSaved(); + } + + public void UpdatePresets(List presets) + { + PresetsList = presets; + + SavePresets(); + + OnPresetsSaved(); + } + + private void SavePresets() + { + try + { + _fileOps.Enter(); + var pl = new PresetsList {Channels = PresetsList, Name = Name}; + var json = JsonConvert.SerializeObject(pl, Formatting.Indented); + + using (var file = File.Open(_filePath, FileMode.Truncate)) + { + file.Write(json, Encoding.UTF8); + } + } + finally + { + _fileOps.Leave(); + } + + } + + private void OnPresetsSaved() + { + var handler = PresetsSaved; + + if (handler == null) return; + + handler(PresetsList); + } + + private void Pulse(Action act) + { + act(true); + CrestronEnvironment.Sleep(PulseTime); + act(false); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs b/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs index a43a7a2c..bae583de 100644 --- a/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs +++ b/src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs @@ -6,15 +6,15 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.Presets -{ +namespace PepperDash.Essentials.Core.Presets; + public class DevicePresetsView { public bool ShowNumbers { get; set; } public bool ShowName { get; set; } public bool ShowIcon { get; set; } - public SubpageReferenceList SRL { get; private set; } + public SubpageReferenceList SRL { get; private set; } public DevicePresetsModel Model { get; private set; } public DevicePresetsView(BasicTriListWithSmartObject tl, DevicePresetsModel model) @@ -56,5 +56,4 @@ namespace PepperDash.Essentials.Core.Presets Detach(); Attach(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/PresetBase.cs b/src/PepperDash.Essentials.Core/Presets/PresetBase.cs index 1eaf7739..8aff8447 100644 --- a/src/PepperDash.Essentials.Core/Presets/PresetBase.cs +++ b/src/PepperDash.Essentials.Core/Presets/PresetBase.cs @@ -8,34 +8,33 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Presets -{ - public class PresetBase - { - [JsonProperty("id")] - public int ID { get; set; } - /// - /// Used to store the name of the preset - /// - [JsonProperty("description")] - public string Description { get; set; } - /// - /// Indicates if the preset is defined(stored) in the codec - /// - [JsonProperty("defined")] - public bool Defined { get; set; } - /// - /// Indicates if the preset has the capability to be defined - /// - [JsonProperty("isDefinable")] - public bool IsDefinable { get; set; } +namespace PepperDash.Essentials.Core.Presets; - public PresetBase(int id, string description, bool def, bool isDef) - { - ID = id; - Description = description; - Defined = def; - IsDefinable = isDef; - } +public class PresetBase +{ + [JsonProperty("id")] + public int ID { get; set; } + /// + /// Used to store the name of the preset + /// + [JsonProperty("description")] + public string Description { get; set; } + /// + /// Indicates if the preset is defined(stored) in the codec + /// + [JsonProperty("defined")] + public bool Defined { get; set; } + /// + /// Indicates if the preset has the capability to be defined + /// + [JsonProperty("isDefinable")] + public bool IsDefinable { get; set; } + + public PresetBase(int id, string description, bool def, bool isDef) + { + ID = id; + Description = description; + Defined = def; + IsDefinable = isDef; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs b/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs index c10ba75d..a2c8423f 100644 --- a/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs +++ b/src/PepperDash.Essentials.Core/Presets/PresetChannel.cs @@ -7,8 +7,8 @@ using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Presets -{ +namespace PepperDash.Essentials.Core.Presets; + public class PresetChannel { @@ -29,5 +29,4 @@ namespace PepperDash.Essentials.Core.Presets [JsonProperty(Required = Required.Always, PropertyName = "channels")] public List Channels { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs b/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs index c4349414..dc63e0ce 100644 --- a/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs +++ b/src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs @@ -10,8 +10,8 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Presets -{ +namespace PepperDash.Essentials.Core.Presets; + public class PresetsListSubpageReferenceListItem : SubpageReferenceListItem { DevicePresetsView View; @@ -46,5 +46,4 @@ namespace PepperDash.Essentials.Core.Presets var icon = View.ShowIcon ? url : ""; Owner.StringInputSig(Index, 3).StringValue = icon; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs b/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs index 596c5921..b1e75164 100644 --- a/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs +++ b/src/PepperDash.Essentials.Core/Queues/ComsMessage.cs @@ -1,73 +1,72 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +/// +/// IBasicCommunication Message for IQueue +/// +public class ComsMessage : IQueueMessage { + private readonly byte[] _bytes; + private readonly IBasicCommunication _coms; + private readonly string _string; + private readonly bool _isByteMessage; + /// - /// IBasicCommunication Message for IQueue + /// Constructor for a string message /// - public class ComsMessage : IQueueMessage + /// IBasicCommunication to send the message + /// Message to send + public ComsMessage(IBasicCommunication coms, string message) { - private readonly byte[] _bytes; - private readonly IBasicCommunication _coms; - private readonly string _string; - private readonly bool _isByteMessage; + Validate(coms, message); + _coms = coms; + _string = message; + } - /// - /// Constructor for a string message - /// - /// IBasicCommunication to send the message - /// Message to send - public ComsMessage(IBasicCommunication coms, string message) + /// + /// Constructor for a byte message + /// + /// IBasicCommunication to send the message + /// Message to send + public ComsMessage(IBasicCommunication coms, byte[] message) + { + Validate(coms, message); + _coms = coms; + _bytes = message; + _isByteMessage = true; + } + + private void Validate(IBasicCommunication coms, object message) + { + if (coms == null) + throw new ArgumentNullException("coms"); + + if (message == null) + throw new ArgumentNullException("message"); + } + + /// + /// Dispatchs the string/byte[] to the IBasicCommunication specified + /// + public void Dispatch() + { + if (_isByteMessage) { - Validate(coms, message); - _coms = coms; - _string = message; + _coms.SendBytes(_bytes); } - - /// - /// Constructor for a byte message - /// - /// IBasicCommunication to send the message - /// Message to send - public ComsMessage(IBasicCommunication coms, byte[] message) + else { - Validate(coms, message); - _coms = coms; - _bytes = message; - _isByteMessage = true; - } - - private void Validate(IBasicCommunication coms, object message) - { - if (coms == null) - throw new ArgumentNullException("coms"); - - if (message == null) - throw new ArgumentNullException("message"); - } - - /// - /// Dispatchs the string/byte[] to the IBasicCommunication specified - /// - public void Dispatch() - { - if (_isByteMessage) - { - _coms.SendBytes(_bytes); - } - else - { - _coms.SendText(_string); - } - } - - /// - /// Shows either the byte[] or string to be sent - /// - public override string ToString() - { - return _bytes != null ? _bytes.ToString() : _string; + _coms.SendText(_string); } } + + /// + /// Shows either the byte[] or string to be sent + /// + public override string ToString() + { + return _bytes != null ? _bytes.ToString() : _string; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs b/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs index 74b406fc..8cb26524 100644 --- a/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs +++ b/src/PepperDash.Essentials.Core/Queues/GenericQueue.cs @@ -6,265 +6,264 @@ using PepperDash.Core; using Serilog.Events; using Thread = Crestron.SimplSharpPro.CrestronThread.Thread; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +/// +/// Threadsafe processing of queued items with pacing if required +/// +public class GenericQueue : IQueue { + private readonly string _key; + protected readonly ConcurrentQueue _queue; + protected readonly Thread _worker; + protected readonly CEvent _waitHandle = new CEvent(); + + private bool _delayEnabled; + private int _delayTime; + + private const Thread.eThreadPriority _defaultPriority = Thread.eThreadPriority.MediumPriority; + /// - /// Threadsafe processing of queued items with pacing if required + /// If the instance has been disposed. /// - public class GenericQueue : IQueue + public bool Disposed { get; private set; } + + /// + /// Returns the capacity of the CrestronQueue (fixed Size property) + /// + public int QueueCapacity { - private readonly string _key; - protected readonly ConcurrentQueue _queue; - protected readonly Thread _worker; - protected readonly CEvent _waitHandle = new CEvent(); - - private bool _delayEnabled; - private int _delayTime; - - private const Thread.eThreadPriority _defaultPriority = Thread.eThreadPriority.MediumPriority; - - /// - /// If the instance has been disposed. - /// - public bool Disposed { get; private set; } - - /// - /// Returns the capacity of the CrestronQueue (fixed Size property) - /// - public int QueueCapacity + get { - get - { - return int.MaxValue; - } - } - - /// - /// Returns the number of elements currently in the CrestronQueue - /// - public int QueueCount - { - get - { - return _queue.Count; - } - } - - /// - /// Constructor with no thread priority - /// - /// - public GenericQueue(string key) - : this(key, _defaultPriority, 0, 0) - { - } - - /// - /// Constructor with queue size - /// - /// - /// Fixed size for the queue to hold - public GenericQueue(string key, int capacity) - : this(key, _defaultPriority, capacity, 0) - { - } - - /// - /// Constructor for generic queue with no pacing - /// - /// Key - /// Pacing in ms between actions - public GenericQueue(int pacing, string key) - : this(key, _defaultPriority, 0, pacing) - { - } - - /// - /// Constructor with pacing and capacity - /// - /// - /// - /// - public GenericQueue(string key, int pacing, int capacity) - : this(key, _defaultPriority, capacity, pacing) - { - } - - /// - /// Constructor with pacing and priority - /// - /// - /// - /// - public GenericQueue(string key, int pacing, Thread.eThreadPriority priority) - : this(key, priority, 0, pacing) - { - } - - /// - /// Constructor with pacing, priority and capacity - /// - /// - /// - /// - public GenericQueue(string key, Thread.eThreadPriority priority, int capacity) - : this(key, priority, capacity, 0) - { - } - - /// - /// Constructor with pacing, priority and capacity - /// - /// - /// - /// - /// - public GenericQueue(string key, int pacing, Thread.eThreadPriority priority, int capacity) - : this(key, priority, capacity, pacing) - { - } - - /// - /// Constructor for generic queue with no pacing - /// - /// Key - /// - /// - /// - protected GenericQueue(string key, Thread.eThreadPriority priority, int capacity, int pacing) - { - _key = key; - int cap = 25; // sets default - if (capacity > 0) - { - cap = capacity; // overrides default - } - - _queue = new ConcurrentQueue(); - _worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running) - { - Priority = priority, - Name = _key - }; - - SetDelayValues(pacing); - } - - private void SetDelayValues(int pacing) - { - _delayEnabled = pacing > 0; - _delayTime = pacing; - - CrestronEnvironment.ProgramStatusEventHandler += programEvent => - { - if (programEvent != eProgramStatusEventType.Stopping) - return; - - Dispose(true); - }; - } - - /// - /// Thread callback - /// - /// The action used to process dequeued items - /// Null when the thread is exited - private object ProcessQueue(object obj) - { - while (true) - { - if (_queue.TryDequeue(out var item) && item == null) - break; - - if (item != null) - { - try - { - //Debug.LogMessage(LogEventLevel.Verbose, this, "Processing queue item: '{0}'", item.ToString()); - item.Dispatch(); - - if (_delayEnabled) - Thread.Sleep(_delayTime); - } - catch (ThreadAbortException) - { - //swallowing this exception, as it should only happen on shut down - } - catch (Exception ex) - { - Debug.LogMessage(LogEventLevel.Information, this, "Caught an exception in the Queue: {1}:{0}", ex.Message, ex); - Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.StackTrace); - - if (ex.InnerException != null) - { - Debug.LogMessage(LogEventLevel.Information, this, "---\r\n{0}", ex.InnerException.Message); - Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.InnerException.StackTrace); - } - } - } - else _waitHandle.Wait(); - } - - return null; - } - - public void Enqueue(IQueueMessage item) - { - if (Disposed) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Queue has been disposed. Enqueuing messages not allowed while program is stopping."); - return; - } - - _queue.Enqueue(item); - _waitHandle.Set(); - } - - /// - /// Disposes the thread and cleans up resources. Thread cannot be restarted once - /// disposed. - /// - public void Dispose() - { - Dispose(true); - CrestronEnvironment.GC.SuppressFinalize(this); - } - - /// - /// Actually does the disposing. If you override this method, be sure to either call the base implementation - /// or clean up all the resources yourself. - /// - /// set to true unless called from finalizer - protected void Dispose(bool disposing) - { - if (Disposed) - return; - - if (disposing) - { - using (_waitHandle) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Disposing..."); - _queue.Enqueue(null); - _waitHandle.Set(); - _worker.Join(); - } - } - - Disposed = true; - } - - ~GenericQueue() - { - Dispose(true); - } - - /// - /// Key - /// - public string Key - { - get { return _key; } + return int.MaxValue; } } + + /// + /// Returns the number of elements currently in the CrestronQueue + /// + public int QueueCount + { + get + { + return _queue.Count; + } + } + + /// + /// Constructor with no thread priority + /// + /// + public GenericQueue(string key) + : this(key, _defaultPriority, 0, 0) + { + } + + /// + /// Constructor with queue size + /// + /// + /// Fixed size for the queue to hold + public GenericQueue(string key, int capacity) + : this(key, _defaultPriority, capacity, 0) + { + } + + /// + /// Constructor for generic queue with no pacing + /// + /// Key + /// Pacing in ms between actions + public GenericQueue(int pacing, string key) + : this(key, _defaultPriority, 0, pacing) + { + } + + /// + /// Constructor with pacing and capacity + /// + /// + /// + /// + public GenericQueue(string key, int pacing, int capacity) + : this(key, _defaultPriority, capacity, pacing) + { + } + + /// + /// Constructor with pacing and priority + /// + /// + /// + /// + public GenericQueue(string key, int pacing, Thread.eThreadPriority priority) + : this(key, priority, 0, pacing) + { + } + + /// + /// Constructor with pacing, priority and capacity + /// + /// + /// + /// + public GenericQueue(string key, Thread.eThreadPriority priority, int capacity) + : this(key, priority, capacity, 0) + { + } + + /// + /// Constructor with pacing, priority and capacity + /// + /// + /// + /// + /// + public GenericQueue(string key, int pacing, Thread.eThreadPriority priority, int capacity) + : this(key, priority, capacity, pacing) + { + } + + /// + /// Constructor for generic queue with no pacing + /// + /// Key + /// + /// + /// + protected GenericQueue(string key, Thread.eThreadPriority priority, int capacity, int pacing) + { + _key = key; + int cap = 25; // sets default + if (capacity > 0) + { + cap = capacity; // overrides default + } + + _queue = new ConcurrentQueue(); + _worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running) + { + Priority = priority, + Name = _key + }; + + SetDelayValues(pacing); + } + + private void SetDelayValues(int pacing) + { + _delayEnabled = pacing > 0; + _delayTime = pacing; + + CrestronEnvironment.ProgramStatusEventHandler += programEvent => + { + if (programEvent != eProgramStatusEventType.Stopping) + return; + + Dispose(true); + }; + } + + /// + /// Thread callback + /// + /// The action used to process dequeued items + /// Null when the thread is exited + private object ProcessQueue(object obj) + { + while (true) + { + if (_queue.TryDequeue(out var item) && item == null) + break; + + if (item != null) + { + try + { + //Debug.LogMessage(LogEventLevel.Verbose, this, "Processing queue item: '{0}'", item.ToString()); + item.Dispatch(); + + if (_delayEnabled) + Thread.Sleep(_delayTime); + } + catch (ThreadAbortException) + { + //swallowing this exception, as it should only happen on shut down + } + catch (Exception ex) + { + Debug.LogMessage(LogEventLevel.Information, this, "Caught an exception in the Queue: {1}:{0}", ex.Message, ex); + Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.StackTrace); + + if (ex.InnerException != null) + { + Debug.LogMessage(LogEventLevel.Information, this, "---\r\n{0}", ex.InnerException.Message); + Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.InnerException.StackTrace); + } + } + } + else _waitHandle.Wait(); + } + + return null; + } + + public void Enqueue(IQueueMessage item) + { + if (Disposed) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Queue has been disposed. Enqueuing messages not allowed while program is stopping."); + return; + } + + _queue.Enqueue(item); + _waitHandle.Set(); + } + + /// + /// Disposes the thread and cleans up resources. Thread cannot be restarted once + /// disposed. + /// + public void Dispose() + { + Dispose(true); + CrestronEnvironment.GC.SuppressFinalize(this); + } + + /// + /// Actually does the disposing. If you override this method, be sure to either call the base implementation + /// or clean up all the resources yourself. + /// + /// set to true unless called from finalizer + protected void Dispose(bool disposing) + { + if (Disposed) + return; + + if (disposing) + { + using (_waitHandle) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Disposing..."); + _queue.Enqueue(null); + _waitHandle.Set(); + _worker.Join(); + } + } + + Disposed = true; + } + + ~GenericQueue() + { + Dispose(true); + } + + /// + /// Key + /// + public string Key + { + get { return _key; } + } } diff --git a/src/PepperDash.Essentials.Core/Queues/IQueue.cs b/src/PepperDash.Essentials.Core/Queues/IQueue.cs index cb3bb947..077f42ab 100644 --- a/src/PepperDash.Essentials.Core/Queues/IQueue.cs +++ b/src/PepperDash.Essentials.Core/Queues/IQueue.cs @@ -1,11 +1,10 @@ using System; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +public interface IQueue : IKeyed, IDisposable where T : class { - public interface IQueue : IKeyed, IDisposable where T : class - { - void Enqueue(T item); - bool Disposed { get; } - } + void Enqueue(T item); + bool Disposed { get; } } diff --git a/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs b/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs index 408bffca..206a1744 100644 --- a/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs +++ b/src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs @@ -1,9 +1,8 @@ using System; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +public interface IQueueMessage { - public interface IQueueMessage - { - void Dispatch(); - } + void Dispatch(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs b/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs index 5617326f..9d9f38cb 100644 --- a/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs +++ b/src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs @@ -1,44 +1,43 @@ using System; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +/// +/// Message class for processing strings via an IQueue +/// +public class ProcessStringMessage : IQueueMessage { + private readonly Action _action; + private readonly string _message; + /// - /// Message class for processing strings via an IQueue + /// Constructor /// - public class ProcessStringMessage : IQueueMessage + /// Message to be processed + /// Action to invoke on the message + public ProcessStringMessage(string message, Action action) { - private readonly Action _action; - private readonly string _message; + _message = message; + _action = action; + } - /// - /// Constructor - /// - /// Message to be processed - /// Action to invoke on the message - public ProcessStringMessage(string message, Action action) - { - _message = message; - _action = action; - } + /// + /// Processes the string with the given action + /// + public void Dispatch() + { + if (_action == null || String.IsNullOrEmpty(_message)) + return; - /// - /// Processes the string with the given action - /// - public void Dispatch() - { - if (_action == null || String.IsNullOrEmpty(_message)) - return; + _action(_message); + } - _action(_message); - } - - /// - /// To string - /// - /// The current message - public override string ToString() - { - return _message ?? String.Empty; - } + /// + /// To string + /// + /// The current message + public override string ToString() + { + return _message ?? String.Empty; } } diff --git a/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs b/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs index 62020af0..44c83e37 100644 --- a/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs +++ b/src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs @@ -2,105 +2,104 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Queues +namespace PepperDash.Essentials.Core.Queues; + +public sealed class StringResponseProcessor : IKeyed, IDisposable { - public sealed class StringResponseProcessor : IKeyed, IDisposable + private readonly Action _processStringAction; + private readonly IQueue _queue; + private readonly IBasicCommunication _coms; + private readonly CommunicationGather _gather; + + private StringResponseProcessor(string key, Action processStringAction) { - private readonly Action _processStringAction; - private readonly IQueue _queue; - private readonly IBasicCommunication _coms; - private readonly CommunicationGather _gather; + _processStringAction = processStringAction; + _queue = new GenericQueue(key); - private StringResponseProcessor(string key, Action processStringAction) + CrestronEnvironment.ProgramStatusEventHandler += programEvent => { - _processStringAction = processStringAction; - _queue = new GenericQueue(key); - - CrestronEnvironment.ProgramStatusEventHandler += programEvent => - { - if (programEvent != eProgramStatusEventType.Stopping) - return; - - Dispose(); - }; - } - - /// - /// Constructor that builds an instance and subscribes to coms TextReceived for processing - /// - /// Com port to process strings from - /// Action to process the incoming strings - public StringResponseProcessor(IBasicCommunication coms, Action processStringAction) - : this(coms.Key, processStringAction) - { - _coms = coms; - coms.TextReceived += OnResponseReceived; - } - - /// - /// Constructor that builds an instance and subscribes to gather Line Received for processing - /// - /// Gather to process strings from - /// Action to process the incoming strings - public StringResponseProcessor(CommunicationGather gather, Action processStringAction) - : this(gather.Port.Key, processStringAction) - { - _gather = gather; - gather.LineReceived += OnResponseReceived; - } - - private void OnResponseReceived(object sender, GenericCommMethodReceiveTextArgs args) - { - _queue.Enqueue(new ProcessStringMessage(args.Text, _processStringAction)); - } - - /// - /// Key - /// - public string Key - { - get { return _queue.Key; } - } - - /// - /// Disposes the instance and cleans up resources. - /// - public void Dispose() - { - Dispose(true); - CrestronEnvironment.GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (Disposed) + if (programEvent != eProgramStatusEventType.Stopping) return; - if (disposing) + Dispose(); + }; + } + + /// + /// Constructor that builds an instance and subscribes to coms TextReceived for processing + /// + /// Com port to process strings from + /// Action to process the incoming strings + public StringResponseProcessor(IBasicCommunication coms, Action processStringAction) + : this(coms.Key, processStringAction) + { + _coms = coms; + coms.TextReceived += OnResponseReceived; + } + + /// + /// Constructor that builds an instance and subscribes to gather Line Received for processing + /// + /// Gather to process strings from + /// Action to process the incoming strings + public StringResponseProcessor(CommunicationGather gather, Action processStringAction) + : this(gather.Port.Key, processStringAction) + { + _gather = gather; + gather.LineReceived += OnResponseReceived; + } + + private void OnResponseReceived(object sender, GenericCommMethodReceiveTextArgs args) + { + _queue.Enqueue(new ProcessStringMessage(args.Text, _processStringAction)); + } + + /// + /// Key + /// + public string Key + { + get { return _queue.Key; } + } + + /// + /// Disposes the instance and cleans up resources. + /// + public void Dispose() + { + Dispose(true); + CrestronEnvironment.GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Disposed) + return; + + if (disposing) + { + if (_coms != null) + _coms.TextReceived -= OnResponseReceived; + + if (_gather != null) { - if (_coms != null) - _coms.TextReceived -= OnResponseReceived; - - if (_gather != null) - { - _gather.LineReceived -= OnResponseReceived; - _gather.Stop(); - } - - _queue.Dispose(); + _gather.LineReceived -= OnResponseReceived; + _gather.Stop(); } - Disposed = true; + _queue.Dispose(); } - /// - /// If the instance has been disposed or not. If it has, you can not use it anymore - /// - public bool Disposed { get; private set; } + Disposed = true; + } - ~StringResponseProcessor() - { - Dispose(false); - } + /// + /// If the instance has been disposed or not. If it has, you can not use it anymore + /// + public bool Disposed { get; private set; } + + ~StringResponseProcessor() + { + Dispose(false); } } diff --git a/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs b/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs index f63d57bf..ded7d9f3 100644 --- a/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs +++ b/src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs @@ -6,115 +6,114 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// An incrementer that can use the values of some other object/primitive value to do its thing. +/// It uses an Action to set the value and a Func to get the value from whatever this is +/// attached to. +/// +public class ActionIncrementer { + public int ChangeAmount { get; set; } + public int MaxValue { get; set; } + public int MinValue { get; set; } + public uint RepeatDelay { get; set; } + public uint RepeatTime { get; set; } + + Action SetAction; + Func GetFunc; + CTimer Timer; + /// - /// An incrementer that can use the values of some other object/primitive value to do its thing. - /// It uses an Action to set the value and a Func to get the value from whatever this is - /// attached to. + /// /// - public class ActionIncrementer + /// + /// + /// + /// + /// + /// Action that will be called when this needs to set the destination value + /// Func that is called to get the current value + public ActionIncrementer(int changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime, Action setAction, Func getFunc) { - public int ChangeAmount { get; set; } - public int MaxValue { get; set; } - public int MinValue { get; set; } - public uint RepeatDelay { get; set; } - public uint RepeatTime { get; set; } + SetAction = setAction; + GetFunc = getFunc; + ChangeAmount = changeAmount; + MaxValue = maxValue; + MinValue = minValue; + RepeatDelay = repeatDelay; + RepeatTime = repeatTime; + } - Action SetAction; - Func GetFunc; - CTimer Timer; + /// + /// Starts incrementing cycle + /// + public void StartUp() + { + if (Timer != null) return; + Go(ChangeAmount); + } - /// - /// - /// - /// - /// - /// - /// - /// - /// Action that will be called when this needs to set the destination value - /// Func that is called to get the current value - public ActionIncrementer(int changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime, Action setAction, Func getFunc) + /// + /// Starts decrementing cycle + /// + public void StartDown() + { + if (Timer != null) return; + Go(-ChangeAmount); + } + + /// + /// Stops the repeat + /// + public void Stop() + { + if (Timer != null) + Timer.Stop(); + Timer = null; + } + + /// + /// Helper that does the work of setting new level, and starting repeat loop, checking against bounds first. + /// + /// + void Go(int change) + { + int currentLevel = GetFunc(); + // Fire once then pause + int newLevel = currentLevel + change; + bool atLimit = CheckLevel(newLevel, out newLevel); + SetAction(newLevel); + + if (atLimit) // Don't go past end + Stop(); + else if (Timer == null) // Only enter the timer if it's not already running + Timer = new CTimer(o => { Go(change); }, null, RepeatDelay, RepeatTime); + } + + /// + /// Helper to check a new level against min/max. Returns revised level if new level + /// will go out of bounds + /// + /// The level to check against bounds + /// Revised level if bounds are exceeded. Min or max + /// true if new level is at or past bounds + bool CheckLevel(int levelIn, out int levelOut) + { + bool isAtLimit = false; + if (levelIn > MaxValue) { - SetAction = setAction; - GetFunc = getFunc; - ChangeAmount = changeAmount; - MaxValue = maxValue; - MinValue = minValue; - RepeatDelay = repeatDelay; - RepeatTime = repeatTime; + levelOut = MaxValue; + isAtLimit = true; } - - /// - /// Starts incrementing cycle - /// - public void StartUp() + else if (levelIn < MinValue) { - if (Timer != null) return; - Go(ChangeAmount); - } - - /// - /// Starts decrementing cycle - /// - public void StartDown() - { - if (Timer != null) return; - Go(-ChangeAmount); - } - - /// - /// Stops the repeat - /// - public void Stop() - { - if (Timer != null) - Timer.Stop(); - Timer = null; - } - - /// - /// Helper that does the work of setting new level, and starting repeat loop, checking against bounds first. - /// - /// - void Go(int change) - { - int currentLevel = GetFunc(); - // Fire once then pause - int newLevel = currentLevel + change; - bool atLimit = CheckLevel(newLevel, out newLevel); - SetAction(newLevel); - - if (atLimit) // Don't go past end - Stop(); - else if (Timer == null) // Only enter the timer if it's not already running - Timer = new CTimer(o => { Go(change); }, null, RepeatDelay, RepeatTime); - } - - /// - /// Helper to check a new level against min/max. Returns revised level if new level - /// will go out of bounds - /// - /// The level to check against bounds - /// Revised level if bounds are exceeded. Min or max - /// true if new level is at or past bounds - bool CheckLevel(int levelIn, out int levelOut) - { - bool isAtLimit = false; - if (levelIn > MaxValue) - { - levelOut = MaxValue; - isAtLimit = true; - } - else if (levelIn < MinValue) - { - levelOut = MinValue; - isAtLimit = true; - } - else - levelOut = levelIn; - return isAtLimit; + levelOut = MinValue; + isAtLimit = true; } + else + levelOut = levelIn; + return isAtLimit; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs b/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs index fefeb702..b26d5fac 100644 --- a/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs +++ b/src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs @@ -4,37 +4,36 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ - public class NumericalHelpers - { - /// - /// Scales a value - /// - /// - /// - /// - /// - /// - /// - public static double Scale(double input, double inMin, double inMax, double outMin, double outMax) +namespace PepperDash.Essentials.Core; + +public class NumericalHelpers +{ + /// + /// Scales a value + /// + /// + /// + /// + /// + /// + /// + public static double Scale(double input, double inMin, double inMax, double outMin, double outMax) + { + //Debug.LogMessage(LogEventLevel.Verbose, this, "Scaling (double) input '{0}' with min '{1}'/max '{2}' to output range min '{3}'/max '{4}'", input, inMin, inMax, outMin, outMax); + + double inputRange = inMax - inMin; + + if (inputRange <= 0) { - //Debug.LogMessage(LogEventLevel.Verbose, this, "Scaling (double) input '{0}' with min '{1}'/max '{2}' to output range min '{3}'/max '{4}'", input, inMin, inMax, outMin, outMax); - - double inputRange = inMax - inMin; - - if (inputRange <= 0) - { - throw new ArithmeticException(string.Format("Invalid Input Range '{0}' for Scaling. Min '{1}' Max '{2}'.", inputRange, inMin, inMax)); - } - - double outputRange = outMax - outMin; - - var output = (((input - inMin) * outputRange) / inputRange) + outMin; - - // Debug.LogMessage(LogEventLevel.Verbose, this, "Scaled output '{0}'", output); - - return output; + throw new ArithmeticException(string.Format("Invalid Input Range '{0}' for Scaling. Min '{1}' Max '{2}'.", inputRange, inMin, inMax)); } + + double outputRange = outMax - outMin; + + var output = (((input - inMin) * outputRange) / inputRange) + outMin; + + // Debug.LogMessage(LogEventLevel.Verbose, this, "Scaled output '{0}'", output); + + return output; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs b/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs index 3d29be77..7ee4c956 100644 --- a/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs +++ b/src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs @@ -8,94 +8,93 @@ using Crestron.SimplSharpPro; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Attaches to UShortInputSig and does incremental ramping of the signal +/// +public class UshortSigIncrementer { - /// - /// Attaches to UShortInputSig and does incremental ramping of the signal - /// - public class UshortSigIncrementer + UShortInputSig TheSig; + public ushort ChangeAmount { get; set; } + public int MaxValue { get; set; } + public int MinValue { get; set; } + public uint RepeatDelay { get; set; } + public uint RepeatTime { get; set; } + bool SignedMode; + CTimer Timer; + + public UshortSigIncrementer(UShortInputSig sig, ushort changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime) { - UShortInputSig TheSig; - public ushort ChangeAmount { get; set; } - public int MaxValue { get; set; } - public int MinValue { get; set; } - public uint RepeatDelay { get; set; } - public uint RepeatTime { get; set; } - bool SignedMode; - CTimer Timer; + TheSig = sig; + ChangeAmount = changeAmount; + MaxValue = maxValue; + MinValue = minValue; + if (MinValue < 0 || MaxValue < 0) SignedMode = true; + RepeatDelay = repeatDelay; + RepeatTime = repeatTime; + if (SignedMode && (MinValue < -32768 || MaxValue > 32767)) + Debug.LogMessage(LogEventLevel.Debug, "UshortSigIncrementer has signed values that exceed range of -32768, 32767"); + } - public UshortSigIncrementer(UShortInputSig sig, ushort changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime) + public void StartUp() + { + if (Timer != null) return; + Go(ChangeAmount); + } + + public void StartDown() + { + if (Timer != null) return; + Go(-ChangeAmount); + } + + void Go(int change) + { + int level; + if (SignedMode) level = TheSig.ShortValue; + else level = TheSig.UShortValue; + + // Fire once then pause + int newLevel = level + change; + bool atLimit = CheckLevel(newLevel, out newLevel); + SetValue((ushort)newLevel); + + + if (atLimit) // Don't go past end + Stop(); + else if (Timer == null) // Only enter the timer if it's not already running + Timer = new CTimer(o => { Go(change); }, null, RepeatDelay, RepeatTime); + } + + bool CheckLevel(int levelIn, out int levelOut) + { + bool IsAtLimit = false; + if (levelIn > MaxValue) { - TheSig = sig; - ChangeAmount = changeAmount; - MaxValue = maxValue; - MinValue = minValue; - if (MinValue < 0 || MaxValue < 0) SignedMode = true; - RepeatDelay = repeatDelay; - RepeatTime = repeatTime; - if (SignedMode && (MinValue < -32768 || MaxValue > 32767)) - Debug.LogMessage(LogEventLevel.Debug, "UshortSigIncrementer has signed values that exceed range of -32768, 32767"); + levelOut = MaxValue; + IsAtLimit = true; } - - public void StartUp() + else if (levelIn < MinValue) { - if (Timer != null) return; - Go(ChangeAmount); + levelOut = MinValue; + IsAtLimit = true; } + else + levelOut = levelIn; + return IsAtLimit; + } - public void StartDown() - { - if (Timer != null) return; - Go(-ChangeAmount); - } + public void Stop() + { + if (Timer != null) + Timer.Stop(); + Timer = null; + } - void Go(int change) - { - int level; - if (SignedMode) level = TheSig.ShortValue; - else level = TheSig.UShortValue; - - // Fire once then pause - int newLevel = level + change; - bool atLimit = CheckLevel(newLevel, out newLevel); - SetValue((ushort)newLevel); - - - if (atLimit) // Don't go past end - Stop(); - else if (Timer == null) // Only enter the timer if it's not already running - Timer = new CTimer(o => { Go(change); }, null, RepeatDelay, RepeatTime); - } - - bool CheckLevel(int levelIn, out int levelOut) - { - bool IsAtLimit = false; - if (levelIn > MaxValue) - { - levelOut = MaxValue; - IsAtLimit = true; - } - else if (levelIn < MinValue) - { - levelOut = MinValue; - IsAtLimit = true; - } - else - levelOut = levelIn; - return IsAtLimit; - } - - public void Stop() - { - if (Timer != null) - Timer.Stop(); - Timer = null; - } - - void SetValue(ushort value) - { - //CrestronConsole.PrintLine("Increment level:{0} / {1}", value, (short)value); - TheSig.UShortValue = value; - } + void SetValue(ushort value) + { + //CrestronConsole.PrintLine("Increment level:{0} / {1}", value, (short)value); + TheSig.UShortValue = value; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index e96e2a23..d19aaa0c 100644 --- a/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -16,543 +16,541 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// A device that when linked to a room can power the room on when enabled during scheduled hours. +/// +public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice { - /// - /// A device that when linked to a room can power the room on when enabled during scheduled hours. - /// - public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice + RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; + + public bool FeatureEnabled { get; private set; } + + public DateTime FeatureEnabledTime { get; private set; } + + ScheduledEvent FeatureEnableEvent; + + const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied"; + + public DateTime FeatureDisabledTime { get; private set; } + + ScheduledEvent FeatureDisableEvent; + + const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied"; + + ScheduledEventGroup FeatureEventGroup; + + public IRoomOccupancy Room { get; private set; } + + private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom; + + public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : + base (config) { - RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; + PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - public bool FeatureEnabled { get; private set; } + FeatureEventGroup = new ScheduledEventGroup(this.Key); - public DateTime FeatureEnabledTime { get; private set; } + FeatureEventGroup.RetrieveAllEvents(); - ScheduledEvent FeatureEnableEvent; + // Add to the global class for tracking + Scheduler.AddEventGroup(FeatureEventGroup); - const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied"; - - public DateTime FeatureDisabledTime { get; private set; } - - ScheduledEvent FeatureDisableEvent; - - const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied"; - - ScheduledEventGroup FeatureEventGroup; - - public IRoomOccupancy Room { get; private set; } - - private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom; - - public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : - base (config) + AddPostActivationAction(() => { - PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - - FeatureEventGroup = new ScheduledEventGroup(this.Key); - - FeatureEventGroup.RetrieveAllEvents(); - - // Add to the global class for tracking - Scheduler.AddEventGroup(FeatureEventGroup); - - AddPostActivationAction(() => - { - // Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to - if (Room != null) - Room.RoomOccupancyIsSet += new EventHandler(RoomOccupancyIsSet); - - else - Debug.LogMessage(LogEventLevel.Debug, this, "Room has no RoomOccupancy object set"); - - var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion"; - - FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase; - - if (FusionRoom == null) - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey); - }); - } - - public override bool CustomActivate() - { - SetUpDevice(); - - return base.CustomActivate(); - } - - /// - /// Sets up device based on config values - /// - void SetUpDevice() - { - Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IRoomOccupancy; - + // Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to if (Room != null) + Room.RoomOccupancyIsSet += new EventHandler(RoomOccupancyIsSet); + + else + Debug.LogMessage(LogEventLevel.Debug, this, "Room has no RoomOccupancy object set"); + + var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion"; + + FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase; + + if (FusionRoom == null) + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey); + }); + } + + public override bool CustomActivate() + { + SetUpDevice(); + + return base.CustomActivate(); + } + + /// + /// Sets up device based on config values + /// + void SetUpDevice() + { + Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IRoomOccupancy; + + if (Room != null) + { + try { - try - { - FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime); + FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime); - if (FeatureEnabledTime != null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Enabled Time: {0}", FeatureEnabledTime.ToString()); - } - else - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime); - } - catch (Exception e) + if (FeatureEnabledTime != null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); + Debug.LogMessage(LogEventLevel.Debug, this, "Enabled Time: {0}", FeatureEnabledTime.ToString()); } - - try - { - FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime); - - if (FeatureDisabledTime != null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Disabled Time: {0}", FeatureDisabledTime.ToString()); - } - else - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse a DateTime config value \n Error: {1}", e); - } - - if (!PropertiesConfig.EnableRoomOnWhenOccupied) - FeatureEventGroup.ClearAllEvents(); else - { - AddEnableEventToGroup(); - - AddDisableEventToGroup(); - - FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack); - - FeatureEventGroup.EnableAllEvents(); - } - - FeatureEnabled = CheckIfFeatureShouldBeEnabled(); + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime); } - else - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey); - } - - - protected override void CustomSetConfig(DeviceConfig config) - { - var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - - if(newPropertiesConfig != null) - PropertiesConfig = newPropertiesConfig; - - ConfigWriter.UpdateDeviceConfig(config); - - SetUpDevice(); - } - - /// - /// Subscribe to feedback from RoomIsOccupiedFeedback on Room - /// - /// - /// - void RoomOccupancyIsSet(object sender, EventArgs e) - { - if (Room.RoomOccupancy != null) + catch (Exception e) { - Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; - Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler(RoomIsOccupiedFeedback_OutputChange); - Debug.LogMessage(LogEventLevel.Debug, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key); - } - } - - void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - Debug.LogMessage(LogEventLevel.Debug, this, "{0}:{1} @ {2}", SchEvent.Name, type, DateTime.Now); - - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) - { - SchEvent.Acknowledge(); - - if (SchEvent.Name == FeatureEnableEventName) - { - - if (PropertiesConfig.EnableRoomOnWhenOccupied) - FeatureEnabled = true; - - Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled by event.*****"); - } - else if (SchEvent.Name == FeatureDisableEventName) - { - FeatureEnabled = false; - - Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled by event.*****"); - } - } - } - - /// - /// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time - /// - /// - bool CheckIfFeatureShouldBeEnabled() - { - bool enabled = false; - - if(PropertiesConfig.EnableRoomOnWhenOccupied) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime); - - if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0) - { - if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence())) - { - enabled = true; - } - } + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); } - if(enabled) - Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled*****"); - else - Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled*****"); - - return enabled; - } - - /// - /// Respond to Occupancy status event - /// - /// - /// - void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - Debug.LogMessage(LogEventLevel.Debug, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue); - if(e.BoolValue) + try { - // Occupancy detected + FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime); - if (FeatureEnabled) + if (FeatureDisabledTime != null) { - var essentialsRoom = Room as IEssentialsRoom; - - if (essentialsRoom != null) { - if (!essentialsRoom.OnFeedback.BoolValue) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Powering Room on to default source"); - - var defaultRouteRoom = Room as IRunDefaultPresentRoute; - - if (defaultRouteRoom != null) - { - defaultRouteRoom.RunDefaultPresentRoute(); - } - } - } - // Check room power state first - + Debug.LogMessage(LogEventLevel.Debug, this, "Disabled Time: {0}", FeatureDisabledTime.ToString()); } - } - } - - void CreateEvent(ScheduledEvent schEvent, string name) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Adding Event: '{0}'", name); - // Create the event - if (schEvent == null) - schEvent = new ScheduledEvent(name, FeatureEventGroup); - - // Set up its initial properties - - schEvent.Acknowledgeable = false; - - if(!schEvent.Persistent) - schEvent.Persistent = true; - - schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); - - // Set config driven properties - - if (schEvent.Name == FeatureEnableEventName) - { - schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature"; - - var eventRecurrennce = CalculateDaysOfWeekRecurrence(); - - var eventTime = new DateTime(); - - // Check to make sure the date for this event is in the future - if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0) - eventTime = FeatureEnabledTime.AddDays(1); else - eventTime = FeatureEnabledTime; - - Debug.LogMessage(LogEventLevel.Debug, this, "eventTime (before recurrence check): {0}", eventTime); - - // Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event - // start date on a day of the week that doesn't match teh recurrence values - while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce)) - { - eventTime = eventTime.AddDays(1); - Debug.LogMessage(LogEventLevel.Debug, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime); - } - - schEvent.DateAndTime.SetAbsoluteEventTime(eventTime); - - Debug.LogMessage(LogEventLevel.Debug, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); - - //CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime); - - schEvent.Recurrence.Weekly(eventRecurrennce); - + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime); } - else if (schEvent.Name == FeatureDisableEventName) + catch (Exception e) { - schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature"; - - // Check to make sure the date for this event is in the future - if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0) - schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1)); - else - schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime); - - Debug.LogMessage(LogEventLevel.Debug, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); - - CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime); - - schEvent.Recurrence.Daily(); + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse a DateTime config value \n Error: {1}", e); } - } - void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2) - { - Debug.LogMessage(LogEventLevel.Debug, this, "time1.Hour = {0}", time1.Hour); - Debug.LogMessage(LogEventLevel.Debug, this, "time2.Hour = {0}", time2.Hour); - Debug.LogMessage(LogEventLevel.Debug, this, "time1.Minute = {0}", time1.Minute); - Debug.LogMessage(LogEventLevel.Debug, this, "time2.Minute = {0}", time2.Minute); - - // Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute - var ackHours = time2.Hour - time1.Hour; - if(ackHours < 0) - ackHours = ackHours + 24; - var ackMinutes = time2.Minute - time1.Minute; - - Debug.LogMessage(LogEventLevel.Debug, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes); - - var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1; - - var ackExpHour = ackTotalMinutes / 60; - var ackExpMinutes = ackTotalMinutes % 60; - - Debug.LogMessage(LogEventLevel.Debug, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes); - - schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours); - schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes); - } - - /// - /// Checks existing event to see if it matches the execution time - /// - /// - /// - bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime) - { - bool isMatch = true; - - // Check to see if hour and minute match - if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute) - return false; - - - return isMatch; - } - - /// - /// Checks existing event to see if it matches the recurrence days - /// - /// - /// - /// - bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays) - { - bool isMatch = true; - - // Check to see if recurrence matches - if (eWeekdays != existingEvent.Recurrence.RecurrenceDays) - return false; - - return isMatch; - } - - /// - /// Adds the Enable event to the local event group and sets its properties based on config - /// - void AddEnableEventToGroup() - { - if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName)) - { - CreateEvent(FeatureEnableEvent, FeatureEnableEventName); - } + if (!PropertiesConfig.EnableRoomOnWhenOccupied) + FeatureEventGroup.ClearAllEvents(); else { - // Check if existing event has same time and recurrence as config values + AddEnableEventToGroup(); - FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName]; - Debug.LogMessage(LogEventLevel.Debug, this, "Enable event already found in group"); + AddDisableEventToGroup(); - // Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event - if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence())) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name); - FeatureEventGroup.DeleteEvent(FeatureEnableEvent); + FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack); - FeatureEnableEvent = null; - - CreateEvent(FeatureEnableEvent, FeatureEnableEventName); - } + FeatureEventGroup.EnableAllEvents(); } + FeatureEnabled = CheckIfFeatureShouldBeEnabled(); } + else + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey); + } - /// - /// Adds the Enable event to the local event group and sets its properties based on config - /// - void AddDisableEventToGroup() + + protected override void CustomSetConfig(DeviceConfig config) + { + var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + + if(newPropertiesConfig != null) + PropertiesConfig = newPropertiesConfig; + + ConfigWriter.UpdateDeviceConfig(config); + + SetUpDevice(); + } + + /// + /// Subscribe to feedback from RoomIsOccupiedFeedback on Room + /// + /// + /// + void RoomOccupancyIsSet(object sender, EventArgs e) + { + if (Room.RoomOccupancy != null) { - if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName)) - { - CreateEvent(FeatureDisableEvent, FeatureDisableEventName); - } - else - { - FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName]; - Debug.LogMessage(LogEventLevel.Debug, this, "Disable event already found in group"); - - // Check config times against DateAndTime of existing event. If different, delete existing event and create new event - if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime)) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name); - - FeatureEventGroup.DeleteEvent(FeatureDisableEvent); - - FeatureDisableEvent = null; - - CreateEvent(FeatureDisableEvent, FeatureDisableEventName); - } - } + Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; + Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler(RoomIsOccupiedFeedback_OutputChange); + Debug.LogMessage(LogEventLevel.Debug, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key); } + } + void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) + { + Debug.LogMessage(LogEventLevel.Debug, this, "{0}:{1} @ {2}", SchEvent.Name, type, DateTime.Now); - /// - /// Calculates the correct bitfield enum value for the event recurrence based on the config values - /// - /// - ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence() + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) { - ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays(); + SchEvent.Acknowledge(); - if (PropertiesConfig.EnableSunday) - value = value | ScheduledEventCommon.eWeekDays.Sunday; - if (PropertiesConfig.EnableMonday) - value = value | ScheduledEventCommon.eWeekDays.Monday; - if (PropertiesConfig.EnableTuesday) - value = value | ScheduledEventCommon.eWeekDays.Tuesday; - if (PropertiesConfig.EnableWednesday) - value = value | ScheduledEventCommon.eWeekDays.Wednesday; - if (PropertiesConfig.EnableThursday) - value = value | ScheduledEventCommon.eWeekDays.Thursday; - if (PropertiesConfig.EnableFriday) - value = value | ScheduledEventCommon.eWeekDays.Friday; - if (PropertiesConfig.EnableSaturday) - value = value | ScheduledEventCommon.eWeekDays.Saturday; - - return value; - } - - /// - /// Callback for event that enables feature. Enables feature if config property is true - /// - /// - /// - void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + if (SchEvent.Name == FeatureEnableEventName) { - if(PropertiesConfig.EnableRoomOnWhenOccupied) + + if (PropertiesConfig.EnableRoomOnWhenOccupied) FeatureEnabled = true; - Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled."); + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled by event.*****"); } - } - - /// - /// Callback for event that enables feature. Disables feature - /// - /// - /// - void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + else if (SchEvent.Name == FeatureDisableEventName) { FeatureEnabled = false; - Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled."); + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled by event.*****"); } } } - public class RoomOnToDefaultSourceWhenOccupiedConfig + /// + /// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time + /// + /// + bool CheckIfFeatureShouldBeEnabled() { - [JsonProperty("roomKey")] - public string RoomKey { get; set; } + bool enabled = false; - [JsonProperty("enableRoomOnWhenOccupied")] - public bool EnableRoomOnWhenOccupied { get; set; } - - [JsonProperty("occupancyStartTime")] - public string OccupancyStartTime { get; set; } - - [JsonProperty("occupancyEndTime")] - public string OccupancyEndTime { get; set; } - - [JsonProperty("enableSunday")] - public bool EnableSunday { get; set; } - - [JsonProperty("enableMonday")] - public bool EnableMonday { get; set; } - - [JsonProperty("enableTuesday")] - public bool EnableTuesday { get; set; } - - [JsonProperty("enableWednesday")] - public bool EnableWednesday { get; set; } - - [JsonProperty("enableThursday")] - public bool EnableThursday { get; set; } - - [JsonProperty("enableFriday")] - public bool EnableFriday { get; set; } - - [JsonProperty("enableSaturday")] - public bool EnableSaturday { get; set; } - } - - public class RoomOnToDefaultSourceWhenOccupiedFactory : EssentialsDeviceFactory - { - public RoomOnToDefaultSourceWhenOccupiedFactory() + if(PropertiesConfig.EnableRoomOnWhenOccupied) { - TypeNames = new List() { "roomonwhenoccupancydetectedfeature" }; + Debug.LogMessage(LogEventLevel.Debug, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime); + + if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0) + { + if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence())) + { + enabled = true; + } + } } - public override EssentialsDevice BuildDevice(DeviceConfig dc) + if(enabled) + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled*****"); + else + Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled*****"); + + return enabled; + } + + /// + /// Respond to Occupancy status event + /// + /// + /// + void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + Debug.LogMessage(LogEventLevel.Debug, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue); + if(e.BoolValue) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RoomOnToDefaultSourceWhenOccupied Device"); - return new RoomOnToDefaultSourceWhenOccupied(dc); + // Occupancy detected + + if (FeatureEnabled) + { + var essentialsRoom = Room as IEssentialsRoom; + + if (essentialsRoom != null) { + if (!essentialsRoom.OnFeedback.BoolValue) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Powering Room on to default source"); + + var defaultRouteRoom = Room as IRunDefaultPresentRoute; + + if (defaultRouteRoom != null) + { + defaultRouteRoom.RunDefaultPresentRoute(); + } + } + } + // Check room power state first + + } } } + void CreateEvent(ScheduledEvent schEvent, string name) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Adding Event: '{0}'", name); + // Create the event + if (schEvent == null) + schEvent = new ScheduledEvent(name, FeatureEventGroup); + + // Set up its initial properties + + schEvent.Acknowledgeable = false; + + if(!schEvent.Persistent) + schEvent.Persistent = true; + + schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); + + // Set config driven properties + + if (schEvent.Name == FeatureEnableEventName) + { + schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature"; + + var eventRecurrennce = CalculateDaysOfWeekRecurrence(); + + var eventTime = new DateTime(); + + // Check to make sure the date for this event is in the future + if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0) + eventTime = FeatureEnabledTime.AddDays(1); + else + eventTime = FeatureEnabledTime; + + Debug.LogMessage(LogEventLevel.Debug, this, "eventTime (before recurrence check): {0}", eventTime); + + // Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event + // start date on a day of the week that doesn't match teh recurrence values + while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce)) + { + eventTime = eventTime.AddDays(1); + Debug.LogMessage(LogEventLevel.Debug, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime); + } + + schEvent.DateAndTime.SetAbsoluteEventTime(eventTime); + + Debug.LogMessage(LogEventLevel.Debug, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); + + //CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime); + + schEvent.Recurrence.Weekly(eventRecurrennce); + + } + else if (schEvent.Name == FeatureDisableEventName) + { + schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature"; + + // Check to make sure the date for this event is in the future + if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0) + schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1)); + else + schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime); + + Debug.LogMessage(LogEventLevel.Debug, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); + + CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime); + + schEvent.Recurrence.Daily(); + } + } + + void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2) + { + Debug.LogMessage(LogEventLevel.Debug, this, "time1.Hour = {0}", time1.Hour); + Debug.LogMessage(LogEventLevel.Debug, this, "time2.Hour = {0}", time2.Hour); + Debug.LogMessage(LogEventLevel.Debug, this, "time1.Minute = {0}", time1.Minute); + Debug.LogMessage(LogEventLevel.Debug, this, "time2.Minute = {0}", time2.Minute); + + // Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute + var ackHours = time2.Hour - time1.Hour; + if(ackHours < 0) + ackHours = ackHours + 24; + var ackMinutes = time2.Minute - time1.Minute; + + Debug.LogMessage(LogEventLevel.Debug, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes); + + var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1; + + var ackExpHour = ackTotalMinutes / 60; + var ackExpMinutes = ackTotalMinutes % 60; + + Debug.LogMessage(LogEventLevel.Debug, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes); + + schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours); + schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes); + } + + /// + /// Checks existing event to see if it matches the execution time + /// + /// + /// + bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime) + { + bool isMatch = true; + + // Check to see if hour and minute match + if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute) + return false; + + + return isMatch; + } + + /// + /// Checks existing event to see if it matches the recurrence days + /// + /// + /// + /// + bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays) + { + bool isMatch = true; + + // Check to see if recurrence matches + if (eWeekdays != existingEvent.Recurrence.RecurrenceDays) + return false; + + return isMatch; + } + + /// + /// Adds the Enable event to the local event group and sets its properties based on config + /// + void AddEnableEventToGroup() + { + if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName)) + { + CreateEvent(FeatureEnableEvent, FeatureEnableEventName); + } + else + { + // Check if existing event has same time and recurrence as config values + + FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName]; + Debug.LogMessage(LogEventLevel.Debug, this, "Enable event already found in group"); + + // Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event + if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence())) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name); + FeatureEventGroup.DeleteEvent(FeatureEnableEvent); + + FeatureEnableEvent = null; + + CreateEvent(FeatureEnableEvent, FeatureEnableEventName); + } + } + + } + + /// + /// Adds the Enable event to the local event group and sets its properties based on config + /// + void AddDisableEventToGroup() + { + if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName)) + { + CreateEvent(FeatureDisableEvent, FeatureDisableEventName); + } + else + { + FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName]; + Debug.LogMessage(LogEventLevel.Debug, this, "Disable event already found in group"); + + // Check config times against DateAndTime of existing event. If different, delete existing event and create new event + if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime)) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name); + + FeatureEventGroup.DeleteEvent(FeatureDisableEvent); + + FeatureDisableEvent = null; + + CreateEvent(FeatureDisableEvent, FeatureDisableEventName); + } + } + } + + + /// + /// Calculates the correct bitfield enum value for the event recurrence based on the config values + /// + /// + ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence() + { + ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays(); + + if (PropertiesConfig.EnableSunday) + value = value | ScheduledEventCommon.eWeekDays.Sunday; + if (PropertiesConfig.EnableMonday) + value = value | ScheduledEventCommon.eWeekDays.Monday; + if (PropertiesConfig.EnableTuesday) + value = value | ScheduledEventCommon.eWeekDays.Tuesday; + if (PropertiesConfig.EnableWednesday) + value = value | ScheduledEventCommon.eWeekDays.Wednesday; + if (PropertiesConfig.EnableThursday) + value = value | ScheduledEventCommon.eWeekDays.Thursday; + if (PropertiesConfig.EnableFriday) + value = value | ScheduledEventCommon.eWeekDays.Friday; + if (PropertiesConfig.EnableSaturday) + value = value | ScheduledEventCommon.eWeekDays.Saturday; + + return value; + } + + /// + /// Callback for event that enables feature. Enables feature if config property is true + /// + /// + /// + void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) + { + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + { + if(PropertiesConfig.EnableRoomOnWhenOccupied) + FeatureEnabled = true; + + Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled."); + } + } + + /// + /// Callback for event that enables feature. Disables feature + /// + /// + /// + void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) + { + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + { + FeatureEnabled = false; + + Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled."); + } + } +} + +public class RoomOnToDefaultSourceWhenOccupiedConfig +{ + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("enableRoomOnWhenOccupied")] + public bool EnableRoomOnWhenOccupied { get; set; } + + [JsonProperty("occupancyStartTime")] + public string OccupancyStartTime { get; set; } + + [JsonProperty("occupancyEndTime")] + public string OccupancyEndTime { get; set; } + + [JsonProperty("enableSunday")] + public bool EnableSunday { get; set; } + + [JsonProperty("enableMonday")] + public bool EnableMonday { get; set; } + + [JsonProperty("enableTuesday")] + public bool EnableTuesday { get; set; } + + [JsonProperty("enableWednesday")] + public bool EnableWednesday { get; set; } + + [JsonProperty("enableThursday")] + public bool EnableThursday { get; set; } + + [JsonProperty("enableFriday")] + public bool EnableFriday { get; set; } + + [JsonProperty("enableSaturday")] + public bool EnableSaturday { get; set; } +} + +public class RoomOnToDefaultSourceWhenOccupiedFactory : EssentialsDeviceFactory +{ + public RoomOnToDefaultSourceWhenOccupiedFactory() + { + TypeNames = new List() { "roomonwhenoccupancydetectedfeature" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RoomOnToDefaultSourceWhenOccupied Device"); + return new RoomOnToDefaultSourceWhenOccupied(dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs index d2a16739..3d1010e4 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs @@ -8,482 +8,481 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a device that manages room combinations by controlling partitions and scenarios. +/// +/// The allows for dynamic configuration of room +/// combinations based on partition states and predefined scenarios. It supports both automatic and manual modes +/// for managing room combinations. In automatic mode, the device determines the current room combination scenario +/// based on partition sensor states. In manual mode, scenarios can be set explicitly by the user. +public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner { + private EssentialsRoomCombinerPropertiesConfig _propertiesConfig; + + private IRoomCombinationScenario _currentScenario; + + private List _rooms; + /// - /// Represents a device that manages room combinations by controlling partitions and scenarios. + /// Gets a list of rooms represented as key-name pairs. /// - /// The allows for dynamic configuration of room - /// combinations based on partition states and predefined scenarios. It supports both automatic and manual modes - /// for managing room combinations. In automatic mode, the device determines the current room combination scenario - /// based on partition sensor states. In manual mode, scenarios can be set explicitly by the user. - public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner + public List Rooms { - private EssentialsRoomCombinerPropertiesConfig _propertiesConfig; - - private IRoomCombinationScenario _currentScenario; - - private List _rooms; - - /// - /// Gets a list of rooms represented as key-name pairs. - /// - public List Rooms + get { - get - { - return _rooms.Cast().ToList(); - } + return _rooms.Cast().ToList(); } + } - private bool _isInAutoMode; + private bool _isInAutoMode; - /// - /// Gets or sets a value indicating whether the system is operating in automatic mode. - /// - /// Changing this property triggers an update event via - /// IsInAutoModeFeedback.FireUpdate(). Ensure that any event listeners are properly configured to handle - /// this update. - public bool IsInAutoMode + /// + /// Gets or sets a value indicating whether the system is operating in automatic mode. + /// + /// Changing this property triggers an update event via + /// IsInAutoModeFeedback.FireUpdate(). Ensure that any event listeners are properly configured to handle + /// this update. + public bool IsInAutoMode + { + get { - get - { - return _isInAutoMode; - } - set - { - if (value == _isInAutoMode) - { - return; - } - - _isInAutoMode = value; - IsInAutoModeFeedback.FireUpdate(); - } + return _isInAutoMode; } - - /// - /// Gets a value indicating whether automatic mode is disabled. - /// - public bool DisableAutoMode + set { - get + if (value == _isInAutoMode) { - return _propertiesConfig.DisableAutoMode; - } - } - - private CTimer _scenarioChangeDebounceTimer; - - private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s - - private Mutex _scenarioChange = new Mutex(); - - /// - /// Initializes a new instance of the class, which manages room combination - /// scenarios and partition states. - /// - /// The class is designed to handle dynamic room - /// combination scenarios based on partition states. It supports both automatic and manual modes for managing - /// room combinations. By default, the instance starts in automatic mode unless the - /// specifies otherwise. After activation, the room combiner initializes partition state providers and sets up - /// the initial room configuration. Additionally, it subscribes to the event to ensure proper initialization of dependent devices - /// before determining or setting the room combination scenario. - /// The unique identifier for the room combiner instance. - /// The configuration properties for the room combiner, including default settings and debounce times. - public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) - : base(key) - { - _propertiesConfig = props; - - Partitions = new List(); - RoomCombinationScenarios = new List(); - - if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) - { - _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; - } - - IsInAutoModeFeedback = new BoolFeedback(() => _isInAutoMode); - - // default to auto mode - IsInAutoMode = true; - - if (_propertiesConfig.defaultToManualMode) - { - IsInAutoMode = false; - } - - IsInAutoModeFeedback.FireUpdate(); - - CreateScenarios(); - - AddPostActivationAction(() => - { - SetupPartitionStateProviders(); - - SetRooms(); - }); - - - // Subscribe to the AllDevicesInitialized event - // We need to wait until all devices are initialized in case - // any actions are dependent on 3rd party devices already being - // connected and initialized - DeviceManager.AllDevicesInitialized += (o, a) => - { - if (IsInAutoMode) - { - DetermineRoomCombinationScenario(); - } - else - { - SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey); - } - }; - } - - private void CreateScenarios() - { - foreach (var scenarioConfig in _propertiesConfig.Scenarios) - { - var scenario = new RoomCombinationScenario(scenarioConfig); - RoomCombinationScenarios.Add(scenario); - } - } - - private void SetRooms() - { - _rooms = new List(); - - foreach (var roomKey in _propertiesConfig.RoomKeys) - { - var room = DeviceManager.GetDeviceForKey(roomKey); - - if (DeviceManager.GetDeviceForKey(roomKey) is IEssentialsRoom essentialsRoom) - { - _rooms.Add(essentialsRoom); - } - } - - var rooms = DeviceManager.AllDevices.OfType().Cast(); - - foreach (var room in rooms) - { - room.Deactivate(); - } - } - - private void SetupPartitionStateProviders() - { - foreach (var pConfig in _propertiesConfig.Partitions) - { - var sensor = DeviceManager.GetDeviceForKey(pConfig.DeviceKey) as IPartitionStateProvider; - - var partition = new EssentialsPartitionController(pConfig.Key, pConfig.Name, sensor, _propertiesConfig.defaultToManualMode, pConfig.AdjacentRoomKeys); - - partition.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; - - Partitions.Add(partition); - } - } - - private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - StartDebounceTimer(); - } - - private void StartDebounceTimer() - { - // default to 500ms for manual mode - var time = 500; - - // if in auto mode, debounce the scenario change - if (IsInAutoMode) time = _scenarioChangeDebounceTimeSeconds * 1000; - - if (_scenarioChangeDebounceTimer == null) - { - _scenarioChangeDebounceTimer = new CTimer((o) => DetermineRoomCombinationScenario(), time); - } - else - { - _scenarioChangeDebounceTimer.Reset(time); - } - } - - /// - /// Determines the current room combination scenario based on the state of the partition sensors - /// - private void DetermineRoomCombinationScenario() - { - if (_scenarioChangeDebounceTimer != null) - { - _scenarioChangeDebounceTimer.Dispose(); - _scenarioChangeDebounceTimer = null; - } - - this.LogInformation("Determining Combination Scenario"); - - var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) => - { - this.LogDebug("Checking scenario {scenarioKey}", s.Key); - // iterate the partition states - foreach (var partitionState in s.PartitionStates) - { - this.LogDebug("checking PartitionState {partitionStateKey}", partitionState.PartitionKey); - // get the partition by key - var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); - - this.LogDebug("Expected State: {partitionPresent} Actual State: {partitionState}", partitionState.PartitionPresent, partition.PartitionPresentFeedback.BoolValue); - - if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue) - { - // the partition can't be found or the state doesn't match - return false; - } - } - // if it hasn't returned false by now we have the matching scenario - return true; - }); - - if (currentScenario != null) - { - this.LogInformation("Found combination Scenario {scenarioKey}", currentScenario.Key); - ChangeScenario(currentScenario); - } - } - - private async Task ChangeScenario(IRoomCombinationScenario newScenario) - { - - - if (newScenario == _currentScenario) - { - return; - } - - // Deactivate the old scenario first - if (_currentScenario != null) - { - Debug.LogMessage(LogEventLevel.Information, "Deactivating scenario {currentScenario}", this, _currentScenario.Name); - await _currentScenario.Deactivate(); - } - - _currentScenario = newScenario; - - // Activate the new scenario - if (_currentScenario != null) - { - Debug.LogMessage(LogEventLevel.Debug, $"Current Scenario: {_currentScenario.Name}", this); - await _currentScenario.Activate(); - } - - RoomCombinationScenarioChanged?.Invoke(this, new EventArgs()); - - - } - - #region IEssentialsRoomCombiner Members - - /// - /// Occurs when the room combination scenario changes. - /// - /// This event is triggered whenever the configuration or state of the room combination - /// changes. Subscribers can use this event to update their logic or UI based on the new scenario. - public event EventHandler RoomCombinationScenarioChanged; - - /// - /// Gets the current room combination scenario. - /// - public IRoomCombinationScenario CurrentScenario - { - get - { - return _currentScenario; - } - } - - /// - /// Gets the feedback indicating whether the system is currently in auto mode. - /// - public BoolFeedback IsInAutoModeFeedback { get; private set; } - - /// - /// Enables auto mode for the room combiner and its partitions, allowing automatic room combination scenarios to - /// be determined. - /// - /// Auto mode allows the room combiner to automatically adjust its configuration based on - /// the state of its partitions. If auto mode is disabled in the configuration, this method logs a warning and - /// does not enable auto mode. - public void SetAutoMode() - { - if(_propertiesConfig.DisableAutoMode) - { - this.LogWarning("Auto mode is disabled for this room combiner. Cannot set to auto mode."); - return; - } - IsInAutoMode = true; - - foreach (var partition in Partitions) - { - partition.SetAutoMode(); - } - - DetermineRoomCombinationScenario(); - } - - /// - /// Switches the system to manual mode, disabling automatic operations. - /// - /// This method sets the system to manual mode by updating the mode state and propagates - /// the change to all partitions. Once in manual mode, automatic operations are disabled for the system and its - /// partitions. - public void SetManualMode() - { - IsInAutoMode = false; - - foreach (var partition in Partitions) - { - partition.SetManualMode(); - } - } - - /// - /// Toggles the current mode between automatic and manual. - /// - /// If the current mode is automatic, this method switches to manual mode. If the - /// current mode is manual, it switches to automatic mode. - public void ToggleMode() - { - if (IsInAutoMode) - { - SetManualMode(); - } - else - { - SetAutoMode(); - } - } - - /// - /// Gets the collection of room combination scenarios. - /// - public List RoomCombinationScenarios { get; private set; } - - /// - /// Gets the collection of partition controllers managed by this instance. - /// - public List Partitions { get; private set; } - - /// - /// Toggles the state of the partition identified by the specified partition key. - /// - /// If no partition with the specified key exists, the method performs no - /// action. - /// The key of the partition whose state is to be toggled. This value cannot be null or empty. - public void TogglePartitionState(string partitionKey) - { - var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)); - - if (partition != null) - { - partition.ToggglePartitionState(); - } - } - - /// - /// Sets the room combination scenario based on the specified scenario key. - /// - /// This method manually adjusts the partition states according to the specified - /// scenario. If the application is in auto mode, the operation will not proceed, and a log message will be - /// generated indicating that the mode must be set to manual first. If the specified scenario key does not - /// match any existing scenario, a debug log message will be generated. For each partition state in the - /// scenario, the corresponding partition will be updated to either "Present" or "Not Present" based on the - /// scenario's configuration. If a partition key in the scenario cannot be found, a debug log message will be - /// generated. - /// The key identifying the room combination scenario to apply. This must match the key of an existing scenario. - public void SetRoomCombinationScenario(string scenarioKey) - { - if (IsInAutoMode) - { - Debug.LogMessage(LogEventLevel.Information, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first."); return; } - // Get the scenario - var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey)); - - - // Set the parition states from the scenario manually - if (scenario != null) - { - Debug.LogMessage(LogEventLevel.Information, this, "Manually setting scenario to '{0}'", scenario.Key); - foreach (var partitionState in scenario.PartitionStates) - { - var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); - - if (partition != null) - { - if (partitionState.PartitionPresent) - { - Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Present for: '{0}'", partition.Key); - partition.SetPartitionStatePresent(); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Not Present for: '{0}'", partition.Key); - partition.SetPartitionStateNotPresent(); - } - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find partition with key: '{0}'", partitionState.PartitionKey); - } - } - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find scenario with key: '{0}'", scenarioKey); - } + _isInAutoMode = value; + IsInAutoModeFeedback.FireUpdate(); } - - #endregion } /// - /// Provides a factory for creating instances of devices. + /// Gets a value indicating whether automatic mode is disabled. /// - /// This factory is responsible for constructing devices - /// based on the provided configuration. It supports the type name "essentialsroomcombiner" for device - /// creation. - public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory + public bool DisableAutoMode { - /// - /// Initializes a new instance of the class. - /// - /// This factory is used to create instances of room combiners with the specified type - /// names. By default, the factory includes the type name "essentialsroomcombiner". - public EssentialsRoomCombinerFactory() + get { - TypeNames = new List { "essentialsroomcombiner" }; - } - - /// - /// Creates and initializes a new instance of the device. - /// - /// This method uses the provided device configuration to extract the properties and - /// create an device. Ensure that the configuration contains valid - /// properties for the device to be created successfully. - /// The device configuration containing the key and properties required to build the device. - /// A new instance of initialized with the specified configuration. - public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EssentialsRoomCombiner Device"); - - var props = dc.Properties.ToObject(); - - return new EssentialsRoomCombiner(dc.Key, props); + return _propertiesConfig.DisableAutoMode; } } + + private CTimer _scenarioChangeDebounceTimer; + + private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s + + private Mutex _scenarioChange = new Mutex(); + + /// + /// Initializes a new instance of the class, which manages room combination + /// scenarios and partition states. + /// + /// The class is designed to handle dynamic room + /// combination scenarios based on partition states. It supports both automatic and manual modes for managing + /// room combinations. By default, the instance starts in automatic mode unless the + /// specifies otherwise. After activation, the room combiner initializes partition state providers and sets up + /// the initial room configuration. Additionally, it subscribes to the event to ensure proper initialization of dependent devices + /// before determining or setting the room combination scenario. + /// The unique identifier for the room combiner instance. + /// The configuration properties for the room combiner, including default settings and debounce times. + public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) + : base(key) + { + _propertiesConfig = props; + + Partitions = new List(); + RoomCombinationScenarios = new List(); + + if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) + { + _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; + } + + IsInAutoModeFeedback = new BoolFeedback(() => _isInAutoMode); + + // default to auto mode + IsInAutoMode = true; + + if (_propertiesConfig.defaultToManualMode) + { + IsInAutoMode = false; + } + + IsInAutoModeFeedback.FireUpdate(); + + CreateScenarios(); + + AddPostActivationAction(() => + { + SetupPartitionStateProviders(); + + SetRooms(); + }); + + + // Subscribe to the AllDevicesInitialized event + // We need to wait until all devices are initialized in case + // any actions are dependent on 3rd party devices already being + // connected and initialized + DeviceManager.AllDevicesInitialized += (o, a) => + { + if (IsInAutoMode) + { + DetermineRoomCombinationScenario(); + } + else + { + SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey); + } + }; + } + + private void CreateScenarios() + { + foreach (var scenarioConfig in _propertiesConfig.Scenarios) + { + var scenario = new RoomCombinationScenario(scenarioConfig); + RoomCombinationScenarios.Add(scenario); + } + } + + private void SetRooms() + { + _rooms = new List(); + + foreach (var roomKey in _propertiesConfig.RoomKeys) + { + var room = DeviceManager.GetDeviceForKey(roomKey); + + if (DeviceManager.GetDeviceForKey(roomKey) is IEssentialsRoom essentialsRoom) + { + _rooms.Add(essentialsRoom); + } + } + + var rooms = DeviceManager.AllDevices.OfType().Cast(); + + foreach (var room in rooms) + { + room.Deactivate(); + } + } + + private void SetupPartitionStateProviders() + { + foreach (var pConfig in _propertiesConfig.Partitions) + { + var sensor = DeviceManager.GetDeviceForKey(pConfig.DeviceKey) as IPartitionStateProvider; + + var partition = new EssentialsPartitionController(pConfig.Key, pConfig.Name, sensor, _propertiesConfig.defaultToManualMode, pConfig.AdjacentRoomKeys); + + partition.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; + + Partitions.Add(partition); + } + } + + private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + StartDebounceTimer(); + } + + private void StartDebounceTimer() + { + // default to 500ms for manual mode + var time = 500; + + // if in auto mode, debounce the scenario change + if (IsInAutoMode) time = _scenarioChangeDebounceTimeSeconds * 1000; + + if (_scenarioChangeDebounceTimer == null) + { + _scenarioChangeDebounceTimer = new CTimer((o) => DetermineRoomCombinationScenario(), time); + } + else + { + _scenarioChangeDebounceTimer.Reset(time); + } + } + + /// + /// Determines the current room combination scenario based on the state of the partition sensors + /// + private void DetermineRoomCombinationScenario() + { + if (_scenarioChangeDebounceTimer != null) + { + _scenarioChangeDebounceTimer.Dispose(); + _scenarioChangeDebounceTimer = null; + } + + this.LogInformation("Determining Combination Scenario"); + + var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) => + { + this.LogDebug("Checking scenario {scenarioKey}", s.Key); + // iterate the partition states + foreach (var partitionState in s.PartitionStates) + { + this.LogDebug("checking PartitionState {partitionStateKey}", partitionState.PartitionKey); + // get the partition by key + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); + + this.LogDebug("Expected State: {partitionPresent} Actual State: {partitionState}", partitionState.PartitionPresent, partition.PartitionPresentFeedback.BoolValue); + + if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue) + { + // the partition can't be found or the state doesn't match + return false; + } + } + // if it hasn't returned false by now we have the matching scenario + return true; + }); + + if (currentScenario != null) + { + this.LogInformation("Found combination Scenario {scenarioKey}", currentScenario.Key); + ChangeScenario(currentScenario); + } + } + + private async Task ChangeScenario(IRoomCombinationScenario newScenario) + { + + + if (newScenario == _currentScenario) + { + return; + } + + // Deactivate the old scenario first + if (_currentScenario != null) + { + Debug.LogMessage(LogEventLevel.Information, "Deactivating scenario {currentScenario}", this, _currentScenario.Name); + await _currentScenario.Deactivate(); + } + + _currentScenario = newScenario; + + // Activate the new scenario + if (_currentScenario != null) + { + Debug.LogMessage(LogEventLevel.Debug, $"Current Scenario: {_currentScenario.Name}", this); + await _currentScenario.Activate(); + } + + RoomCombinationScenarioChanged?.Invoke(this, new EventArgs()); + + + } + + #region IEssentialsRoomCombiner Members + + /// + /// Occurs when the room combination scenario changes. + /// + /// This event is triggered whenever the configuration or state of the room combination + /// changes. Subscribers can use this event to update their logic or UI based on the new scenario. + public event EventHandler RoomCombinationScenarioChanged; + + /// + /// Gets the current room combination scenario. + /// + public IRoomCombinationScenario CurrentScenario + { + get + { + return _currentScenario; + } + } + + /// + /// Gets the feedback indicating whether the system is currently in auto mode. + /// + public BoolFeedback IsInAutoModeFeedback { get; private set; } + + /// + /// Enables auto mode for the room combiner and its partitions, allowing automatic room combination scenarios to + /// be determined. + /// + /// Auto mode allows the room combiner to automatically adjust its configuration based on + /// the state of its partitions. If auto mode is disabled in the configuration, this method logs a warning and + /// does not enable auto mode. + public void SetAutoMode() + { + if(_propertiesConfig.DisableAutoMode) + { + this.LogWarning("Auto mode is disabled for this room combiner. Cannot set to auto mode."); + return; + } + IsInAutoMode = true; + + foreach (var partition in Partitions) + { + partition.SetAutoMode(); + } + + DetermineRoomCombinationScenario(); + } + + /// + /// Switches the system to manual mode, disabling automatic operations. + /// + /// This method sets the system to manual mode by updating the mode state and propagates + /// the change to all partitions. Once in manual mode, automatic operations are disabled for the system and its + /// partitions. + public void SetManualMode() + { + IsInAutoMode = false; + + foreach (var partition in Partitions) + { + partition.SetManualMode(); + } + } + + /// + /// Toggles the current mode between automatic and manual. + /// + /// If the current mode is automatic, this method switches to manual mode. If the + /// current mode is manual, it switches to automatic mode. + public void ToggleMode() + { + if (IsInAutoMode) + { + SetManualMode(); + } + else + { + SetAutoMode(); + } + } + + /// + /// Gets the collection of room combination scenarios. + /// + public List RoomCombinationScenarios { get; private set; } + + /// + /// Gets the collection of partition controllers managed by this instance. + /// + public List Partitions { get; private set; } + + /// + /// Toggles the state of the partition identified by the specified partition key. + /// + /// If no partition with the specified key exists, the method performs no + /// action. + /// The key of the partition whose state is to be toggled. This value cannot be null or empty. + public void TogglePartitionState(string partitionKey) + { + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)); + + if (partition != null) + { + partition.ToggglePartitionState(); + } + } + + /// + /// Sets the room combination scenario based on the specified scenario key. + /// + /// This method manually adjusts the partition states according to the specified + /// scenario. If the application is in auto mode, the operation will not proceed, and a log message will be + /// generated indicating that the mode must be set to manual first. If the specified scenario key does not + /// match any existing scenario, a debug log message will be generated. For each partition state in the + /// scenario, the corresponding partition will be updated to either "Present" or "Not Present" based on the + /// scenario's configuration. If a partition key in the scenario cannot be found, a debug log message will be + /// generated. + /// The key identifying the room combination scenario to apply. This must match the key of an existing scenario. + public void SetRoomCombinationScenario(string scenarioKey) + { + if (IsInAutoMode) + { + Debug.LogMessage(LogEventLevel.Information, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first."); + return; + } + + // Get the scenario + var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey)); + + + // Set the parition states from the scenario manually + if (scenario != null) + { + Debug.LogMessage(LogEventLevel.Information, this, "Manually setting scenario to '{0}'", scenario.Key); + foreach (var partitionState in scenario.PartitionStates) + { + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); + + if (partition != null) + { + if (partitionState.PartitionPresent) + { + Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Present for: '{0}'", partition.Key); + partition.SetPartitionStatePresent(); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Not Present for: '{0}'", partition.Key); + partition.SetPartitionStateNotPresent(); + } + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find partition with key: '{0}'", partitionState.PartitionKey); + } + } + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find scenario with key: '{0}'", scenarioKey); + } + } + + #endregion +} + +/// +/// Provides a factory for creating instances of devices. +/// +/// This factory is responsible for constructing devices +/// based on the provided configuration. It supports the type name "essentialsroomcombiner" for device +/// creation. +public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory +{ + /// + /// Initializes a new instance of the class. + /// + /// This factory is used to create instances of room combiners with the specified type + /// names. By default, the factory includes the type name "essentialsroomcombiner". + public EssentialsRoomCombinerFactory() + { + TypeNames = new List { "essentialsroomcombiner" }; + } + + /// + /// Creates and initializes a new instance of the device. + /// + /// This method uses the provided device configuration to extract the properties and + /// create an device. Ensure that the configuration contains valid + /// properties for the device to be created successfully. + /// The device configuration containing the key and properties required to build the device. + /// A new instance of initialized with the specified configuration. + public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EssentialsRoomCombiner Device"); + + var props = dc.Properties.ToObject(); + + return new EssentialsRoomCombiner(dc.Key, props); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index fec7e380..9e4f6a15 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -4,145 +4,144 @@ using PepperDash.Core; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Config properties for an EssentialsRoomCombiner device +/// +public class EssentialsRoomCombinerPropertiesConfig { - /// - /// Config properties for an EssentialsRoomCombiner device + /// + /// Gets or sets a value indicating whether the system operates in automatic mode. + /// Some systems don't have partitions sensors, and show shouldn't allow auto mode to be turned on. When this is true in the configuration, + /// auto mode won't be allowed to be turned on. /// - public class EssentialsRoomCombinerPropertiesConfig - { - /// - /// Gets or sets a value indicating whether the system operates in automatic mode. - /// Some systems don't have partitions sensors, and show shouldn't allow auto mode to be turned on. When this is true in the configuration, - /// auto mode won't be allowed to be turned on. - /// - [JsonProperty("disableAutoMode")] - public bool DisableAutoMode { get; set; } - - /// - /// The list of partitions that device the rooms - /// - [JsonProperty("partitions")] - public List Partitions {get; set;} - - /// - /// The list of combinations scenarios for the rooms - /// - [JsonProperty("scenarios")] - public List Scenarios { get; set; } - - /// - /// The list of rooms keys that can be combined - /// - [JsonProperty("roomKeys")] - public List RoomKeys {get; set;} - - /// - /// Set to true to default to manual mode - /// - [JsonProperty("defaultToManualMode")] - public bool defaultToManualMode { get; set; } - - /// - /// The key of the scenario to default to at system startup if in manual mode - /// - [JsonProperty("defaultScenarioKey")] - public string defaultScenarioKey { get; set; } - - /// - /// Gets or sets the debounce time, in seconds, for scenario changes. - /// - [JsonProperty("scenarioChangeDebounceTimeSeconds")] - public int ScenarioChangeDebounceTimeSeconds { get; set; } - } + [JsonProperty("disableAutoMode")] + public bool DisableAutoMode { get; set; } /// - /// Config properties for a partition that separates rooms + /// The list of partitions that device the rooms /// - public class PartitionConfig : IKeyName - { - /// - /// Gets or sets the unique key associated with the object. - /// - [JsonProperty("key")] - public string Key { get; set; } - - /// - /// Gets or sets the name associated with the object. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Key of the device that implements IPartitionStateProvider to provide the state of the partition - /// - [JsonProperty("deviceKey")] - public string DeviceKey { get; set; } - - /// - /// Keys of the rooms that this partion would be located between - /// - [JsonProperty("adjacentRoomKeys")] - public List AdjacentRoomKeys { get; set; } - } + [JsonProperty("partitions")] + public List Partitions {get; set;} /// - /// Config propeties for a room combination scenario + /// The list of combinations scenarios for the rooms /// - public class RoomCombinationScenarioConfig : IKeyName - { - /// - /// Gets or sets the key associated with the object. - /// - [JsonProperty("key")] - public string Key { get; set; } - - /// - /// Gets or sets the name associated with the object. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the collection of partition states. - /// - [JsonProperty("partitionStates")] - public List PartitionStates { get; set; } - - /// - /// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to - /// - [JsonProperty("uiMap")] - public Dictionary UiMap { get; set; } - - /// - /// Gets or sets the list of actions to be performed during device activation. - /// - [JsonProperty("activationActions")] - public List ActivationActions { get; set; } - - /// - /// Gets or sets the list of actions to be performed when a device is deactivated. - /// - [JsonProperty("deactivationActions")] - public List DeactivationActions { get; set; } - } + [JsonProperty("scenarios")] + public List Scenarios { get; set; } /// - /// Config properties to represent the state of a partition sensor in a RoomCombinationScenario + /// The list of rooms keys that can be combined /// - public class PartitionState - { - /// - /// Gets or sets the partition key used to group and organize data within a storage system. - /// - [JsonProperty("partitionKey")] - public string PartitionKey { get; set; } + [JsonProperty("roomKeys")] + public List RoomKeys {get; set;} - /// - /// Gets or sets a value indicating whether a partition is currently present. - /// - [JsonProperty("partitionSensedState")] - public bool PartitionPresent { get; set; } - } + /// + /// Set to true to default to manual mode + /// + [JsonProperty("defaultToManualMode")] + public bool defaultToManualMode { get; set; } + + /// + /// The key of the scenario to default to at system startup if in manual mode + /// + [JsonProperty("defaultScenarioKey")] + public string defaultScenarioKey { get; set; } + + /// + /// Gets or sets the debounce time, in seconds, for scenario changes. + /// + [JsonProperty("scenarioChangeDebounceTimeSeconds")] + public int ScenarioChangeDebounceTimeSeconds { get; set; } +} + +/// +/// Config properties for a partition that separates rooms +/// +public class PartitionConfig : IKeyName +{ + /// + /// Gets or sets the unique key associated with the object. + /// + [JsonProperty("key")] + public string Key { get; set; } + + /// + /// Gets or sets the name associated with the object. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Key of the device that implements IPartitionStateProvider to provide the state of the partition + /// + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + /// + /// Keys of the rooms that this partion would be located between + /// + [JsonProperty("adjacentRoomKeys")] + public List AdjacentRoomKeys { get; set; } +} + +/// +/// Config propeties for a room combination scenario +/// +public class RoomCombinationScenarioConfig : IKeyName +{ + /// + /// Gets or sets the key associated with the object. + /// + [JsonProperty("key")] + public string Key { get; set; } + + /// + /// Gets or sets the name associated with the object. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the collection of partition states. + /// + [JsonProperty("partitionStates")] + public List PartitionStates { get; set; } + + /// + /// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to + /// + [JsonProperty("uiMap")] + public Dictionary UiMap { get; set; } + + /// + /// Gets or sets the list of actions to be performed during device activation. + /// + [JsonProperty("activationActions")] + public List ActivationActions { get; set; } + + /// + /// Gets or sets the list of actions to be performed when a device is deactivated. + /// + [JsonProperty("deactivationActions")] + public List DeactivationActions { get; set; } +} + +/// +/// Config properties to represent the state of a partition sensor in a RoomCombinationScenario +/// +public class PartitionState +{ + /// + /// Gets or sets the partition key used to group and organize data within a storage system. + /// + [JsonProperty("partitionKey")] + public string PartitionKey { get; set; } + + /// + /// Gets or sets a value indicating whether a partition is currently present. + /// + [JsonProperty("partitionSensedState")] + public bool PartitionPresent { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs b/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs index 04dfd16f..bf015b6f 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs @@ -4,129 +4,127 @@ using System.Threading.Tasks; using Newtonsoft.Json; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Describes the functionality for an EssentailsRoomCombiner device +/// +public interface IEssentialsRoomCombiner : IKeyed { /// - /// Describes the functionality for an EssentailsRoomCombiner device + /// Indicates that the room combination scenario has changed /// - public interface IEssentialsRoomCombiner : IKeyed - { - /// - /// Indicates that the room combination scenario has changed - /// - event EventHandler RoomCombinationScenarioChanged; + event EventHandler RoomCombinationScenarioChanged; - /// - /// The current room combination scenario - /// - [JsonProperty("currentScenario")] - IRoomCombinationScenario CurrentScenario { get; } + /// + /// The current room combination scenario + /// + [JsonProperty("currentScenario")] + IRoomCombinationScenario CurrentScenario { get; } - /// - /// When true, indicates the current mode is auto mode - /// - [JsonIgnore] - BoolFeedback IsInAutoModeFeedback {get;} - - /// - /// Gets a value indicating whether the automatic mode is disabled. - /// - [JsonProperty("disableAutoMode")] - bool DisableAutoMode { get; } - /// - /// Gets a value indicating whether the system is operating in automatic mode. - /// - [JsonProperty("isInAutoMode")] - bool IsInAutoMode { get; } - - /// - /// Gets the collection of rooms associated with the current object. - /// - [JsonProperty("rooms")] - List Rooms { get; } - - /// - /// Sets auto mode - /// - void SetAutoMode(); - - /// - /// Sets manual mode - /// - void SetManualMode(); - - /// - /// Toggles the current mode between auto and manual - /// - void ToggleMode(); - - /// - /// The available room combinatino scenarios - /// - [JsonProperty("roomCombinationScenarios")] - List RoomCombinationScenarios { get; } - - /// - /// The partition - /// - [JsonProperty("partitions")] - List Partitions { get; } - - /// - /// Toggles the state of a manual partition sensor - /// - /// - void TogglePartitionState(string partitionKey); - - /// - /// Sets the room combination scenario (if in manual mode) - /// - /// - void SetRoomCombinationScenario(string scenarioKey); - } + /// + /// When true, indicates the current mode is auto mode + /// + [JsonIgnore] + BoolFeedback IsInAutoModeFeedback {get;} /// - /// Represents a scenario for combining rooms, including activation, deactivation, and associated state. + /// Gets a value indicating whether the automatic mode is disabled. /// - /// This interface defines the behavior for managing room combination scenarios, including - /// activation and deactivation, tracking the active state, and managing related partition states and UI mappings. - /// Implementations of this interface are expected to handle the logic for room combinations based on the provided - /// partition states and UI mappings. - public interface IRoomCombinationScenario : IKeyName - { - /// - /// When true, indicates that this room combination scenario is active - /// - [JsonIgnore] - BoolFeedback IsActiveFeedback { get; } + [JsonProperty("disableAutoMode")] + bool DisableAutoMode { get; } + /// + /// Gets a value indicating whether the system is operating in automatic mode. + /// + [JsonProperty("isInAutoMode")] + bool IsInAutoMode { get; } - /// - /// Gets a value indicating whether the entity is active. - /// - [JsonProperty("isActive")] - bool IsActive { get; } + /// + /// Gets the collection of rooms associated with the current object. + /// + [JsonProperty("rooms")] + List Rooms { get; } - /// - /// Activates this room combination scenario - /// - Task Activate(); + /// + /// Sets auto mode + /// + void SetAutoMode(); - /// - /// Deactivates this room combination scenario - /// - Task Deactivate(); + /// + /// Sets manual mode + /// + void SetManualMode(); - /// - /// The state of the partitions that would activate this scenario - /// - [JsonProperty("partitionStates")] - List PartitionStates { get; } + /// + /// Toggles the current mode between auto and manual + /// + void ToggleMode(); - /// - /// The mapping of UIs by key to rooms by key - /// - [JsonProperty("uiMap")] - Dictionary UiMap { get; set; } - } + /// + /// The available room combinatino scenarios + /// + [JsonProperty("roomCombinationScenarios")] + List RoomCombinationScenarios { get; } + /// + /// The partition + /// + [JsonProperty("partitions")] + List Partitions { get; } + + /// + /// Toggles the state of a manual partition sensor + /// + /// + void TogglePartitionState(string partitionKey); + + /// + /// Sets the room combination scenario (if in manual mode) + /// + /// + void SetRoomCombinationScenario(string scenarioKey); +} + +/// +/// Represents a scenario for combining rooms, including activation, deactivation, and associated state. +/// +/// This interface defines the behavior for managing room combination scenarios, including +/// activation and deactivation, tracking the active state, and managing related partition states and UI mappings. +/// Implementations of this interface are expected to handle the logic for room combinations based on the provided +/// partition states and UI mappings. +public interface IRoomCombinationScenario : IKeyName +{ + /// + /// When true, indicates that this room combination scenario is active + /// + [JsonIgnore] + BoolFeedback IsActiveFeedback { get; } + + /// + /// Gets a value indicating whether the entity is active. + /// + [JsonProperty("isActive")] + bool IsActive { get; } + + /// + /// Activates this room combination scenario + /// + Task Activate(); + + /// + /// Deactivates this room combination scenario + /// + Task Deactivate(); + + /// + /// The state of the partitions that would activate this scenario + /// + [JsonProperty("partitionStates")] + List PartitionStates { get; } + + /// + /// The mapping of UIs by key to rooms by key + /// + [JsonProperty("uiMap")] + Dictionary UiMap { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs b/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs index b0b338ec..575528a5 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs @@ -5,107 +5,105 @@ using Serilog.Events; using System.Collections.Generic; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a room combination scenario +/// +public class RoomCombinationScenario : IRoomCombinationScenario, IKeyName { - /// - /// Represents a room combination scenario - /// - public class RoomCombinationScenario : IRoomCombinationScenario, IKeyName + private RoomCombinationScenarioConfig _config; + + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("partitionStates")] + public List PartitionStates { get; private set; } + + [JsonProperty("uiMap")] + public Dictionary UiMap { get; set; } + + private bool _isActive; + + [JsonProperty("isActive")] + public bool IsActive { - private RoomCombinationScenarioConfig _config; - - [JsonProperty("key")] - public string Key { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("partitionStates")] - public List PartitionStates { get; private set; } - - [JsonProperty("uiMap")] - public Dictionary UiMap { get; set; } - - private bool _isActive; - - [JsonProperty("isActive")] - public bool IsActive + get { return _isActive; } + set { - get { return _isActive; } - set + if (value == _isActive) { - if (value == _isActive) - { - return; - } + return; + } - _isActive = value; - IsActiveFeedback.FireUpdate(); + _isActive = value; + IsActiveFeedback.FireUpdate(); + } + } + + [JsonIgnore] + public BoolFeedback IsActiveFeedback { get; private set; } + + private List activationActions; + + private List deactivationActions; + + public RoomCombinationScenario(RoomCombinationScenarioConfig config) + { + Key = config.Key; + + Name = config.Name; + + PartitionStates = config.PartitionStates; + + UiMap = config.UiMap; + + activationActions = config.ActivationActions; + + deactivationActions = config.DeactivationActions; + + _config = config; + + IsActiveFeedback = new BoolFeedback(() => _isActive); + } + + public async Task Activate() + { + this.LogInformation("Activating Scenario {name} with {activationActionCount} action(s) defined", Name, activationActions.Count); + + List tasks = new List(); + + if (activationActions != null) + { + foreach (var action in activationActions) + { + this.LogInformation("Running Activation action {@action}", action); + await DeviceJsonApi.DoDeviceActionAsync(action); } } - [JsonIgnore] - public BoolFeedback IsActiveFeedback { get; private set; } + IsActive = true; + } - private List activationActions; + public async Task Deactivate() + { + this.LogInformation("Deactivating Scenario {name} with {deactivationActionCount} action(s) defined", Name, deactivationActions.Count); - private List deactivationActions; + List tasks = new List(); - public RoomCombinationScenario(RoomCombinationScenarioConfig config) + if (deactivationActions != null) { - Key = config.Key; - - Name = config.Name; - - PartitionStates = config.PartitionStates; - - UiMap = config.UiMap; - - activationActions = config.ActivationActions; - - deactivationActions = config.DeactivationActions; - - _config = config; - - IsActiveFeedback = new BoolFeedback(() => _isActive); - } - - public async Task Activate() - { - this.LogInformation("Activating Scenario {name} with {activationActionCount} action(s) defined", Name, activationActions.Count); - - List tasks = new List(); - - if (activationActions != null) + foreach (var action in deactivationActions) { - foreach (var action in activationActions) - { - this.LogInformation("Running Activation action {@action}", action); - await DeviceJsonApi.DoDeviceActionAsync(action); - } + this.LogInformation("Running deactivation action {actionDeviceKey}:{actionMethod}", action.DeviceKey, action.MethodName); + await DeviceJsonApi.DoDeviceActionAsync(action); } - - IsActive = true; - } - - public async Task Deactivate() - { - this.LogInformation("Deactivating Scenario {name} with {deactivationActionCount} action(s) defined", Name, deactivationActions.Count); - - List tasks = new List(); - - if (deactivationActions != null) - { - foreach (var action in deactivationActions) - { - this.LogInformation("Running deactivation action {actionDeviceKey}:{actionMethod}", action.DeviceKey, action.MethodName); - await DeviceJsonApi.DoDeviceActionAsync(action); - } - } - - IsActive = false; } + IsActive = false; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs index 2eb56fd3..9420a3ac 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs @@ -1,8 +1,7 @@  -namespace PepperDash.Essentials.Room.Config -{ - public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig - { +namespace PepperDash.Essentials.Room.Config; + +public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig +{ - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs index a0b3499f..2ac5f2ff 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs @@ -1,34 +1,33 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// +/// +public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig { /// - /// + /// The key of the default display device /// - public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig - { - /// - /// The key of the default display device - /// - [JsonProperty("defaultDisplayKey")] - public string DefaultDisplayKey { get; set; } + [JsonProperty("defaultDisplayKey")] + public string DefaultDisplayKey { get; set; } - /// - /// The key of the default audio device - /// - [JsonProperty("defaultAudioKey")] - public string DefaultAudioKey { get; set; } + /// + /// The key of the default audio device + /// + [JsonProperty("defaultAudioKey")] + public string DefaultAudioKey { get; set; } - /// - /// The key of the source list for the room - /// - [JsonProperty("sourceListKey")] - public string SourceListKey { get; set; } + /// + /// The key of the source list for the room + /// + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } - /// - /// The key of the default source item from the source list - /// - [JsonProperty("defaultSourceItem")] - public string DefaultSourceItem { get; set; } - } + /// + /// The key of the default source item from the source list + /// + [JsonProperty("defaultSourceItem")] + public string DefaultSourceItem { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs index 27164f57..852eff32 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs @@ -1,13 +1,12 @@  using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Config -{ +namespace PepperDash.Essentials.Room.Config; - public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig - { + +public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig +{ [JsonProperty("defaultDisplayKey")] public string DefaultDisplayKey { get; set; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs index 6d8762fa..a7c9344b 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs @@ -4,31 +4,29 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// +/// +public class EssentialsNDisplayRoomPropertiesConfig : EssentialsConferenceRoomPropertiesConfig { - /// - /// - /// - public class EssentialsNDisplayRoomPropertiesConfig : EssentialsConferenceRoomPropertiesConfig + [JsonProperty("defaultAudioBehavior")] + public string DefaultAudioBehavior { get; set; } + [JsonProperty("defaultVideoBehavior")] + public string DefaultVideoBehavior { get; set; } + [JsonProperty("displays")] + public Dictionary Displays { get; set; } + + public EssentialsNDisplayRoomPropertiesConfig() { - [JsonProperty("defaultAudioBehavior")] - public string DefaultAudioBehavior { get; set; } - [JsonProperty("defaultVideoBehavior")] - public string DefaultVideoBehavior { get; set; } - [JsonProperty("displays")] - public Dictionary Displays { get; set; } - - public EssentialsNDisplayRoomPropertiesConfig() - { - Displays = new Dictionary(); - } - + Displays = new Dictionary(); } - public class DisplayItem : IKeyName - { - public string Key { get; set; } - public string Name { get; set; } - } +} +public class DisplayItem : IKeyName +{ + public string Key { get; set; } + public string Name { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsPresentationPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsPresentationPropertiesConfig.cs index 53333f07..accf09ed 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsPresentationPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsPresentationPropertiesConfig.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -namespace PepperDash.Essentials.Room.Config -{ - /// - /// - /// - public class EssentialsPresentationRoomPropertiesConfig : EssentialsRoomPropertiesConfig - { - public string DefaultAudioBehavior { get; set; } - public string DefaultAudioKey { get; set; } - public string DefaultVideoBehavior { get; set; } - public List DisplayKeys { get; set; } - public string SourceListKey { get; set; } - public bool HasDsp { get; set; } +namespace PepperDash.Essentials.Room.Config; - public EssentialsPresentationRoomPropertiesConfig() - { - DisplayKeys = new List(); - } +/// +/// +/// +public class EssentialsPresentationRoomPropertiesConfig : EssentialsRoomPropertiesConfig +{ + public string DefaultAudioBehavior { get; set; } + public string DefaultAudioKey { get; set; } + public string DefaultVideoBehavior { get; set; } + public List DisplayKeys { get; set; } + public string SourceListKey { get; set; } + public bool HasDsp { get; set; } + + public EssentialsPresentationRoomPropertiesConfig() + { + DisplayKeys = new List(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs index e9a2c29b..d2302d5a 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs @@ -7,27 +7,27 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Privacy; using Serilog.Events; -namespace PepperDash.Essentials.Room.Config -{ +namespace PepperDash.Essentials.Room.Config; + public class EssentialsRoomConfigHelper { - /// - /// Gets and operating, standalone emergegncy object that can be plugged into a room. - /// Returns null if there is no emergency defined - /// - public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room) + /// + /// Gets and operating, standalone emergegncy object that can be plugged into a room. + /// Returns null if there is no emergency defined + /// + public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room) + { + // This emergency + var emergency = props.Emergency; + if (emergency != null) { - // This emergency - var emergency = props.Emergency; - if (emergency != null) - { - //switch on emergency type here. Right now only contact and shutdown - var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room); - DeviceManager.AddDevice(e); - return e; - } - return null; + //switch on emergency type here. Right now only contact and shutdown + var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room); + DeviceManager.AddDevice(e); + return e; } + return null; + } /// /// @@ -64,30 +64,30 @@ namespace PepperDash.Essentials.Room.Config if (behaviour == "trackroomstate") { // Tie LED enable to room power state - var essRoom = room as IEssentialsRoom; - essRoom.OnFeedback.OutputChange += (o, a) => + var essRoom = room as IEssentialsRoom; + essRoom.OnFeedback.OutputChange += (o, a) => { - if (essRoom.OnFeedback.BoolValue) + if (essRoom.OnFeedback.BoolValue) mP.EnableLeds = true; else mP.EnableLeds = false; }; - mP.EnableLeds = essRoom.OnFeedback.BoolValue; + mP.EnableLeds = essRoom.OnFeedback.BoolValue; } else if (behaviour == "trackcallstate") { // Tie LED enable to room power state - var inCallRoom = room as IHasInCallFeedback; - inCallRoom.InCallFeedback.OutputChange += (o, a) => + var inCallRoom = room as IHasInCallFeedback; + inCallRoom.InCallFeedback.OutputChange += (o, a) => { - if (inCallRoom.InCallFeedback.BoolValue) + if (inCallRoom.InCallFeedback.BoolValue) mP.EnableLeds = true; else mP.EnableLeds = false; }; - mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue; + mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue; } return mP; @@ -95,9 +95,9 @@ namespace PepperDash.Essentials.Room.Config } - /// - /// - /// +/// +/// +/// public class EssentialsRoomPropertiesConfig { [JsonProperty("addresses")] @@ -115,23 +115,23 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("helpMessage")] public string HelpMessage { get; set; } - /// - /// Read this value to get the help message. It checks for the old and new config format. - /// - public string HelpMessageForDisplay + /// + /// Read this value to get the help message. It checks for the old and new config format. + /// + public string HelpMessageForDisplay + { + get { - get + if(Help != null && !string.IsNullOrEmpty(Help.Message)) { - if(Help != null && !string.IsNullOrEmpty(Help.Message)) - { - return Help.Message; - } - else - { - return HelpMessage; - } + return Help.Message; + } + else + { + return HelpMessage; } } + } [JsonProperty("environment")] public EssentialsEnvironmentPropertiesConfig Environment { get; set; } @@ -139,8 +139,8 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("logo")] public EssentialsLogoPropertiesConfig LogoLight { get; set; } - [JsonProperty("logoDark")] - public EssentialsLogoPropertiesConfig LogoDark { get; set; } + [JsonProperty("logoDark")] + public EssentialsLogoPropertiesConfig LogoDark { get; set; } [JsonProperty("microphonePrivacy")] public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; } @@ -163,215 +163,214 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("volumes")] public EssentialsRoomVolumesConfig Volumes { get; set; } - [JsonProperty("fusion")] - public EssentialsRoomFusionConfig Fusion { get; set; } + [JsonProperty("fusion")] + public EssentialsRoomFusionConfig Fusion { get; set; } - [JsonProperty("essentialsRoomUiBehaviorConfig", NullValueHandling=NullValueHandling.Ignore)] - public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } + [JsonProperty("essentialsRoomUiBehaviorConfig", NullValueHandling=NullValueHandling.Ignore)] + public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } [JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")] public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; } - /// - /// Indicates if this room represents a combination of other rooms - /// - [JsonProperty("isRoomCombinationScenario")] - public bool IsRoomCombinationScenario { get; set; } + /// + /// Indicates if this room represents a combination of other rooms + /// + [JsonProperty("isRoomCombinationScenario")] + public bool IsRoomCombinationScenario { get; set; } - public EssentialsRoomPropertiesConfig() - { - LogoLight = new EssentialsLogoPropertiesConfig(); - LogoDark = new EssentialsLogoPropertiesConfig(); - } + public EssentialsRoomPropertiesConfig() + { + LogoLight = new EssentialsLogoPropertiesConfig(); + LogoDark = new EssentialsLogoPropertiesConfig(); + } } - public class EssentialsRoomUiBehaviorConfig - { - [JsonProperty("disableActivityButtonsWhileWarmingCooling")] - public bool DisableActivityButtonsWhileWarmingCooling { get; set; } - } +public class EssentialsRoomUiBehaviorConfig +{ + [JsonProperty("disableActivityButtonsWhileWarmingCooling")] + public bool DisableActivityButtonsWhileWarmingCooling { get; set; } +} - public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig - { - [JsonProperty("defaultAudioKey")] - public string DefaultAudioKey { get; set; } - [JsonProperty("sourceListKey")] - public string SourceListKey { get; set; } - [JsonProperty("destinationListKey")] - public string DestinationListKey { get; set; } - [JsonProperty("audioControlPointListKey")] - public string AudioControlPointListKey { get; set; } - [JsonProperty("cameraListKey")] - public string CameraListKey { get; set; } +public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig +{ + [JsonProperty("defaultAudioKey")] + public string DefaultAudioKey { get; set; } + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } + [JsonProperty("destinationListKey")] + public string DestinationListKey { get; set; } + [JsonProperty("audioControlPointListKey")] + public string AudioControlPointListKey { get; set; } + [JsonProperty("cameraListKey")] + public string CameraListKey { get; set; } - [JsonProperty("defaultSourceItem")] - public string DefaultSourceItem { get; set; } - /// - /// Indicates if the room supports advanced sharing - /// - [JsonProperty("supportsAdvancedSharing")] - public bool SupportsAdvancedSharing { get; set; } - /// - /// Indicates if non-tech users can change the share mode - /// - [JsonProperty("userCanChangeShareMode")] - public bool UserCanChangeShareMode { get; set; } + [JsonProperty("defaultSourceItem")] + public string DefaultSourceItem { get; set; } + /// + /// Indicates if the room supports advanced sharing + /// + [JsonProperty("supportsAdvancedSharing")] + public bool SupportsAdvancedSharing { get; set; } + /// + /// Indicates if non-tech users can change the share mode + /// + [JsonProperty("userCanChangeShareMode")] + public bool UserCanChangeShareMode { get; set; } - [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] - public string MatrixRoutingKey { get; set; } - } + [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] + public string MatrixRoutingKey { get; set; } +} - public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig - { - [JsonProperty("videoCodecKey")] - public string VideoCodecKey { get; set; } - [JsonProperty("audioCodecKey")] - public string AudioCodecKey { get; set; } +public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig +{ + [JsonProperty("videoCodecKey")] + public string VideoCodecKey { get; set; } + [JsonProperty("audioCodecKey")] + public string AudioCodecKey { get; set; } - } +} public class EssentialsEnvironmentPropertiesConfig { public bool Enabled { get; set; } - [JsonProperty("deviceKeys")] - public List DeviceKeys { get; set; } + [JsonProperty("deviceKeys")] + public List DeviceKeys { get; set; } - public EssentialsEnvironmentPropertiesConfig() - { - DeviceKeys = new List(); - } + public EssentialsEnvironmentPropertiesConfig() + { + DeviceKeys = new List(); + } } - public class EssentialsRoomFusionConfig +public class EssentialsRoomFusionConfig +{ + public uint IpIdInt { - public uint IpIdInt + get { - get + try { - try - { - return Convert.ToUInt32(IpId, 16); - } - catch (Exception) - { - throw new FormatException(string.Format("ERROR:Unable to convert IP ID: {0} to hex. Error:\n{1}", IpId)); - } - + return Convert.ToUInt32(IpId, 16); } + catch (Exception) + { + throw new FormatException(string.Format("ERROR:Unable to convert IP ID: {0} to hex. Error:\n{1}", IpId)); + } + } - - [JsonProperty("ipId")] - public string IpId { get; set; } - - [JsonProperty("joinMapKey")] - public string JoinMapKey { get; set; } - } - public class EssentialsRoomMicrophonePrivacyConfig - { + [JsonProperty("ipId")] + public string IpId { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + +} + +public class EssentialsRoomMicrophonePrivacyConfig +{ [JsonProperty("deviceKey")] public string DeviceKey { get; set; } [JsonProperty("behaviour")] public string Behaviour { get; set; } - } +} - /// - /// Properties for the help text box - /// - public class EssentialsHelpPropertiesConfig - { +/// +/// Properties for the help text box +/// +public class EssentialsHelpPropertiesConfig +{ [JsonProperty("message")] public string Message { get; set; } [JsonProperty("showCallButton")] public bool ShowCallButton { get; set; } - + /// - /// Defaults to "Call Help Desk" - /// + /// Defaults to "Call Help Desk" + /// [JsonProperty("callButtonText")] public string CallButtonText { get; set; } - public EssentialsHelpPropertiesConfig() - { - CallButtonText = "Call Help Desk"; - } - } - - /// - /// - /// - public class EssentialsOneButtonMeetingPropertiesConfig + public EssentialsHelpPropertiesConfig() { + CallButtonText = "Call Help Desk"; + } +} + +/// +/// +/// +public class EssentialsOneButtonMeetingPropertiesConfig +{ [JsonProperty("enable")] public bool Enable { get; set; } - } +} - public class EssentialsRoomAddressPropertiesConfig - { +public class EssentialsRoomAddressPropertiesConfig +{ [JsonProperty("phoneNumber")] public string PhoneNumber { get; set; } [JsonProperty("sipAddress")] public string SipAddress { get; set; } - } +} - /// - /// Properties for the room's logo on panels - /// - public class EssentialsLogoPropertiesConfig - { +/// +/// Properties for the room's logo on panels +/// +public class EssentialsLogoPropertiesConfig +{ [JsonProperty("type")] public string Type { get; set; } [JsonProperty("url")] public string Url { get; set; } - /// - /// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo - /// - public string GetLogoUrlLight() - { - if (Type == "url") - return Url; - if (Type == "system") - return string.Format("http://{0}:8080/logo.png", - CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); - return null; - } - - public string GetLogoUrlDark() - { - if (Type == "url") - return Url; - if (Type == "system") - return string.Format("http://{0}:8080/logo-dark.png", - CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); - return null; - } + /// + /// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo + /// + public string GetLogoUrlLight() + { + if (Type == "url") + return Url; + if (Type == "system") + return string.Format("http://{0}:8080/logo.png", + CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); + return null; } - /// - /// Represents occupancy sensor(s) setup for a room - /// - public class EssentialsRoomOccSensorConfig + public string GetLogoUrlDark() { + if (Type == "url") + return Url; + if (Type == "system") + return string.Format("http://{0}:8080/logo-dark.png", + CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); + return null; + } +} + +/// +/// Represents occupancy sensor(s) setup for a room +/// +public class EssentialsRoomOccSensorConfig +{ [JsonProperty("deviceKey")] public string DeviceKey { get; set; } [JsonProperty("timeoutMinutes")] public int TimeoutMinutes { get; set; } - } +} public class EssentialsRoomTechConfig { [JsonProperty("password")] public string Password { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs index dbc068eb..f3440043 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs @@ -1,30 +1,29 @@ -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// +/// +public class EssentialsRoomEmergencyConfig +{ + public EssentialsRoomEmergencyTriggerConfig Trigger { get; set; } + + public string Behavior { get; set; } +} + +/// +/// +/// +public class EssentialsRoomEmergencyTriggerConfig { /// - /// + /// contact,versiport /// - public class EssentialsRoomEmergencyConfig - { - public EssentialsRoomEmergencyTriggerConfig Trigger { get; set; } - - public string Behavior { get; set; } - } - + public string Type { get; set; } /// - /// + /// Input number if contact /// - public class EssentialsRoomEmergencyTriggerConfig - { - /// - /// contact,versiport - /// - public string Type { get; set; } - /// - /// Input number if contact - /// - public int Number { get; set; } + public int Number { get; set; } - public bool TriggerOnClose { get; set; } + public bool TriggerOnClose { get; set; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs index 617b7c9f..a41d0005 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -6,38 +6,37 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +public class EssentialsRoomScheduledEventsConfig { - public class EssentialsRoomScheduledEventsConfig - { - [JsonProperty("scheduledEvents")] - public List ScheduledEvents; - } + [JsonProperty("scheduledEvents")] + public List ScheduledEvents; +} - public class ScheduledEventConfig - { - [JsonProperty("key")] - public string Key; +public class ScheduledEventConfig +{ + [JsonProperty("key")] + public string Key; - [JsonProperty("name")] - public string Name; + [JsonProperty("name")] + public string Name; - [JsonProperty("days")] - public ScheduledEventCommon.eWeekDays Days; + [JsonProperty("days")] + public ScheduledEventCommon.eWeekDays Days; - [JsonProperty("time")] - public string Time; + [JsonProperty("time")] + public string Time; - [JsonProperty("actions")] - public List Actions; + [JsonProperty("actions")] + public List Actions; - [JsonProperty("persistent")] - public bool Persistent; + [JsonProperty("persistent")] + public bool Persistent; - [JsonProperty("acknowledgeable")] - public bool Acknowledgeable; + [JsonProperty("acknowledgeable")] + public bool Acknowledgeable; - [JsonProperty("enable")] - public bool Enable; - } + [JsonProperty("enable")] + public bool Enable; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs index 507bac5e..67e0ba2c 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs @@ -3,75 +3,74 @@ using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +public class EssentialsTechRoomConfig { - public class EssentialsTechRoomConfig + /// + /// The key of the dummy device used to enable routing + /// + [JsonProperty("dummySourceKey")] + public string DummySourceKey { get; set; } + + /// + /// The keys of the displays assigned to this room + /// + [JsonProperty("displays")] + public List Displays { get; set; } + + /// + /// The keys of the tuners assinged to this room + /// + [JsonProperty("tuners")] + public List Tuners { get; set; } + + /// + /// PIN to access the room as a normal user + /// + [JsonProperty("userPin")] + public string UserPin { get; set; } + + /// + /// PIN to access the room as a tech user + /// + [JsonProperty("techPin")] + public string TechPin { get; set; } + + /// + /// Name of the presets file. Path prefix is assumed to be /html/presets/lists/ + /// + [JsonProperty("presetsFileName")] + public string PresetsFileName { get; set; } + + [JsonProperty("scheduledEvents")] + public List ScheduledEvents { get; set; } + + /// + /// Indicates that the room is the primary when true + /// + [JsonProperty("isPrimary")] + public bool IsPrimary { get; set; } + + /// + /// Indicates which tuners should mirror preset recall when two rooms are configured in a primary->secondary scenario + /// + [JsonProperty("mirroredTuners")] + public Dictionary MirroredTuners { get; set; } + + [JsonProperty("helpMessage")] + public string HelpMessage { get; set; } + + /// + /// Indicates the room + /// + [JsonProperty("isTvPresetsProvider")] + public bool IsTvPresetsProvider; + + public EssentialsTechRoomConfig() { - /// - /// The key of the dummy device used to enable routing - /// - [JsonProperty("dummySourceKey")] - public string DummySourceKey { get; set; } - - /// - /// The keys of the displays assigned to this room - /// - [JsonProperty("displays")] - public List Displays { get; set; } - - /// - /// The keys of the tuners assinged to this room - /// - [JsonProperty("tuners")] - public List Tuners { get; set; } - - /// - /// PIN to access the room as a normal user - /// - [JsonProperty("userPin")] - public string UserPin { get; set; } - - /// - /// PIN to access the room as a tech user - /// - [JsonProperty("techPin")] - public string TechPin { get; set; } - - /// - /// Name of the presets file. Path prefix is assumed to be /html/presets/lists/ - /// - [JsonProperty("presetsFileName")] - public string PresetsFileName { get; set; } - - [JsonProperty("scheduledEvents")] - public List ScheduledEvents { get; set; } - - /// - /// Indicates that the room is the primary when true - /// - [JsonProperty("isPrimary")] - public bool IsPrimary { get; set; } - - /// - /// Indicates which tuners should mirror preset recall when two rooms are configured in a primary->secondary scenario - /// - [JsonProperty("mirroredTuners")] - public Dictionary MirroredTuners { get; set; } - - [JsonProperty("helpMessage")] - public string HelpMessage { get; set; } - - /// - /// Indicates the room - /// - [JsonProperty("isTvPresetsProvider")] - public bool IsTvPresetsProvider; - - public EssentialsTechRoomConfig() - { - Displays = new List(); - Tuners = new List(); - ScheduledEvents = new List(); - } + Displays = new List(); + Tuners = new List(); + ScheduledEvents = new List(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs index 5b9450f2..c509ad85 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs @@ -1,91 +1,90 @@ using System; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Config +namespace PepperDash.Essentials.Room.Config; + +/// +/// +/// +public class EssentialsRoomVolumesConfig { - /// - /// - /// - public class EssentialsRoomVolumesConfig - { - public EssentialsVolumeLevelConfig Master { get; set; } - public EssentialsVolumeLevelConfig Program { get; set; } - public EssentialsVolumeLevelConfig AudioCallRx { get; set; } - public EssentialsVolumeLevelConfig AudioCallTx { get; set; } - } + public EssentialsVolumeLevelConfig Master { get; set; } + public EssentialsVolumeLevelConfig Program { get; set; } + public EssentialsVolumeLevelConfig AudioCallRx { get; set; } + public EssentialsVolumeLevelConfig AudioCallTx { get; set; } +} + +/// +/// +/// +public class EssentialsVolumeLevelConfig +{ + public string DeviceKey { get; set; } + public string Label { get; set; } + public int Level { get; set; } /// - /// + /// Helper to get the device associated with key - one timer. /// - public class EssentialsVolumeLevelConfig + public IBasicVolumeWithFeedback GetDevice() { - public string DeviceKey { get; set; } - public string Label { get; set; } - public int Level { get; set; } - - /// - /// Helper to get the device associated with key - one timer. - /// - public IBasicVolumeWithFeedback GetDevice() + throw new NotImplementedException("This method references DM CHASSIS Directly"); + /* + // DM output card format: deviceKey--output~number, dm8x8-1--output~4 + var match = Regex.Match(DeviceKey, @"([-_\w]+)--(\w+)~(\d+)"); + if (match.Success) { - throw new NotImplementedException("This method references DM CHASSIS Directly"); - /* - // DM output card format: deviceKey--output~number, dm8x8-1--output~4 - var match = Regex.Match(DeviceKey, @"([-_\w]+)--(\w+)~(\d+)"); - if (match.Success) + var devKey = match.Groups[1].Value; + var chassis = DeviceManager.GetDeviceForKey(devKey) as DmChassisController; + if (chassis != null) { - var devKey = match.Groups[1].Value; - var chassis = DeviceManager.GetDeviceForKey(devKey) as DmChassisController; - if (chassis != null) - { - var outputNum = Convert.ToUInt32(match.Groups[3].Value); - if (chassis.VolumeControls.ContainsKey(outputNum)) // should always... - return chassis.VolumeControls[outputNum]; - } - // No volume for some reason. We have failed as developers - return null; + var outputNum = Convert.ToUInt32(match.Groups[3].Value); + if (chassis.VolumeControls.ContainsKey(outputNum)) // should always... + return chassis.VolumeControls[outputNum]; } - - // DSP/DMPS format: deviceKey--levelName, biampTesira-1--master - match = Regex.Match(DeviceKey, @"([-_\w]+)--(.+)"); - if (match.Success) - { - var devKey = match.Groups[1].Value; - var dsp = DeviceManager.GetDeviceForKey(devKey) as BiampTesiraForteDsp; - if (dsp != null) - { - var levelTag = match.Groups[2].Value; - if (dsp.LevelControlPoints.ContainsKey(levelTag)) // should always... - return dsp.LevelControlPoints[levelTag]; - } - - var dmps = DeviceManager.GetDeviceForKey(devKey) as DmpsAudioOutputController; - if (dmps != null) - { - var levelTag = match.Groups[2].Value; - switch (levelTag) - { - case "master": - return dmps.MasterVolumeLevel; - case "source": - return dmps.SourceVolumeLevel; - case "micsmaster": - return dmps.MicsMasterVolumeLevel; - case "codec1": - return dmps.Codec1VolumeLevel; - case "codec2": - return dmps.Codec2VolumeLevel; - default: - return dmps.MasterVolumeLevel; - } - } - // No volume for some reason. We have failed as developers - return null; - } - + // No volume for some reason. We have failed as developers return null; } - * */ + + // DSP/DMPS format: deviceKey--levelName, biampTesira-1--master + match = Regex.Match(DeviceKey, @"([-_\w]+)--(.+)"); + if (match.Success) + { + var devKey = match.Groups[1].Value; + var dsp = DeviceManager.GetDeviceForKey(devKey) as BiampTesiraForteDsp; + if (dsp != null) + { + var levelTag = match.Groups[2].Value; + if (dsp.LevelControlPoints.ContainsKey(levelTag)) // should always... + return dsp.LevelControlPoints[levelTag]; + } + + var dmps = DeviceManager.GetDeviceForKey(devKey) as DmpsAudioOutputController; + if (dmps != null) + { + var levelTag = match.Groups[2].Value; + switch (levelTag) + { + case "master": + return dmps.MasterVolumeLevel; + case "source": + return dmps.SourceVolumeLevel; + case "micsmaster": + return dmps.MicsMasterVolumeLevel; + case "codec1": + return dmps.Codec1VolumeLevel; + case "codec2": + return dmps.Codec2VolumeLevel; + default: + return dmps.MasterVolumeLevel; + } + } + // No volume for some reason. We have failed as developers + return null; } + + return null; + } + * */ } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs index fdd9b857..3b5832a9 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Config -{ +namespace PepperDash.Essentials.Room.Config; + public class SimplRoomPropertiesConfig : EssentialsHuddleVtc1PropertiesConfig { [JsonProperty("roomPhoneNumber")] @@ -21,5 +21,4 @@ namespace PepperDash.Essentials.Room.Config public string Name { get; set; } [JsonProperty("number")] public string Number { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs b/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs index 48d24ab0..ee81c4d0 100644 --- a/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs +++ b/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs @@ -2,95 +2,94 @@ using Crestron.SimplSharpPro; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency { - public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency + public event EventHandler EmergencyStateChange; + + IEssentialsRoom Room; + string Behavior; + bool TriggerOnClose; + + public bool InEmergency { get; private set; } + + public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) : + base(key) { - public event EventHandler EmergencyStateChange; + Room = room; + var cs = Global.ControlSystem; - IEssentialsRoom Room; - string Behavior; - bool TriggerOnClose; - - public bool InEmergency { get; private set; } - - public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) : - base(key) + if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase)) { - Room = room; - var cs = Global.ControlSystem; - - if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase)) + var portNum = (uint)config.Trigger.Number; + if (portNum <= cs.NumberOfDigitalInputPorts) { - var portNum = (uint)config.Trigger.Number; - if (portNum <= cs.NumberOfDigitalInputPorts) - { - cs.DigitalInputPorts[portNum].Register(); - cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange; - } - } - else if (config.Trigger.Type.Equals("versiport", StringComparison.OrdinalIgnoreCase)) - { - var portNum = (uint)config.Trigger.Number; - if (portNum <= cs.NumberOfVersiPorts) - { - cs.VersiPorts[portNum].Register(); - cs.VersiPorts[portNum].SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); - cs.VersiPorts[portNum].DisablePullUpResistor = true; - cs.VersiPorts[portNum].VersiportChange += EssentialsRoomEmergencyContactClosure_VersiportChange; - } - } - Behavior = config.Behavior; - TriggerOnClose = config.Trigger.TriggerOnClose; - } - - private void EssentialsRoomEmergencyContactClosure_VersiportChange(Versiport port, VersiportEventArgs args) - { - if (args.Event == eVersiportEvent.DigitalInChange) - { - ContactClosure_StateChange(port.DigitalIn); + cs.DigitalInputPorts[portNum].Register(); + cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange; } } - - void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) + else if (config.Trigger.Type.Equals("versiport", StringComparison.OrdinalIgnoreCase)) { - ContactClosure_StateChange(args.State); - } - - void ContactClosure_StateChange(bool portState) - { - if (portState && TriggerOnClose || !portState && !TriggerOnClose) + var portNum = (uint)config.Trigger.Number; + if (portNum <= cs.NumberOfVersiPorts) { - InEmergency = true; - if (EmergencyStateChange != null) - EmergencyStateChange(this, new EventArgs()); - RunEmergencyBehavior(); - } - else - { - InEmergency = false; - if (EmergencyStateChange != null) - EmergencyStateChange(this, new EventArgs()); + cs.VersiPorts[portNum].Register(); + cs.VersiPorts[portNum].SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); + cs.VersiPorts[portNum].DisablePullUpResistor = true; + cs.VersiPorts[portNum].VersiportChange += EssentialsRoomEmergencyContactClosure_VersiportChange; } } + Behavior = config.Behavior; + TriggerOnClose = config.Trigger.TriggerOnClose; + } - /// - /// - /// - public void RunEmergencyBehavior() + private void EssentialsRoomEmergencyContactClosure_VersiportChange(Versiport port, VersiportEventArgs args) + { + if (args.Event == eVersiportEvent.DigitalInChange) { - if (Behavior.Equals("shutdown")) - Room.Shutdown(); + ContactClosure_StateChange(port.DigitalIn); + } + } + + void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) + { + ContactClosure_StateChange(args.State); + } + + void ContactClosure_StateChange(bool portState) + { + if (portState && TriggerOnClose || !portState && !TriggerOnClose) + { + InEmergency = true; + if (EmergencyStateChange != null) + EmergencyStateChange(this, new EventArgs()); + RunEmergencyBehavior(); + } + else + { + InEmergency = false; + if (EmergencyStateChange != null) + EmergencyStateChange(this, new EventArgs()); } } /// - /// Describes the functionality of a room emergency contact closure + /// /// - public interface IEssentialsRoomEmergency + public void RunEmergencyBehavior() { - event EventHandler EmergencyStateChange; - - bool InEmergency { get; } + if (Behavior.Equals("shutdown")) + Room.Shutdown(); } +} + +/// +/// Describes the functionality of a room emergency contact closure +/// +public interface IEssentialsRoomEmergency +{ + event EventHandler EmergencyStateChange; + + bool InEmergency { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs b/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs index 232c02ed..c4866b92 100644 --- a/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs +++ b/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs @@ -12,188 +12,188 @@ using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// +/// +public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom { /// - /// + /// /// - public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom + public BoolFeedback OnFeedback { get; private set; } + + /// + /// Fires when the RoomOccupancy object is set + /// + public event EventHandler RoomOccupancyIsSet; + + public BoolFeedback IsWarmingUpFeedback { get; private set; } + public BoolFeedback IsCoolingDownFeedback { get; private set; } + + public IOccupancyStatusProvider RoomOccupancy { get; protected set; } + + public bool OccupancyStatusProviderIsRemote { get; private set; } + + public List EnvironmentalControlDevices { get; protected set; } + + public bool HasEnvironmentalControlDevices { - /// - /// - /// - public BoolFeedback OnFeedback { get; private set; } - - /// - /// Fires when the RoomOccupancy object is set - /// - public event EventHandler RoomOccupancyIsSet; - - public BoolFeedback IsWarmingUpFeedback { get; private set; } - public BoolFeedback IsCoolingDownFeedback { get; private set; } - - public IOccupancyStatusProvider RoomOccupancy { get; protected set; } - - public bool OccupancyStatusProviderIsRemote { get; private set; } - - public List EnvironmentalControlDevices { get; protected set; } - - public bool HasEnvironmentalControlDevices + get { - get - { - return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0; - } + return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0; } + } - protected abstract Func IsWarmingFeedbackFunc { get; } - protected abstract Func IsCoolingFeedbackFunc { get; } + protected abstract Func IsWarmingFeedbackFunc { get; } + protected abstract Func IsCoolingFeedbackFunc { get; } - /// - /// Indicates if this room is Mobile Control Enabled - /// - public bool IsMobileControlEnabled { get; private set; } + /// + /// Indicates if this room is Mobile Control Enabled + /// + public bool IsMobileControlEnabled { get; private set; } - /// - /// The bridge for this room if Mobile Control is enabled - /// - public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; } + /// + /// The bridge for this room if Mobile Control is enabled + /// + public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; } - protected const string _defaultListKey = "default"; + protected const string _defaultListKey = "default"; - /// - /// The config name of the source list - /// + /// + /// The config name of the source list + /// /// private string _sourceListKey; - public string SourceListKey { + public string SourceListKey { get { - if(string.IsNullOrEmpty(_sourceListKey)) - { - return _defaultListKey; - } - else - { - return _sourceListKey; - } + if(string.IsNullOrEmpty(_sourceListKey)) + { + return _defaultListKey; + } + else + { + return _sourceListKey; + } } protected set { - if (value != _sourceListKey) - { - _sourceListKey = value; - } + if (value != _sourceListKey) + { + _sourceListKey = value; + } } } - private string _destinationListKey; - public string DestinationListKey + private string _destinationListKey; + public string DestinationListKey + { + get { - get + if (string.IsNullOrEmpty(_destinationListKey)) { - if (string.IsNullOrEmpty(_destinationListKey)) - { - return _defaultListKey; - } - else - { - return _destinationListKey; - } + return _defaultListKey; } - protected set + else { - if (value != _destinationListKey) - { - _destinationListKey = value; - } + return _destinationListKey; } } - - private string _audioControlPointListKey; - public string AudioControlPointListKey + protected set { - get + if (value != _destinationListKey) { - if (string.IsNullOrEmpty(_audioControlPointListKey)) - { - return _defaultListKey; - } - else - { - return _destinationListKey; - } - } - protected set - { - if (value != _audioControlPointListKey) - { - _audioControlPointListKey = value; - } + _destinationListKey = value; } } + } - private string _cameraListKey; - public string CameraListKey + private string _audioControlPointListKey; + public string AudioControlPointListKey + { + get { - get + if (string.IsNullOrEmpty(_audioControlPointListKey)) { - if (string.IsNullOrEmpty(_cameraListKey)) - { - return _defaultListKey; - } - else - { - return _cameraListKey; - } + return _defaultListKey; } - protected set + else { - if (value != _cameraListKey) - { - _cameraListKey = value; - } + return _destinationListKey; } } + protected set + { + if (value != _audioControlPointListKey) + { + _audioControlPointListKey = value; + } + } + } - /// - /// Timer used for informing the UIs of a shutdown - /// - public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } + private string _cameraListKey; + public string CameraListKey + { + get + { + if (string.IsNullOrEmpty(_cameraListKey)) + { + return _defaultListKey; + } + else + { + return _cameraListKey; + } + } + protected set + { + if (value != _cameraListKey) + { + _cameraListKey = value; + } + } + } - /// - /// - /// - public int ShutdownPromptSeconds { get; set; } - public int ShutdownVacancySeconds { get; set; } - public eShutdownType ShutdownType { get; private set; } + /// + /// Timer used for informing the UIs of a shutdown + /// + public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } - public EssentialsRoomEmergencyBase Emergency { get; set; } + /// + /// + /// + public int ShutdownPromptSeconds { get; set; } + public int ShutdownVacancySeconds { get; set; } + public eShutdownType ShutdownType { get; private set; } - public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } + public EssentialsRoomEmergencyBase Emergency { get; set; } - public string LogoUrlLightBkgnd { get; set; } + public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } - public string LogoUrlDarkBkgnd { get; set; } + public string LogoUrlLightBkgnd { get; set; } - protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } + public string LogoUrlDarkBkgnd { get; set; } - public eVacancyMode VacancyMode { get; private set; } + protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } - /// - /// Seconds after vacancy prompt is displayed until shutdown - /// - protected int RoomVacancyShutdownSeconds; + public eVacancyMode VacancyMode { get; private set; } - /// - /// Seconds after vacancy detected until prompt is displayed - /// - protected int RoomVacancyShutdownPromptSeconds; + /// + /// Seconds after vacancy prompt is displayed until shutdown + /// + protected int RoomVacancyShutdownSeconds; - /// - /// - /// - protected abstract Func OnFeedbackFunc { get; } + /// + /// Seconds after vacancy detected until prompt is displayed + /// + protected int RoomVacancyShutdownPromptSeconds; + + /// + /// + /// + protected abstract Func OnFeedbackFunc { get; } protected Dictionary SavedVolumeLevels = new Dictionary(); @@ -203,293 +203,292 @@ namespace PepperDash.Essentials.Core public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; } - public EssentialsRoomBase(DeviceConfig config) - : base(config) + public EssentialsRoomBase(DeviceConfig config) + : base(config) + { + EnvironmentalControlDevices = new List(); + + // Setup the ShutdownPromptTimer + ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); + ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => { - EnvironmentalControlDevices = new List(); + if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) + ShutdownType = eShutdownType.None; + }; - // Setup the ShutdownPromptTimer - ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); - ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => - { - if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) - ShutdownType = eShutdownType.None; - }; + ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered - ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered + ShutdownPromptSeconds = 60; + ShutdownVacancySeconds = 120; + + ShutdownType = eShutdownType.None; - ShutdownPromptSeconds = 60; - ShutdownVacancySeconds = 120; - - ShutdownType = eShutdownType.None; + RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer"); + //RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) => + //{ + // if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue) + // ShutdownType = ShutdownType.Vacancy; + //}; + RoomVacancyShutdownTimer.HasFinished += new EventHandler(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered - RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer"); - //RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) => - //{ - // if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue) - // ShutdownType = ShutdownType.Vacancy; - //}; - RoomVacancyShutdownTimer.HasFinished += new EventHandler(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered + RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning + RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt + VacancyMode = eVacancyMode.None; - RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning - RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt - VacancyMode = eVacancyMode.None; + OnFeedback = new BoolFeedback(OnFeedbackFunc); - OnFeedback = new BoolFeedback(OnFeedbackFunc); + IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); + IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); - IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); - IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); + AddPostActivationAction(() => + { + if (RoomOccupancy != null) + OnRoomOccupancyIsSet(); + }); + } - AddPostActivationAction(() => - { - if (RoomOccupancy != null) - OnRoomOccupancyIsSet(); - }); + public override bool CustomActivate() + { + SetUpMobileControl(); + + return base.CustomActivate(); + } + + /// + /// Sets the SourceListKey property to the passed in value or the default if no value passed in + /// + /// + protected void SetSourceListKey(string sourceListKey) + { + if (!string.IsNullOrEmpty(sourceListKey)) + { + SourceListKey = sourceListKey; } - - public override bool CustomActivate() + else { - SetUpMobileControl(); - - return base.CustomActivate(); + sourceListKey = _defaultListKey; } + } - /// - /// Sets the SourceListKey property to the passed in value or the default if no value passed in - /// - /// - protected void SetSourceListKey(string sourceListKey) + protected void SetDestinationListKey(string destinationListKey) + { + if (!string.IsNullOrEmpty(destinationListKey)) { - if (!string.IsNullOrEmpty(sourceListKey)) - { - SourceListKey = sourceListKey; - } - else - { - sourceListKey = _defaultListKey; - } + DestinationListKey = destinationListKey; } + } - protected void SetDestinationListKey(string destinationListKey) + /// + /// If mobile control is enabled, sets the appropriate properties + /// + void SetUpMobileControl() + { + var mcBridgeKey = string.Format("mobileControlBridge-{0}", Key); + var mcBridge = DeviceManager.GetDeviceForKey(mcBridgeKey); + if (mcBridge == null) { - if (!string.IsNullOrEmpty(destinationListKey)) - { - DestinationListKey = destinationListKey; - } + Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge Not found for this room."); + IsMobileControlEnabled = false; + return; } - - /// - /// If mobile control is enabled, sets the appropriate properties - /// - void SetUpMobileControl() + else { - var mcBridgeKey = string.Format("mobileControlBridge-{0}", Key); - var mcBridge = DeviceManager.GetDeviceForKey(mcBridgeKey); - if (mcBridge == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge Not found for this room."); - IsMobileControlEnabled = false; - return; - } - else - { - MobileControlRoomBridge = mcBridge as IMobileControlRoomMessenger; - Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge found and enabled for this room"); - IsMobileControlEnabled = true; - } + MobileControlRoomBridge = mcBridge as IMobileControlRoomMessenger; + Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge found and enabled for this room"); + IsMobileControlEnabled = true; } + } - void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) + void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) + { + switch (VacancyMode) { - switch (VacancyMode) - { - case eVacancyMode.None: - StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + case eVacancyMode.None: + StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + break; + case eVacancyMode.InInitialVacancy: + StartRoomVacancyTimer(eVacancyMode.InShutdownWarning); + break; + case eVacancyMode.InShutdownWarning: + { + StartShutdown(eShutdownType.Vacancy); + Debug.LogMessage(LogEventLevel.Information, this, "Shutting Down due to vacancy."); break; - case eVacancyMode.InInitialVacancy: - StartRoomVacancyTimer(eVacancyMode.InShutdownWarning); - break; - case eVacancyMode.InShutdownWarning: - { - StartShutdown(eShutdownType.Vacancy); - Debug.LogMessage(LogEventLevel.Information, this, "Shutting Down due to vacancy."); - break; - } - default: - break; - } + } + default: + break; } + } - /// - /// - /// - /// - public void StartShutdown(eShutdownType type) - { - // Check for shutdowns running. Manual should override other shutdowns + /// + /// + /// + /// + public void StartShutdown(eShutdownType type) + { + // Check for shutdowns running. Manual should override other shutdowns - if (type == eShutdownType.Manual) - ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; - else if (type == eShutdownType.Vacancy) - ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; - ShutdownType = type; - ShutdownPromptTimer.Start(); + if (type == eShutdownType.Manual) + ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; + else if (type == eShutdownType.Vacancy) + ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; + ShutdownType = type; + ShutdownPromptTimer.Start(); - Debug.LogMessage(LogEventLevel.Information, this, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); - } + Debug.LogMessage(LogEventLevel.Information, this, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); + } - public void StartRoomVacancyTimer(eVacancyMode mode) - { - if (mode == eVacancyMode.None) - RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; - else if (mode == eVacancyMode.InInitialVacancy) - RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; - else if (mode == eVacancyMode.InShutdownWarning) - RoomVacancyShutdownTimer.SecondsToCount = 60; - VacancyMode = mode; - RoomVacancyShutdownTimer.Start(); + public void StartRoomVacancyTimer(eVacancyMode mode) + { + if (mode == eVacancyMode.None) + RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; + else if (mode == eVacancyMode.InInitialVacancy) + RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; + else if (mode == eVacancyMode.InShutdownWarning) + RoomVacancyShutdownTimer.SecondsToCount = 60; + VacancyMode = mode; + RoomVacancyShutdownTimer.Start(); - Debug.LogMessage(LogEventLevel.Information, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount); - } + Debug.LogMessage(LogEventLevel.Information, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount); + } - /// - /// Resets the vacancy mode and shutsdwon the room - /// - public void Shutdown() - { - VacancyMode = eVacancyMode.None; - EndShutdown(); - } + /// + /// Resets the vacancy mode and shutsdwon the room + /// + public void Shutdown() + { + VacancyMode = eVacancyMode.None; + EndShutdown(); + } - /// - /// This method is for the derived class to define it's specific shutdown - /// requirements but should not be called directly. It is called by Shutdown() - /// - protected abstract void EndShutdown(); + /// + /// This method is for the derived class to define it's specific shutdown + /// requirements but should not be called directly. It is called by Shutdown() + /// + protected abstract void EndShutdown(); - /// - /// Override this to implement a default volume level(s) method - /// - public abstract void SetDefaultLevels(); + /// + /// Override this to implement a default volume level(s) method + /// + public abstract void SetDefaultLevels(); - /// - /// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device - /// - /// - public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes) - { + /// + /// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device + /// + /// + public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes) + { if (statusProvider == null) { Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Occupancy sensor device is null"); return; } - Debug.LogMessage(LogEventLevel.Information, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key); - Debug.LogMessage(LogEventLevel.Information, this, "Timeout Minutes from Config is: {0}", timeoutMinutes); + Debug.LogMessage(LogEventLevel.Information, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key); + Debug.LogMessage(LogEventLevel.Information, this, "Timeout Minutes from Config is: {0}", timeoutMinutes); - // If status provider is fusion, set flag to remote - if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) - OccupancyStatusProviderIsRemote = true; + // If status provider is fusion, set flag to remote + if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) + OccupancyStatusProviderIsRemote = true; - if(timeoutMinutes > 0) - RoomVacancyShutdownSeconds = timeoutMinutes * 60; + if(timeoutMinutes > 0) + RoomVacancyShutdownSeconds = timeoutMinutes * 60; - Debug.LogMessage(LogEventLevel.Information, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); + Debug.LogMessage(LogEventLevel.Information, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); - RoomOccupancy = statusProvider; + RoomOccupancy = statusProvider; - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; - OnRoomOccupancyIsSet(); - } - - void OnRoomOccupancyIsSet() - { - var handler = RoomOccupancyIsSet; - if (handler != null) - handler(this, new EventArgs()); - } - - /// - /// To allow base class to power room on to last source - /// - public abstract void PowerOnToDefaultOrLastSource(); - - /// - /// To allow base class to power room on to default source - /// - /// - public abstract bool RunDefaultPresentRoute(); - - void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) - { - if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false && AllowVacancyTimerToStart()) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Notice: Vacancy Detected"); - // Trigger the timer when the room is vacant - StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Notice: Occupancy Detected"); - // Reset the timer when the room is occupied - RoomVacancyShutdownTimer.Cancel(); - } - } - - /// - /// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed - /// - /// - public abstract void RoomVacatedForTimeoutPeriod(object o); - - /// - /// Allow the vacancy event from an occupancy sensor to turn the room off. - /// - /// If the timer should be allowed. Defaults to true - protected virtual bool AllowVacancyTimerToStart() - { - return true; - } - } - - /// - /// To describe the various ways a room may be shutting down - /// - public enum eShutdownType - { - None = 0, - External, - Manual, - Vacancy + OnRoomOccupancyIsSet(); } - public enum eVacancyMode + void OnRoomOccupancyIsSet() { - None = 0, - InInitialVacancy, - InShutdownWarning + var handler = RoomOccupancyIsSet; + if (handler != null) + handler(this, new EventArgs()); } /// - /// + /// To allow base class to power room on to last source /// - public enum eWarmingCoolingMode + public abstract void PowerOnToDefaultOrLastSource(); + + /// + /// To allow base class to power room on to default source + /// + /// + public abstract bool RunDefaultPresentRoute(); + + void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) { - None, - Warming, - Cooling + if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false && AllowVacancyTimerToStart()) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Notice: Vacancy Detected"); + // Trigger the timer when the room is vacant + StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Notice: Occupancy Detected"); + // Reset the timer when the room is occupied + RoomVacancyShutdownTimer.Cancel(); + } } - public abstract class EssentialsRoomEmergencyBase : IKeyed - { - public string Key { get; private set; } + /// + /// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed + /// + /// + public abstract void RoomVacatedForTimeoutPeriod(object o); - public EssentialsRoomEmergencyBase(string key) - { - Key = key; - } + /// + /// Allow the vacancy event from an occupancy sensor to turn the room off. + /// + /// If the timer should be allowed. Defaults to true + protected virtual bool AllowVacancyTimerToStart() + { + return true; + } +} + +/// +/// To describe the various ways a room may be shutting down +/// +public enum eShutdownType +{ + None = 0, + External, + Manual, + Vacancy +} + +public enum eVacancyMode +{ + None = 0, + InInitialVacancy, + InShutdownWarning +} + +/// +/// +/// +public enum eWarmingCoolingMode +{ + None, + Warming, + Cooling +} + +public abstract class EssentialsRoomEmergencyBase : IKeyed +{ + public string Key { get; private set; } + + public EssentialsRoomEmergencyBase(string key) + { + Key = key; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs b/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs index d452c0b9..f3283a74 100644 --- a/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs +++ b/src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs @@ -10,42 +10,40 @@ using PepperDash.Essentials.Core.Devices; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Describes the basic functionality of an EssentialsRoom +/// +public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls { - /// - /// Describes the basic functionality of an EssentialsRoom - /// - public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls - { - BoolFeedback OnFeedback { get; } + BoolFeedback OnFeedback { get; } - BoolFeedback IsWarmingUpFeedback { get; } - BoolFeedback IsCoolingDownFeedback { get; } + BoolFeedback IsWarmingUpFeedback { get; } + BoolFeedback IsCoolingDownFeedback { get; } - bool IsMobileControlEnabled { get; } - IMobileControlRoomMessenger MobileControlRoomBridge { get; } + bool IsMobileControlEnabled { get; } + IMobileControlRoomMessenger MobileControlRoomBridge { get; } - string SourceListKey { get; } + string SourceListKey { get; } - string DestinationListKey { get; } + string DestinationListKey { get; } - string AudioControlPointListKey { get; } + string AudioControlPointListKey { get; } - string CameraListKey { get; } + string CameraListKey { get; } - SecondsCountdownTimer ShutdownPromptTimer { get; } - int ShutdownPromptSeconds { get; } - int ShutdownVacancySeconds { get; } - eShutdownType ShutdownType { get; } + SecondsCountdownTimer ShutdownPromptTimer { get; } + int ShutdownPromptSeconds { get; } + int ShutdownVacancySeconds { get; } + eShutdownType ShutdownType { get; } - string LogoUrlLightBkgnd { get; } - string LogoUrlDarkBkgnd { get; } + string LogoUrlLightBkgnd { get; } + string LogoUrlDarkBkgnd { get; } - void StartShutdown(eShutdownType type); + void StartShutdown(eShutdownType type); - void Shutdown(); - - void PowerOnToDefaultOrLastSource(); - } + void Shutdown(); + void PowerOnToDefaultOrLastSource(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs b/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs index c2595151..b655ce61 100644 --- a/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs +++ b/src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs @@ -2,19 +2,18 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IRoomEventSchedule { - public interface IRoomEventSchedule - { - void AddOrUpdateScheduledEvent(ScheduledEventConfig eventConfig); + void AddOrUpdateScheduledEvent(ScheduledEventConfig eventConfig); - List GetScheduledEvents(); + List GetScheduledEvents(); - event EventHandler ScheduledEventsChanged; - } - - public class ScheduledEventEventArgs : EventArgs - { - public List ScheduledEvents; - } + event EventHandler ScheduledEventsChanged; +} + +public class ScheduledEventEventArgs : EventArgs +{ + public List ScheduledEvents; } diff --git a/src/PepperDash.Essentials.Core/Room/Interfaces.cs b/src/PepperDash.Essentials.Core/Room/Interfaces.cs index 6bad45df..ddbfe16a 100644 --- a/src/PepperDash.Essentials.Core/Room/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Room/Interfaces.cs @@ -7,165 +7,164 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// For rooms with in call feedback +/// +public interface IHasInCallFeedback { - /// - /// For rooms with in call feedback - /// - public interface IHasInCallFeedback + BoolFeedback InCallFeedback { get; } +} + +/// +/// For rooms with a single display +/// +public interface IHasDefaultDisplay +{ + IRoutingSink DefaultDisplay { get; } +} + +/// +/// For rooms with multiple displays +/// +public interface IHasMultipleDisplays +{ + Dictionary Displays { get; } +} + +/// +/// For rooms with routing +/// +public interface IRunRouteAction +{ + void RunRouteAction(string routeKey, string sourceListKey); + + void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); +} + +/// +/// Simplified routing direct from source to destination +/// +public interface IRunDirectRouteAction +{ + void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); +} + +/// +/// Describes a room with matrix routing +/// +public interface IHasMatrixRouting +{ + string MatrixRoutingDeviceKey { get; } + + List EndpointKeys { get; } +} + +/// +/// Describes a room with routing endpoints +/// +public interface IHasRoutingEndpoints +{ + List EndpointKeys { get; } +} + +/// +/// Describes a room with a shutdown prompt timer +/// +public interface IShutdownPromptTimer +{ + SecondsCountdownTimer ShutdownPromptTimer { get; } + + void SetShutdownPromptSeconds(int seconds); + + void StartShutdown(eShutdownType type); +} + +/// +/// Describes a room with a tech password +/// +public interface ITechPassword +{ + event EventHandler TechPasswordValidateResult; + + event EventHandler TechPasswordChanged; + + int TechPasswordLength { get; } + + void ValidateTechPassword(string password); + + void SetTechPassword(string oldPassword, string newPassword); +} + +public class TechPasswordEventArgs : EventArgs +{ + public bool IsValid { get; private set; } + + public TechPasswordEventArgs(bool isValid) { - BoolFeedback InCallFeedback { get; } + IsValid = isValid; } +} - /// - /// For rooms with a single display - /// - public interface IHasDefaultDisplay - { - IRoutingSink DefaultDisplay { get; } - } +/// +/// For rooms that default presentation only routing +/// +public interface IRunDefaultPresentRoute +{ + bool RunDefaultPresentRoute(); +} - /// - /// For rooms with multiple displays - /// - public interface IHasMultipleDisplays - { - Dictionary Displays { get; } - } +/// +/// For rooms that have default presentation and calling routes +/// +public interface IRunDefaultCallRoute : IRunDefaultPresentRoute +{ + bool RunDefaultCallRoute(); +} - /// - /// For rooms with routing - /// - public interface IRunRouteAction - { - void RunRouteAction(string routeKey, string sourceListKey); +/// +/// Describes environmental controls available on a room such as lighting, shades, temperature, etc. +/// +public interface IEnvironmentalControls +{ + List EnvironmentalControlDevices { get; } - void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); - } + bool HasEnvironmentalControlDevices { get; } +} - /// - /// Simplified routing direct from source to destination - /// - public interface IRunDirectRouteAction - { - void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); - } - - /// - /// Describes a room with matrix routing - /// - public interface IHasMatrixRouting - { - string MatrixRoutingDeviceKey { get; } +public interface IRoomOccupancy:IKeyed +{ + IOccupancyStatusProvider RoomOccupancy { get; } + bool OccupancyStatusProviderIsRemote { get; } - List EndpointKeys { get; } - } + void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes); - /// - /// Describes a room with routing endpoints - /// - public interface IHasRoutingEndpoints - { - List EndpointKeys { get; } - } + void RoomVacatedForTimeoutPeriod(object o); - /// - /// Describes a room with a shutdown prompt timer - /// - public interface IShutdownPromptTimer - { - SecondsCountdownTimer ShutdownPromptTimer { get; } + void StartRoomVacancyTimer(eVacancyMode mode); - void SetShutdownPromptSeconds(int seconds); + eVacancyMode VacancyMode { get; } - void StartShutdown(eShutdownType type); - } + event EventHandler RoomOccupancyIsSet; +} - /// - /// Describes a room with a tech password - /// - public interface ITechPassword - { - event EventHandler TechPasswordValidateResult; +public interface IEmergency +{ + EssentialsRoomEmergencyBase Emergency { get; } +} - event EventHandler TechPasswordChanged; +public interface IMicrophonePrivacy +{ + Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; } +} - int TechPasswordLength { get; } +public interface IHasAccessoryDevices : IKeyName +{ + List AccessoryDeviceKeys { get; } +} - void ValidateTechPassword(string password); - - void SetTechPassword(string oldPassword, string newPassword); - } - - public class TechPasswordEventArgs : EventArgs - { - public bool IsValid { get; private set; } - - public TechPasswordEventArgs(bool isValid) - { - IsValid = isValid; - } - } - - /// - /// For rooms that default presentation only routing - /// - public interface IRunDefaultPresentRoute - { - bool RunDefaultPresentRoute(); - } - - /// - /// For rooms that have default presentation and calling routes - /// - public interface IRunDefaultCallRoute : IRunDefaultPresentRoute - { - bool RunDefaultCallRoute(); - } - - /// - /// Describes environmental controls available on a room such as lighting, shades, temperature, etc. - /// - public interface IEnvironmentalControls - { - List EnvironmentalControlDevices { get; } - - bool HasEnvironmentalControlDevices { get; } - } - - public interface IRoomOccupancy:IKeyed - { - IOccupancyStatusProvider RoomOccupancy { get; } - bool OccupancyStatusProviderIsRemote { get; } - - void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes); - - void RoomVacatedForTimeoutPeriod(object o); - - void StartRoomVacancyTimer(eVacancyMode mode); - - eVacancyMode VacancyMode { get; } - - event EventHandler RoomOccupancyIsSet; - } - - public interface IEmergency - { - EssentialsRoomEmergencyBase Emergency { get; } - } - - public interface IMicrophonePrivacy - { - Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; } - } - - public interface IHasAccessoryDevices : IKeyName - { - List AccessoryDeviceKeys { get; } - } - - public interface IHasCiscoNavigatorTouchpanel - { - string CiscoNavigatorTouchpanelKey { get; } - } +public interface IHasCiscoNavigatorTouchpanel +{ + string CiscoNavigatorTouchpanelKey { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Room.cs b/src/PepperDash.Essentials.Core/Room/Room.cs index 5e190bc9..2531b21a 100644 --- a/src/PepperDash.Essentials.Core/Room/Room.cs +++ b/src/PepperDash.Essentials.Core/Room/Room.cs @@ -8,8 +8,8 @@ using Crestron.SimplSharpPro; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + //*************************************************************************************************** public abstract class Room : Device, IHasFeedback @@ -42,15 +42,14 @@ namespace PepperDash.Essentials.Core { get { - return new FeedbackCollection - { - RoomIsOnFeedback, - IsCoolingDownFeedback, - IsWarmingUpFeedback - }; + return new FeedbackCollection + { + RoomIsOnFeedback, + IsCoolingDownFeedback, + IsWarmingUpFeedback + }; } } #endregion - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs b/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs index f46f10b1..53028969 100644 --- a/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs +++ b/src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs @@ -6,10 +6,9 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IOccupancyStatusProvider { - public interface IOccupancyStatusProvider - { - BoolFeedback RoomIsOccupiedFeedback { get; } - } + BoolFeedback RoomIsOccupiedFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs b/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs index d8b50a9b..57a5119e 100644 --- a/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs +++ b/src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Routing -{ +namespace PepperDash.Essentials.Core.Routing; + public class DummyRoutingInputsDevice : Device, IRoutingSource, IRoutingOutputs { /// @@ -32,5 +32,4 @@ namespace PepperDash.Essentials.Core.Routing AudioVideoOutputPort = new RoutingOutputPort("internal", eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.BackplaneOnly, null, this, true); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index f3eec22a..da58b586 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -9,429 +9,428 @@ using System.Linq; using Debug = PepperDash.Core.Debug; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// Extensions added to any IRoutingInputs classes to provide discovery-based routing +/// on those destinations. +/// +public static class Extensions { + /// + /// Stores pending route requests, keyed by the destination device key. + /// Used primarily to handle routing requests while a device is cooling down. + /// + private static readonly Dictionary RouteRequests = new Dictionary(); /// - /// Extensions added to any IRoutingInputs classes to provide discovery-based routing - /// on those destinations. + /// A queue to process route requests and releases sequentially. /// - public static class Extensions + private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue"); + + /// + /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute + /// and then attempts a new Route and if sucessful, stores that RouteDescriptor + /// in RouteDescriptorCollection.DefaultCollection + /// + public static void ReleaseAndMakeRoute(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, string destinationPortKey = "", string sourcePortKey = "") { - /// - /// Stores pending route requests, keyed by the destination device key. - /// Used primarily to handle routing requests while a device is cooling down. - /// - private static readonly Dictionary RouteRequests = new Dictionary(); + // Remove this line before committing!!!!! + 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); - /// - /// A queue to process route requests and releases sequentially. - /// - private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue"); + 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); - /// - /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute - /// and then attempts a new Route and if sucessful, stores that RouteDescriptor - /// in RouteDescriptorCollection.DefaultCollection - /// - public static void ReleaseAndMakeRoute(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, string destinationPortKey = "", string sourcePortKey = "") + ReleaseAndMakeRoute(destination, source, signalType, inputPort, outputPort); + } + + /// + /// Will release the existing route to the destination, if a route is found. This does not CLEAR the route, only stop counting usage time on any output ports that have a usage tracker set + /// + /// destination to clear + public static void ReleaseRoute(this IRoutingInputs destination) + { + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty, false)); + } + + /// + /// Will release the existing route to the destination, if a route is found. This does not CLEAR the route, only stop counting usage time on any output ports that have a usage tracker set + /// + /// destination to clear + /// Input to use to find existing route + public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey) + { + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey, false)); + } + + /// + /// Clears the route on the destination. This will remove any routes that are currently in use + /// + /// Destination + public static void ClearRoute(this IRoutingInputs destination) + { + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty, true)); + } + + /// + /// Clears the route on the destination. This will remove any routes that are currently in use + /// + /// destination + /// input to use to find existing route + public static void ClearRoute(this IRoutingInputs destination, string inputPortKey) + { + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey, true)); + } + + /// + /// Removes the route request for the destination. This will remove any routes that are currently in use + /// + /// destination device key + public static void RemoveRouteRequestForDestination(string destinationKey) + { + Debug.LogMessage(LogEventLevel.Information, "Removing route request for {destination}", null, destinationKey); + + var result = RouteRequests.Remove(destinationKey); + + var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found"; + + Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, destinationKey); + } + + /// + /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. + /// Routes of type AudioVideo will be built as two separate routes, audio and video. If + /// a route is discovered, a new RouteDescriptor is returned. If one or both parts + /// of an audio/video route are discovered a route descriptor is returned. If no route is + /// discovered, then null is returned + /// + public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) + { + // if it's a single signal type, find the route + if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) && + !(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio))) { - // Remove this line before committing!!!!! - 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); + var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType); - 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); + if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) + singleTypeRouteDescriptor = null; - ReleaseAndMakeRoute(destination, source, signalType, inputPort, outputPort); - } - - /// - /// Will release the existing route to the destination, if a route is found. This does not CLEAR the route, only stop counting usage time on any output ports that have a usage tracker set - /// - /// destination to clear - public static void ReleaseRoute(this IRoutingInputs destination) - { - routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty, false)); - } - - /// - /// Will release the existing route to the destination, if a route is found. This does not CLEAR the route, only stop counting usage time on any output ports that have a usage tracker set - /// - /// destination to clear - /// Input to use to find existing route - public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey) - { - routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey, false)); - } - - /// - /// Clears the route on the destination. This will remove any routes that are currently in use - /// - /// Destination - public static void ClearRoute(this IRoutingInputs destination) - { - routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty, true)); - } - - /// - /// Clears the route on the destination. This will remove any routes that are currently in use - /// - /// destination - /// input to use to find existing route - public static void ClearRoute(this IRoutingInputs destination, string inputPortKey) - { - routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey, true)); - } - - /// - /// Removes the route request for the destination. This will remove any routes that are currently in use - /// - /// destination device key - public static void RemoveRouteRequestForDestination(string destinationKey) - { - Debug.LogMessage(LogEventLevel.Information, "Removing route request for {destination}", null, destinationKey); - - var result = RouteRequests.Remove(destinationKey); - - var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found"; - - Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, destinationKey); - } - - /// - /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices. - /// Routes of type AudioVideo will be built as two separate routes, audio and video. If - /// a route is discovered, a new RouteDescriptor is returned. If one or both parts - /// of an audio/video route are discovered a route descriptor is returned. If no route is - /// discovered, then null is returned - /// - public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) - { - // if it's a single signal type, find the route - if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) && - !(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio))) + var routes = singleTypeRouteDescriptor?.Routes ?? new List(); + foreach (var route in routes) { - var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType); - Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType); - - if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) - singleTypeRouteDescriptor = null; - - var routes = singleTypeRouteDescriptor?.Routes ?? new List(); - foreach (var route in routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); - } - - return (singleTypeRouteDescriptor, null); - } - // otherwise, audioVideo needs to be handled as two steps. - - Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); - - RouteDescriptor audioRouteDescriptor; - - if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) - { - audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); - } else - { - audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); + Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); } - var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); + return (singleTypeRouteDescriptor, null); + } + // otherwise, audioVideo needs to be handled as two steps. - if (!audioSuccess) - Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key); - var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); + RouteDescriptor audioRouteDescriptor; - var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); - - if (!videoSuccess) - Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); - - foreach (var route in audioRouteDescriptor.Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); - } - - foreach (var route in videoRouteDescriptor.Routes) - { - Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); - } - - - if (!audioSuccess && !videoSuccess) - return (null, null); - - - return (audioRouteDescriptor, videoRouteDescriptor); + if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) + { + audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio); + } else + { + audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio); } - /// - /// Internal method to handle the logic for releasing an existing route and making a new one. - /// Handles devices with cooling states by queueing the request. - /// - /// The destination device. - /// The source device. - /// The type of signal to route. - /// The specific destination input port (optional). - /// The specific source output port (optional). - private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null) + var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); + + if (!audioSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key); + + var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video); + + var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); + + if (!videoSuccess) + Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key); + + foreach (var route in audioRouteDescriptor.Routes) { - if (destination == null) throw new ArgumentNullException(nameof(destination)); - if (source == null) throw new ArgumentNullException(nameof(source)); - if (destinationPort == null) Debug.LogMessage(LogEventLevel.Information, "Destination port is null"); - if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "Source port is null"); + Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString()); + } - var routeRequest = new RouteRequest - { - Destination = destination, - DestinationPort = destinationPort, - Source = source, - SourcePort = sourcePort, - SignalType = signalType - }; + foreach (var route in videoRouteDescriptor.Routes) + { + Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString()); + } - var coolingDevice = destination as IWarmingCooling; - //We already have a route request for this device, and it's a cooling device and is cooling - if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; + if (!audioSuccess && !videoSuccess) + return (null, null); - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; - RouteRequests[destination.Key] = routeRequest; + return (audioRouteDescriptor, videoRouteDescriptor); + } - 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); + /// + /// Internal method to handle the logic for releasing an existing route and making a new one. + /// Handles devices with cooling states by queueing the request. + /// + /// The destination device. + /// The source device. + /// The type of signal to route. + /// The specific destination input port (optional). + /// The specific source output port (optional). + private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null) + { + if (destination == null) throw new ArgumentNullException(nameof(destination)); + if (source == null) throw new ArgumentNullException(nameof(source)); + if (destinationPort == null) Debug.LogMessage(LogEventLevel.Information, "Destination port is null"); + if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "Source port is null"); + var routeRequest = new RouteRequest + { + Destination = destination, + DestinationPort = destinationPort, + Source = source, + SourcePort = sourcePort, + SignalType = signalType + }; + + var coolingDevice = destination as IWarmingCooling; + + //We already have a route request for this device, and it's a cooling device and is cooling + if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; + + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + + RouteRequests[destination.Key] = routeRequest; + + Debug.LogMessage(LogEventLevel.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); + + return; + } + + //New Request + if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) + { + coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + + 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); + return; + } + + if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) + { + var handledRequest = RouteRequests[destination.Key]; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= handledRequest.HandleCooldown; + + 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); + } + + routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty, false)); + + routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); + } + + /// + /// Executes the actual routing based on a . + /// Finds the route path, adds it to the collection, and executes the switches. + /// + /// The route request details. + private static void RunRouteRequest(RouteRequest request) + { + try + { + if (request.Source == null) return; - } - //New Request - if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) - { - coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; + var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); - 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); + if (audioOrSingleRoute == null && videoRoute == null) return; - } - if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute); + + if (videoRoute != null) { - var handledRequest = RouteRequests[destination.Key]; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= handledRequest.HandleCooldown; - - 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); + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); } - routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty, false)); + Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); - routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); - } - - /// - /// Executes the actual routing based on a . - /// Finds the route path, adds it to the collection, and executes the switches. - /// - /// The route request details. - private static void RunRouteRequest(RouteRequest request) + audioOrSingleRoute.ExecuteRoutes(); + videoRoute?.ExecuteRoutes(); + } catch(Exception ex) { - try - { - if (request.Source == null) - return; - - var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); - - if (audioOrSingleRoute == null && videoRoute == null) - return; - - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute); - - if (videoRoute != null) - { - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); - } - - Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); - - audioOrSingleRoute.ExecuteRoutes(); - videoRoute?.ExecuteRoutes(); - } catch(Exception ex) - { - Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); - } - } - - /// - /// Will release the existing route on the destination, if it is found in RouteDescriptorCollection.DefaultCollection - /// - /// - /// The input port key to use to find the route. If empty, will use the first available input port - /// If true, will clear the route on the destination. This will remove any routes that are currently in use - private static void ReleaseRouteInternal(IRoutingInputs destination, string inputPortKey, bool clearRoute) - { - try - { - Debug.LogMessage(LogEventLevel.Information, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - - if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) - { - var coolingDevice = destination as IWarmingCooling; - - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; - } - - RouteRequests.Remove(destination.Key); - - var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey); - if (current != null) - { - Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); - current.ReleaseRoutes(clearRoute); - } - } catch (Exception ex) - { - Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - } - } - - /// - /// The recursive part of this. Will stop on each device, search its inputs for the - /// desired source and if not found, invoke this function for the each input port - /// hoping to find the source. - /// - /// - /// - /// The RoutingOutputPort whose link is being checked for a route - /// Prevents Devices from being twice-checked - /// This recursive function should not be called with AudioVideo - /// Just an informational counter - /// The RouteDescriptor being populated as the route is discovered - /// true if source is hit - private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, - RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, - eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) - { - cycle++; - - 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()); - - RoutingInputPort goodInputPort = null; - - IEnumerable destinationTieLines; - TieLine directTie = null; - - if (destinationPort == null) - { - destinationTieLines = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo)); - } - else - { - destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type.HasFlag(signalType))); - } - - // find the TieLine without a port - if (destinationPort == null && sourcePort == null) - { - directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key); - } - // find a tieLine to a specific destination port without a specific source port - else if (destinationPort != null && sourcePort == null) - { - directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key); - } - // find a tieline to a specific source port without a specific destination port - else if (destinationPort == null & sourcePort != null) - { - directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key); - } - // find a tieline to a specific source port and destination port - else if (destinationPort != null && sourcePort != null) - { - directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key); - } - - if (directTie != null) // Found a tie directly to the source - { - goodInputPort = directTie.DestinationPort; - } - else // no direct-connect. Walk back devices. - { - Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, source.Key); - - // No direct tie? Run back out on the inputs' attached devices... - // Only the ones that are routing devices - var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); - - //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration - if (alreadyCheckedDevices == null) - alreadyCheckedDevices = new List(); - alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); - - foreach (var tieLine in midpointTieLines) - { - var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingInputsOutputs; - - // Check if this previous device has already been walked - if (alreadyCheckedDevices.Contains(midpointDevice)) - { - Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key); - continue; - } - - var midpointOutputPort = tieLine.SourcePort; - - Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, midpointDevice.Key); - - // haven't seen this device yet. Do it. Pass the output port to the next - // level to enable switching on success - var upstreamRoutingSuccess = midpointDevice.GetRouteToSource(source, midpointOutputPort, - alreadyCheckedDevices, signalType, cycle, routeTable, null, sourcePort); - - if (upstreamRoutingSuccess) - { - Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); - Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key); - Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort); - goodInputPort = tieLine.DestinationPort; - break; // Stop looping the inputs in this cycle - } - } - } - - - if (goodInputPort == null) - { - Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); - return false; - } - - // we have a route on corresponding inputPort. *** Do the route *** - - if (destination is IRoutingSink) - { - // it's a sink device - routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); - } - else if (destination is IRouting) - { - routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort)); - } - else // device is merely IRoutingInputOutputs - Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); - - return true; + Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); } } + + /// + /// Will release the existing route on the destination, if it is found in RouteDescriptorCollection.DefaultCollection + /// + /// + /// The input port key to use to find the route. If empty, will use the first available input port + /// If true, will clear the route on the destination. This will remove any routes that are currently in use + private static void ReleaseRouteInternal(IRoutingInputs destination, string inputPortKey, bool clearRoute) + { + try + { + Debug.LogMessage(LogEventLevel.Information, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + + if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) + { + var coolingDevice = destination as IWarmingCooling; + + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; + } + + RouteRequests.Remove(destination.Key); + + var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey); + if (current != null) + { + Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); + current.ReleaseRoutes(clearRoute); + } + } catch (Exception ex) + { + Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + } + } + + /// + /// The recursive part of this. Will stop on each device, search its inputs for the + /// desired source and if not found, invoke this function for the each input port + /// hoping to find the source. + /// + /// + /// + /// The RoutingOutputPort whose link is being checked for a route + /// Prevents Devices from being twice-checked + /// This recursive function should not be called with AudioVideo + /// Just an informational counter + /// The RouteDescriptor being populated as the route is discovered + /// true if source is hit + private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, + RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, + eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) + { + cycle++; + + 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()); + + RoutingInputPort goodInputPort = null; + + IEnumerable destinationTieLines; + TieLine directTie = null; + + if (destinationPort == null) + { + destinationTieLines = TieLineCollection.Default.Where(t => + t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo)); + } + else + { + destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type.HasFlag(signalType))); + } + + // find the TieLine without a port + if (destinationPort == null && sourcePort == null) + { + directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key); + } + // find a tieLine to a specific destination port without a specific source port + else if (destinationPort != null && sourcePort == null) + { + directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key); + } + // find a tieline to a specific source port without a specific destination port + else if (destinationPort == null & sourcePort != null) + { + directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key); + } + // find a tieline to a specific source port and destination port + else if (destinationPort != null && sourcePort != null) + { + directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key); + } + + if (directTie != null) // Found a tie directly to the source + { + goodInputPort = directTie.DestinationPort; + } + else // no direct-connect. Walk back devices. + { + Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, source.Key); + + // No direct tie? Run back out on the inputs' attached devices... + // Only the ones that are routing devices + var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); + + //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration + if (alreadyCheckedDevices == null) + alreadyCheckedDevices = new List(); + alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); + + foreach (var tieLine in midpointTieLines) + { + var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingInputsOutputs; + + // Check if this previous device has already been walked + if (alreadyCheckedDevices.Contains(midpointDevice)) + { + Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key); + continue; + } + + var midpointOutputPort = tieLine.SourcePort; + + Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, midpointDevice.Key); + + // haven't seen this device yet. Do it. Pass the output port to the next + // level to enable switching on success + var upstreamRoutingSuccess = midpointDevice.GetRouteToSource(source, midpointOutputPort, + alreadyCheckedDevices, signalType, cycle, routeTable, null, sourcePort); + + if (upstreamRoutingSuccess) + { + Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination); + Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key); + Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort); + goodInputPort = tieLine.DestinationPort; + break; // Stop looping the inputs in this cycle + } + } + } + + + if (goodInputPort == null) + { + Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key); + return false; + } + + // we have a route on corresponding inputPort. *** Do the route *** + + if (destination is IRoutingSink) + { + // it's a sink device + routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); + } + else if (destination is IRouting) + { + routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort)); + } + else // device is merely IRoutingInputOutputs + Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination); + + return true; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs index 505a8652..055ac2e7 100644 --- a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs +++ b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs @@ -9,22 +9,21 @@ using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing.Interfaces */ -namespace PepperDash.Essentials.Core -{ - /// - /// The handler type for a Room's SourceInfoChange - /// - public delegate void SourceInfoChangeHandler(SourceListItem info, ChangeType type); - //******************************************************************************************* - // Interfaces +namespace PepperDash.Essentials.Core; - /// - /// For rooms with a single presentation source, change event - /// - public interface IHasCurrentSourceInfoChange - { - string CurrentSourceInfoKey { get; set; } - SourceListItem CurrentSourceInfo { get; set; } - event SourceInfoChangeHandler CurrentSourceChange; - } +/// +/// The handler type for a Room's SourceInfoChange +/// +public delegate void SourceInfoChangeHandler(SourceListItem info, ChangeType type); +//******************************************************************************************* +// Interfaces + +/// +/// For rooms with a single presentation source, change event +/// +public interface IHasCurrentSourceInfoChange +{ + string CurrentSourceInfoKey { get; set; } + SourceListItem CurrentSourceInfo { get; set; } + event SourceInfoChangeHandler CurrentSourceChange; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IInputSync.cs b/src/PepperDash.Essentials.Core/Routing/IInputSync.cs index accb70a7..61218f27 100644 --- a/src/PepperDash.Essentials.Core/Routing/IInputSync.cs +++ b/src/PepperDash.Essentials.Core/Routing/IInputSync.cs @@ -5,12 +5,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.Routing -{ - public interface IVideoSync : IKeyed - { - bool VideoSyncDetected { get; } +namespace PepperDash.Essentials.Core.Routing; - event EventHandler VideoSyncChanged; - } +public interface IVideoSync : IKeyed +{ + bool VideoSyncDetected { get; } + + event EventHandler VideoSyncChanged; } diff --git a/src/PepperDash.Essentials.Core/Routing/IMatrixRouting.cs b/src/PepperDash.Essentials.Core/Routing/IMatrixRouting.cs index d7dc8c79..aad35e14 100644 --- a/src/PepperDash.Essentials.Core/Routing/IMatrixRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/IMatrixRouting.cs @@ -1,12 +1,11 @@ using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Routing -{ - public interface IMatrixRouting - { - Dictionary InputSlots { get; } - Dictionary OutputSlots { get; } +namespace PepperDash.Essentials.Core.Routing; - void Route(string inputSlotKey, string outputSlotKey, eRoutingSignalType type); - } +public interface IMatrixRouting +{ + Dictionary InputSlots { get; } + Dictionary OutputSlots { get; } + + void Route(string inputSlotKey, string outputSlotKey, eRoutingSignalType type); } diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs index 52290bd2..38b3fa31 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs @@ -1,10 +1,9 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines a receiver that has internal routing (DM-RMC-4K-Z-SCALER-C) +/// +public interface IRmcRouting : IRoutingNumeric { - /// - /// Defines a receiver that has internal routing (DM-RMC-4K-Z-SCALER-C) - /// - public interface IRmcRouting : IRoutingNumeric - { - IntFeedback AudioVideoSourceNumericFeedback { get; } - } + IntFeedback AudioVideoSourceNumericFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs index a8e6d5f0..660183c1 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an IRmcRouting with a feedback event +/// +public interface IRmcRoutingWithFeedback : IRmcRouting { - /// - /// Defines an IRmcRouting with a feedback event - /// - public interface IRmcRoutingWithFeedback : IRmcRouting - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRouting.cs b/src/PepperDash.Essentials.Core/Routing/IRouting.cs index e3231858..4856a956 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRouting.cs @@ -1,21 +1,20 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core -{ - /// - /// Defines a midpoint device as have internal routing. Any devices in the middle of the - /// signal chain, that do switching, must implement this for routing to work otherwise - /// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough - /// device. - /// - public interface IRouting : IRoutingInputsOutputs +namespace PepperDash.Essentials.Core; + +/// +/// Defines a midpoint device as have internal routing. Any devices in the middle of the +/// signal chain, that do switching, must implement this for routing to work otherwise +/// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough +/// device. +/// +public interface IRouting : IRoutingInputsOutputs { void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType); - } +} - /*public interface IRouting : IRoutingInputsOutputs - { - void ExecuteSwitch(TInputSelector inputSelector, TOutputSelector outputSelector, eRoutingSignalType signalType); - }*/ -} \ No newline at end of file +/*public interface IRouting : IRoutingInputsOutputs +{ + void ExecuteSwitch(TInputSelector inputSelector, TOutputSelector outputSelector, eRoutingSignalType signalType); +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs index b8b22915..651bb6a8 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs @@ -3,14 +3,13 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an event structure for reporting output route data +/// +public interface IRoutingFeedback : IKeyName { - /// - /// Defines an event structure for reporting output route data - /// - public interface IRoutingFeedback : IKeyName - { - event EventHandler NumericSwitchChange; - //void OnSwitchChange(RoutingNumericEventArgs e); - } + event EventHandler NumericSwitchChange; + //void OnSwitchChange(RoutingNumericEventArgs e); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs index 0f6d7834..8b3ac157 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs @@ -9,11 +9,10 @@ using Crestron.SimplSharpPro.DM; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public interface IRoutingHasVideoInputSyncFeedbacks { FeedbackCollection VideoInputSyncFeedbacks { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs index faee0fe9..a50062b5 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs @@ -1,7 +1,6 @@ -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + +public interface IRoutingInputSlot: IRoutingSlot, IOnline, IVideoSync { - public interface IRoutingInputSlot: IRoutingSlot, IOnline, IVideoSync - { - string TxDeviceKey { get; } - } + string TxDeviceKey { get; } } diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs index ff96fded..129b198f 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs @@ -1,18 +1,17 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ - /// - /// Defines a class that has a collection of RoutingInputPorts - /// - public interface IRoutingInputs : IKeyed +namespace PepperDash.Essentials.Core; + +/// +/// Defines a class that has a collection of RoutingInputPorts +/// +public interface IRoutingInputs : IKeyed { RoutingPortCollection InputPorts { get; } } /* public interface IRoutingInputs : IKeyed - { - RoutingPortCollection, TSelector> InputPorts { get; } - }*/ -} \ No newline at end of file +{ + RoutingPortCollection, TSelector> InputPorts { get; } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs index e202fa3c..56cb9290 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs @@ -1,16 +1,15 @@ -namespace PepperDash.Essentials.Core -{ - /// - /// For devices like RMCs, baluns, other devices with no switching. - /// - public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs +namespace PepperDash.Essentials.Core; + +/// +/// For devices like RMCs, baluns, other devices with no switching. +/// +public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs { } /* /// - /// For devices like RMCs, baluns, other devices with no switching. - /// - public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs - { - }*/ -} \ No newline at end of file +/// For devices like RMCs, baluns, other devices with no switching. +/// +public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs +{ +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs index d41909f1..8788948e 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs @@ -1,7 +1,6 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IRoutingNumeric : IRouting { - public interface IRoutingNumeric : IRouting - { - void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type); - } + void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs index e278a193..a59e9699 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an IRoutingNumeric with a feedback event +/// +public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback { - /// - /// Defines an IRoutingNumeric with a feedback event - /// - public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs index 478961cc..60587b8a 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + +public interface IRoutingOutputSlot : IRoutingSlot { - public interface IRoutingOutputSlot : IRoutingSlot - { - event EventHandler OutputSlotChanged; + event EventHandler OutputSlotChanged; - string RxDeviceKey { get; } + string RxDeviceKey { get; } - Dictionary CurrentRoutes { get; } - } -} + Dictionary CurrentRoutes { get; } +} diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs index d3bc70de..69bd0d68 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs @@ -1,19 +1,18 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ - /// - /// Defines a class that has a collection of RoutingOutputPorts - /// +namespace PepperDash.Essentials.Core; - public interface IRoutingOutputs : IKeyed +/// +/// Defines a class that has a collection of RoutingOutputPorts +/// + +public interface IRoutingOutputs : IKeyed { RoutingPortCollection OutputPorts { get; } } /* public interface IRoutingOutputs : IKeyed - { - RoutingPortCollection, TSelector> OutputPorts { get; } - }*/ -} \ No newline at end of file +{ + RoutingPortCollection, TSelector> OutputPorts { get; } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs index b05c7744..68e207a2 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -1,23 +1,22 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// For fixed-source endpoint devices +/// +public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange +{ +} + +public interface IRoutingSinkWithInputPort :IRoutingSink { - /// - /// For fixed-source endpoint devices - /// - public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange - { - } + RoutingInputPort CurrentInputPort { get; } +} +/*/// +/// For fixed-source endpoint devices +/// +public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange +{ + void UpdateRouteRequest(RouteRequest request); - public interface IRoutingSinkWithInputPort :IRoutingSink - { - RoutingInputPort CurrentInputPort { get; } - } - /*/// - /// For fixed-source endpoint devices - /// - public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange - { - void UpdateRouteRequest(RouteRequest request); - - RouteRequest GetRouteRequest(); - }*/ -} \ No newline at end of file + RouteRequest GetRouteRequest(); +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs index d3d3e600..f55b4f27 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs @@ -2,24 +2,23 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + + +/// +/// For fixed-source endpoint devices +/// +public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching { - /// - /// For fixed-source endpoint devices - /// - public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching - { - - } +} /* /// - /// For fixed-source endpoint devices - /// - public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching - { - RouteSwitchDescriptor CurrentRoute { get; } +/// For fixed-source endpoint devices +/// +public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching +{ + RouteSwitchDescriptor CurrentRoute { get; } - event EventHandler InputChanged; - }*/ -} \ No newline at end of file + event EventHandler InputChanged; +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs index d6f97c07..010369a6 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs @@ -1,27 +1,26 @@ using System; -namespace PepperDash.Essentials.Core -{ - public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort); +namespace PepperDash.Essentials.Core; - /// - /// Endpoint device like a display, that selects inputs - /// - public interface IRoutingSinkWithSwitching : IRoutingSink +public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort); + +/// +/// Endpoint device like a display, that selects inputs +/// +public interface IRoutingSinkWithSwitching : IRoutingSink { void ExecuteSwitch(object inputSelector); - } +} - public interface IRoutingSinkWithSwitchingWithInputPort:IRoutingSinkWithSwitching, IRoutingSinkWithInputPort - { - event InputChangedEventHandler InputChanged; - } +public interface IRoutingSinkWithSwitchingWithInputPort:IRoutingSinkWithSwitching, IRoutingSinkWithInputPort +{ + event InputChangedEventHandler InputChanged; +} /* /// - /// Endpoint device like a display, that selects inputs - /// - public interface IRoutingSinkWithSwitching : IRoutingSink - { - void ExecuteSwitch(TSelector inputSelector); - }*/ -} \ No newline at end of file +/// Endpoint device like a display, that selects inputs +/// +public interface IRoutingSinkWithSwitching : IRoutingSink +{ + void ExecuteSwitch(TSelector inputSelector); +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs index 7fabfb8b..e3faf171 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs @@ -5,12 +5,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Core.Routing -{ - public interface IRoutingSlot:IKeyName - { - int SlotNumber { get; } +namespace PepperDash.Essentials.Core.Routing; - eRoutingSignalType SupportedSignalTypes { get; } - } +public interface IRoutingSlot:IKeyName +{ + int SlotNumber { get; } + + eRoutingSignalType SupportedSignalTypes { get; } } diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs index d3f61e72..5eaaabf8 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Marker interface to identify a device that acts as the origin of a signal path (). +/// +public interface IRoutingSource : IRoutingOutputs { - /// - /// Marker interface to identify a device that acts as the origin of a signal path (). - /// - public interface IRoutingSource : IRoutingOutputs - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs index 407133ef..dc027db9 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs @@ -1,15 +1,14 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines a routing device () that supports explicitly clearing a route on an output. +/// +public interface IRoutingWithClear : IRouting { /// - /// Defines a routing device () that supports explicitly clearing a route on an output. + /// Clears a route to an output, however a device needs to do that /// - public interface IRoutingWithClear : IRouting - { - /// - /// Clears a route to an output, however a device needs to do that - /// - /// Output to clear - /// signal type to clear - void ClearRoute(object outputSelector, eRoutingSignalType signalType); - } + /// Output to clear + /// signal type to clear + void ClearRoute(object outputSelector, eRoutingSignalType signalType); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs index a328441a..471e098c 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs @@ -1,27 +1,26 @@ using System.Collections.Generic; using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Delegate for handling route change events on devices implementing . +/// +/// The routing device where the change occurred. +/// A descriptor of the new route that was established. +public delegate void RouteChangedEventHandler(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute); +/// +/// Defines a routing device () that provides feedback about its current routes. +/// +public interface IRoutingWithFeedback : IRouting { /// - /// Delegate for handling route change events on devices implementing . + /// Gets a list describing the currently active routes on this device. /// - /// The routing device where the change occurred. - /// A descriptor of the new route that was established. - public delegate void RouteChangedEventHandler(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute); - /// - /// Defines a routing device () that provides feedback about its current routes. - /// - public interface IRoutingWithFeedback : IRouting - { - /// - /// Gets a list describing the currently active routes on this device. - /// - List CurrentRoutes { get; } + List CurrentRoutes { get; } - /// - /// Event triggered when a route changes on this device. - /// - event RouteChangedEventHandler RouteChanged; - } + /// + /// Event triggered when a route changes on this device. + /// + event RouteChangedEventHandler RouteChanged; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs b/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs index a157e8d1..67901117 100644 --- a/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs +++ b/src/PepperDash.Essentials.Core/Routing/ITxRouting.cs @@ -1,18 +1,17 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a routing device (typically a transmitter or source) that provides numeric feedback for its current route. +/// Extends . +/// +public interface ITxRouting : IRoutingNumeric { /// - /// Represents a routing device (typically a transmitter or source) that provides numeric feedback for its current route. - /// Extends . + /// Feedback indicating the currently routed video source by its numeric identifier. /// - public interface ITxRouting : IRoutingNumeric - { - /// - /// Feedback indicating the currently routed video source by its numeric identifier. - /// - IntFeedback VideoSourceNumericFeedback { get; } - /// - /// Feedback indicating the currently routed audio source by its numeric identifier. - /// - IntFeedback AudioSourceNumericFeedback { get; } - } + IntFeedback VideoSourceNumericFeedback { get; } + /// + /// Feedback indicating the currently routed audio source by its numeric identifier. + /// + IntFeedback AudioSourceNumericFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs b/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs index 484fa134..0ba49439 100644 --- a/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs +++ b/src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs @@ -1,9 +1,8 @@ -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Defines an IRmcRouting with a feedback event +/// +public interface ITxRoutingWithFeedback : ITxRouting { - /// - /// Defines an IRmcRouting with a feedback event - /// - public interface ITxRoutingWithFeedback : ITxRouting - { - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs index e02dd30e..c69285dd 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs @@ -7,209 +7,208 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a collection of individual route steps between a Source and a Destination device for a specific signal type. +/// +public class RouteDescriptor { /// - /// Represents a collection of individual route steps between a Source and a Destination device for a specific signal type. + /// The destination device (sink or midpoint) for the route. /// - public class RouteDescriptor + public IRoutingInputs Destination { get; private set; } + + /// + /// The specific input port on the destination device used for this route. Can be null if not specified or applicable. + /// + public RoutingInputPort InputPort { get; private set; } + + /// + /// The source device for the route. + /// + public IRoutingOutputs Source { get; private set; } + + /// + /// The type of signal being routed (e.g., Audio, Video). This descriptor represents a single signal type. + /// + public eRoutingSignalType SignalType { get; private set; } + + /// + /// A list of individual switching steps required to establish the route. + /// + public List Routes { get; private set; } + + /// + /// Initializes a new instance of the class for a route without a specific destination input port. + /// + /// The source device. + /// The destination device. + /// The type of signal being routed. + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType) { - /// - /// The destination device (sink or midpoint) for the route. - /// - public IRoutingInputs Destination { get; private set; } + } - /// - /// The specific input port on the destination device used for this route. Can be null if not specified or applicable. - /// - public RoutingInputPort InputPort { get; private set; } + /// + /// Initializes a new instance of the class for a route with a specific destination input port. + /// + /// The source device. + /// The destination device. + /// The destination input port (optional). + /// The signal type for this route. + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType) + { + Destination = destination; + InputPort = inputPort; + Source = source; + SignalType = signalType; + Routes = new List(); + } - /// - /// The source device for the route. - /// - public IRoutingOutputs Source { get; private set; } - - /// - /// The type of signal being routed (e.g., Audio, Video). This descriptor represents a single signal type. - /// - public eRoutingSignalType SignalType { get; private set; } - - /// - /// A list of individual switching steps required to establish the route. - /// - public List Routes { get; private set; } - - /// - /// Initializes a new instance of the class for a route without a specific destination input port. - /// - /// The source device. - /// The destination device. - /// The type of signal being routed. - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType) + /// + /// Executes all the switching steps defined in the list. + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) { - } + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); - /// - /// Initializes a new instance of the class for a route with a specific destination input port. - /// - /// The source device. - /// The destination device. - /// The destination input port (optional). - /// The signal type for this route. - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType) - { - Destination = destination; - InputPort = inputPort; - Source = source; - SignalType = signalType; - Routes = new List(); - } - - /// - /// Executes all the switching steps defined in the list. - /// - public void ExecuteRoutes() - { - foreach (var route in Routes) + if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) { - Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); - - if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) - { - sink.ExecuteSwitch(route.InputPort.Selector); - continue; - } - - if (route.SwitchingDevice is IRouting switchingDevice) - { - switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - - route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - - Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } + sink.ExecuteSwitch(route.InputPort.Selector); + continue; } - } - /// - /// Releases the usage tracking for the route and optionally clears the route on the switching devices. - /// - /// If true, attempts to clear the route on the switching devices (e.g., set input to null/0). - public void ReleaseRoutes(bool clearRoute = false) - { - foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting)) + if (route.SwitchingDevice is IRouting switchingDevice) { - if (route.SwitchingDevice is IRouting switchingDevice) - { - if(clearRoute) - { - try - { - switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType); - } - catch (Exception e) - { - Debug.LogError("Error executing switch: {exception}", e.Message); - } - } + switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - if (route.OutputPort == null) - { - continue; - } + route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - if (route.OutputPort.InUseTracker != null) - { - 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); - } - else - { - Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key); - } - } + Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); } } - - /// - /// Returns a string representation of the route descriptor, including source, destination, and individual route steps. - /// - /// A string describing the route. - public override string ToString() - { - var routesText = Routes.Select(r => r.ToString()).ToArray(); - return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); - } } - /*/// - /// Represents an collection of individual route steps between Source and Destination + /// + /// Releases the usage tracking for the route and optionally clears the route on the switching devices. /// - public class RouteDescriptor + /// If true, attempts to clear the route on the switching devices (e.g., set input to null/0). + public void ReleaseRoutes(bool clearRoute = false) { - public IRoutingInputs Destination { get; private set; } - public IRoutingOutputs Source { get; private set; } - public eRoutingSignalType SignalType { get; private set; } - public List> Routes { get; private set; } - - - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting)) { - Destination = destination; - Source = source; - SignalType = signalType; - Routes = new List>(); - } - - /// - /// Executes all routes described in this collection. Typically called via - /// extension method IRoutingInputs.ReleaseAndMakeRoute() - /// - public void ExecuteRoutes() - { - foreach (var route in Routes) + if (route.SwitchingDevice is IRouting switchingDevice) { - Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); - - if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) + if(clearRoute) + { + try + { + switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType); + } + catch (Exception e) + { + Debug.LogError("Error executing switch: {exception}", e.Message); + } + } + + if (route.OutputPort == null) { - sink.ExecuteSwitch(route.InputPort.Selector); continue; } - if (route.SwitchingDevice is IRouting switchingDevice) + if (route.OutputPort.InUseTracker != null) { - switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - - route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); - - Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); - } - } - } - - /// - /// Releases all routes in this collection. Typically called via - /// extension method IRoutingInputs.ReleaseAndMakeRoute() - /// - public void ReleaseRoutes() - { - foreach (var route in Routes) - { - if (route.SwitchingDevice is IRouting) - { - // Pull the route from the port. Whatever is watching the output's in use tracker is - // responsible for responding appropriately. route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); } + else + { + Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key); + } } } + } - public override string ToString() + /// + /// Returns a string representation of the route descriptor, including source, destination, and individual route steps. + /// + /// A string describing the route. + public override string ToString() + { + var routesText = Routes.Select(r => r.ToString()).ToArray(); + return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } +} + +/*/// +/// Represents an collection of individual route steps between Source and Destination +/// +public class RouteDescriptor +{ + public IRoutingInputs Destination { get; private set; } + public IRoutingOutputs Source { get; private set; } + public eRoutingSignalType SignalType { get; private set; } + public List> Routes { get; private set; } + + + public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) + { + Destination = destination; + Source = source; + SignalType = signalType; + Routes = new List>(); + } + + /// + /// Executes all routes described in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ExecuteRoutes() + { + foreach (var route in Routes) { - var routesText = Routes.Select(r => r.ToString()).ToArray(); - return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString()); + + if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) + { + sink.ExecuteSwitch(route.InputPort.Selector); + continue; + } + + if (route.SwitchingDevice is IRouting switchingDevice) + { + switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); + + route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); + + Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } } - }*/ -} \ No newline at end of file + } + + /// + /// Releases all routes in this collection. Typically called via + /// extension method IRoutingInputs.ReleaseAndMakeRoute() + /// + public void ReleaseRoutes() + { + foreach (var route in Routes) + { + if (route.SwitchingDevice is IRouting) + { + // Pull the route from the port. Whatever is watching the output's in use tracker is + // responsible for responding appropriately. + route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); + Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); + } + } + } + + public override string ToString() + { + var routesText = Routes.Select(r => r.ToString()).ToArray(); + return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs index 9bafc128..617d99f1 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs @@ -4,90 +4,90 @@ using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// A collection of RouteDescriptors - typically the static DefaultCollection is used +/// +public class RouteDescriptorCollection { - /// - /// A collection of RouteDescriptors - typically the static DefaultCollection is used - /// - public class RouteDescriptorCollection + public static RouteDescriptorCollection DefaultCollection { - public static RouteDescriptorCollection DefaultCollection + get { - get - { - if (_DefaultCollection == null) - _DefaultCollection = new RouteDescriptorCollection(); - return _DefaultCollection; - } - } - private static RouteDescriptorCollection _DefaultCollection; - - private readonly List RouteDescriptors = new List(); - - /// - /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the - /// destination exists already, it will not be added - in order to preserve - /// proper route releasing. - /// - /// - public void AddRouteDescriptor(RouteDescriptor descriptor) - { - if (descriptor == null) - { - return; - } - - if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination) - && RouteDescriptors.Any(t => t.Destination == descriptor.Destination && t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) - { - Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, - "Route to [{0}] already exists in global routes table", descriptor?.Source?.Key); - return; - } - RouteDescriptors.Add(descriptor); - } - - /// - /// Gets the RouteDescriptor for a destination - /// - /// null if no RouteDescriptor for a destination exists - public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) - { - Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}'", destination?.Key ?? null); - - return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); - } - - public RouteDescriptor GetRouteDescriptorForDestinationAndInputPort(IRoutingInputs destination, string inputPortKey) - { - Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination && rd.InputPort != null && rd.InputPort.Key == inputPortKey); - } - - /// - /// Returns the RouteDescriptor for a given destination AND removes it from collection. - /// Returns null if no route with the provided destination exists. - /// - public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, string inputPortKey = "") - { - Debug.LogMessage(LogEventLevel.Information, "Removing route descriptor for '{destination}':'{inputPortKey}'", destination.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - - var descr = string.IsNullOrEmpty(inputPortKey) - ? GetRouteDescriptorForDestination(destination) - : GetRouteDescriptorForDestinationAndInputPort(destination, inputPortKey); - if (descr != null) - RouteDescriptors.Remove(descr); - - Debug.LogMessage(LogEventLevel.Information, "Found route descriptor {routeDescriptor}", destination, descr); - - return descr; + if (_DefaultCollection == null) + _DefaultCollection = new RouteDescriptorCollection(); + return _DefaultCollection; } } + private static RouteDescriptorCollection _DefaultCollection; - /*/// - /// A collection of RouteDescriptors - typically the static DefaultCollection is used + private readonly List RouteDescriptors = new List(); + + /// + /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the + /// destination exists already, it will not be added - in order to preserve + /// proper route releasing. /// - public class RouteDescriptorCollection + /// + public void AddRouteDescriptor(RouteDescriptor descriptor) + { + if (descriptor == null) + { + return; + } + + if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination) + && RouteDescriptors.Any(t => t.Destination == descriptor.Destination && t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) + { + Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, + "Route to [{0}] already exists in global routes table", descriptor?.Source?.Key); + return; + } + RouteDescriptors.Add(descriptor); + } + + /// + /// Gets the RouteDescriptor for a destination + /// + /// null if no RouteDescriptor for a destination exists + public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) + { + Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}'", destination?.Key ?? null); + + return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); + } + + public RouteDescriptor GetRouteDescriptorForDestinationAndInputPort(IRoutingInputs destination, string inputPortKey) + { + Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination && rd.InputPort != null && rd.InputPort.Key == inputPortKey); + } + + /// + /// Returns the RouteDescriptor for a given destination AND removes it from collection. + /// Returns null if no route with the provided destination exists. + /// + public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, string inputPortKey = "") + { + Debug.LogMessage(LogEventLevel.Information, "Removing route descriptor for '{destination}':'{inputPortKey}'", destination.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + + var descr = string.IsNullOrEmpty(inputPortKey) + ? GetRouteDescriptorForDestination(destination) + : GetRouteDescriptorForDestinationAndInputPort(destination, inputPortKey); + if (descr != null) + RouteDescriptors.Remove(descr); + + Debug.LogMessage(LogEventLevel.Information, "Found route descriptor {routeDescriptor}", destination, descr); + + return descr; + } +} + +/*/// +/// A collection of RouteDescriptors - typically the static DefaultCollection is used +/// +public class RouteDescriptorCollection { public static RouteDescriptorCollection DefaultCollection { @@ -139,5 +139,4 @@ namespace PepperDash.Essentials.Core RouteDescriptors.Remove(descr); return descr; } - }*/ -} \ No newline at end of file + }*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs index a8bdf015..08752257 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequest.cs @@ -2,77 +2,76 @@ using Serilog.Events; using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a request to establish a route between a source and a destination device. +/// +public class RouteRequest { /// - /// Represents a request to establish a route between a source and a destination device. + /// The specific input port on the destination device to use for the route. Can be null if the port should be automatically determined or is not applicable. /// - public class RouteRequest + public RoutingInputPort DestinationPort { get; set; } + + /// + /// The specific output port on the source device to use for the route. Can be null if the port should be automatically determined or is not applicable. + /// + public RoutingOutputPort SourcePort { get; set; } + + /// + /// The destination device (sink or midpoint) for the route. + /// + public IRoutingInputs Destination { get; set; } + + /// + /// The source device for the route. + /// + public IRoutingOutputs Source { get; set; } + + /// + /// The type of signal being routed (e.g., Audio, Video, AudioVideo). + /// + public eRoutingSignalType SignalType { get; set; } + + /// + /// Handles the route request after a device's cooldown period has finished. + /// This method is typically subscribed to the IsCoolingDownFeedback.OutputChange event. + /// + /// The object that triggered the event (usually the cooling device). + /// Event arguments indicating the cooldown state change. + public void HandleCooldown(object sender, FeedbackEventArgs args) { - /// - /// The specific input port on the destination device to use for the route. Can be null if the port should be automatically determined or is not applicable. - /// - public RoutingInputPort DestinationPort { get; set; } - - /// - /// The specific output port on the source device to use for the route. Can be null if the port should be automatically determined or is not applicable. - /// - public RoutingOutputPort SourcePort { get; set; } - - /// - /// The destination device (sink or midpoint) for the route. - /// - public IRoutingInputs Destination { get; set; } - - /// - /// The source device for the route. - /// - public IRoutingOutputs Source { get; set; } - - /// - /// The type of signal being routed (e.g., Audio, Video, AudioVideo). - /// - public eRoutingSignalType SignalType { get; set; } - - /// - /// Handles the route request after a device's cooldown period has finished. - /// This method is typically subscribed to the IsCoolingDownFeedback.OutputChange event. - /// - /// The object that triggered the event (usually the cooling device). - /// Event arguments indicating the cooldown state change. - public void HandleCooldown(object sender, FeedbackEventArgs args) + try { - try + Debug.LogMessage(LogEventLevel.Information, "Handling cooldown route request: {destination}:{destinationPort} -> {source}:{sourcePort} {type}", null, Destination?.Key ?? "empty destination", DestinationPort?.Key ?? "no destination port", Source?.Key ?? "empty source", SourcePort?.Key ?? "empty source port", SignalType.ToString()); + + if (args.BoolValue == true) { - Debug.LogMessage(LogEventLevel.Information, "Handling cooldown route request: {destination}:{destinationPort} -> {source}:{sourcePort} {type}", null, Destination?.Key ?? "empty destination", DestinationPort?.Key ?? "no destination port", Source?.Key ?? "empty source", SourcePort?.Key ?? "empty source port", SignalType.ToString()); - - if (args.BoolValue == true) - { - return; - } - - Debug.LogMessage(LogEventLevel.Information, "Cooldown complete. Making route from {destination} to {source}", Destination?.Key, Source?.Key); - - Destination.ReleaseAndMakeRoute(Source, SignalType, DestinationPort?.Key ?? string.Empty, SourcePort?.Key ?? string.Empty); - - if (sender is IWarmingCooling coolingDevice) - { - Debug.LogMessage(LogEventLevel.Debug, "Unsubscribing from cooling feedback for {destination}", null, Destination.Key); - coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; - } - } catch(Exception ex) - { - Debug.LogMessage(ex, "Exception handling cooldown", Destination); + return; } - } - /// - /// Returns a string representation of the route request. - /// - /// A string describing the source and destination of the route request. - public override string ToString() + Debug.LogMessage(LogEventLevel.Information, "Cooldown complete. Making route from {destination} to {source}", Destination?.Key, Source?.Key); + + Destination.ReleaseAndMakeRoute(Source, SignalType, DestinationPort?.Key ?? string.Empty, SourcePort?.Key ?? string.Empty); + + if (sender is IWarmingCooling coolingDevice) + { + Debug.LogMessage(LogEventLevel.Debug, "Unsubscribing from cooling feedback for {destination}", null, Destination.Key); + coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; + } + } catch(Exception ex) { - return $"Route {Source?.Key ?? "No Source Device"}:{SourcePort?.Key ?? "auto"} to {Destination?.Key ?? "No Destination Device"}:{DestinationPort?.Key ?? "auto"}"; + Debug.LogMessage(ex, "Exception handling cooldown", Destination); } } + + /// + /// Returns a string representation of the route request. + /// + /// A string describing the source and destination of the route request. + public override string ToString() + { + return $"Route {Source?.Key ?? "No Source Device"}:{SourcePort?.Key ?? "auto"} to {Destination?.Key ?? "No Destination Device"}:{DestinationPort?.Key ?? "auto"}"; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs index 07b52c2c..1f7ab486 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs @@ -3,87 +3,86 @@ using PepperDash.Essentials.Core.Queues; using System; using Serilog.Events; -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + +/// +/// Represents an item in the route request queue. +/// +public class RouteRequestQueueItem : IQueueMessage { /// - /// Represents an item in the route request queue. + /// The action to perform for the route request. /// - public class RouteRequestQueueItem : IQueueMessage + private readonly Action action; + /// + /// The route request data. + /// + private readonly RouteRequest routeRequest; + + /// + /// Initializes a new instance of the class. + /// + /// The action to perform. + /// The route request data. + public RouteRequestQueueItem(Action routeAction, RouteRequest request) { - /// - /// The action to perform for the route request. - /// - private readonly Action action; - /// - /// The route request data. - /// - private readonly RouteRequest routeRequest; - - /// - /// Initializes a new instance of the class. - /// - /// The action to perform. - /// The route request data. - public RouteRequestQueueItem(Action routeAction, RouteRequest request) - { - action = routeAction; - routeRequest = request; - } - - /// - /// Dispatches the route request action. - /// - public void Dispatch() - { - Debug.LogMessage(LogEventLevel.Information, "Dispatching route request {routeRequest}", null, routeRequest); - action(routeRequest); - } + action = routeAction; + routeRequest = request; } /// - /// Represents an item in the queue for releasing a route. + /// Dispatches the route request action. /// - public class ReleaseRouteQueueItem : IQueueMessage + public void Dispatch() { - /// - /// The action to perform for releasing the route. - /// - private readonly Action action; - /// - /// The destination device whose route is being released. - /// - private readonly IRoutingInputs destination; - /// - /// The specific input port key on the destination to release, or null/empty for any/default. - /// - private readonly string inputPortKey; - /// - /// Indicates whether to clear the route (send null) or just release the usage tracking. - /// - private readonly bool clearRoute; - - /// - /// Initializes a new instance of the class. - /// - /// The action to perform. - /// The destination device. - /// The input port key. - /// True to clear the route, false to just release. - public ReleaseRouteQueueItem(Action action, IRoutingInputs destination, string inputPortKey, bool clearRoute) - { - this.action = action; - this.destination = destination; - this.inputPortKey = inputPortKey; - this.clearRoute = clearRoute; - } - - /// - /// Dispatches the release route action. - /// - public void Dispatch() - { - Debug.LogMessage(LogEventLevel.Information, "Dispatching release route request for {destination}:{inputPortKey}", null, destination?.Key ?? "no destination", string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - action(destination, inputPortKey, clearRoute); - } + Debug.LogMessage(LogEventLevel.Information, "Dispatching route request {routeRequest}", null, routeRequest); + action(routeRequest); + } +} + +/// +/// Represents an item in the queue for releasing a route. +/// +public class ReleaseRouteQueueItem : IQueueMessage +{ + /// + /// The action to perform for releasing the route. + /// + private readonly Action action; + /// + /// The destination device whose route is being released. + /// + private readonly IRoutingInputs destination; + /// + /// The specific input port key on the destination to release, or null/empty for any/default. + /// + private readonly string inputPortKey; + /// + /// Indicates whether to clear the route (send null) or just release the usage tracking. + /// + private readonly bool clearRoute; + + /// + /// Initializes a new instance of the class. + /// + /// The action to perform. + /// The destination device. + /// The input port key. + /// True to clear the route, false to just release. + public ReleaseRouteQueueItem(Action action, IRoutingInputs destination, string inputPortKey, bool clearRoute) + { + this.action = action; + this.destination = destination; + this.inputPortKey = inputPortKey; + this.clearRoute = clearRoute; + } + + /// + /// Dispatches the release route action. + /// + public void Dispatch() + { + Debug.LogMessage(LogEventLevel.Information, "Dispatching release route request for {destination}:{inputPortKey}", null, destination?.Key ?? "no destination", string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + action(destination, inputPortKey, clearRoute); } } diff --git a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs index 6394a3bc..20430852 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs @@ -1,9 +1,9 @@ -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a single switching step within a larger route, detailing the switching device, input port, and optionally the output port. - /// - public class RouteSwitchDescriptor +namespace PepperDash.Essentials.Core; + +/// +/// Represents a single switching step within a larger route, detailing the switching device, input port, and optionally the output port. +/// +public class RouteSwitchDescriptor { /// /// The device performing the switch (derived from the InputPort's parent). @@ -44,39 +44,38 @@ /// A string describing the switch operation. public override string ToString() { - if (SwitchingDevice is IRouting) - return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches output {(OutputPort != null ? OutputPort.Key : "No output port")} to input {(InputPort != null ? InputPort.Key : "No input port")}"; - else - return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches to input {(InputPort != null ? InputPort.Key : "No input port")}"; + if (SwitchingDevice is IRouting) + return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches output {(OutputPort != null ? OutputPort.Key : "No output port")} to input {(InputPort != null ? InputPort.Key : "No input port")}"; + else + return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches to input {(InputPort != null ? InputPort.Key : "No input port")}"; } } - /*/// - /// Represents an individual link for a route - /// - public class RouteSwitchDescriptor +/*/// +/// Represents an individual link for a route +/// +public class RouteSwitchDescriptor +{ + public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } + public RoutingOutputPort OutputPort { get; set; } + public RoutingInputPort InputPort { get; set; } + + public RouteSwitchDescriptor(RoutingInputPort inputPort) { - public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } - public RoutingOutputPort OutputPort { get; set; } - public RoutingInputPort InputPort { get; set; } + InputPort = inputPort; + } - public RouteSwitchDescriptor(RoutingInputPort inputPort) - { - InputPort = inputPort; - } + public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) + { + InputPort = inputPort; + OutputPort = outputPort; + } - public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) - { - InputPort = inputPort; - OutputPort = outputPort; - } - - public override string ToString() - { - if (SwitchingDevice is IRouting) - return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); - else - return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); - } - }*/ -} \ No newline at end of file + public override string ToString() + { + if (SwitchingDevice is IRouting) + return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); + else + return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs index 9afdb33d..8211f3e6 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs @@ -3,308 +3,307 @@ using PepperDash.Essentials.Core.Config; using System; using System.Linq; -namespace PepperDash.Essentials.Core.Routing +namespace PepperDash.Essentials.Core.Routing; + +/// +/// Manages routing feedback by subscribing to route changes on midpoint and sink devices, +/// tracing the route back to the original source, and updating the CurrentSourceInfo on sink devices. +/// +public class RoutingFeedbackManager:EssentialsDevice { /// - /// Manages routing feedback by subscribing to route changes on midpoint and sink devices, - /// tracing the route back to the original source, and updating the CurrentSourceInfo on sink devices. + /// Initializes a new instance of the class. /// - public class RoutingFeedbackManager:EssentialsDevice + /// The unique key for this manager device. + /// The name of this manager device. + public RoutingFeedbackManager(string key, string name): base(key, name) + { + AddPreActivationAction(SubscribeForMidpointFeedback); + AddPreActivationAction(SubscribeForSinkFeedback); + } + + + /// + /// Subscribes to the RouteChanged event on all devices implementing . + /// + private void SubscribeForMidpointFeedback() { - /// - /// Initializes a new instance of the class. - /// - /// The unique key for this manager device. - /// The name of this manager device. - public RoutingFeedbackManager(string key, string name): base(key, name) - { - AddPreActivationAction(SubscribeForMidpointFeedback); - AddPreActivationAction(SubscribeForSinkFeedback); - } + var midpointDevices = DeviceManager.AllDevices.OfType(); - - /// - /// Subscribes to the RouteChanged event on all devices implementing . - /// - private void SubscribeForMidpointFeedback() + foreach (var device in midpointDevices) { - var midpointDevices = DeviceManager.AllDevices.OfType(); - - foreach (var device in midpointDevices) - { - device.RouteChanged += HandleMidpointUpdate; - } + device.RouteChanged += HandleMidpointUpdate; } + } - /// - /// Subscribes to the InputChanged event on all devices implementing . - /// - private void SubscribeForSinkFeedback() + /// + /// Subscribes to the InputChanged event on all devices implementing . + /// + private void SubscribeForSinkFeedback() + { + var sinkDevices = DeviceManager.AllDevices.OfType(); + + foreach (var device in sinkDevices) + { + device.InputChanged += HandleSinkUpdate; + } + } + + /// + /// Handles the RouteChanged event from a midpoint device. + /// Triggers an update for all sink devices. + /// + /// The midpoint device that reported a route change. + /// The descriptor of the new route. + private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute) + { + try { - var sinkDevices = DeviceManager.AllDevices.OfType(); + var devices = DeviceManager.AllDevices.OfType(); - foreach (var device in sinkDevices) - { - device.InputChanged += HandleSinkUpdate; - } + foreach (var device in devices) + { + UpdateDestination(device, device.CurrentInputPort); + } } - - /// - /// Handles the RouteChanged event from a midpoint device. - /// Triggers an update for all sink devices. - /// - /// The midpoint device that reported a route change. - /// The descriptor of the new route. - private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute) + catch (Exception ex) { - try - { - var devices = DeviceManager.AllDevices.OfType(); - - foreach (var device in devices) - { - UpdateDestination(device, device.CurrentInputPort); - } - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex); - } + Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex); } + } - /// - /// Handles the InputChanged event from a sink device. - /// Triggers an update for the specific sink device. - /// - /// The sink device that reported an input change. - /// The new input port selected on the sink device. - private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort) + /// + /// Handles the InputChanged event from a sink device. + /// Triggers an update for the specific sink device. + /// + /// The sink device that reported an input change. + /// The new input port selected on the sink device. + private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort) + { + try { - try - { - UpdateDestination(sender, currentInputPort); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex); - } + UpdateDestination(sender, currentInputPort); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex); + } + } + + /// + /// Updates the CurrentSourceInfo and CurrentSourceInfoKey properties on a destination (sink) device + /// based on its currently selected input port by tracing the route back through tie lines. + /// + /// The destination sink device to update. + /// The currently selected input port on the destination device. + private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) + { + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key); + + if(inputPort == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key); + return; } - /// - /// Updates the CurrentSourceInfo and CurrentSourceInfoKey properties on a destination (sink) device - /// based on its currently selected input port by tracing the route back through tie lines. - /// - /// The destination sink device to update. - /// The currently selected input port on the destination device. - private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) - { - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key); + TieLine firstTieLine; + try + { + var tieLines = TieLineCollection.Default; - if(inputPort == null) + firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key); + + if (firstTieLine == null) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key); - return; - } - - TieLine firstTieLine; - try - { - var tieLines = TieLineCollection.Default; - - firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key); - - if (firstTieLine == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort); - - var tempSourceListItem = new SourceListItem - { - SourceKey = "$transient", - Name = inputPort.Key, - }; - - - destination.CurrentSourceInfo = tempSourceListItem; ; - destination.CurrentSourceInfoKey = "$transient"; - return; - } - } catch (Exception ex) - { - Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex); - return; - } - - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); - - TieLine sourceTieLine; - try - { - sourceTieLine = GetRootTieLine(firstTieLine); - - if (sourceTieLine == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort); - - var tempSourceListItem = new SourceListItem - { - SourceKey = "$transient", - Name = "None", - }; - - destination.CurrentSourceInfo = tempSourceListItem; - destination.CurrentSourceInfoKey = string.Empty; - return; - } - } catch(Exception ex) - { - Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex); - return; - } - - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine); - - // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet. - var room = DeviceManager.AllDevices.OfType().FirstOrDefault((r) => { - if(r is IHasMultipleDisplays roomMultipleDisplays) - { - return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key); - } - - if(r is IHasDefaultDisplay roomDefaultDisplay) - { - return roomDefaultDisplay.DefaultDisplay.Key == destination.Key; - } - - return false; - }); - - if(room == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No room found for display {destination}", this, destination.Key); - return; - } - - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key); - - var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); - - if (sourceList == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", this, room.SourceListKey, sourceTieLine); - return; - } - - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key); - - var sourceListItem = sourceList.FirstOrDefault(sli => { - //// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, - // "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}", - // this, - // sli.Key, - // sli.Value.SourceKey, - // sourceTieLine.SourcePort.ParentDevice.Key); - - return sli.Value.SourceKey.Equals(sourceTieLine.SourcePort.ParentDevice.Key,StringComparison.InvariantCultureIgnoreCase); - }); - - var source = sourceListItem.Value; - var sourceKey = sourceListItem.Key; - - if (source == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination); + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort); var tempSourceListItem = new SourceListItem { SourceKey = "$transient", - Name = sourceTieLine.SourcePort.Key, + Name = inputPort.Key, }; + + destination.CurrentSourceInfo = tempSourceListItem; ; destination.CurrentSourceInfoKey = "$transient"; - destination.CurrentSourceInfo = tempSourceListItem; return; } - - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {@source} with key {sourceKey}", this, source, sourceKey); - - destination.CurrentSourceInfoKey = sourceKey; - destination.CurrentSourceInfo = source; - + } catch (Exception ex) + { + Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex); + return; } - /// - /// Recursively traces a route back from a given tie line to find the root source tie line. - /// It navigates through midpoint devices () by checking their current routes. - /// - /// The starting tie line (typically connected to a sink or midpoint). - /// The connected to the original source device, or null if the source cannot be determined. - private TieLine GetRootTieLine(TieLine tieLine) + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); + + TieLine sourceTieLine; + try { - TieLine nextTieLine = null; - try + sourceTieLine = GetRootTieLine(firstTieLine); + + if (sourceTieLine == null) { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine); + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort); - if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) + var tempSourceListItem = new SourceListItem { - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint); + SourceKey = "$transient", + Name = "None", + }; - if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key); - return null; - } + destination.CurrentSourceInfo = tempSourceListItem; + destination.CurrentSourceInfoKey = string.Empty; + return; + } + } catch(Exception ex) + { + Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex); + return; + } - var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine); + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine); - return route.OutputPort != null && route.InputPort != null && route.OutputPort?.Key == tieLine.SourcePort.Key && route.OutputPort?.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key; - }); + // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet. + var room = DeviceManager.AllDevices.OfType().FirstOrDefault((r) => { + if(r is IHasMultipleDisplays roomMultipleDisplays) + { + return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key); + } - if (currentRoute == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); - return null; - } + if(r is IHasDefaultDisplay roomDefaultDisplay) + { + return roomDefaultDisplay.DefaultDisplay.Key == destination.Key; + } - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint); + return false; + }); + + if(room == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No room found for display {destination}", this, destination.Key); + return; + } - nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key); - return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; }); + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key); - if (nextTieLine != null) - { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine); - return GetRootTieLine(nextTieLine); - } + var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine); - return nextTieLine; + if (sourceList == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", this, room.SourceListKey, sourceTieLine); + return; + } + + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key); + + var sourceListItem = sourceList.FirstOrDefault(sli => { + //// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, + // "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}", + // this, + // sli.Key, + // sli.Value.SourceKey, + // sourceTieLine.SourcePort.ParentDevice.Key); + + return sli.Value.SourceKey.Equals(sourceTieLine.SourcePort.ParentDevice.Key,StringComparison.InvariantCultureIgnoreCase); + }); + + var source = sourceListItem.Value; + var sourceKey = sourceListItem.Key; + + if (source == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination); + + var tempSourceListItem = new SourceListItem + { + SourceKey = "$transient", + Name = sourceTieLine.SourcePort.Key, + }; + + destination.CurrentSourceInfoKey = "$transient"; + destination.CurrentSourceInfo = tempSourceListItem; + return; + } + + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {@source} with key {sourceKey}", this, source, sourceKey); + + destination.CurrentSourceInfoKey = sourceKey; + destination.CurrentSourceInfo = source; + + } + + /// + /// Recursively traces a route back from a given tie line to find the root source tie line. + /// It navigates through midpoint devices () by checking their current routes. + /// + /// The starting tie line (typically connected to a sink or midpoint). + /// The connected to the original source device, or null if the source cannot be determined. + private TieLine GetRootTieLine(TieLine tieLine) + { + TieLine nextTieLine = null; + try + { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine); + + if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) + { + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint); + + if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key); + return null; } - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); + var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine); - if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain + return route.OutputPort != null && route.InputPort != null && route.OutputPort?.Key == tieLine.SourcePort.Key && route.OutputPort?.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key; + }); + + if (currentRoute == null) { - // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); - return tieLine; + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort); + return null; } - nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key ); + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint); + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key); + return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; }); if (nextTieLine != null) { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine); return GetRootTieLine(nextTieLine); } - } catch (Exception ex) - { - Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex); - return null; + + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine); + return nextTieLine; } + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource); + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name)); + + if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain + { + // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine); + return tieLine; + } + + nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key ); + + if (nextTieLine != null) + { + return GetRootTieLine(nextTieLine); + } + } catch (Exception ex) + { + Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex); return null; } + + return null; } } diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs index c949db4e..479f202d 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs @@ -2,18 +2,18 @@ using System; -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a basic routing input port on a device. - /// - public class RoutingInputPort : RoutingPort +namespace PepperDash.Essentials.Core; + +/// +/// Represents a basic routing input port on a device. +/// +public class RoutingInputPort : RoutingPort { - /// - /// The IRoutingInputs object this lives on - /// - [JsonIgnore] - public IRoutingInputs ParentDevice { get; private set; } + /// + /// The IRoutingInputs object this lives on + /// + [JsonIgnore] + public IRoutingInputs ParentDevice { get; private set; } /// /// Constructor for a basic RoutingInputPort @@ -41,48 +41,47 @@ namespace PepperDash.Essentials.Core ParentDevice = parent; } - /// - /// Returns a string representation of the input port. - /// - /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". - public override string ToString() - { - return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; - } + /// + /// Returns a string representation of the input port. + /// + /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". + public override string ToString() + { + return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; + } +} + +/*/// +/// Basic RoutingInput with no statuses. +/// +public class RoutingInputPort : RoutingPort +{ + /// + /// The IRoutingInputs object this lives on + /// + public IRoutingInputs ParentDevice { get; private set; } + + /// + /// Constructor for a basic RoutingInputPort + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingInputs object this lives on + public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingInputs parent) + : this(key, type, connType, selector, parent, false) + { } - /*/// - /// Basic RoutingInput with no statuses. + /// + /// Constructor for a virtual routing input port that lives inside a device. For example + /// the ports that link a DM card to a DM matrix bus /// - public class RoutingInputPort : RoutingPort + /// true for internal ports + public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingInputs parent, bool isInternal) + : base(key, type, connType, selector, isInternal) { - /// - /// The IRoutingInputs object this lives on - /// - public IRoutingInputs ParentDevice { get; private set; } - - /// - /// Constructor for a basic RoutingInputPort - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingInputs object this lives on - public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - TSelector selector, IRoutingInputs parent) - : this(key, type, connType, selector, parent, false) - { - } - - /// - /// Constructor for a virtual routing input port that lives inside a device. For example - /// the ports that link a DM card to a DM matrix bus - /// - /// true for internal ports - public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - TSelector selector, IRoutingInputs parent, bool isInternal) - : base(key, type, connType, selector, isInternal) - { - ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); - } - }*/ -} \ No newline at end of file + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs b/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs index e0c6bba0..d9719789 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs @@ -1,10 +1,10 @@ -namespace PepperDash.Essentials.Core -{ - /// - /// Represents a routing input port that provides video status feedback (e.g., sync, resolution). - /// Suitable for devices like DM transmitters or DM input cards. - /// - public class RoutingInputPortWithVideoStatuses : RoutingInputPort +namespace PepperDash.Essentials.Core; + +/// +/// Represents a routing input port that provides video status feedback (e.g., sync, resolution). +/// Suitable for devices like DM transmitters or DM input cards. +/// +public class RoutingInputPortWithVideoStatuses : RoutingInputPort { /// /// Provides feedback outputs for video statuses associated with this port. @@ -27,5 +27,4 @@ { VideoStatus = new VideoStatusOutputs(funcs); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs b/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs index a0e706ac..89cd3d5c 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs @@ -1,83 +1,82 @@ using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Provides event arguments for routing changes, potentially including numeric or port object references. +/// +public class RoutingNumericEventArgs : EventArgs { /// - /// Provides event arguments for routing changes, potentially including numeric or port object references. + /// The numeric representation of the output, if applicable. /// - public class RoutingNumericEventArgs : EventArgs + public uint? Output { get; set; } + /// + /// The numeric representation of the input, if applicable. + /// + public uint? Input { get; set; } + + /// + /// The type of signal involved in the routing change. + /// + public eRoutingSignalType SigType { get; set; } + /// + /// The input port involved in the routing change, if applicable. + /// + public RoutingInputPort InputPort { get; set; } + /// + /// The output port involved in the routing change, if applicable. + /// + public RoutingOutputPort OutputPort { get; set; } + + /// + /// Initializes a new instance of the class using numeric identifiers. + /// + /// The numeric output identifier. + /// The numeric input identifier. + /// The signal type. + public RoutingNumericEventArgs(uint output, uint input, eRoutingSignalType sigType) : this(output, input, null, null, sigType) { - /// - /// The numeric representation of the output, if applicable. - /// - public uint? Output { get; set; } - /// - /// The numeric representation of the input, if applicable. - /// - public uint? Input { get; set; } + } - /// - /// The type of signal involved in the routing change. - /// - public eRoutingSignalType SigType { get; set; } - /// - /// The input port involved in the routing change, if applicable. - /// - public RoutingInputPort InputPort { get; set; } - /// - /// The output port involved in the routing change, if applicable. - /// - public RoutingOutputPort OutputPort { get; set; } + /// + /// Initializes a new instance of the class using port objects. + /// + /// The output port object. + /// The input port object. + /// The signal type. + public RoutingNumericEventArgs(RoutingOutputPort outputPort, RoutingInputPort inputPort, + eRoutingSignalType sigType) + : this(null, null, outputPort, inputPort, sigType) + { + } - /// - /// Initializes a new instance of the class using numeric identifiers. - /// - /// The numeric output identifier. - /// The numeric input identifier. - /// The signal type. - public RoutingNumericEventArgs(uint output, uint input, eRoutingSignalType sigType) : this(output, input, null, null, sigType) - { - } + /// + /// Initializes a new instance of the class with default values. + /// + public RoutingNumericEventArgs() + : this(null, null, null, null, 0) + { - /// - /// Initializes a new instance of the class using port objects. - /// - /// The output port object. - /// The input port object. - /// The signal type. - public RoutingNumericEventArgs(RoutingOutputPort outputPort, RoutingInputPort inputPort, - eRoutingSignalType sigType) - : this(null, null, outputPort, inputPort, sigType) - { - } + } - /// - /// Initializes a new instance of the class with default values. - /// - public RoutingNumericEventArgs() - : this(null, null, null, null, 0) - { - - } + /// + /// Initializes a new instance of the class with potentially mixed identifiers. + /// + /// The numeric output identifier (optional). + /// The numeric input identifier (optional). + /// The output port object (optional). + /// The input port object (optional). + /// The signal type. + public RoutingNumericEventArgs(uint? output, uint? input, RoutingOutputPort outputPort, + RoutingInputPort inputPort, eRoutingSignalType sigType) + { + OutputPort = outputPort; + InputPort = inputPort; - /// - /// Initializes a new instance of the class with potentially mixed identifiers. - /// - /// The numeric output identifier (optional). - /// The numeric input identifier (optional). - /// The output port object (optional). - /// The input port object (optional). - /// The signal type. - public RoutingNumericEventArgs(uint? output, uint? input, RoutingOutputPort outputPort, - RoutingInputPort inputPort, eRoutingSignalType sigType) - { - OutputPort = outputPort; - InputPort = inputPort; - - Output = output; - Input = input; - SigType = sigType; - } + Output = output; + Input = input; + SigType = sigType; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs index 1cae64c0..083486e7 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs @@ -2,18 +2,18 @@ using System; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a basic routing output port on a device. +/// +public class RoutingOutputPort : RoutingPort { /// - /// Represents a basic routing output port on a device. + /// The IRoutingOutputs object this port lives on. /// - public class RoutingOutputPort : RoutingPort - { - /// - /// The IRoutingOutputs object this port lives on. - /// - [JsonIgnore] - public IRoutingOutputs ParentDevice { get; private set; } + [JsonIgnore] + public IRoutingOutputs ParentDevice { get; private set; } /// /// Tracks which destinations are currently using this output port. @@ -48,52 +48,51 @@ namespace PepperDash.Essentials.Core object selector, IRoutingOutputs parent, bool isInternal) : base(key, type, connType, selector, isInternal) { - ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); InUseTracker = new InUseTracking(); } - /// - /// Returns a string representation of the output port. - /// - /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". - public override string ToString() - { - return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; - } + /// + /// Returns a string representation of the output port. + /// + /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". + public override string ToString() + { + return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; + } } - /*public class RoutingOutputPort : RoutingPort +/*public class RoutingOutputPort : RoutingPort +{ + /// + /// The IRoutingOutputs object this port lives on + /// + public IRoutingOutputs ParentDevice { get; private set; } + + public InUseTracking InUseTracker { get; private set; } + + + /// + /// + /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. + /// May be string, number, whatever + /// The IRoutingOutputs object this port lives on + public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingOutputs parent) + : this(key, type, connType, selector, parent, false) { - /// - /// The IRoutingOutputs object this port lives on - /// - public IRoutingOutputs ParentDevice { get; private set; } + } - public InUseTracking InUseTracker { get; private set; } + public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, + TSelector selector, IRoutingOutputs parent, bool isInternal) + : base(key, type, connType, selector, isInternal) + { + ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); + InUseTracker = new InUseTracking(); + } - - /// - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingOutputs object this port lives on - public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - TSelector selector, IRoutingOutputs parent) - : this(key, type, connType, selector, parent, false) - { - } - - public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - TSelector selector, IRoutingOutputs parent, bool isInternal) - : base(key, type, connType, selector, isInternal) - { - ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); - InUseTracker = new InUseTracking(); - } - - public override string ToString() - { - return ParentDevice.Key + ":" + Key; - } - }*/ -} \ No newline at end of file + public override string ToString() + { + return ParentDevice.Key + ":" + Key; + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs index 64fae203..e7deadcc 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPort.cs @@ -1,12 +1,12 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ - /// - /// Base class for and . - /// - public abstract class RoutingPort : IKeyed +namespace PepperDash.Essentials.Core; + +/// +/// Base class for and . +/// +public abstract class RoutingPort : IKeyed { /// /// The unique key identifying this port within its parent device. @@ -28,14 +28,14 @@ namespace PepperDash.Essentials.Core /// Indicates if this port represents an internal connection within a device (e.g., card to backplane). /// public bool IsInternal { get; private set; } - /// - /// An object used to match feedback values to this port, if applicable. - /// - public object FeedbackMatchObject { get; set; } - /// - /// A reference to the underlying hardware port object (e.g., SimplSharpPro Port), if applicable. - /// - public object Port { get; set; } + /// + /// An object used to match feedback values to this port, if applicable. + /// + public object FeedbackMatchObject { get; set; } + /// + /// A reference to the underlying hardware port object (e.g., SimplSharpPro Port), if applicable. + /// + public object Port { get; set; } /// /// Initializes a new instance of the class. @@ -53,25 +53,24 @@ namespace PepperDash.Essentials.Core Selector = selector; IsInternal = isInternal; } - } +} - /*public abstract class RoutingPort:IKeyed +/*public abstract class RoutingPort:IKeyed +{ + public string Key { get; private set; } + public eRoutingSignalType Type { get; private set; } + public eRoutingPortConnectionType ConnectionType { get; private set; } + public readonly TSelector Selector; + public bool IsInternal { get; private set; } + public object FeedbackMatchObject { get; set; } + public object Port { get; set; } + + public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, bool isInternal) { - public string Key { get; private set; } - public eRoutingSignalType Type { get; private set; } - public eRoutingPortConnectionType ConnectionType { get; private set; } - public readonly TSelector Selector; - public bool IsInternal { get; private set; } - public object FeedbackMatchObject { get; set; } - public object Port { get; set; } - - public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, bool isInternal) - { - Key = key; - Type = type; - ConnectionType = connType; - Selector = selector; - IsInternal = isInternal; - } - }*/ -} \ No newline at end of file + Key = key; + Type = type; + ConnectionType = connType; + Selector = selector; + IsInternal = isInternal; + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs index e1e6bc19..07334465 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Basically a List , with an indexer to find ports by key name /// @@ -25,16 +25,15 @@ namespace PepperDash.Essentials.Core /// Basically a List , with an indexer to find ports by key name /// public class RoutingPortCollection : List where T : RoutingPort +{ + /// + /// Case-insensitive port lookup linked to ports' keys + /// + public T this[string key] { - /// - /// Case-insensitive port lookup linked to ports' keys - /// - public T this[string key] + get { - get - { - return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - } + return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); } - }*/ -} \ No newline at end of file + } +}*/ \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs b/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs index 96a2ca32..a783a0b0 100644 --- a/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs +++ b/src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs @@ -4,249 +4,248 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Defines constant string values for common routing port keys. - /// These should correspond directly with the portNames var in the config tool. +/// These should correspond directly with the portNames var in the config tool. /// public class RoutingPortNames { - /// - /// antennaIn - /// + /// + /// antennaIn + /// public const string AntennaIn = "antennaIn"; - /// - /// anyAudioIn - /// + /// + /// anyAudioIn + /// public const string AnyAudioIn = "anyAudioIn"; - /// - /// anyAudioOut - /// + /// + /// anyAudioOut + /// public const string AnyAudioOut = "anyAudioOut"; - /// - /// anyOut - /// - public const string AnyOut = "anyOut"; - /// - /// anyVideoIn - /// - public const string AnyVideoIn = "anyVideoIn"; - /// - /// anyVideoOut - /// + /// + /// anyOut + /// + public const string AnyOut = "anyOut"; + /// + /// anyVideoIn + /// + public const string AnyVideoIn = "anyVideoIn"; + /// + /// anyVideoOut + /// public const string AnyVideoOut = "anyVideoOut"; - /// - /// balancedAudioOut - /// + /// + /// balancedAudioOut + /// public const string BalancedAudioOut = "balancedAudioOut"; - /// - /// codecOsd - /// - public const string CodecOsd = "codecOsd"; - /// - /// componentIn - /// + /// + /// codecOsd + /// + public const string CodecOsd = "codecOsd"; + /// + /// componentIn + /// public const string ComponentIn = "componentIn"; - /// - /// componentOut - /// + /// + /// componentOut + /// public const string ComponentOut = "componentOut"; - /// - /// compositeIn - /// + /// + /// compositeIn + /// public const string CompositeIn = "compositeIn"; - /// - /// compositeOut - /// + /// + /// compositeOut + /// public const string CompositeOut = "compositeOut"; - /// - /// displayPortIn - /// + /// + /// displayPortIn + /// public const string DisplayPortIn = "displayPortIn"; - /// - /// displayPortIn1 - /// + /// + /// displayPortIn1 + /// public const string DisplayPortIn1 = "displayPortIn1"; - /// - /// displayPortIn2 - /// + /// + /// displayPortIn2 + /// public const string DisplayPortIn2 = "displayPortIn2"; - /// - /// displayPortIn3 - /// + /// + /// displayPortIn3 + /// public const string DisplayPortIn3 = "displayPortIn3"; - /// - /// displayPortOut - /// + /// + /// displayPortOut + /// public const string DisplayPortOut = "displayPortOut"; - /// - /// dmIn - /// + /// + /// dmIn + /// public const string DmIn = "dmIn"; - /// - /// dmOut - /// + /// + /// dmOut + /// public const string DmOut = "dmOut"; - /// - /// dviIn - /// + /// + /// dviIn + /// public const string DviIn = "dviIn"; - /// - /// dviIn1 - /// - public const string DviIn1 = "dviIn1"; - /// - /// dviOut - /// - public const string DviOut = "dviOut"; - /// - /// hdmiIn - /// + /// + /// dviIn1 + /// + public const string DviIn1 = "dviIn1"; + /// + /// dviOut + /// + public const string DviOut = "dviOut"; + /// + /// hdmiIn + /// public const string HdmiIn = "hdmiIn"; - /// - /// hdmiIn1 - /// + /// + /// hdmiIn1 + /// public const string HdmiIn1 = "hdmiIn1"; - /// - /// hdmiIn1PC - /// - public const string HdmiIn1PC = "hdmiIn1PC"; - /// - /// hdmiIn2 - /// + /// + /// hdmiIn1PC + /// + public const string HdmiIn1PC = "hdmiIn1PC"; + /// + /// hdmiIn2 + /// public const string HdmiIn2 = "hdmiIn2"; - /// - /// hdmiIn2PC - /// - public const string HdmiIn2PC = "hdmiIn2PC"; - /// - /// hdmiIn3 - /// + /// + /// hdmiIn2PC + /// + public const string HdmiIn2PC = "hdmiIn2PC"; + /// + /// hdmiIn3 + /// public const string HdmiIn3 = "hdmiIn3"; - /// - /// hdmiIn4 - /// + /// + /// hdmiIn4 + /// public const string HdmiIn4 = "hdmiIn4"; - /// - /// hdmiIn5 - /// + /// + /// hdmiIn5 + /// public const string HdmiIn5 = "hdmiIn5"; - /// - /// hdmiIn6 - /// + /// + /// hdmiIn6 + /// public const string HdmiIn6 = "hdmiIn6"; - /// - /// hdmiOut - /// + /// + /// hdmiOut + /// public const string HdmiOut = "hdmiOut"; - /// - /// hdmiOut1 - /// - public const string HdmiOut1 = "hdmiOut1"; - /// - /// hdmiOut2 - /// - public const string HdmiOut2 = "hdmiOut2"; - /// - /// hdmiOut3 - /// - public const string HdmiOut3 = "hdmiOut3"; - /// - /// hdmiOut4 - /// - public const string HdmiOut4 = "hdmiOut4"; - /// - /// hdmiOut5 - /// - public const string HdmiOut5 = "hdmiOut5"; - /// - /// hdmiOut6 - /// - public const string HdmiOut6 = "hdmiOut6"; - /// - /// none - /// - public const string None = "none"; - /// - /// rgbIn - /// + /// + /// hdmiOut1 + /// + public const string HdmiOut1 = "hdmiOut1"; + /// + /// hdmiOut2 + /// + public const string HdmiOut2 = "hdmiOut2"; + /// + /// hdmiOut3 + /// + public const string HdmiOut3 = "hdmiOut3"; + /// + /// hdmiOut4 + /// + public const string HdmiOut4 = "hdmiOut4"; + /// + /// hdmiOut5 + /// + public const string HdmiOut5 = "hdmiOut5"; + /// + /// hdmiOut6 + /// + public const string HdmiOut6 = "hdmiOut6"; + /// + /// none + /// + public const string None = "none"; + /// + /// rgbIn + /// public const string RgbIn = "rgbIn"; - /// - /// rgbIn1 - /// - public const string RgbIn1 = "rgbIn1"; - /// - /// rgbIn2 - /// - public const string RgbIn2 = "rgbIn2"; - /// - /// vgaIn - /// + /// + /// rgbIn1 + /// + public const string RgbIn1 = "rgbIn1"; + /// + /// rgbIn2 + /// + public const string RgbIn2 = "rgbIn2"; + /// + /// vgaIn + /// public const string VgaIn = "vgaIn"; - /// - /// vgaIn1 - /// - public const string VgaIn1 = "vgaIn1"; - /// - /// vgaOut - /// + /// + /// vgaIn1 + /// + public const string VgaIn1 = "vgaIn1"; + /// + /// vgaOut + /// public const string VgaOut = "vgaOut"; - /// - /// IPC/OPS - /// - public const string IpcOps = "ipcOps"; - /// - /// MediaPlayer - /// - public const string MediaPlayer = "mediaPlayer"; - /// - /// UsbCIn - /// - public const string UsbCIn = "usbCIn"; - /// - /// UsbCIn1 - /// - public const string UsbCIn1 = "usbCIn1"; - /// - /// UsbCIn2 - /// - public const string UsbCIn2 = "usbCIn2"; - /// - /// UsbCIn3 - /// - public const string UsbCIn3 = "usbCIn3"; - /// - /// UsbCOut - /// - public const string UsbCOut = "usbCOut"; - /// - /// UsbCOut1 - /// - public const string UsbCOut1 = "usbCOut1"; - /// - /// UsbCOut2 - /// - public const string UsbCOut2 = "usbCOut2"; - /// - /// UsbCOut3 - /// - public const string UsbCOut3 = "usbCOut3"; - /// - /// HdBaseTIn - /// - public const string HdBaseTIn = "hdBaseTIn"; - /// - /// HdBaseTOut - /// - public const string HdBaseTOut = "hdBaseTOut"; - /// - /// SdiIn - /// - public const string SdiIn = "sdiIn"; - /// - /// SdiOut - /// - public const string SdiOut = "sdiOut"; - } + /// + /// IPC/OPS + /// + public const string IpcOps = "ipcOps"; + /// + /// MediaPlayer + /// + public const string MediaPlayer = "mediaPlayer"; + /// + /// UsbCIn + /// + public const string UsbCIn = "usbCIn"; + /// + /// UsbCIn1 + /// + public const string UsbCIn1 = "usbCIn1"; + /// + /// UsbCIn2 + /// + public const string UsbCIn2 = "usbCIn2"; + /// + /// UsbCIn3 + /// + public const string UsbCIn3 = "usbCIn3"; + /// + /// UsbCOut + /// + public const string UsbCOut = "usbCOut"; + /// + /// UsbCOut1 + /// + public const string UsbCOut1 = "usbCOut1"; + /// + /// UsbCOut2 + /// + public const string UsbCOut2 = "usbCOut2"; + /// + /// UsbCOut3 + /// + public const string UsbCOut3 = "usbCOut3"; + /// + /// HdBaseTIn + /// + public const string HdBaseTIn = "hdBaseTIn"; + /// + /// HdBaseTOut + /// + public const string HdBaseTOut = "hdBaseTOut"; + /// + /// SdiIn + /// + public const string SdiIn = "sdiIn"; + /// + /// SdiOut + /// + public const string SdiOut = "sdiOut"; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/TieLine.cs b/src/PepperDash.Essentials.Core/Routing/TieLine.cs index f3a2c71d..39a07aba 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLine.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLine.cs @@ -2,152 +2,151 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Represents a connection (tie line) between a and a . +/// +public class TieLine { /// - /// Represents a connection (tie line) between a and a . + /// The source output port of the tie line. /// - public class TieLine - { - /// - /// The source output port of the tie line. - /// - public RoutingOutputPort SourcePort { get; private set; } - /// - /// The destination input port of the tie line. - /// - public RoutingInputPort DestinationPort { get; private set; } - //public int InUseCount { get { return DestinationUsingThis.Count; } } - - /// - /// Gets the type of this tie line. Will either be the type of the destination port - /// or the type of OverrideType when it is set. - /// - public eRoutingSignalType Type - { - get - { - if (OverrideType.HasValue) return OverrideType.Value; - return DestinationPort.Type; - } - } - - /// - /// Use this to override the Type property for the destination port. For example, - /// when the tie line is type AudioVideo, and the signal flow should be limited to - /// Audio-only or Video only, changing this type will alter the signal paths - /// available to the routing algorithm without affecting the actual Type - /// of the destination port. - /// - public eRoutingSignalType? OverrideType { get; set; } - - //List DestinationUsingThis = new List(); - - /// - /// Gets a value indicating whether this tie line represents an internal connection within a device (both source and destination ports are internal). - /// - public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } } - /// - /// Gets a value indicating whether the signal types of the source and destination ports differ. - /// - public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } } - /// - /// Gets a value indicating whether the connection types of the source and destination ports differ. - /// - public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } } - /// - /// A descriptive note about any type mismatch, if applicable. - /// - public string TypeMismatchNote { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The source output port. - /// The destination input port. - public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort) - { - if (sourcePort == null || destinationPort == null) - throw new ArgumentNullException("source or destination port"); - SourcePort = sourcePort; - DestinationPort = destinationPort; - } - - /// - /// Creates a tie line with an overriding Type. See help for OverrideType property for info. - /// - /// The source output port. - /// The destination input port. - /// The signal type to limit the link to. Overrides DestinationPort.Type for routing calculations. - public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType? overrideType) : - this(sourcePort, destinationPort) - { - OverrideType = overrideType; - } - - /// - /// Creates a tie line with an overriding Type. See help for OverrideType property for info. - /// - /// The source output port. - /// The destination input port. - /// The signal type to limit the link to. Overrides DestinationPort.Type for routing calculations. - public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) : - this(sourcePort, destinationPort) - { - OverrideType = overrideType; - } - - /// - /// Will link up video status from supporting inputs to connected outputs. - /// - public void Activate() - { - // Now does nothing - } - - /// - /// Deactivates the tie line. - /// - public void Deactivate() - { - // Now does nothing - } - - /// - /// Returns a string representation of the tie line. - /// - /// A string describing the source, destination, and type of the tie line. - public override string ToString() - { - return string.Format("Tie line: {0}:{1} --> {2}:{3} {4}", SourcePort.ParentDevice.Key, SourcePort.Key, - DestinationPort.ParentDevice.Key, DestinationPort.Key, Type.ToString()); - } - } - - //******************************************************************************** + public RoutingOutputPort SourcePort { get; private set; } + /// + /// The destination input port of the tie line. + /// + public RoutingInputPort DestinationPort { get; private set; } + //public int InUseCount { get { return DestinationUsingThis.Count; } } /// - /// Represents a collection of objects. + /// Gets the type of this tie line. Will either be the type of the destination port + /// or the type of OverrideType when it is set. /// - public class TieLineCollection : List + public eRoutingSignalType Type { - /// - /// Gets the default singleton instance of the . - /// - public static TieLineCollection Default + get { - get - { - if (_Default == null) - _Default = new TieLineCollection(); - return _Default; - } + if (OverrideType.HasValue) return OverrideType.Value; + return DestinationPort.Type; } - - /// - /// Backing field for the singleton instance. - /// - [JsonIgnore] - private static TieLineCollection _Default; } + + /// + /// Use this to override the Type property for the destination port. For example, + /// when the tie line is type AudioVideo, and the signal flow should be limited to + /// Audio-only or Video only, changing this type will alter the signal paths + /// available to the routing algorithm without affecting the actual Type + /// of the destination port. + /// + public eRoutingSignalType? OverrideType { get; set; } + + //List DestinationUsingThis = new List(); + + /// + /// Gets a value indicating whether this tie line represents an internal connection within a device (both source and destination ports are internal). + /// + public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } } + /// + /// Gets a value indicating whether the signal types of the source and destination ports differ. + /// + public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } } + /// + /// Gets a value indicating whether the connection types of the source and destination ports differ. + /// + public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } } + /// + /// A descriptive note about any type mismatch, if applicable. + /// + public string TypeMismatchNote { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The source output port. + /// The destination input port. + public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort) + { + if (sourcePort == null || destinationPort == null) + throw new ArgumentNullException("source or destination port"); + SourcePort = sourcePort; + DestinationPort = destinationPort; + } + + /// + /// Creates a tie line with an overriding Type. See help for OverrideType property for info. + /// + /// The source output port. + /// The destination input port. + /// The signal type to limit the link to. Overrides DestinationPort.Type for routing calculations. + public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType? overrideType) : + this(sourcePort, destinationPort) + { + OverrideType = overrideType; + } + + /// + /// Creates a tie line with an overriding Type. See help for OverrideType property for info. + /// + /// The source output port. + /// The destination input port. + /// The signal type to limit the link to. Overrides DestinationPort.Type for routing calculations. + public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) : + this(sourcePort, destinationPort) + { + OverrideType = overrideType; + } + + /// + /// Will link up video status from supporting inputs to connected outputs. + /// + public void Activate() + { + // Now does nothing + } + + /// + /// Deactivates the tie line. + /// + public void Deactivate() + { + // Now does nothing + } + + /// + /// Returns a string representation of the tie line. + /// + /// A string describing the source, destination, and type of the tie line. + public override string ToString() + { + return string.Format("Tie line: {0}:{1} --> {2}:{3} {4}", SourcePort.ParentDevice.Key, SourcePort.Key, + DestinationPort.ParentDevice.Key, DestinationPort.Key, Type.ToString()); + } +} + +//******************************************************************************** + +/// +/// Represents a collection of objects. +/// +public class TieLineCollection : List +{ + /// + /// Gets the default singleton instance of the . + /// + public static TieLineCollection Default + { + get + { + if (_Default == null) + _Default = new TieLineCollection(); + return _Default; + } + } + + /// + /// Backing field for the singleton instance. + /// + [JsonIgnore] + private static TieLineCollection _Default; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs index 5090f9c2..d5c582b8 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs @@ -11,8 +11,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.Config -{ +namespace PepperDash.Essentials.Core.Config; + /// /// Represents the configuration data for a single tie line between two routing ports. /// @@ -48,12 +48,12 @@ namespace PepperDash.Essentials.Core.Config /// public string DestinationPort { get; set; } - /// - /// Optional override for the signal type of the tie line. If set, this overrides the destination port's type for routing calculations. - /// - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] - public eRoutingSignalType? OverrideType { get; set; } + /// + /// Optional override for the signal type of the tie line. If set, this overrides the destination port's type for routing calculations. + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public eRoutingSignalType? OverrideType { get; set; } /// /// Returns the appropriate tie line for either a card-based device or @@ -79,19 +79,19 @@ namespace PepperDash.Essentials.Core.Config return null; } - //Get the source port - var sourceOutputPort = sourceDev.OutputPorts[SourcePort]; + //Get the source port + var sourceOutputPort = sourceDev.OutputPorts[SourcePort]; - if (sourceOutputPort == null) + if (sourceOutputPort == null) { LogError("Source does not contain port"); return null; } - //Get the Destination port - var destinationInputPort = destDev.InputPorts[DestinationPort]; + //Get the Destination port + var destinationInputPort = destDev.InputPorts[DestinationPort]; - if (destinationInputPort == null) + if (destinationInputPort == null) { LogError("Destination does not contain port"); return null; @@ -118,5 +118,4 @@ namespace PepperDash.Essentials.Core.Config return string.Format("{0}.{1}.{2} --> {3}.{4}.{5}", SourceKey, SourceCard, SourcePort, DestinationKey, DestinationCard, DestinationPort); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs b/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs index 436ef9e6..f57037be 100644 --- a/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs +++ b/src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs @@ -1,8 +1,7 @@ -namespace PepperDash.Essentials.Core -{ - public enum eRoutingPortConnectionType +namespace PepperDash.Essentials.Core; + +public enum eRoutingPortConnectionType { None, BackplaneOnly, DisplayPort, Dvi, Hdmi, Rgb, Vga, LineAudio, DigitalAudio, Sdi, Composite, Component, DmCat, DmMmFiber, DmSmFiber, Speaker, Streaming, UsbC, HdBaseT - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs b/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs index b5f3d9f7..7e623058 100644 --- a/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs +++ b/src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs @@ -1,16 +1,15 @@ using System; -namespace PepperDash.Essentials.Core -{ - [Flags] +namespace PepperDash.Essentials.Core; + +[Flags] public enum eRoutingSignalType { Audio = 1, Video = 2, AudioVideo = Audio | Video, - UsbOutput = 8, - UsbInput = 16, - SecondaryAudio = 32 - } -} \ No newline at end of file + UsbOutput = 8, + UsbInput = 16, + SecondaryAudio = 32 + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs b/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs index 4614e661..d89efd2c 100644 --- a/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs +++ b/src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs @@ -5,99 +5,97 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CrestronGlobalSecretsProvider : ISecretProvider { - public class CrestronGlobalSecretsProvider : ISecretProvider + public string Key { get; set; } + //Added for reference + public string Description { get; private set; } + + public CrestronGlobalSecretsProvider(string key) { - public string Key { get; set; } - //Added for reference - public string Description { get; private set; } + Key = key; + Description = String.Format("Default secret provider serving all local applications"); - public CrestronGlobalSecretsProvider(string key) + } + + static CrestronGlobalSecretsProvider() + { + //Added for future encrypted reference + var secureSupported = CrestronSecureStorage.Supported; + + CrestronDataStoreStatic.InitCrestronDataStore(); + if (secureSupported) { - Key = key; - Description = String.Format("Default secret provider serving all local applications"); - - } - - static CrestronGlobalSecretsProvider() - { - //Added for future encrypted reference - var secureSupported = CrestronSecureStorage.Supported; - - CrestronDataStoreStatic.InitCrestronDataStore(); - if (secureSupported) - { - //doThingsFuture - } - } - - /// - /// Set secret for item in the CrestronSecretsProvider - /// - /// Secret Key - /// Secret Value - public bool SetSecret(string key, object value) - { - var secret = value as string; - CrestronDataStore.CDS_ERROR returnCode; - - if (String.IsNullOrEmpty(secret)) - { - returnCode = CrestronDataStoreStatic.clearGlobal(key); - if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - { - Debug.LogMessage(LogEventLevel.Information, this, "Successfully removed secret \"{0}\"", secret); - return true; - } - } - - else - { - returnCode = CrestronDataStoreStatic.SetGlobalStringValue(key, secret); - if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - { - Debug.LogMessage(LogEventLevel.Information, this, "Successfully set secret \"{0}\"", secret); - return true; - } - } - - Debug.LogMessage(LogEventLevel.Information, this, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString()); - return false; - } - - /// - /// Retrieve secret for item in the CrestronSecretsProvider - /// - /// Secret Key - /// ISecret Object containing key, provider, and value - public ISecret GetSecret(string key) - { - string mySecret; - var getErrorCode = CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret); - - switch (getErrorCode) - { - case CrestronDataStore.CDS_ERROR.CDS_SUCCESS: - Debug.LogMessage(LogEventLevel.Verbose, this, "Secret Successfully retrieved for {0}:{1}", Key, key); - return new CrestronSecret(key, mySecret, this); - default: - Debug.LogMessage(LogEventLevel.Information, this, "Unable to retrieve secret for {0}:{1} - {2}", - Key, key, getErrorCode.ToString()); - return null; - } - } - - /// - /// Determine if a secret is present within the provider without retrieving it - /// - /// Secret Key - /// bool if present - public bool TestSecret(string key) - { - string mySecret; - return CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; + //doThingsFuture } } + /// + /// Set secret for item in the CrestronSecretsProvider + /// + /// Secret Key + /// Secret Value + public bool SetSecret(string key, object value) + { + var secret = value as string; + CrestronDataStore.CDS_ERROR returnCode; + + if (String.IsNullOrEmpty(secret)) + { + returnCode = CrestronDataStoreStatic.clearGlobal(key); + if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + { + Debug.LogMessage(LogEventLevel.Information, this, "Successfully removed secret \"{0}\"", secret); + return true; + } + } + + else + { + returnCode = CrestronDataStoreStatic.SetGlobalStringValue(key, secret); + if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + { + Debug.LogMessage(LogEventLevel.Information, this, "Successfully set secret \"{0}\"", secret); + return true; + } + } + + Debug.LogMessage(LogEventLevel.Information, this, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString()); + return false; + } + + /// + /// Retrieve secret for item in the CrestronSecretsProvider + /// + /// Secret Key + /// ISecret Object containing key, provider, and value + public ISecret GetSecret(string key) + { + string mySecret; + var getErrorCode = CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret); + + switch (getErrorCode) + { + case CrestronDataStore.CDS_ERROR.CDS_SUCCESS: + Debug.LogMessage(LogEventLevel.Verbose, this, "Secret Successfully retrieved for {0}:{1}", Key, key); + return new CrestronSecret(key, mySecret, this); + default: + Debug.LogMessage(LogEventLevel.Information, this, "Unable to retrieve secret for {0}:{1} - {2}", + Key, key, getErrorCode.ToString()); + return null; + } + } + + /// + /// Determine if a secret is present within the provider without retrieving it + /// + /// Secret Key + /// bool if present + public bool TestSecret(string key) + { + string mySecret; + return CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs b/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs index 6c355d30..0bffd23e 100644 --- a/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs +++ b/src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs @@ -6,99 +6,97 @@ using Crestron.SimplSharpPro; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CrestronLocalSecretsProvider : ISecretProvider { - public class CrestronLocalSecretsProvider : ISecretProvider + public string Key { get; set; } + //Added for reference + public string Description { get; private set; } + + + public CrestronLocalSecretsProvider(string key) { - public string Key { get; set; } - //Added for reference - public string Description { get; private set; } + Key = key; + Description = String.Format("Default secret provider serving Essentials Application {0}", InitialParametersClass.ApplicationNumber); + } + static CrestronLocalSecretsProvider() + { + //Added for future encrypted reference + var secureSupported = CrestronSecureStorage.Supported; - public CrestronLocalSecretsProvider(string key) + CrestronDataStoreStatic.InitCrestronDataStore(); + if (secureSupported) { - Key = key; - Description = String.Format("Default secret provider serving Essentials Application {0}", InitialParametersClass.ApplicationNumber); - } - - static CrestronLocalSecretsProvider() - { - //Added for future encrypted reference - var secureSupported = CrestronSecureStorage.Supported; - - CrestronDataStoreStatic.InitCrestronDataStore(); - if (secureSupported) - { - //doThingsFuture - } - } - - /// - /// Set secret for item in the CrestronSecretsProvider - /// - /// Secret Key - /// Secret Value - public bool SetSecret(string key, object value) - { - var secret = value as string; - CrestronDataStore.CDS_ERROR returnCode; - - if (String.IsNullOrEmpty(secret)) - { - returnCode = CrestronDataStoreStatic.clearLocal(key); - if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - { - Debug.LogMessage(LogEventLevel.Information, this, "Successfully removed secret \"{0}\"", secret); - return true; - } - } - - else - { - returnCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret); - if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - { - Debug.LogMessage(LogEventLevel.Information, this, "Successfully set secret \"{0}\"", secret); - return true; - } - } - - Debug.LogMessage(LogEventLevel.Information, this, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString()); - return false; - } - - /// - /// Retrieve secret for item in the CrestronSecretsProvider - /// - /// Secret Key - /// ISecret Object containing key, provider, and value - public ISecret GetSecret(string key) - { - string mySecret; - var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret); - - switch (getErrorCode) - { - case CrestronDataStore.CDS_ERROR.CDS_SUCCESS: - Debug.LogMessage(LogEventLevel.Verbose, this, "Secret Successfully retrieved for {0}:{1}", Key, key); - return new CrestronSecret(key, mySecret, this); - default: - Debug.LogMessage(LogEventLevel.Information, this, "Unable to retrieve secret for {0}:{1} - {2}", - Key, key, getErrorCode.ToString()); - return null; - } - } - - /// - /// Determine if a secret is present within the provider without retrieving it - /// - /// Secret Key - /// bool if present - public bool TestSecret(string key) - { - string mySecret; - return CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; + //doThingsFuture } } + /// + /// Set secret for item in the CrestronSecretsProvider + /// + /// Secret Key + /// Secret Value + public bool SetSecret(string key, object value) + { + var secret = value as string; + CrestronDataStore.CDS_ERROR returnCode; + + if (String.IsNullOrEmpty(secret)) + { + returnCode = CrestronDataStoreStatic.clearLocal(key); + if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + { + Debug.LogMessage(LogEventLevel.Information, this, "Successfully removed secret \"{0}\"", secret); + return true; + } + } + + else + { + returnCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret); + if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + { + Debug.LogMessage(LogEventLevel.Information, this, "Successfully set secret \"{0}\"", secret); + return true; + } + } + + Debug.LogMessage(LogEventLevel.Information, this, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString()); + return false; + } + + /// + /// Retrieve secret for item in the CrestronSecretsProvider + /// + /// Secret Key + /// ISecret Object containing key, provider, and value + public ISecret GetSecret(string key) + { + string mySecret; + var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret); + + switch (getErrorCode) + { + case CrestronDataStore.CDS_ERROR.CDS_SUCCESS: + Debug.LogMessage(LogEventLevel.Verbose, this, "Secret Successfully retrieved for {0}:{1}", Key, key); + return new CrestronSecret(key, mySecret, this); + default: + Debug.LogMessage(LogEventLevel.Information, this, "Unable to retrieve secret for {0}:{1} - {2}", + Key, key, getErrorCode.ToString()); + return null; + } + } + + /// + /// Determine if a secret is present within the provider without retrieving it + /// + /// Secret Key + /// bool if present + public bool TestSecret(string key) + { + string mySecret; + return CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs b/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs index 27fbcdad..1b628a44 100644 --- a/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs +++ b/src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs @@ -4,25 +4,23 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Special container class for CrestronSecret provider +/// +public class CrestronSecret : ISecret { - /// - /// Special container class for CrestronSecret provider - /// - public class CrestronSecret : ISecret + public ISecretProvider Provider { get; private set; } + public string Key { get; private set; } + + public object Value { get; private set; } + + public CrestronSecret(string key, string value, ISecretProvider provider) { - public ISecretProvider Provider { get; private set; } - public string Key { get; private set; } - - public object Value { get; private set; } - - public CrestronSecret(string key, string value, ISecretProvider provider) - { - Key = key; - Value = value; - Provider = provider; - } - + Key = key; + Value = value; + Provider = provider; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs b/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs index d2fd750a..f0b7fd38 100644 --- a/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Secrets/Interfaces.cs @@ -1,58 +1,57 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// All ISecrecretProvider classes must implement this interface. +/// +public interface ISecretProvider : IKeyed { /// - /// All ISecrecretProvider classes must implement this interface. + /// Set secret value for provider by key /// - public interface ISecretProvider : IKeyed - { - /// - /// Set secret value for provider by key - /// - /// key of secret to set - /// value to set secret to - /// - bool SetSecret(string key, object value); - - /// - /// Return object containing secret from provider - /// - /// key of secret to retrieve - /// - ISecret GetSecret(string key); - - /// - /// Verifies presence of secret - /// - /// key of secret to chek - /// - bool TestSecret(string key); - - /// - /// Description of the secrets provider - /// - string Description { get; } - } + /// key of secret to set + /// value to set secret to + /// + bool SetSecret(string key, object value); /// - /// interface for delivering secrets in Essentials. + /// Return object containing secret from provider /// - public interface ISecret - { - /// - /// Instance of ISecretProvider that the secret belongs to - /// - ISecretProvider Provider { get; } + /// key of secret to retrieve + /// + ISecret GetSecret(string key); - /// - /// Key of the secret in the provider - /// - string Key { get; } + /// + /// Verifies presence of secret + /// + /// key of secret to chek + /// + bool TestSecret(string key); - /// - /// Value of the secret - /// - object Value { get; } - } + /// + /// Description of the secrets provider + /// + string Description { get; } +} + +/// +/// interface for delivering secrets in Essentials. +/// +public interface ISecret +{ + /// + /// Instance of ISecretProvider that the secret belongs to + /// + ISecretProvider Provider { get; } + + /// + /// Key of the secret in the provider + /// + string Key { get; } + + /// + /// Value of the secret + /// + object Value { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs b/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs index 8309b7e9..f66c0c60 100644 --- a/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs +++ b/src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs @@ -5,372 +5,375 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public static class SecretsManager { - public static class SecretsManager + public static Dictionary Secrets { get; private set; } + + /// + /// Initialize the SecretsManager + /// + public static void Initialize() { - public static Dictionary Secrets { get; private set; } - - /// - /// Initialize the SecretsManager - /// - public static void Initialize() + try + { + AddSecretProvider("default", new CrestronLocalSecretsProvider("default")); + + AddSecretProvider("CrestronGlobalSecrets", new CrestronGlobalSecretsProvider("CrestronGlobalSecrets")); + + CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret", + "Adds secret to secrets provider", + ConsoleAccessLevelEnum.AccessOperator); + + CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret", + "Updates secret in secrets provider", + ConsoleAccessLevelEnum.AccessAdministrator); + + CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret", + "Deletes secret from secrest provider", + ConsoleAccessLevelEnum.AccessAdministrator); + + CrestronConsole.AddNewConsoleCommand(ListProviders, "secretproviderlist", + "Return list of all valid secrets providers", + ConsoleAccessLevelEnum.AccessAdministrator); + + CrestronConsole.AddNewConsoleCommand(GetProviderInfo, "secretproviderinfo", + "Return data about secrets provider", + ConsoleAccessLevelEnum.AccessAdministrator); + } + catch (Exception e) { + Debug.LogError(e, "SecretsManager Initialize failed"); + } + } - AddSecretProvider("default", new CrestronLocalSecretsProvider("default")); + static SecretsManager() + { + Secrets = new Dictionary(); + } - AddSecretProvider("CrestronGlobalSecrets", new CrestronGlobalSecretsProvider("CrestronGlobalSecrets")); + /// + /// Get Secret Provider from dictionary by key + /// + /// Dictionary Key for provider + /// ISecretProvider + public static ISecretProvider GetSecretProviderByKey(string key) + { + ISecretProvider secret; - CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret", - "Adds secret to secrets provider", - ConsoleAccessLevelEnum.AccessOperator); + Secrets.TryGetValue(key, out secret); - CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret", - "Updates secret in secrets provider", - ConsoleAccessLevelEnum.AccessAdministrator); - - CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret", - "Deletes secret from secrest provider", - ConsoleAccessLevelEnum.AccessAdministrator); - - CrestronConsole.AddNewConsoleCommand(ListProviders, "secretproviderlist", - "Return list of all valid secrets providers", - ConsoleAccessLevelEnum.AccessAdministrator); - - CrestronConsole.AddNewConsoleCommand(GetProviderInfo, "secretproviderinfo", - "Return data about secrets provider", - ConsoleAccessLevelEnum.AccessAdministrator); + if (secret == null) + { + Debug.LogMessage(LogEventLevel.Debug, "SecretsManager unable to retrieve SecretProvider with the key '{0}'", key); } + return secret; + } - static SecretsManager() + public static void GetProviderInfo(string cmd) + { + string response; + var args = cmd.Split(' '); + + if (cmd.Length == 0 || (args.Length == 1 && args[0] == "?")) { - Secrets = new Dictionary(); - } - - /// - /// Get Secret Provider from dictionary by key - /// - /// Dictionary Key for provider - /// ISecretProvider - public static ISecretProvider GetSecretProviderByKey(string key) - { - ISecretProvider secret; - - Secrets.TryGetValue(key, out secret); - - if (secret == null) - { - Debug.LogMessage(LogEventLevel.Debug, "SecretsManager unable to retrieve SecretProvider with the key '{0}'", key); - } - return secret; - } - - public static void GetProviderInfo(string cmd) - { - string response; - var args = cmd.Split(' '); - - if (cmd.Length == 0 || (args.Length == 1 && args[0] == "?")) - { - response = "Returns data about secrets provider. Format 'secretproviderinfo '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - if (args.Length == 1) - { - var provider = GetSecretProviderByKey(args[0]); - - if (provider == null) - { - response = "Invalid secrets provider key"; - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - response = String.Format("{0} : {1}", provider.Key, provider.Description); - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - response = "Improper number of arguments"; - CrestronConsole.ConsoleCommandResponse(response); - - } - - - /// - /// Console Command that returns all valid secrets in the essentials program. - /// - /// - public static void ListProviders(string cmd) - { - var response = String.Empty; - var args = cmd.Split(' '); - - if (cmd.Length == 0) - { - if (Secrets != null && Secrets.Count > 0) - { - response = Secrets.Aggregate(response, - (current, secretProvider) => current + (secretProvider.Key + "\n\r")); - } - else - { - response = "No Secrets Providers Available"; - } - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - if (args.Length == 1 && args[0] == "?") - { - response = "Reports all valid and preset Secret providers"; - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - - response = "Improper number of arguments"; - CrestronConsole.ConsoleCommandResponse(response); - - } - - /// - /// Add secret provider to secrets dictionary - /// - /// Key of new entry - /// New Provider Entry - public static void AddSecretProvider(string key, ISecretProvider provider) - { - if (!Secrets.ContainsKey(key)) - { - Secrets.Add(key, provider); - Debug.LogMessage(LogEventLevel.Debug, "Secrets provider '{0}' added to SecretsManager", key); - return; - } - Debug.LogMessage(LogEventLevel.Information, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key ); - } - - /// - /// Add secret provider to secrets dictionary, with optional overwrite parameter - /// - /// Key of new entry - /// New provider entry - /// true to overwrite any existing providers in the dictionary - public static void AddSecretProvider(string key, ISecretProvider provider, bool overwrite) - { - if (!Secrets.ContainsKey(key)) - { - Secrets.Add(key, provider); - Debug.LogMessage(LogEventLevel.Debug, "Secrets provider '{0}' added to SecretsManager", key); - return; - } - if (overwrite) - { - Secrets.Add(key, provider); - Debug.LogMessage(LogEventLevel.Debug, "Provider with the key '{0}' already exists in secrets. Overwriting with new secrets provider.", key); - return; - } - Debug.LogMessage(LogEventLevel.Information, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key); - } - - private static void SetSecretProcess(string cmd) - { - string response; - var args = cmd.Split(' '); - - if (args.Length == 0) - { - //some Instructional Text - response = "Adds secrets to secret provider. Format 'setsecret '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - if (args.Length == 1 && args[0] == "?") - { - response = "Adds secrets to secret provider. Format 'setsecret '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - if (args.Length < 3) - { - response = "Improper number of arguments"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - var provider = GetSecretProviderByKey(args[0]); - - if (provider == null) - { - //someFail - response = "Provider key invalid"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - var key = args[1]; - var secret = args[2]; - - CrestronConsole.ConsoleCommandResponse(SetSecret(provider, key, secret)); - } - - private static void UpdateSecretProcess(string cmd) - { - string response; - var args = cmd.Split(' '); - - if (args.Length == 0) - { - //some Instructional Text - response = "Updates secrets in secret provider. Format 'updatesecret '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - if (args.Length == 1 && args[0] == "?") - { - response = "Updates secrets in secret provider. Format 'updatesecret '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - - if (args.Length < 3) - { - //someFail - response = "Improper number of arguments"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - var provider = GetSecretProviderByKey(args[0]); - - if (provider == null) - { - //someFail - response = "Provider key invalid"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - var key = args[1]; - var secret = args[2]; - - CrestronConsole.ConsoleCommandResponse(UpdateSecret(provider, key, secret)); - - } - - private static string UpdateSecret(ISecretProvider provider, string key, string secret) - { - var secretPresent = provider.TestSecret(key); - - Debug.LogMessage(LogEventLevel.Verbose, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key); - - if (!secretPresent) - return - String.Format( - "Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to modify it"); - var response = provider.SetSecret(key, secret) - ? String.Format( - "Secret successfully set for {0}:{1}", - provider.Key, key) - : String.Format( - "Unable to set secret for {0}:{1}", - provider.Key, key); - return response; - } - - private static string SetSecret(ISecretProvider provider, string key, string secret) - { - var secretPresent = provider.TestSecret(key); - - Debug.LogMessage(LogEventLevel.Verbose, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key); - - if (secretPresent) - return - String.Format( - "Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it"); - var response = provider.SetSecret(key, secret) - ? String.Format( - "Secret successfully set for {0}:{1}", - provider.Key, key) - : String.Format( - "Unable to set secret for {0}:{1}", - provider.Key, key); - return response; - - } - - private static void DeleteSecretProcess(string cmd) - { - string response; - var args = cmd.Split(' '); - - if (args.Length == 0) - { - //some Instructional Text - response = "Deletes secrets in secret provider. Format 'deletesecret '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - if (args.Length == 1 && args[0] == "?") - { - response = "Deletes secrets in secret provider. Format 'deletesecret '"; - CrestronConsole.ConsoleCommandResponse(response); - return; - } - - - - if (args.Length < 2) - { - //someFail - response = "Improper number of arguments"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - var provider = GetSecretProviderByKey(args[0]); - - if (provider == null) - { - //someFail - response = "Provider key invalid"; - CrestronConsole.ConsoleCommandResponse(response); - return; - - } - - var key = args[1]; - - - provider.SetSecret(key, ""); - response = provider.SetSecret(key, "") - ? String.Format( - "Secret successfully deleted for {0}:{1}", - provider.Key, key) - : String.Format( - "Unable to delete secret for {0}:{1}", - provider.Key, key); + response = "Returns data about secrets provider. Format 'secretproviderinfo '"; CrestronConsole.ConsoleCommandResponse(response); return; - } + + if (args.Length == 1) + { + var provider = GetSecretProviderByKey(args[0]); + + if (provider == null) + { + response = "Invalid secrets provider key"; + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + response = String.Format("{0} : {1}", provider.Key, provider.Description); + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + response = "Improper number of arguments"; + CrestronConsole.ConsoleCommandResponse(response); + } + /// + /// Console Command that returns all valid secrets in the essentials program. + /// + /// + public static void ListProviders(string cmd) + { + var response = String.Empty; + var args = cmd.Split(' '); + + if (cmd.Length == 0) + { + if (Secrets != null && Secrets.Count > 0) + { + response = Secrets.Aggregate(response, + (current, secretProvider) => current + (secretProvider.Key + "\n\r")); + } + else + { + response = "No Secrets Providers Available"; + } + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + if (args.Length == 1 && args[0] == "?") + { + response = "Reports all valid and preset Secret providers"; + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + + response = "Improper number of arguments"; + CrestronConsole.ConsoleCommandResponse(response); + + } + + /// + /// Add secret provider to secrets dictionary + /// + /// Key of new entry + /// New Provider Entry + public static void AddSecretProvider(string key, ISecretProvider provider) + { + if (!Secrets.ContainsKey(key)) + { + Secrets.Add(key, provider); + Debug.LogMessage(LogEventLevel.Debug, "Secrets provider '{0}' added to SecretsManager", key); + return; + } + Debug.LogMessage(LogEventLevel.Information, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key ); + } + + /// + /// Add secret provider to secrets dictionary, with optional overwrite parameter + /// + /// Key of new entry + /// New provider entry + /// true to overwrite any existing providers in the dictionary + public static void AddSecretProvider(string key, ISecretProvider provider, bool overwrite) + { + if (!Secrets.ContainsKey(key)) + { + Secrets.Add(key, provider); + Debug.LogMessage(LogEventLevel.Debug, "Secrets provider '{0}' added to SecretsManager", key); + return; + } + if (overwrite) + { + Secrets.Add(key, provider); + Debug.LogMessage(LogEventLevel.Debug, "Provider with the key '{0}' already exists in secrets. Overwriting with new secrets provider.", key); + return; + } + Debug.LogMessage(LogEventLevel.Information, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key); + } + + private static void SetSecretProcess(string cmd) + { + string response; + var args = cmd.Split(' '); + + if (args.Length == 0) + { + //some Instructional Text + response = "Adds secrets to secret provider. Format 'setsecret '"; + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + if (args.Length == 1 && args[0] == "?") + { + response = "Adds secrets to secret provider. Format 'setsecret '"; + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + if (args.Length < 3) + { + response = "Improper number of arguments"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + var provider = GetSecretProviderByKey(args[0]); + + if (provider == null) + { + //someFail + response = "Provider key invalid"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + var key = args[1]; + var secret = args[2]; + + CrestronConsole.ConsoleCommandResponse(SetSecret(provider, key, secret)); + } + + private static void UpdateSecretProcess(string cmd) + { + string response; + var args = cmd.Split(' '); + + if (args.Length == 0) + { + //some Instructional Text + response = "Updates secrets in secret provider. Format 'updatesecret '"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + if (args.Length == 1 && args[0] == "?") + { + response = "Updates secrets in secret provider. Format 'updatesecret '"; + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + + if (args.Length < 3) + { + //someFail + response = "Improper number of arguments"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + var provider = GetSecretProviderByKey(args[0]); + + if (provider == null) + { + //someFail + response = "Provider key invalid"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + var key = args[1]; + var secret = args[2]; + + CrestronConsole.ConsoleCommandResponse(UpdateSecret(provider, key, secret)); + + } + + private static string UpdateSecret(ISecretProvider provider, string key, string secret) + { + var secretPresent = provider.TestSecret(key); + + Debug.LogMessage(LogEventLevel.Verbose, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key); + + if (!secretPresent) + return + String.Format( + "Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to modify it"); + var response = provider.SetSecret(key, secret) + ? String.Format( + "Secret successfully set for {0}:{1}", + provider.Key, key) + : String.Format( + "Unable to set secret for {0}:{1}", + provider.Key, key); + return response; + } + + private static string SetSecret(ISecretProvider provider, string key, string secret) + { + var secretPresent = provider.TestSecret(key); + + Debug.LogMessage(LogEventLevel.Verbose, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key); + + if (secretPresent) + return + String.Format( + "Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it"); + var response = provider.SetSecret(key, secret) + ? String.Format( + "Secret successfully set for {0}:{1}", + provider.Key, key) + : String.Format( + "Unable to set secret for {0}:{1}", + provider.Key, key); + return response; + + } + + private static void DeleteSecretProcess(string cmd) + { + string response; + var args = cmd.Split(' '); + + if (args.Length == 0) + { + //some Instructional Text + response = "Deletes secrets in secret provider. Format 'deletesecret '"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + if (args.Length == 1 && args[0] == "?") + { + response = "Deletes secrets in secret provider. Format 'deletesecret '"; + CrestronConsole.ConsoleCommandResponse(response); + return; + } + + + + if (args.Length < 2) + { + //someFail + response = "Improper number of arguments"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + var provider = GetSecretProviderByKey(args[0]); + + if (provider == null) + { + //someFail + response = "Provider key invalid"; + CrestronConsole.ConsoleCommandResponse(response); + return; + + } + + var key = args[1]; + + + provider.SetSecret(key, ""); + response = provider.SetSecret(key, "") + ? String.Format( + "Secret successfully deleted for {0}:{1}", + provider.Key, key) + : String.Format( + "Unable to delete secret for {0}:{1}", + provider.Key, key); + CrestronConsole.ConsoleCommandResponse(response); + return; + + + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs index f092d5d3..b447851a 100644 --- a/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs @@ -7,16 +7,15 @@ using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +/// +/// Provide a way to easily deserialize into a secret object from config +/// +public class SecretsPropertiesConfig { - /// - /// Provide a way to easily deserialize into a secret object from config - /// - public class SecretsPropertiesConfig - { - [JsonProperty("provider")] - public string Provider { get; set; } - [JsonProperty("key")] - public string Key { get; set; } - } + [JsonProperty("provider")] + public string Provider { get; set; } + [JsonProperty("key")] + public string Key { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs b/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs index 93fcbc52..d595e7f0 100644 --- a/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs @@ -1,44 +1,44 @@ using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Core.Shades -{ +namespace PepperDash.Essentials.Core.Shades; + /// /// Requirements for an object that contains shades /// - public interface IShades - { - List Shades { get; } - } +public interface IShades +{ + List Shades { get; } +} - /// - /// Requirements for a device that implements basic Open/Close/Stop shade control (Uses 3 relays) - /// - public interface IShadesOpenCloseStop - { - void Open(); - void Close(); - void Stop(); - } +/// +/// Requirements for a device that implements basic Open/Close/Stop shade control (Uses 3 relays) +/// +public interface IShadesOpenCloseStop +{ + void Open(); + void Close(); + void Stop(); +} - public interface IShadesOpenClosePreset : IShadesOpenCloseStop - { - void RecallPreset(uint presetNumber); - void SavePreset(uint presetNumber); - string StopOrPresetButtonLabel { get; } +public interface IShadesOpenClosePreset : IShadesOpenCloseStop +{ + void RecallPreset(uint presetNumber); + void SavePreset(uint presetNumber); + string StopOrPresetButtonLabel { get; } - event EventHandler PresetSaved; - } + event EventHandler PresetSaved; +} - /// - /// Requirements for a shade device that provides raising/lowering feedback - /// - public interface IShadesRaiseLowerFeedback - { +/// +/// Requirements for a shade device that provides raising/lowering feedback +/// +public interface IShadesRaiseLowerFeedback +{ BoolFeedback ShadeIsLoweringFeedback { get; } BoolFeedback ShadeIsRaisingFeedback { get; } - } +} /// /// Requirements for a shade/scene that is open or closed @@ -96,5 +96,4 @@ namespace PepperDash.Essentials.Core.Shades IShadesStopOrMove, IShadesFeedback, IShadesRaiseLowerFeedback { - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs b/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs index c44abac6..fbd63063 100644 --- a/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs +++ b/src/PepperDash.Essentials.Core/Shades/ShadeBase.cs @@ -7,24 +7,23 @@ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; -namespace PepperDash.Essentials.Core.Shades +namespace PepperDash.Essentials.Core.Shades; + + +[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] +public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop { - - [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] - public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop + public ShadeBase(string key, string name) + : base(key, name) { - public ShadeBase(string key, string name) - : base(key, name) - { - } - - #region iShadesOpenClose Members - - public abstract void Open(); - public abstract void Stop(); - public abstract void Close(); - - #endregion } + + #region iShadesOpenClose Members + + public abstract void Open(); + public abstract void Stop(); + public abstract void Close(); + + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SigHelper.cs b/src/PepperDash.Essentials.Core/SigHelper.cs index 86395114..c97b706e 100644 --- a/src/PepperDash.Essentials.Core/SigHelper.cs +++ b/src/PepperDash.Essentials.Core/SigHelper.cs @@ -7,8 +7,8 @@ using Crestron.SimplSharpPro; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Helper class for various Sig events /// @@ -68,5 +68,4 @@ namespace PepperDash.Essentials.Core { sig.CreateRamp(level, time / 10); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs index 2307be7e..3dfaff6a 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.SmartObjects -{ +namespace PepperDash.Essentials.Core.SmartObjects; + public class SmartObjectDPad : SmartObjectHelperBase { public BoolOutputSig SigUp { get { return GetBoolOutputNamed("Up"); } } @@ -20,5 +20,4 @@ namespace PepperDash.Essentials.Core.SmartObjects : base(so, useUserObjectHandler) { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs index 5d768803..793fb50d 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs @@ -10,8 +10,8 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.SmartObjects -{ +namespace PepperDash.Essentials.Core.SmartObjects; + public class SmartObjectDynamicList : SmartObjectHelperBase { public const string SigNameScrollToItem = "Scroll To Item"; @@ -34,12 +34,12 @@ namespace PepperDash.Essentials.Core.SmartObjects /// public int MaxCount { get; private set; } - /// - /// Wrapper for smart object - /// - /// - /// True if the standard user object action handler will be used - /// The starting join of the string sigs for the button labels + /// + /// Wrapper for smart object + /// + /// + /// True if the standard user object action handler will be used + /// The starting join of the string sigs for the button labels public SmartObjectDynamicList(SmartObject so, bool useUserObjectHandler, uint nameSigOffset) : base(so, useUserObjectHandler) { try @@ -125,5 +125,4 @@ namespace PepperDash.Essentials.Core.SmartObjects for(ushort i = 1; i <= MaxCount; i++) SmartObject.BooleanOutput[string.Format("Item {0} Pressed", i)].UserObject = null; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs index 23bf4530..ce035471 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs @@ -9,8 +9,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core.SmartObjects -{ +namespace PepperDash.Essentials.Core.SmartObjects; + public class SmartObjectHelperBase { public SmartObject SmartObject { get; private set; } @@ -36,36 +36,36 @@ namespace PepperDash.Essentials.Core.SmartObjects SmartObject.SigChange -= this.SmartObject_SigChange; } - /// - /// Helper to get a sig name with debugging when fail - /// - /// - /// + /// + /// Helper to get a sig name with debugging when fail + /// + /// + /// public BoolOutputSig GetBoolOutputNamed(string name) { if (SmartObject.BooleanOutput.Contains(name)) return SmartObject.BooleanOutput[name]; - else - Debug.LogMessage(LogEventLevel.Information, "WARNING: Cannot get signal. Smart object {0} on trilist {1:x2} does not contain signal '{2}'", - SmartObject.ID, SmartObject.Device.ID, name); + else + Debug.LogMessage(LogEventLevel.Information, "WARNING: Cannot get signal. Smart object {0} on trilist {1:x2} does not contain signal '{2}'", + SmartObject.ID, SmartObject.Device.ID, name); return null; } - /// - /// Sets action on signal after checking for existence. - /// - /// - /// - public void SetBoolAction(string name, Action a) + /// + /// Sets action on signal after checking for existence. + /// + /// + /// + public void SetBoolAction(string name, Action a) + { + if (SmartObject.BooleanOutput.Contains(name)) + SmartObject.BooleanOutput[name].UserObject = a; + else { - if (SmartObject.BooleanOutput.Contains(name)) - SmartObject.BooleanOutput[name].UserObject = a; - else - { - Debug.LogMessage(LogEventLevel.Information, "WARNING: Cannot set action. Smart object {0} on trilist {1:x2} does not contain signal '{2}'", - SmartObject.ID, SmartObject.Device.ID, name); - } + Debug.LogMessage(LogEventLevel.Information, "WARNING: Cannot set action. Smart object {0} on trilist {1:x2} does not contain signal '{2}'", + SmartObject.ID, SmartObject.Device.ID, name); } + } /// /// Standard Action listener @@ -83,5 +83,4 @@ namespace PepperDash.Essentials.Core.SmartObjects (uo as Action)(args.Sig.StringValue); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs index 7e574242..6409a4b3 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs @@ -6,18 +6,18 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.SmartObjects -{ +namespace PepperDash.Essentials.Core.SmartObjects; + public class SmartObjectNumeric : SmartObjectHelperBase { - /// - /// Defaults to "Misc_1". The name of the button in VTPro (Usually the text) - /// - public string Misc1SigName { get; set; } - /// - /// Defaults to "Misc_2". The name of the button in VTPro (Usually the text) - /// - public string Misc2SigName { get; set; } + /// + /// Defaults to "Misc_1". The name of the button in VTPro (Usually the text) + /// + public string Misc1SigName { get; set; } + /// + /// Defaults to "Misc_2". The name of the button in VTPro (Usually the text) + /// + public string Misc2SigName { get; set; } public BoolOutputSig Digit1 { get { return GetBoolOutputNamed("1"); } } public BoolOutputSig Digit2 { get { return GetBoolOutputNamed("2"); } } @@ -34,8 +34,7 @@ namespace PepperDash.Essentials.Core.SmartObjects public SmartObjectNumeric(SmartObject so, bool useUserObjectHandler) : base(so, useUserObjectHandler) { - Misc1SigName = "Misc_1"; - Misc2SigName = "Misc_2"; + Misc1SigName = "Misc_1"; + Misc2SigName = "Misc_2"; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs index f92e182b..0e875125 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs @@ -12,16 +12,16 @@ using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ - ////***************************************************************************** - ///// - ///// Base class for all subpage reference list controllers - ///// - //public class SubpageReferenceListController - //{ - // public SubpageReferenceList TheList { get; protected set; } - //} +namespace PepperDash.Essentials.Core; + +////***************************************************************************** +///// +///// Base class for all subpage reference list controllers +///// +//public class SubpageReferenceListController +//{ +// public SubpageReferenceList TheList { get; protected set; } +//} //***************************************************************************** /// @@ -76,7 +76,7 @@ namespace PepperDash.Essentials.Core } else Debug.LogMessage(LogEventLevel.Information, "ERROR: TriList 0x{0:X2} Cannot load smart object {1}. Verify correct SGD file is loaded", - triList.ID, smartObjectId); + triList.ID, smartObjectId); } /// @@ -145,7 +145,7 @@ namespace PepperDash.Essentials.Core public UShortOutputSig GetUShortOutputSig(uint index, uint sigNum) { if (sigNum > UShortIncrement) return null; - return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum))); + return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum))); } /// @@ -160,7 +160,7 @@ namespace PepperDash.Essentials.Core public StringOutputSig GetStringOutputSig(uint index, uint sigNum) { if (sigNum > StringIncrement) return null; - return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum))); + return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum))); } /// @@ -261,5 +261,4 @@ namespace PepperDash.Essentials.Core else if (uo is Action) (uo as Action)(args.Sig.StringValue); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs index 30e15f74..e5c0dc8a 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.UI; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class SubpageReferenceListItem { /// @@ -30,5 +30,4 @@ namespace PepperDash.Essentials.Core } public virtual void Refresh() { } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs b/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs index cbb470d6..b44005e3 100644 --- a/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs +++ b/src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs @@ -7,153 +7,152 @@ using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class SecondsCountdownTimer: IKeyed { - public class SecondsCountdownTimer: IKeyed + public event EventHandler HasStarted; + public event EventHandler HasFinished; + public event EventHandler WasCancelled; + + public string Key { get; private set; } + + public BoolFeedback IsRunningFeedback { get; private set; } + bool _isRunning; + + public IntFeedback PercentFeedback { get; private set; } + public StringFeedback TimeRemainingFeedback { get; private set; } + + public IntFeedback SecondsRemainingFeedback { get; private set; } + + public bool CountsDown { get; set; } + + /// + /// The number of seconds to countdown + /// + public int SecondsToCount { get; set; } + + public DateTime StartTime { get; private set; } + public DateTime FinishTime { get; private set; } + + private CTimer _secondTimer; + + /// + /// Constructor + /// + /// + public SecondsCountdownTimer(string key) { - public event EventHandler HasStarted; - public event EventHandler HasFinished; - public event EventHandler WasCancelled; + Key = key; + IsRunningFeedback = new BoolFeedback(() => _isRunning); - public string Key { get; private set; } + TimeRemainingFeedback = new StringFeedback(() => + { + // Need to handle up and down here. - public BoolFeedback IsRunningFeedback { get; private set; } - bool _isRunning; + var timeSpan = FinishTime - DateTime.Now; - public IntFeedback PercentFeedback { get; private set; } - public StringFeedback TimeRemainingFeedback { get; private set; } + Debug.LogMessage(LogEventLevel.Verbose, + "timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this, + timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds); - public IntFeedback SecondsRemainingFeedback { get; private set; } - - public bool CountsDown { get; set; } - - /// - /// The number of seconds to countdown - /// - public int SecondsToCount { get; set; } - - public DateTime StartTime { get; private set; } - public DateTime FinishTime { get; private set; } - - private CTimer _secondTimer; - - /// - /// Constructor - /// - /// - public SecondsCountdownTimer(string key) - { - Key = key; - IsRunningFeedback = new BoolFeedback(() => _isRunning); - - TimeRemainingFeedback = new StringFeedback(() => + if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds { - // Need to handle up and down here. + return String.Format("{0:00}", timeSpan.Seconds); + } - var timeSpan = FinishTime - DateTime.Now; + return Math.Floor(timeSpan.TotalSeconds) < 0 + ? "00" + : String.Format("{0:00}:{1:00}", timeSpan.Minutes, timeSpan.Seconds); + }); - Debug.LogMessage(LogEventLevel.Verbose, - "timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this, - timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds); + SecondsRemainingFeedback = new IntFeedback(() => (int)(FinishTime - DateTime.Now).TotalSeconds); - if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds - { - return String.Format("{0:00}", timeSpan.Seconds); - } + PercentFeedback = + new IntFeedback( + () => + (int) + (Math.Floor((FinishTime - DateTime.Now).TotalSeconds)/ + Math.Floor((FinishTime - StartTime).TotalSeconds)*100)); + } - return Math.Floor(timeSpan.TotalSeconds) < 0 - ? "00" - : String.Format("{0:00}:{1:00}", timeSpan.Minutes, timeSpan.Seconds); - }); + /// + /// Starts the Timer + /// + public void Start() + { + if (_isRunning) + return; + StartTime = DateTime.Now; + FinishTime = StartTime + TimeSpan.FromSeconds(SecondsToCount); - SecondsRemainingFeedback = new IntFeedback(() => (int)(FinishTime - DateTime.Now).TotalSeconds); + if (_secondTimer != null) + _secondTimer.Stop(); + _secondTimer = new CTimer(SecondElapsedTimerCallback, null, 0, 1000); + _isRunning = true; + IsRunningFeedback.FireUpdate(); - PercentFeedback = - new IntFeedback( - () => - (int) - (Math.Floor((FinishTime - DateTime.Now).TotalSeconds)/ - Math.Floor((FinishTime - StartTime).TotalSeconds)*100)); - } + var handler = HasStarted; + if (handler != null) + handler(this, new EventArgs()); + } - /// - /// Starts the Timer - /// - public void Start() + /// + /// Restarts the timer + /// + public void Reset() + { + _isRunning = false; + IsRunningFeedback.FireUpdate(); + Start(); + } + + /// + /// Cancels the timer (without triggering it to finish) + /// + public void Cancel() + { + StopHelper(); + + var handler = WasCancelled; + if (handler != null) + handler(this, new EventArgs()); + } + + /// + /// Called upon expiration, or calling this will force timer to finish. + /// + public void Finish() + { + StopHelper(); + + var handler = HasFinished; + if (handler != null) + handler(this, new EventArgs()); + } + + void StopHelper() + { + if (_secondTimer != null) { - if (_isRunning) - return; - StartTime = DateTime.Now; - FinishTime = StartTime + TimeSpan.FromSeconds(SecondsToCount); - - if (_secondTimer != null) - _secondTimer.Stop(); - _secondTimer = new CTimer(SecondElapsedTimerCallback, null, 0, 1000); - _isRunning = true; - IsRunningFeedback.FireUpdate(); - - var handler = HasStarted; - if (handler != null) - handler(this, new EventArgs()); + _secondTimer.Stop(); + _secondTimer = null; } - /// - /// Restarts the timer - /// - public void Reset() + _isRunning = false; + IsRunningFeedback.FireUpdate(); + } + + void SecondElapsedTimerCallback(object o) + { + if (DateTime.Now >= FinishTime) { - _isRunning = false; - IsRunningFeedback.FireUpdate(); - Start(); + Finish(); + return; } - /// - /// Cancels the timer (without triggering it to finish) - /// - public void Cancel() - { - StopHelper(); - - var handler = WasCancelled; - if (handler != null) - handler(this, new EventArgs()); - } - - /// - /// Called upon expiration, or calling this will force timer to finish. - /// - public void Finish() - { - StopHelper(); - - var handler = HasFinished; - if (handler != null) - handler(this, new EventArgs()); - } - - void StopHelper() - { - if (_secondTimer != null) - { - _secondTimer.Stop(); - _secondTimer = null; - } - - _isRunning = false; - IsRunningFeedback.FireUpdate(); - } - - void SecondElapsedTimerCallback(object o) - { - if (DateTime.Now >= FinishTime) - { - Finish(); - return; - } - - PercentFeedback.FireUpdate(); - TimeRemainingFeedback.FireUpdate(); - SecondsRemainingFeedback.FireUpdate(); - } + PercentFeedback.FireUpdate(); + TimeRemainingFeedback.FireUpdate(); + SecondsRemainingFeedback.FireUpdate(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs b/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs index 968c10bb..f9f32176 100644 --- a/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs +++ b/src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs @@ -14,167 +14,164 @@ using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core.Timers +namespace PepperDash.Essentials.Core.Timers; + +/// +/// A device that runs a retriggerable timer and can execute actions specified in config +/// +[Description("A retriggerable timer device")] +public class RetriggerableTimer : EssentialsDevice { - /// - /// A device that runs a retriggerable timer and can execute actions specified in config - /// - [Description("A retriggerable timer device")] - public class RetriggerableTimer : EssentialsDevice + private RetriggerableTimerPropertiesConfig _propertiesConfig; + + private CTimer _timer; + private long _timerIntervalMs; + + public RetriggerableTimer(string key, DeviceConfig config) + : base(key, config.Name) { - private RetriggerableTimerPropertiesConfig _propertiesConfig; + var props = config.Properties.ToObject(); + _propertiesConfig = props; - private CTimer _timer; - private long _timerIntervalMs; - - public RetriggerableTimer(string key, DeviceConfig config) - : base(key, config.Name) + if (_propertiesConfig != null) { - var props = config.Properties.ToObject(); - _propertiesConfig = props; + _timerIntervalMs = _propertiesConfig.TimerIntervalMs; + } + } - if (_propertiesConfig != null) - { - _timerIntervalMs = _propertiesConfig.TimerIntervalMs; - } + public override bool CustomActivate() + { + if (_propertiesConfig.StartTimerOnActivation) + { + StartTimer(); } - public override bool CustomActivate() + return base.CustomActivate(); + } + + private void CleanUpTimer() + { + if (_timer != null) { - if (_propertiesConfig.StartTimerOnActivation) - { - StartTimer(); - } - - return base.CustomActivate(); - } - - private void CleanUpTimer() - { - if (_timer != null) - { - _timer.Stop(); - _timer.Dispose(); - } - - _timer = null; - } - - public void StartTimer() - { - CleanUpTimer(); - Debug.LogMessage(LogEventLevel.Information, this, "Starting Timer"); - - _timer = new CTimer(TimerElapsedCallback, GetActionFromConfig(eRetriggerableTimerEvents.Elapsed), _timerIntervalMs, _timerIntervalMs); - } - - public void StopTimer() - { - Debug.LogMessage(LogEventLevel.Information, this, "Stopping Timer"); _timer.Stop(); - - ExecuteAction(GetActionFromConfig(eRetriggerableTimerEvents.Stopped)); + _timer.Dispose(); } - private DeviceActionWrapper GetActionFromConfig(eRetriggerableTimerEvents eventType) - { - var action = _propertiesConfig.Events[eRetriggerableTimerEvents.Elapsed]; + _timer = null; + } - if (action != null) - return action; - else return null; - } + public void StartTimer() + { + CleanUpTimer(); + Debug.LogMessage(LogEventLevel.Information, this, "Starting Timer"); - /// - /// Executes the Elapsed action from confing when the timer elapses - /// - /// - private void TimerElapsedCallback(object action) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Timer Elapsed. Executing Action"); + _timer = new CTimer(TimerElapsedCallback, GetActionFromConfig(eRetriggerableTimerEvents.Elapsed), _timerIntervalMs, _timerIntervalMs); + } - if (action == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Timer elapsed but unable to execute action. Action is null."); - return; - } + public void StopTimer() + { + Debug.LogMessage(LogEventLevel.Information, this, "Stopping Timer"); + _timer.Stop(); - var devAction = action as DeviceActionWrapper; - if (devAction != null) - ExecuteAction(devAction); - else - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to cast action as DeviceActionWrapper. Cannot Execute"); - } + ExecuteAction(GetActionFromConfig(eRetriggerableTimerEvents.Stopped)); + } - } + private DeviceActionWrapper GetActionFromConfig(eRetriggerableTimerEvents eventType) + { + var action = _propertiesConfig.Events[eRetriggerableTimerEvents.Elapsed]; - private void ExecuteAction(DeviceActionWrapper action) - { - if (action == null) - return; - - try - { - DeviceJsonApi.DoDeviceAction(action); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); - } - //finally // Not sure this is needed - //{ - // _Timer.Reset(0, _TimerIntervalMs); - //} - } + if (action != null) + return action; + else return null; } /// - /// Configuration Properties for RetriggerableTimer + /// Executes the Elapsed action from confing when the timer elapses /// - public class RetriggerableTimerPropertiesConfig + /// + private void TimerElapsedCallback(object action) { - [JsonProperty("startTimerOnActivation")] - public bool StartTimerOnActivation { get; set; } + Debug.LogMessage(LogEventLevel.Debug, this, "Timer Elapsed. Executing Action"); - [JsonProperty("timerIntervalMs")] - public long TimerIntervalMs { get; set; } - - [JsonProperty("events")] - public Dictionary Events { get; set; } - - public RetriggerableTimerPropertiesConfig() + if (action == null) { - Events = new Dictionary(); - } - } - - /// - /// The set of values describing events on the timer - /// - public enum eRetriggerableTimerEvents - { - Elapsed, - Stopped, - } - - /// - /// Factory class - /// - public class RetriggerableTimerFactory : EssentialsDeviceFactory - { - public RetriggerableTimerFactory() - { - TypeNames = new List() { "retriggerabletimer" }; + Debug.LogMessage(LogEventLevel.Debug, this, "Timer elapsed but unable to execute action. Action is null."); + return; } - public override EssentialsDevice BuildDevice(DeviceConfig dc) + var devAction = action as DeviceActionWrapper; + if (devAction != null) + ExecuteAction(devAction); + else { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RetriggerableTimer Device"); - - return new RetriggerableTimer(dc.Key, dc); + Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to cast action as DeviceActionWrapper. Cannot Execute"); } + } + private void ExecuteAction(DeviceActionWrapper action) + { + if (action == null) + return; + try + { + DeviceJsonApi.DoDeviceAction(action); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); + } + //finally // Not sure this is needed + //{ + // _Timer.Reset(0, _TimerIntervalMs); + //} + } +} + +/// +/// Configuration Properties for RetriggerableTimer +/// +public class RetriggerableTimerPropertiesConfig +{ + [JsonProperty("startTimerOnActivation")] + public bool StartTimerOnActivation { get; set; } + + [JsonProperty("timerIntervalMs")] + public long TimerIntervalMs { get; set; } + + [JsonProperty("events")] + public Dictionary Events { get; set; } + + public RetriggerableTimerPropertiesConfig() + { + Events = new Dictionary(); + } +} + +/// +/// The set of values describing events on the timer +/// +public enum eRetriggerableTimerEvents +{ + Elapsed, + Stopped, +} + +/// +/// Factory class +/// +public class RetriggerableTimerFactory : EssentialsDeviceFactory +{ + public RetriggerableTimerFactory() + { + TypeNames = new List() { "retriggerabletimer" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RetriggerableTimer Device"); + + return new RetriggerableTimer(dc.Key, dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs index aa4dac6d..478869b3 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs @@ -1,91 +1,90 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public class CrestronTouchpanelPropertiesConfig { - public class CrestronTouchpanelPropertiesConfig - { - [JsonProperty("control")] - public EssentialsControlPropertiesConfig ControlProperties { get; set; } + [JsonProperty("control")] + public EssentialsControlPropertiesConfig ControlProperties { get; set; } - [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] - public string IpId { get; set; } + [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] + public string IpId { get; set; } - [JsonProperty("defaultRoomKey", NullValueHandling = NullValueHandling.Ignore)] - public string DefaultRoomKey { get; set; } - - [JsonProperty("roomListKey", NullValueHandling = NullValueHandling.Ignore)] - public string RoomListKey { get; set; } + [JsonProperty("defaultRoomKey", NullValueHandling = NullValueHandling.Ignore)] + public string DefaultRoomKey { get; set; } + + [JsonProperty("roomListKey", NullValueHandling = NullValueHandling.Ignore)] + public string RoomListKey { get; set; } - [JsonProperty("sgdFile", NullValueHandling = NullValueHandling.Ignore)] - public string SgdFile { get; set; } + [JsonProperty("sgdFile", NullValueHandling = NullValueHandling.Ignore)] + public string SgdFile { get; set; } - [JsonProperty("projectName", NullValueHandling = NullValueHandling.Ignore)] - public string ProjectName { get; set; } + [JsonProperty("projectName", NullValueHandling = NullValueHandling.Ignore)] + public string ProjectName { get; set; } - [JsonProperty("showVolumeGauge", NullValueHandling = NullValueHandling.Ignore)] - public bool? ShowVolumeGauge { get; set; } + [JsonProperty("showVolumeGauge", NullValueHandling = NullValueHandling.Ignore)] + public bool? ShowVolumeGauge { get; set; } - [JsonProperty("usesSplashPage", NullValueHandling = NullValueHandling.Ignore)] - public bool? UsesSplashPage { get; set; } + [JsonProperty("usesSplashPage", NullValueHandling = NullValueHandling.Ignore)] + public bool? UsesSplashPage { get; set; } - [JsonProperty("showDate", NullValueHandling = NullValueHandling.Ignore)] - public bool? ShowDate { get; set; } + [JsonProperty("showDate", NullValueHandling = NullValueHandling.Ignore)] + public bool? ShowDate { get; set; } - [JsonProperty("showTime", NullValueHandling = NullValueHandling.Ignore)] - public bool? ShowTime { get; set; } + [JsonProperty("showTime", NullValueHandling = NullValueHandling.Ignore)] + public bool? ShowTime { get; set; } - [JsonProperty("setup", NullValueHandling = NullValueHandling.Ignore)] - public UiSetupPropertiesConfig Setup { get; set; } + [JsonProperty("setup", NullValueHandling = NullValueHandling.Ignore)] + public UiSetupPropertiesConfig Setup { get; set; } - [JsonProperty("headerStyle", NullValueHandling = NullValueHandling.Ignore)] - public string HeaderStyle { get; set; } + [JsonProperty("headerStyle", NullValueHandling = NullValueHandling.Ignore)] + public string HeaderStyle { get; set; } - [JsonProperty("includeInFusionRoomHealth", NullValueHandling = NullValueHandling.Ignore)] - public bool? IncludeInFusionRoomHealth { get; set; } + [JsonProperty("includeInFusionRoomHealth", NullValueHandling = NullValueHandling.Ignore)] + public bool? IncludeInFusionRoomHealth { get; set; } - [JsonProperty("screenSaverTimeoutMin", NullValueHandling = NullValueHandling.Ignore)] - public uint? ScreenSaverTimeoutMin { get; set; } + [JsonProperty("screenSaverTimeoutMin", NullValueHandling = NullValueHandling.Ignore)] + public uint? ScreenSaverTimeoutMin { get; set; } - [JsonProperty("screenSaverMovePositionIntervalMs", NullValueHandling = NullValueHandling.Ignore)] - public uint? ScreenSaverMovePositionIntervalMs { get; set; } + [JsonProperty("screenSaverMovePositionIntervalMs", NullValueHandling = NullValueHandling.Ignore)] + public uint? ScreenSaverMovePositionIntervalMs { get; set; } - /// - /// The count of sources that will trigger the "additional" arrows to show on the SRL. - /// Defaults to 5 - /// - [JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)] - public int? SourcesOverflowCount { get; set; } - - public CrestronTouchpanelPropertiesConfig() : this(false) { } - - public CrestronTouchpanelPropertiesConfig(bool setDefaultValues = false) - { - if(!setDefaultValues) { return; } - SourcesOverflowCount = 5; - HeaderStyle = Habanero; - - // Default values - ScreenSaverTimeoutMin = 5; - ScreenSaverMovePositionIntervalMs = 15000; - } - - /// - /// "habanero" - /// - public const string Habanero = "habanero"; - /// - /// "verbose" - /// - public const string Verbose = "verbose"; - } - /// - /// + /// The count of sources that will trigger the "additional" arrows to show on the SRL. + /// Defaults to 5 /// - public class UiSetupPropertiesConfig + [JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)] + public int? SourcesOverflowCount { get; set; } + + public CrestronTouchpanelPropertiesConfig() : this(false) { } + + public CrestronTouchpanelPropertiesConfig(bool setDefaultValues = false) { - [JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)] - public bool IsVisible { get; set; } - } + if(!setDefaultValues) { return; } + SourcesOverflowCount = 5; + HeaderStyle = Habanero; + + // Default values + ScreenSaverTimeoutMin = 5; + ScreenSaverMovePositionIntervalMs = 15000; + } + + /// + /// "habanero" + /// + public const string Habanero = "habanero"; + /// + /// "verbose" + /// + public const string Verbose = "verbose"; +} + +/// +/// +/// +public class UiSetupPropertiesConfig +{ + [JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)] + public bool IsVisible { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs b/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs index 946f4f9d..5a035405 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs @@ -5,10 +5,9 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core +namespace PepperDash.Essentials.Core; + +public interface IHasBasicTriListWithSmartObject { - public interface IHasBasicTriListWithSmartObject - { - BasicTriListWithSmartObject Panel { get; } - } + BasicTriListWithSmartObject Panel { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs b/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs index 5e068c12..091eaad8 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs @@ -5,207 +5,207 @@ using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core.Touchpanels.Keyboards +namespace PepperDash.Essentials.Core.Touchpanels.Keyboards; + +public class HabaneroKeyboardController { - public class HabaneroKeyboardController - { - /// - /// Single-key press events, rather than using a built-up text string on the OutputFeedback - /// - public event EventHandler KeyPress; + /// + /// Single-key press events, rather than using a built-up text string on the OutputFeedback + /// + public event EventHandler KeyPress; - public BasicTriList TriList { get; private set; } + public BasicTriList TriList { get; private set; } - public StringFeedback OutputFeedback { get; private set; } + public StringFeedback OutputFeedback { get; private set; } - public bool IsVisible { get; private set; } + public bool IsVisible { get; private set; } - public string DotComButtonString { get; set; } + public string DotComButtonString { get; set; } - public string GoButtonText { get; set; } + public string GoButtonText { get; set; } - public string SecondaryButtonText { get; set; } + public string SecondaryButtonText { get; set; } - public bool GoButtonVisible { get; set; } + public bool GoButtonVisible { get; set; } - public bool SecondaryButtonVisible { get; set; } + public bool SecondaryButtonVisible { get; set; } - int ShiftMode = 0; - - StringBuilder Output; + int ShiftMode = 0; + + StringBuilder Output; - public Action HideAction { get; set; } + public Action HideAction { get; set; } CTimer BackspaceTimer; - /// - /// - /// - /// - public HabaneroKeyboardController(BasicTriList trilist) - { - TriList = trilist; - Output = new StringBuilder(); - OutputFeedback = new StringFeedback(() => Output.ToString()); - DotComButtonString = ".com"; - } + /// + /// + /// + /// + public HabaneroKeyboardController(BasicTriList trilist) + { + TriList = trilist; + Output = new StringBuilder(); + OutputFeedback = new StringFeedback(() => Output.ToString()); + DotComButtonString = ".com"; + } - /// - /// Shows the keyboard and attaches sig handlers in the range of 2901-2969 - /// - public void Show() - { - if (IsVisible) - return; + /// + /// Shows the keyboard and attaches sig handlers in the range of 2901-2969 + /// + public void Show() + { + if (IsVisible) + return; - TriList.SetSigTrueAction(ClosePressJoin, Hide); - TriList.SetSigTrueAction(GoButtonPressJoin, () => OnKeyPress(KeyboardSpecialKey.GoButton)); - TriList.SetSigTrueAction(SecondaryButtonPressJoin, () => OnKeyPress(KeyboardSpecialKey.SecondaryButton)); - TriList.SetSigTrueAction(2921, () => Press(A(ShiftMode))); - TriList.SetSigTrueAction(2922, () => Press(B(ShiftMode))); - TriList.SetSigTrueAction(2923, () => Press(C(ShiftMode))); - TriList.SetSigTrueAction(2924, () => Press(D(ShiftMode))); - TriList.SetSigTrueAction(2925, () => Press(E(ShiftMode))); - TriList.SetSigTrueAction(2926, () => Press(F(ShiftMode))); - TriList.SetSigTrueAction(2927, () => Press(G(ShiftMode))); - TriList.SetSigTrueAction(2928, () => Press(H(ShiftMode))); - TriList.SetSigTrueAction(2929, () => Press(I(ShiftMode))); - TriList.SetSigTrueAction(2930, () => Press(J(ShiftMode))); - TriList.SetSigTrueAction(2931, () => Press(K(ShiftMode))); - TriList.SetSigTrueAction(2932, () => Press(L(ShiftMode))); - TriList.SetSigTrueAction(2933, () => Press(M(ShiftMode))); - TriList.SetSigTrueAction(2934, () => Press(N(ShiftMode))); - TriList.SetSigTrueAction(2935, () => Press(O(ShiftMode))); - TriList.SetSigTrueAction(2936, () => Press(P(ShiftMode))); - TriList.SetSigTrueAction(2937, () => Press(Q(ShiftMode))); - TriList.SetSigTrueAction(2938, () => Press(R(ShiftMode))); - TriList.SetSigTrueAction(2939, () => Press(S(ShiftMode))); - TriList.SetSigTrueAction(2940, () => Press(T(ShiftMode))); - TriList.SetSigTrueAction(2941, () => Press(U(ShiftMode))); - TriList.SetSigTrueAction(2942, () => Press(V(ShiftMode))); - TriList.SetSigTrueAction(2943, () => Press(W(ShiftMode))); - TriList.SetSigTrueAction(2944, () => Press(X(ShiftMode))); - TriList.SetSigTrueAction(2945, () => Press(Y(ShiftMode))); - TriList.SetSigTrueAction(2946, () => Press(Z(ShiftMode))); - TriList.SetSigTrueAction(2947, () => Press('.')); - TriList.SetSigTrueAction(2948, () => Press('@')); - TriList.SetSigTrueAction(2949, () => Press(' ')); + TriList.SetSigTrueAction(ClosePressJoin, Hide); + TriList.SetSigTrueAction(GoButtonPressJoin, () => OnKeyPress(KeyboardSpecialKey.GoButton)); + TriList.SetSigTrueAction(SecondaryButtonPressJoin, () => OnKeyPress(KeyboardSpecialKey.SecondaryButton)); + TriList.SetSigTrueAction(2921, () => Press(A(ShiftMode))); + TriList.SetSigTrueAction(2922, () => Press(B(ShiftMode))); + TriList.SetSigTrueAction(2923, () => Press(C(ShiftMode))); + TriList.SetSigTrueAction(2924, () => Press(D(ShiftMode))); + TriList.SetSigTrueAction(2925, () => Press(E(ShiftMode))); + TriList.SetSigTrueAction(2926, () => Press(F(ShiftMode))); + TriList.SetSigTrueAction(2927, () => Press(G(ShiftMode))); + TriList.SetSigTrueAction(2928, () => Press(H(ShiftMode))); + TriList.SetSigTrueAction(2929, () => Press(I(ShiftMode))); + TriList.SetSigTrueAction(2930, () => Press(J(ShiftMode))); + TriList.SetSigTrueAction(2931, () => Press(K(ShiftMode))); + TriList.SetSigTrueAction(2932, () => Press(L(ShiftMode))); + TriList.SetSigTrueAction(2933, () => Press(M(ShiftMode))); + TriList.SetSigTrueAction(2934, () => Press(N(ShiftMode))); + TriList.SetSigTrueAction(2935, () => Press(O(ShiftMode))); + TriList.SetSigTrueAction(2936, () => Press(P(ShiftMode))); + TriList.SetSigTrueAction(2937, () => Press(Q(ShiftMode))); + TriList.SetSigTrueAction(2938, () => Press(R(ShiftMode))); + TriList.SetSigTrueAction(2939, () => Press(S(ShiftMode))); + TriList.SetSigTrueAction(2940, () => Press(T(ShiftMode))); + TriList.SetSigTrueAction(2941, () => Press(U(ShiftMode))); + TriList.SetSigTrueAction(2942, () => Press(V(ShiftMode))); + TriList.SetSigTrueAction(2943, () => Press(W(ShiftMode))); + TriList.SetSigTrueAction(2944, () => Press(X(ShiftMode))); + TriList.SetSigTrueAction(2945, () => Press(Y(ShiftMode))); + TriList.SetSigTrueAction(2946, () => Press(Z(ShiftMode))); + TriList.SetSigTrueAction(2947, () => Press('.')); + TriList.SetSigTrueAction(2948, () => Press('@')); + TriList.SetSigTrueAction(2949, () => Press(' ')); TriList.SetSigHeldAction(2950, 500, StartBackspaceRepeat, StopBackspaceRepeat, Backspace); //TriList.SetSigTrueAction(2950, Backspace); - TriList.SetSigTrueAction(2951, Shift); - TriList.SetSigTrueAction(2952, NumShift); - TriList.SetSigTrueAction(2953, Clear); - TriList.SetSigTrueAction(2954, () => Press(DotComButtonString)); + TriList.SetSigTrueAction(2951, Shift); + TriList.SetSigTrueAction(2952, NumShift); + TriList.SetSigTrueAction(2953, Clear); + TriList.SetSigTrueAction(2954, () => Press(DotComButtonString)); - TriList.SetBool(GoButtonVisibleJoin, GoButtonVisible); - TriList.SetString(GoButtonTextJoin, GoButtonText); - TriList.SetBool(SecondaryButtonVisibleJoin, SecondaryButtonVisible); - TriList.SetString(SecondaryButtonTextJoin, SecondaryButtonText); + TriList.SetBool(GoButtonVisibleJoin, GoButtonVisible); + TriList.SetString(GoButtonTextJoin, GoButtonText); + TriList.SetBool(SecondaryButtonVisibleJoin, SecondaryButtonVisible); + TriList.SetString(SecondaryButtonTextJoin, SecondaryButtonText); - TriList.SetBool(KeyboardVisible, true); + TriList.SetBool(KeyboardVisible, true); + ShowKeys(); + IsVisible = true; + } + + /// + /// Hides the keyboard and disconnects ALL sig handlers from 2901 - 2969 + /// + public void Hide() + { + if (!IsVisible) + return; + + for (uint i = 2901; i < 2970; i++) + TriList.ClearBoolSigAction(i); + + // run attached actions + if(HideAction != null) + HideAction(); + + TriList.SetBool(KeyboardVisible, false); + IsVisible = false; + } + + /// + /// + /// + /// + public void Press(char c) + { + OnKeyPress(c.ToString()); + Output.Append(c); + OutputFeedback.FireUpdate(); + ResetShift(); + } + + /// + /// + /// + /// + public void Press(string s) + { + OnKeyPress(s); + Output.Append(s); + OutputFeedback.FireUpdate(); + ResetShift(); + } + + /// + /// + /// + public void EnableGoButton() + { + TriList.SetBool(GoButtonEnableJoin, true); + } + + /// + /// + /// + public void DisableGoButton() + { + TriList.SetBool(GoButtonEnableJoin, false); + } + + void ResetShift() + { + if (ShiftMode == 1) + { + ShiftMode = 0; ShowKeys(); - IsVisible = true; } - - /// - /// Hides the keyboard and disconnects ALL sig handlers from 2901 - 2969 - /// - public void Hide() + else if (ShiftMode == 3) { - if (!IsVisible) - return; - - for (uint i = 2901; i < 2970; i++) - TriList.ClearBoolSigAction(i); - - // run attached actions - if(HideAction != null) - HideAction(); - - TriList.SetBool(KeyboardVisible, false); - IsVisible = false; + ShiftMode = 2; + ShowKeys(); } + } - /// - /// - /// - /// - public void Press(char c) - { - OnKeyPress(c.ToString()); - Output.Append(c); - OutputFeedback.FireUpdate(); - ResetShift(); - } - - /// - /// - /// - /// - public void Press(string s) - { - OnKeyPress(s); - Output.Append(s); - OutputFeedback.FireUpdate(); - ResetShift(); - } - - /// - /// - /// - public void EnableGoButton() - { - TriList.SetBool(GoButtonEnableJoin, true); - } - - /// - /// - /// - public void DisableGoButton() - { - TriList.SetBool(GoButtonEnableJoin, false); - } - - void ResetShift() - { - if (ShiftMode == 1) - { - ShiftMode = 0; - ShowKeys(); - } - else if (ShiftMode == 3) - { - ShiftMode = 2; - ShowKeys(); - } - } - - char A(int i) { return new char[] { 'a', 'A', '?', '?' }[i]; } - char B(int i) { return new char[] { 'b', 'B', ':', ':' }[i]; } - char C(int i) { return new char[] { 'c', 'C', '>', '>' }[i]; } - char D(int i) { return new char[] { 'd', 'D', '_', '_' }[i]; } - char E(int i) { return new char[] { 'e', 'E', '3', '#' }[i]; } - char F(int i) { return new char[] { 'f', 'F', '=', '=' }[i]; } - char G(int i) { return new char[] { 'g', 'G', '+', '+' }[i]; } - char H(int i) { return new char[] { 'h', 'H', '[', '[' }[i]; } - char I(int i) { return new char[] { 'i', 'I', '8', '*' }[i]; } - char J(int i) { return new char[] { 'j', 'J', ']', ']' }[i]; } - char K(int i) { return new char[] { 'k', 'K', '/', '/' }[i]; } - char L(int i) { return new char[] { 'l', 'L', '\\', '\\' }[i]; } - char M(int i) { return new char[] { 'm', 'M', '"', '"' }[i]; } - char N(int i) { return new char[] { 'n', 'N', '\'', '\'' }[i]; } - char O(int i) { return new char[] { 'o', 'O', '9', '(' }[i]; } - char P(int i) { return new char[] { 'p', 'P', '0', ')' }[i]; } - char Q(int i) { return new char[] { 'q', 'Q', '1', '!' }[i]; } - char R(int i) { return new char[] { 'r', 'R', '4', '$' }[i]; } - char S(int i) { return new char[] { 's', 'S', '-', '-' }[i]; } - char T(int i) { return new char[] { 't', 'T', '5', '%' }[i]; } - char U(int i) { return new char[] { 'u', 'U', '7', '&' }[i]; } - char V(int i) { return new char[] { 'v', 'V', ';', ';' }[i]; } - char W(int i) { return new char[] { 'w', 'W', '2', '@' }[i]; } - char X(int i) { return new char[] { 'x', 'X', '<', '<' }[i]; } - char Y(int i) { return new char[] { 'y', 'Y', '6', '^' }[i]; } - char Z(int i) { return new char[] { 'z', 'Z', ',', ',' }[i]; } + char A(int i) { return new char[] { 'a', 'A', '?', '?' }[i]; } + char B(int i) { return new char[] { 'b', 'B', ':', ':' }[i]; } + char C(int i) { return new char[] { 'c', 'C', '>', '>' }[i]; } + char D(int i) { return new char[] { 'd', 'D', '_', '_' }[i]; } + char E(int i) { return new char[] { 'e', 'E', '3', '#' }[i]; } + char F(int i) { return new char[] { 'f', 'F', '=', '=' }[i]; } + char G(int i) { return new char[] { 'g', 'G', '+', '+' }[i]; } + char H(int i) { return new char[] { 'h', 'H', '[', '[' }[i]; } + char I(int i) { return new char[] { 'i', 'I', '8', '*' }[i]; } + char J(int i) { return new char[] { 'j', 'J', ']', ']' }[i]; } + char K(int i) { return new char[] { 'k', 'K', '/', '/' }[i]; } + char L(int i) { return new char[] { 'l', 'L', '\\', '\\' }[i]; } + char M(int i) { return new char[] { 'm', 'M', '"', '"' }[i]; } + char N(int i) { return new char[] { 'n', 'N', '\'', '\'' }[i]; } + char O(int i) { return new char[] { 'o', 'O', '9', '(' }[i]; } + char P(int i) { return new char[] { 'p', 'P', '0', ')' }[i]; } + char Q(int i) { return new char[] { 'q', 'Q', '1', '!' }[i]; } + char R(int i) { return new char[] { 'r', 'R', '4', '$' }[i]; } + char S(int i) { return new char[] { 's', 'S', '-', '-' }[i]; } + char T(int i) { return new char[] { 't', 'T', '5', '%' }[i]; } + char U(int i) { return new char[] { 'u', 'U', '7', '&' }[i]; } + char V(int i) { return new char[] { 'v', 'V', ';', ';' }[i]; } + char W(int i) { return new char[] { 'w', 'W', '2', '@' }[i]; } + char X(int i) { return new char[] { 'x', 'X', '<', '<' }[i]; } + char Y(int i) { return new char[] { 'y', 'Y', '6', '^' }[i]; } + char Z(int i) { return new char[] { 'z', 'Z', ',', ',' }[i]; } /// /// Does what it says @@ -230,207 +230,206 @@ namespace PepperDash.Essentials.Core.Touchpanels.Keyboards } } - void Backspace() + void Backspace() + { + OnKeyPress(KeyboardSpecialKey.Backspace); + + if (Output.Length > 0) { - OnKeyPress(KeyboardSpecialKey.Backspace); - - if (Output.Length > 0) - { - Output.Remove(Output.Length - 1, 1); - OutputFeedback.FireUpdate(); - } - } - - void Clear() - { - OnKeyPress(KeyboardSpecialKey.Clear); - - Output.Remove(0, Output.Length); + Output.Remove(Output.Length - 1, 1); OutputFeedback.FireUpdate(); } + } - /* When in mode 0 (lowercase): - * shift button: up arrow 0 - * numShift button: 123/#$@#$ 0 - * - * - shift --> mode 1 - * - double-tap shift --> caps lock - * - numShift --> mode 2 - * - * mode 1 (uppercase) - * shift button: down arrow 1 - * numShift button: 123/##$# 0 - * - * - shift --> mode 0 - * - numShift --> mode 2 - * - * - Tapping any key will go back to mode 0 - * - * mode 2 (numbers-sym) - * Shift button: #$#$#$ 2 - * numShift: ABC 1 - * - * - shift --> mode 3 - * - double-tap shift --> caps lock - * - numShift --> mode 0 - * - * mode 3 (sym) - * Shift button: 123 3 - * numShift: ABC 1 - * - * - shift --> mode 2 - * - numShift --> mode 0 - * - * - Tapping any key will go back to mode 2 - */ - void Shift() - { - if (ShiftMode == 0) - ShiftMode = 1; - else if (ShiftMode == 1) - ShiftMode = 0; - else if (ShiftMode == 2) - ShiftMode = 3; - else - ShiftMode = 2; + void Clear() + { + OnKeyPress(KeyboardSpecialKey.Clear); - ShowKeys(); - } + Output.Remove(0, Output.Length); + OutputFeedback.FireUpdate(); + } - void NumShift() - { - if (ShiftMode == 0 || ShiftMode == 1) - ShiftMode = 2; - else if (ShiftMode == 2 || ShiftMode == 3) - ShiftMode = 0; - ShowKeys(); - } + /* When in mode 0 (lowercase): + * shift button: up arrow 0 + * numShift button: 123/#$@#$ 0 + * + * - shift --> mode 1 + * - double-tap shift --> caps lock + * - numShift --> mode 2 + * + * mode 1 (uppercase) + * shift button: down arrow 1 + * numShift button: 123/##$# 0 + * + * - shift --> mode 0 + * - numShift --> mode 2 + * + * - Tapping any key will go back to mode 0 + * + * mode 2 (numbers-sym) + * Shift button: #$#$#$ 2 + * numShift: ABC 1 + * + * - shift --> mode 3 + * - double-tap shift --> caps lock + * - numShift --> mode 0 + * + * mode 3 (sym) + * Shift button: 123 3 + * numShift: ABC 1 + * + * - shift --> mode 2 + * - numShift --> mode 0 + * + * - Tapping any key will go back to mode 2 + */ + void Shift() + { + if (ShiftMode == 0) + ShiftMode = 1; + else if (ShiftMode == 1) + ShiftMode = 0; + else if (ShiftMode == 2) + ShiftMode = 3; + else + ShiftMode = 2; - void ShowKeys() - { - TriList.SetString(2921, A(ShiftMode).ToString()); - TriList.SetString(2922, B(ShiftMode).ToString()); - TriList.SetString(2923, C(ShiftMode).ToString()); - TriList.SetString(2924, D(ShiftMode).ToString()); - TriList.SetString(2925, E(ShiftMode).ToString()); - TriList.SetString(2926, F(ShiftMode).ToString()); - TriList.SetString(2927, G(ShiftMode).ToString()); - TriList.SetString(2928, H(ShiftMode).ToString()); - TriList.SetString(2929, I(ShiftMode).ToString()); - TriList.SetString(2930, J(ShiftMode).ToString()); - TriList.SetString(2931, K(ShiftMode).ToString()); - TriList.SetString(2932, L(ShiftMode).ToString()); - TriList.SetString(2933, M(ShiftMode).ToString()); - TriList.SetString(2934, N(ShiftMode).ToString()); - TriList.SetString(2935, O(ShiftMode).ToString()); - TriList.SetString(2936, P(ShiftMode).ToString()); - TriList.SetString(2937, Q(ShiftMode).ToString()); - TriList.SetString(2938, R(ShiftMode).ToString()); - TriList.SetString(2939, S(ShiftMode).ToString()); - TriList.SetString(2940, T(ShiftMode).ToString()); - TriList.SetString(2941, U(ShiftMode).ToString()); - TriList.SetString(2942, V(ShiftMode).ToString()); - TriList.SetString(2943, W(ShiftMode).ToString()); - TriList.SetString(2944, X(ShiftMode).ToString()); - TriList.SetString(2945, Y(ShiftMode).ToString()); - TriList.SetString(2946, Z(ShiftMode).ToString()); - TriList.SetString(2954, DotComButtonString); + ShowKeys(); + } - TriList.SetUshort(2951, (ushort)ShiftMode); // 0 = up, 1 = down, 2 = #, 3 = 123 - TriList.SetUshort(2952, (ushort)(ShiftMode < 2 ? 0 : 1)); // 0 = #, 1 = abc - } + void NumShift() + { + if (ShiftMode == 0 || ShiftMode == 1) + ShiftMode = 2; + else if (ShiftMode == 2 || ShiftMode == 3) + ShiftMode = 0; + ShowKeys(); + } - /// - /// Event fire helper for text - /// - /// - void OnKeyPress(string text) - { - var handler = KeyPress; - if (handler != null) - KeyPress(this, new KeyboardControllerPressEventArgs(text)); - } - - /// - /// event helper for special keys - /// - /// - void OnKeyPress(KeyboardSpecialKey key) - { - var handler = KeyPress; - if (handler != null) - KeyPress(this, new KeyboardControllerPressEventArgs(key)); - } - - - /// - /// 2901 - /// - public const uint KeyboardVisible = 2901; - /// - /// 2902 - /// - public const uint ClosePressJoin = 2902; - /// - /// 2903 - /// - public const uint GoButtonPressJoin = 2903; - /// - /// 2903 - /// - public const uint GoButtonTextJoin = 2903; - /// - /// 2904 - /// - public const uint SecondaryButtonPressJoin = 2904; - /// - /// 2904 - /// - public const uint SecondaryButtonTextJoin = 2904; - /// - /// 2905 - /// - public const uint GoButtonVisibleJoin = 2905; - /// - /// 2906 - /// - public const uint SecondaryButtonVisibleJoin = 2906; - /// - /// 2907 - /// - public const uint GoButtonEnableJoin = 2907; - /// - /// 2910 - /// - public const uint ClearPressJoin = 2910; - /// - /// 2911 - /// - public const uint ClearVisibleJoin = 2911; + void ShowKeys() + { + TriList.SetString(2921, A(ShiftMode).ToString()); + TriList.SetString(2922, B(ShiftMode).ToString()); + TriList.SetString(2923, C(ShiftMode).ToString()); + TriList.SetString(2924, D(ShiftMode).ToString()); + TriList.SetString(2925, E(ShiftMode).ToString()); + TriList.SetString(2926, F(ShiftMode).ToString()); + TriList.SetString(2927, G(ShiftMode).ToString()); + TriList.SetString(2928, H(ShiftMode).ToString()); + TriList.SetString(2929, I(ShiftMode).ToString()); + TriList.SetString(2930, J(ShiftMode).ToString()); + TriList.SetString(2931, K(ShiftMode).ToString()); + TriList.SetString(2932, L(ShiftMode).ToString()); + TriList.SetString(2933, M(ShiftMode).ToString()); + TriList.SetString(2934, N(ShiftMode).ToString()); + TriList.SetString(2935, O(ShiftMode).ToString()); + TriList.SetString(2936, P(ShiftMode).ToString()); + TriList.SetString(2937, Q(ShiftMode).ToString()); + TriList.SetString(2938, R(ShiftMode).ToString()); + TriList.SetString(2939, S(ShiftMode).ToString()); + TriList.SetString(2940, T(ShiftMode).ToString()); + TriList.SetString(2941, U(ShiftMode).ToString()); + TriList.SetString(2942, V(ShiftMode).ToString()); + TriList.SetString(2943, W(ShiftMode).ToString()); + TriList.SetString(2944, X(ShiftMode).ToString()); + TriList.SetString(2945, Y(ShiftMode).ToString()); + TriList.SetString(2946, Z(ShiftMode).ToString()); + TriList.SetString(2954, DotComButtonString); + TriList.SetUshort(2951, (ushort)ShiftMode); // 0 = up, 1 = down, 2 = #, 3 = 123 + TriList.SetUshort(2952, (ushort)(ShiftMode < 2 ? 0 : 1)); // 0 = #, 1 = abc } /// - /// + /// Event fire helper for text /// - public class KeyboardControllerPressEventArgs : EventArgs + /// + void OnKeyPress(string text) { - public string Text { get; private set; } - public KeyboardSpecialKey SpecialKey { get; private set; } - - public KeyboardControllerPressEventArgs(string text) - { - Text = text; - } - - public KeyboardControllerPressEventArgs(KeyboardSpecialKey key) - { - SpecialKey = key; - } + var handler = KeyPress; + if (handler != null) + KeyPress(this, new KeyboardControllerPressEventArgs(text)); } - public enum KeyboardSpecialKey + /// + /// event helper for special keys + /// + /// + void OnKeyPress(KeyboardSpecialKey key) { - None = 0, Backspace, Clear, GoButton, SecondaryButton + var handler = KeyPress; + if (handler != null) + KeyPress(this, new KeyboardControllerPressEventArgs(key)); } + + + /// + /// 2901 + /// + public const uint KeyboardVisible = 2901; + /// + /// 2902 + /// + public const uint ClosePressJoin = 2902; + /// + /// 2903 + /// + public const uint GoButtonPressJoin = 2903; + /// + /// 2903 + /// + public const uint GoButtonTextJoin = 2903; + /// + /// 2904 + /// + public const uint SecondaryButtonPressJoin = 2904; + /// + /// 2904 + /// + public const uint SecondaryButtonTextJoin = 2904; + /// + /// 2905 + /// + public const uint GoButtonVisibleJoin = 2905; + /// + /// 2906 + /// + public const uint SecondaryButtonVisibleJoin = 2906; + /// + /// 2907 + /// + public const uint GoButtonEnableJoin = 2907; + /// + /// 2910 + /// + public const uint ClearPressJoin = 2910; + /// + /// 2911 + /// + public const uint ClearVisibleJoin = 2911; + +} + +/// +/// +/// +public class KeyboardControllerPressEventArgs : EventArgs +{ + public string Text { get; private set; } + public KeyboardSpecialKey SpecialKey { get; private set; } + + public KeyboardControllerPressEventArgs(string text) + { + Text = text; + } + + public KeyboardControllerPressEventArgs(KeyboardSpecialKey key) + { + SpecialKey = key; + } +} + +public enum KeyboardSpecialKey +{ + None = 0, Backspace, Clear, GoButton, SecondaryButton } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs b/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs index 4dbe7158..91bde7f5 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs @@ -4,8 +4,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public class ModalDialog { /// @@ -16,10 +16,10 @@ namespace PepperDash.Essentials.Core /// Bool press 3992 /// public const uint Button2Join = 3992; - /// - /// 3993 - /// - public const uint CancelButtonJoin = 3993; + /// + /// 3993 + /// + public const uint CancelButtonJoin = 3993; /// ///For visibility of single button. Bool feedback 3994 /// @@ -32,10 +32,10 @@ namespace PepperDash.Essentials.Core /// Shows the timer guage if in use. Bool feedback 3996 /// public const uint TimerVisibleJoin = 3996; - /// - /// Visibility join to show "X" button 3997 - /// - public const uint CancelVisibleJoin = 3997; + /// + /// Visibility join to show "X" button 3997 + /// + public const uint CancelVisibleJoin = 3997; /// /// Shows the modal subpage. Boolean feeback join 3999 /// @@ -44,7 +44,7 @@ namespace PepperDash.Essentials.Core /// /// The seconds value of the countdown timer. Ushort join 3991 /// - //public const uint TimerSecondsJoin = 3991; + //public const uint TimerSecondsJoin = 3991; /// /// The full ushort value of the countdown timer for a gauge. Ushort join 3992 /// @@ -79,10 +79,10 @@ namespace PepperDash.Essentials.Core get { return TriList.BooleanInput[ModalVisibleJoin].BoolValue; } } - /// - /// - /// - public bool CanCancel { get; private set; } + /// + /// + /// + public bool CanCancel { get; private set; } BasicTriList TriList; @@ -100,10 +100,10 @@ namespace PepperDash.Essentials.Core TriList = triList; // Attach actions to buttons - triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); + triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); triList.SetSigFalseAction(Button2Join, () => OnModalComplete(2)); - triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); - CanCancel = true; + triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); + CanCancel = true; } /// @@ -148,15 +148,15 @@ namespace PepperDash.Essentials.Core TriList.StringInput[Button2TextJoin].StringValue = button2Text; } // Show/hide guage - TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; - - CanCancel = showCancel; - TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; + TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; + + CanCancel = showCancel; + TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; //Reveal and activate TriList.BooleanInput[ModalVisibleJoin].BoolValue = true; - WakePanel(); + WakePanel(); return true; } @@ -164,49 +164,47 @@ namespace PepperDash.Essentials.Core return false; } - /// - /// Wakes the panel by turning on the backlight if off - /// - public void WakePanel() + /// + /// Wakes the panel by turning on the backlight if off + /// + public void WakePanel() + { + try { - try - { - var panel = TriList as TswFt5Button; + var panel = TriList as TswFt5Button; - if (panel != null && panel.ExtenderSystemReservedSigs.BacklightOffFeedback.BoolValue) - panel.ExtenderSystemReservedSigs.BacklightOn(); - } - catch - { - Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); - } + if (panel != null && panel.ExtenderSystemReservedSigs.BacklightOffFeedback.BoolValue) + panel.ExtenderSystemReservedSigs.BacklightOn(); } + catch + { + Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); + } + } - /// - /// Hide dialog from elsewhere, fires CompleteAction - /// + /// + /// Hide dialog from elsewhere, fires CompleteAction + /// public void CancelDialog() { - OnModalComplete(0); + OnModalComplete(0); } - /// - /// Hides dialog. Fires no action - /// - public void HideDialog() - { - TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; - } + /// + /// Hides dialog. Fires no action + /// + public void HideDialog() + { + TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; + } // When the modal is cleared or times out, clean up the various bits void OnModalComplete(uint buttonNum) { TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; - var action = ModalCompleteAction; - if (action != null) - action(buttonNum); + var action = ModalCompleteAction; + if (action != null) + action(buttonNum); } - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs b/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs index 8649d292..f97b8358 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs @@ -7,8 +7,8 @@ using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; -namespace PepperDash.Essentials.Core.Touchpanels -{ +namespace PepperDash.Essentials.Core.Touchpanels; + /// /// A wrapper class for the touchpanel portion of an MPC3 class process to allow for configurable /// behavior of the keybad buttons @@ -75,9 +75,9 @@ namespace PepperDash.Essentials.Core.Touchpanels return; } - TryParseInt(key, out int buttonNumber); + TryParseInt(key, out int buttonNumber); - var buttonEventTypes = config.EventTypes; + var buttonEventTypes = config.EventTypes; BoolOutputSig enabledFb = null; BoolOutputSig disabledFb = null; @@ -161,10 +161,10 @@ namespace PepperDash.Essentials.Core.Touchpanels return; } - TryParseInt(key, out int buttonNumber); + TryParseInt(key, out int buttonNumber); - // Link up the button feedbacks to the specified device feedback - var buttonFeedback = config.Feedback; + // Link up the button feedbacks to the specified device feedback + var buttonFeedback = config.Feedback; if (buttonFeedback == null || string.IsNullOrEmpty(buttonFeedback.DeviceKey)) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback not configured, skipping.", @@ -176,14 +176,14 @@ namespace PepperDash.Essentials.Core.Touchpanels try { - if (!(DeviceManager.GetDeviceForKey(buttonFeedback.DeviceKey) is Device device)) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback deviceKey '{1}' not found.", - key, buttonFeedback.DeviceKey); - return; - } + if (!(DeviceManager.GetDeviceForKey(buttonFeedback.DeviceKey) is Device device)) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback deviceKey '{1}' not found.", + key, buttonFeedback.DeviceKey); + return; + } - deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName); + deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName); if (deviceFeedback == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedbackName property '{1}' not found.", @@ -223,36 +223,36 @@ namespace PepperDash.Essentials.Core.Touchpanels var boolFeedback = deviceFeedback as BoolFeedback; - switch (key) - { - case ("power"): + switch (key) + { + case ("power"): + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower); + break; + } + case ("volumeup"): + case ("volumedown"): + case ("volumefeedback"): + { + if (deviceFeedback is IntFeedback intFeedback) { - boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower); - break; + var volumeFeedback = intFeedback; + volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph); } - case ("volumeup"): - case ("volumedown"): - case ("volumefeedback"): - { - if (deviceFeedback is IntFeedback intFeedback) - { - var volumeFeedback = intFeedback; - volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph); - } - break; - } - case ("mute"): - { - boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackMute); - break; - } - default: - { - boolFeedback?.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]); - break; - } - } + break; + } + case ("mute"): + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackMute); + break; + } + default: + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]); + break; + } } + } /// /// Try parse int helper method @@ -359,5 +359,4 @@ namespace PepperDash.Essentials.Core.Touchpanels [JsonProperty("feedbackName")] public string FeedbackName { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs b/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs index bfbb73f0..0d31e44d 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs @@ -9,8 +9,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Extensions used for more-clear attachment of Actions to user objects on sigs /// @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Core { /// /// Attaches Action to Sig's user object and returns the same Sig. This provides no protection - /// from null sigs + /// from null sigs /// /// The BoolOutputSig to attach the Action to /// An action to run when sig is pressed and when released @@ -64,14 +64,14 @@ namespace PepperDash.Essentials.Core return sig.SetBoolSigAction(b => { if (!b) a(); }); } - /// - /// Sets an action to a held sig - /// - /// The sig - public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction) - { - return SetSigHeldAction(tl, sigNum, heldMs, heldAction, null); - } + /// + /// Sets an action to a held sig + /// + /// The sig + public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction) + { + return SetSigHeldAction(tl, sigNum, heldMs, heldAction, null); + } /// /// Sets an action to a held sig as well as a released-without-hold action @@ -114,14 +114,14 @@ namespace PepperDash.Essentials.Core } - /// - /// Sets an action to a held sig as well as a released-without-hold action - /// - /// The sig - public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction, Action releaseAction) - { + /// + /// Sets an action to a held sig as well as a released-without-hold action + /// + /// The sig + public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction, Action releaseAction) + { return tl.BooleanOutput[sigNum].SetSigHeldAction(heldMs, heldAction, null, releaseAction); - } + } /// /// Sets an action to a held sig, an action for the release of hold, as well as a released-without-hold action @@ -206,35 +206,35 @@ namespace PepperDash.Essentials.Core return ClearSigAction(tl.StringOutput[sigNum]) as StringOutputSig; } - /// - /// Clears all actions on all sigs - /// - public static void ClearAllSigActions(this BasicTriList t1) + /// + /// Clears all actions on all sigs + /// + public static void ClearAllSigActions(this BasicTriList t1) + { + foreach (var sig in t1.BooleanOutput) { - foreach (var sig in t1.BooleanOutput) - { - ClearSigAction(sig); - } - - foreach (var sig in t1.UShortOutput) - { - ClearSigAction(sig); - } - - foreach (var sig in t1.StringOutput) - { - ClearSigAction(sig); - } + ClearSigAction(sig); } - /// - /// Helper method to set the value of a bool Sig on TriList - /// - public static void SetBool(this BasicTriList tl, uint sigNum, bool value) + foreach (var sig in t1.UShortOutput) { - tl.BooleanInput[sigNum].BoolValue = value; + ClearSigAction(sig); } + foreach (var sig in t1.StringOutput) + { + ClearSigAction(sig); + } + } + + /// + /// Helper method to set the value of a bool Sig on TriList + /// + public static void SetBool(this BasicTriList tl, uint sigNum, bool value) + { + tl.BooleanInput[sigNum].BoolValue = value; + } + /// /// Sends an true-false pulse to the sig /// @@ -256,21 +256,21 @@ namespace PepperDash.Essentials.Core tl.BooleanInput[sigNum].Pulse(ms); } - /// - /// Helper method to set the value of a ushort Sig on TriList - /// - public static void SetUshort(this BasicTriList tl, uint sigNum, ushort value) - { - tl.UShortInput[sigNum].UShortValue = value; - } + /// + /// Helper method to set the value of a ushort Sig on TriList + /// + public static void SetUshort(this BasicTriList tl, uint sigNum, ushort value) + { + tl.UShortInput[sigNum].UShortValue = value; + } - /// - /// Helper method to set the value of a string Sig on TriList - /// - public static void SetString(this BasicTriList tl, uint sigNum, string value) - { - tl.StringInput[sigNum].StringValue = value; - } + /// + /// Helper method to set the value of a string Sig on TriList + /// + public static void SetString(this BasicTriList tl, uint sigNum, string value) + { + tl.StringInput[sigNum].StringValue = value; + } public static void SetString(this BasicTriList tl, uint sigNum, string value, eStringEncoding encoding) { @@ -310,5 +310,4 @@ namespace PepperDash.Essentials.Core { return tl.StringOutput[sigNum].StringValue; } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs b/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs index e1a69707..b804c370 100644 --- a/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs +++ b/src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs @@ -7,8 +7,8 @@ using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + public abstract class HandlerBridge { public bool IsAttached { get; protected set; } @@ -22,5 +22,4 @@ namespace PepperDash.Essentials.Core /// Removes the handler from the panel's user objects /// public abstract void DetachFromTriListOutputs(); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs index c272a65a..892027cf 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs @@ -1,8 +1,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + public class DiscPlayerMediumPageManager : MediumLeftSwitchablePageManager { IDiscPlayerControls Player; @@ -38,5 +38,4 @@ namespace PepperDash.Essentials.Core.PageManagers TriList.BooleanInput[BackingPageJoin].BoolValue = false; TriList.BooleanInput[LeftSubpageJoin].BoolValue = false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs index 1f261f87..2323f0ce 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs @@ -2,8 +2,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + /// /// The PageManager classes are used to bridge a device to subpage /// visibility. @@ -92,5 +92,4 @@ namespace PepperDash.Essentials.Core.PageManagers { return GetOffsetJoin(DisplayUiType); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs index 539bb9d4..b47ab255 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs @@ -7,8 +7,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Presets; using Serilog.Events; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + public class ThreePanelPlusOnePageManager : PageManager { protected BasicTriListWithSmartObject TriList; @@ -37,7 +37,7 @@ namespace PepperDash.Essentials.Core.PageManagers public ThreePanelPlusOnePageManager(BasicTriListWithSmartObject trilist) { TriList = trilist; - CurrentVisiblePosition5Item = 1; + CurrentVisiblePosition5Item = 1; } /// @@ -56,8 +56,8 @@ namespace PepperDash.Essentials.Core.PageManagers { // Project the joins into corresponding sigs. var fixedSigs = FixedVisibilityJoins.Select(u => TriList.BooleanInput[u]).ToList(); - foreach (var sig in fixedSigs) - sig.BoolValue = true; + foreach (var sig in fixedSigs) + sig.BoolValue = true; if (ShowPosition5Tabs) { @@ -65,32 +65,32 @@ namespace PepperDash.Essentials.Core.PageManagers TriList.BooleanInput[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = true; // hook up tab object var tabSo = TriList.SmartObjects[Position5TabsId]; - tabSo.BooleanOutput["Tab Button 1 Press"].UserObject = new Action(b => { if (!b) ShowTab(1); }); - tabSo.BooleanOutput["Tab Button 2 Press"].UserObject = new Action(b => { if (!b) ShowTab(2); }); - tabSo.SigChange -= tabSo_SigChange; - tabSo.SigChange += tabSo_SigChange; - } + tabSo.BooleanOutput["Tab Button 1 Press"].UserObject = new Action(b => { if (!b) ShowTab(1); }); + tabSo.BooleanOutput["Tab Button 2 Press"].UserObject = new Action(b => { if (!b) ShowTab(2); }); + tabSo.SigChange -= tabSo_SigChange; + tabSo.SigChange += tabSo_SigChange; + } } - void tabSo_SigChange(Crestron.SimplSharpPro.GenericBase currentDevice, Crestron.SimplSharpPro.SmartObjectEventArgs args) - { - var uo = args.Sig.UserObject; - if(uo is Action) - (uo as Action)(args.Sig.BoolValue); - } + void tabSo_SigChange(Crestron.SimplSharpPro.GenericBase currentDevice, Crestron.SimplSharpPro.SmartObjectEventArgs args) + { + var uo = args.Sig.UserObject; + if(uo is Action) + (uo as Action)(args.Sig.BoolValue); + } public override void Hide() { - var fixedSigs = FixedVisibilityJoins.Select(u => TriList.BooleanInput[u]).ToList(); - foreach (var sig in fixedSigs) - sig.BoolValue = false; + var fixedSigs = FixedVisibilityJoins.Select(u => TriList.BooleanInput[u]).ToList(); + foreach (var sig in fixedSigs) + sig.BoolValue = false; if (ShowPosition5Tabs) { - TriList.BooleanInput[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = false; + TriList.BooleanInput[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = false; - //var tabSo = TriList.SmartObjects[Position5TabsId]; - //tabSo.BooleanOutput["Tab Button 1 Press"].UserObject = null; - //tabSo.BooleanOutput["Tab Button 2 Press"].UserObject = null; + //var tabSo = TriList.SmartObjects[Position5TabsId]; + //tabSo.BooleanOutput["Tab Button 1 Press"].UserObject = null; + //tabSo.BooleanOutput["Tab Button 2 Press"].UserObject = null; } } @@ -140,37 +140,37 @@ namespace PepperDash.Essentials.Core.PageManagers bool dvr = stb.HasDvr; bool numbers = stb.HasNumeric; - if (dpad && !preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10031, 10091 }; - else if (!dpad && preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10032, 10091 }; - else if (!dpad && !preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10033, 10091 }; - else if (!dpad && !preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10034, 10091 }; + if (dpad && !preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10031, 10091 }; + else if (!dpad && preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10032, 10091 }; + else if (!dpad && !preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10033, 10091 }; + else if (!dpad && !preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10034, 10091 }; - else if (dpad && preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10042, 10021, 10092 }; - else if (dpad && !preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10043, 10021, 10092 }; - else if (dpad && !preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10021, 10092 }; - else if (!dpad && preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10043, 10022, 10092 }; - else if (!dpad && preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10022, 10092 }; - else if (!dpad && !preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10023, 10092 }; + else if (dpad && preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10042, 10021, 10092 }; + else if (dpad && !preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10043, 10021, 10092 }; + else if (dpad && !preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10021, 10092 }; + else if (!dpad && preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10043, 10022, 10092 }; + else if (!dpad && preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10022, 10092 }; + else if (!dpad && !preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10023, 10092 }; - else if (dpad && preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10053, 10032, 10011, 10093 }; - else if (dpad && preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10032, 10011, 10093 }; - else if (dpad && !preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10033, 10011, 10093 }; - else if (!dpad && preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10033, 10012, 10093 }; + else if (dpad && preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10053, 10032, 10011, 10093 }; + else if (dpad && preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10032, 10011, 10093 }; + else if (dpad && !preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10033, 10011, 10093 }; + else if (!dpad && preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10033, 10012, 10093 }; - else if (dpad && preset && dvr && numbers) - { - FixedVisibilityJoins = new uint[] { 10081, 10032, 10011, 10093 }; // special case - ShowPosition5Tabs = true; - } - // Bad config case - else - { - Debug.LogMessage(LogEventLevel.Debug, stb, "WARNING: Not configured to show any UI elements"); - FixedVisibilityJoins = new uint[] { 10091 }; - } + else if (dpad && preset && dvr && numbers) + { + FixedVisibilityJoins = new uint[] { 10081, 10032, 10011, 10093 }; // special case + ShowPosition5Tabs = true; + } + // Bad config case + else + { + Debug.LogMessage(LogEventLevel.Debug, stb, "WARNING: Not configured to show any UI elements"); + FixedVisibilityJoins = new uint[] { 10091 }; + } // Build presets - if (stb.HasPresets && stb.TvPresets != null) + if (stb.HasPresets && stb.TvPresets != null) { PresetsView = new DevicePresetsView(trilist, stb.TvPresets); } @@ -185,9 +185,8 @@ namespace PepperDash.Essentials.Core.PageManagers public override void Hide() { - if (PresetsView != null) - PresetsView.Detach(); + if (PresetsView != null) + PresetsView.Detach(); base.Hide(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs index 2797695e..4a480422 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs @@ -2,8 +2,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + /// /// A fixed-layout page manager that expects a DPad on the right, fixed portion of the page, and a two/three /// tab switchable area on the left for presets, numeric and transport controls @@ -56,5 +56,4 @@ namespace PepperDash.Essentials.Core.PageManagers TriList.BooleanInput[BackingPageJoin].BoolValue = false; TriList.BooleanInput[LeftSubpageJoin].BoolValue = false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs b/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs index dd7d605c..f4d05364 100644 --- a/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs +++ b/src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs @@ -2,8 +2,8 @@ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Core.PageManagers -{ +namespace PepperDash.Essentials.Core.PageManagers; + /// /// A simple class that hides and shows the default subpage for a given source type /// @@ -27,5 +27,4 @@ namespace PepperDash.Essentials.Core.PageManagers { TriList.BooleanInput[BackingPageJoin].BoolValue = false; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs b/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs index 1d83ea5b..ecc0fdae 100644 --- a/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs +++ b/src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs @@ -11,149 +11,149 @@ using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Serilog.Events; -namespace PepperDash.Essentials.Core.UI +namespace PepperDash.Essentials.Core.UI; + +public abstract class TouchpanelBase: EssentialsDevice, IHasBasicTriListWithSmartObject { - public abstract class TouchpanelBase: EssentialsDevice, IHasBasicTriListWithSmartObject + protected CrestronTouchpanelPropertiesConfig _config; + public BasicTriListWithSmartObject Panel { get; private set; } + + /// + /// Constructor for use with device Factory. A touch panel device will be created based on the provided IP-ID and the + /// type of the panel. The SGD File path can be specified using the config property, or a default one located in the program directory if none + /// is provided. + /// + /// Essentials Device Key + /// Essentials Device Name + /// Touchpanel Type to build + /// Touchpanel Configuration + /// IP-ID to use for touch panel + protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config) + :base(key, name) { - protected CrestronTouchpanelPropertiesConfig _config; - public BasicTriListWithSmartObject Panel { get; private set; } - /// - /// Constructor for use with device Factory. A touch panel device will be created based on the provided IP-ID and the - /// type of the panel. The SGD File path can be specified using the config property, or a default one located in the program directory if none - /// is provided. - /// - /// Essentials Device Key - /// Essentials Device Name - /// Touchpanel Type to build - /// Touchpanel Configuration - /// IP-ID to use for touch panel - protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config) - :base(key, name) + if (panel == null) { + Debug.LogMessage(LogEventLevel.Information, this, "Panel is not valid. Touchpanel class WILL NOT work correctly"); + return; + } - if (panel == null) + Panel = panel; + + Panel.SigChange += Panel_SigChange; + + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + tsw.ExtenderSystemReservedSigs.Use(); + tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange + += ExtenderSystemReservedSigs_DeviceExtenderSigChange; + + tsw.ButtonStateChange += Tsw_ButtonStateChange; + } + + _config = config; + + AddPreActivationAction(() => { + if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success) + Debug.LogMessage(LogEventLevel.Information, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason); + + // Give up cleanly if SGD is not present. + var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile; + if (!File.Exists(sgdName)) { - Debug.LogMessage(LogEventLevel.Information, this, "Panel is not valid. Touchpanel class WILL NOT work correctly"); - return; - } + Debug.LogMessage(LogEventLevel.Information, this, "Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName); - Panel = panel; + sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile; - Panel.SigChange += Panel_SigChange; - - if (Panel is TswFt5ButtonSystem) - { - var tsw = Panel as TswFt5ButtonSystem; - tsw.ExtenderSystemReservedSigs.Use(); - tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange - += ExtenderSystemReservedSigs_DeviceExtenderSigChange; - - tsw.ButtonStateChange += Tsw_ButtonStateChange; - } - - _config = config; - - AddPreActivationAction(() => { - if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success) - Debug.LogMessage(LogEventLevel.Information, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason); - - // Give up cleanly if SGD is not present. - var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile; if (!File.Exists(sgdName)) { - Debug.LogMessage(LogEventLevel.Information, this, "Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName); - - sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile; - - if (!File.Exists(sgdName)) - { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName); - return; - } + Debug.LogMessage(LogEventLevel.Information, this, "Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName); + return; } + } - Panel.LoadSmartObjects(sgdName); - }); + Panel.LoadSmartObjects(sgdName); + }); - AddPostActivationAction(() => + AddPostActivationAction(() => + { + // Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event + var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner; + + if (roomCombiner != null) { - // Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event - var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner; + // Subscribe to the even + roomCombiner.RoomCombinationScenarioChanged += new EventHandler(roomCombiner_RoomCombinationScenarioChanged); - if (roomCombiner != null) + // Connect to the initial roomKey + if (roomCombiner.CurrentScenario != null) { - // Subscribe to the even - roomCombiner.RoomCombinationScenarioChanged += new EventHandler(roomCombiner_RoomCombinationScenarioChanged); - - // Connect to the initial roomKey - if (roomCombiner.CurrentScenario != null) - { - // Use the current scenario - DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); - } - else - { - // Current Scenario not yet set. Use default - SetupPanelDrivers(_config.DefaultRoomKey); - } + // Use the current scenario + DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); } else { - // No room combiner, use the default key + // Current Scenario not yet set. Use default SetupPanelDrivers(_config.DefaultRoomKey); } - }); - } - - /// - /// Setup Panel operation - /// - /// Room Key for this panel - protected abstract void SetupPanelDrivers(string roomKey); - - - /// - /// Event handler for System Extender Events - /// - /// - /// - protected abstract void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args); - - - /// - /// - /// - /// - /// - protected virtual void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e) - { - var roomCombiner = sender as IEssentialsRoomCombiner; - - DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); - } - - /// - /// Determines the room key to use based on the scenario - /// - /// - protected virtual void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario) - { - string newRoomKey = null; - - if (scenario.UiMap.ContainsKey(Key)) - { - newRoomKey = scenario.UiMap[Key]; } - else if (scenario.UiMap.ContainsKey(_config.DefaultRoomKey)) + else { - newRoomKey = scenario.UiMap[_config.DefaultRoomKey]; + // No room combiner, use the default key + SetupPanelDrivers(_config.DefaultRoomKey); } + }); + } - SetupPanelDrivers(newRoomKey); + /// + /// Setup Panel operation + /// + /// Room Key for this panel + protected abstract void SetupPanelDrivers(string roomKey); + + + /// + /// Event handler for System Extender Events + /// + /// + /// + protected abstract void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args); + + + /// + /// + /// + /// + /// + protected virtual void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e) + { + var roomCombiner = sender as IEssentialsRoomCombiner; + + DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); + } + + /// + /// Determines the room key to use based on the scenario + /// + /// + protected virtual void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario) + { + string newRoomKey = null; + + if (scenario.UiMap.ContainsKey(Key)) + { + newRoomKey = scenario.UiMap[Key]; + } + else if (scenario.UiMap.ContainsKey(_config.DefaultRoomKey)) + { + newRoomKey = scenario.UiMap[_config.DefaultRoomKey]; } - private void Panel_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args) + SetupPanelDrivers(newRoomKey); + } + + private void Panel_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args) { Debug.LogMessage(LogEventLevel.Verbose, this, "Sig change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); var uo = args.Sig.UserObject; @@ -171,5 +171,4 @@ namespace PepperDash.Essentials.Core.UI if(uo is Action) (uo as Action)(args.Button.State == eButtonState.Pressed); } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs b/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs index 5c519f60..e78dec8a 100644 --- a/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs +++ b/src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs @@ -14,149 +14,147 @@ using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Core.Utilities +namespace PepperDash.Essentials.Core.Utilities; + +/// +/// A device that executes a sequence of actions with optional delays between actions +/// +[Description("A device that executes a sequence of actions with optional delays between actions")] +public class ActionSequence : EssentialsDevice { - /// - /// A device that executes a sequence of actions with optional delays between actions - /// - [Description("A device that executes a sequence of actions with optional delays between actions")] - public class ActionSequence : EssentialsDevice + private ActionSequencePropertiesConfig _propertiesConfig; + + private CrestronQueue _actionQueue; + + private Thread _worker; + + private bool _allowActionsToExecute; + + public ActionSequence(string key, DeviceConfig config) + : base(key, config.Name) { - private ActionSequencePropertiesConfig _propertiesConfig; + var props = config.Properties.ToObject(); + _propertiesConfig = props; - private CrestronQueue _actionQueue; - - private Thread _worker; - - private bool _allowActionsToExecute; - - public ActionSequence(string key, DeviceConfig config) - : base(key, config.Name) + if (_propertiesConfig != null) { - var props = config.Properties.ToObject(); - _propertiesConfig = props; - - if (_propertiesConfig != null) + if (_propertiesConfig.ActionSequence.Count > 0) { - if (_propertiesConfig.ActionSequence.Count > 0) - { - _actionQueue = new CrestronQueue(_propertiesConfig.ActionSequence.Count); - } + _actionQueue = new CrestronQueue(_propertiesConfig.ActionSequence.Count); } } + } - /// - /// Starts executing the sequenced actions - /// - public void StartSequence() + /// + /// Starts executing the sequenced actions + /// + public void StartSequence() + { + if (_worker !=null && _worker.ThreadState == Thread.eThreadStates.ThreadRunning) { - if (_worker !=null && _worker.ThreadState == Thread.eThreadStates.ThreadRunning) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Thread already running. Cannot Start Sequence"); - return; - } - - Debug.LogMessage(LogEventLevel.Debug, this, "Starting Action Sequence"); - _allowActionsToExecute = true; - AddActionsToQueue(); - _worker = new Thread(ProcessActions, null, Thread.eThreadStartOptions.Running); + Debug.LogMessage(LogEventLevel.Debug, this, "Thread already running. Cannot Start Sequence"); + return; } - /// - /// Stops executing the sequenced actions - /// - public void StopSequence() + Debug.LogMessage(LogEventLevel.Debug, this, "Starting Action Sequence"); + _allowActionsToExecute = true; + AddActionsToQueue(); + _worker = new Thread(ProcessActions, null, Thread.eThreadStartOptions.Running); + } + + /// + /// Stops executing the sequenced actions + /// + public void StopSequence() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Action Sequence"); + _allowActionsToExecute = false; + _worker.Abort(); + } + + /// + /// Populates the queue from the configuration information + /// + private void AddActionsToQueue() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Adding {0} actions to queue", _propertiesConfig.ActionSequence.Count); + + for (int i = 0; i < _propertiesConfig.ActionSequence.Count; i++) { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Action Sequence"); - _allowActionsToExecute = false; - _worker.Abort(); + _actionQueue.Enqueue(_propertiesConfig.ActionSequence[i]); } + } - /// - /// Populates the queue from the configuration information - /// - private void AddActionsToQueue() + private object ProcessActions(object obj) + { + while (_allowActionsToExecute && _actionQueue.Count > 0) { - Debug.LogMessage(LogEventLevel.Debug, this, "Adding {0} actions to queue", _propertiesConfig.ActionSequence.Count); + SequencedDeviceActionWrapper action = null; - for (int i = 0; i < _propertiesConfig.ActionSequence.Count; i++) - { - _actionQueue.Enqueue(_propertiesConfig.ActionSequence[i]); - } - } - - private object ProcessActions(object obj) - { - while (_allowActionsToExecute && _actionQueue.Count > 0) - { - SequencedDeviceActionWrapper action = null; - - action = _actionQueue.Dequeue(); - if (action == null) - break; - - // Delay before executing - if (action.DelayMs > 0) - Thread.Sleep(action.DelayMs); - - ExecuteAction(action); - } - - return null; - } - - private void ExecuteAction(DeviceActionWrapper action) - { + action = _actionQueue.Dequeue(); if (action == null) - return; + break; - try - { - DeviceJsonApi.DoDeviceAction(action); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); - } + // Delay before executing + if (action.DelayMs > 0) + Thread.Sleep(action.DelayMs); + + ExecuteAction(action); } + + return null; } - /// - /// Configuration Properties for ActionSequence - /// - public class ActionSequencePropertiesConfig + private void ExecuteAction(DeviceActionWrapper action) { - [JsonProperty("actionSequence")] - public List ActionSequence { get; set; } + if (action == null) + return; - public ActionSequencePropertiesConfig() + try { - ActionSequence = new List(); + DeviceJsonApi.DoDeviceAction(action); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); } } +} - public class SequencedDeviceActionWrapper : DeviceActionWrapper +/// +/// Configuration Properties for ActionSequence +/// +public class ActionSequencePropertiesConfig +{ + [JsonProperty("actionSequence")] + public List ActionSequence { get; set; } + + public ActionSequencePropertiesConfig() { - [JsonProperty("delayMs")] - public int DelayMs { get; set; } + ActionSequence = new List(); } +} - /// - /// Factory class - /// - public class ActionSequenceFactory : EssentialsDeviceFactory +public class SequencedDeviceActionWrapper : DeviceActionWrapper +{ + [JsonProperty("delayMs")] + public int DelayMs { get; set; } +} + +/// +/// Factory class +/// +public class ActionSequenceFactory : EssentialsDeviceFactory +{ + public ActionSequenceFactory() { - public ActionSequenceFactory() - { - TypeNames = new List() { "actionsequence" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ActionSequence Device"); - - return new ActionSequence(dc.Key, dc); - } + TypeNames = new List() { "actionsequence" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ActionSequence Device"); + + return new ActionSequence(dc.Key, dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs b/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs index 62d0040a..c3efc5e2 100644 --- a/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs +++ b/src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; -namespace PepperDash.Essentials.Core -{ +namespace PepperDash.Essentials.Core; + /// /// Use this class to pass in values to RoutingInputPorts. Unused properties will have default /// funcs assigned to them. @@ -144,5 +144,4 @@ namespace PepperDash.Essentials.Core // bool VideoSync { get; } //} - //public delegate void VideoStatusChangeHandler(IBasicVideoStatus device, eVideoStatusChangeType type); -} \ No newline at end of file + //public delegate void VideoStatusChangeHandler(IBasicVideoStatus device, eVideoStatusChangeType type); \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs index 94dbf5ad..84b594e1 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs @@ -8,8 +8,8 @@ using PepperDash.Core.Web; using PepperDash.Essentials.Core.Web.RequestHandlers; using Serilog.Events; -namespace PepperDash.Essentials.Core.Web -{ +namespace PepperDash.Essentials.Core.Web; + public class EssentialsWebApi : EssentialsDevice { private readonly WebApiServer _server; @@ -72,146 +72,146 @@ namespace PepperDash.Essentials.Core.Web private void SetupRoutes() { - var routes = new List - { - new HttpCwsRoute("versions") - { - Name = "ReportVersions", - RouteHandler = new ReportVersionsRequestHandler() - }, - new HttpCwsRoute("appdebug") - { - Name = "AppDebug", - RouteHandler = new AppDebugRequestHandler() - }, - new HttpCwsRoute("devices") - { - Name = "DevList", - RouteHandler = new DevListRequestHandler() - }, - new HttpCwsRoute("deviceCommands/{deviceKey}") - { - Name = "DevJson", - RouteHandler = new DevJsonRequestHandler() - }, - new HttpCwsRoute("deviceProperties/{deviceKey}") - { - Name = "DevProps", - RouteHandler = new DevPropsRequestHandler() - }, - new HttpCwsRoute("deviceMethods/{deviceKey}") - { - Name = "DevMethods", - RouteHandler = new DevMethodsRequestHandler() - }, - new HttpCwsRoute("deviceFeedbacks/{deviceKey}") - { - Name = "GetFeedbacksForDeviceKey", - RouteHandler = new GetFeedbacksForDeviceRequestHandler() - }, - new HttpCwsRoute("deviceStreamDebug") - { - Name = "SetDeviceStreamDebug", - RouteHandler = new SetDeviceStreamDebugRequestHandler() - }, - new HttpCwsRoute("disableAllStreamDebug") - { - Name = "DisableAllStreamDebug", - RouteHandler = new DisableAllStreamDebugRequestHandler() - }, - new HttpCwsRoute("config") - { - Name = "ShowConfig", - RouteHandler = new ShowConfigRequestHandler() - }, - new HttpCwsRoute("types") - { - Name = "GetTypes", - RouteHandler = new GetTypesRequestHandler() - }, - new HttpCwsRoute("types/{filter}") - { - Name = "GetTypesByFilter", - RouteHandler = new GetTypesByFilterRequestHandler() - }, - new HttpCwsRoute("joinMap/{bridgeKey}") - { - Name = "GetJoinMapsForBridgeKey", - RouteHandler = new GetJoinMapForBridgeKeyRequestHandler() - }, - new HttpCwsRoute("joinMap/{bridgeKey}/{deviceKey}") - { - Name = "GetJoinMapsForDeviceKey", - RouteHandler = new GetJoinMapForDeviceKeyRequestHandler() - }, - new HttpCwsRoute("debugSession") - { - Name = "DebugSession", - RouteHandler = new DebugSessionRequestHandler() - }, - new HttpCwsRoute("doNotLoadConfigOnNextBoot") - { - Name = "DoNotLoadConfigOnNextBoot", - RouteHandler = new DoNotLoadConfigOnNextBootRequestHandler() - }, - new HttpCwsRoute("restartProgram") - { - Name = "Restart Program", - RouteHandler = new RestartProgramRequestHandler() - }, - new HttpCwsRoute("loadConfig") - { - Name = "Load Config", - RouteHandler = new LoadConfigRequestHandler() - }, - new HttpCwsRoute("tielines") - { - Name = "Get TieLines", - RouteHandler = new GetTieLinesRequestHandler() - }, - new HttpCwsRoute("device/{deviceKey}/routingPorts") - { - Name = "Get Routing Ports for a device", - RouteHandler = new GetRoutingPortsHandler() - }, - }; - - AddRoute(routes); - } - - /// - /// Add a single route to the API. MUST be done during the activation phase - /// - /// - public void AddRoute(HttpCwsRoute route) + var routes = new List { - _server.AddRoute(route); - } - - /// - /// Add a collection of routes to the API. MUST be done during the activation phase - /// - /// - public void AddRoute(List routes) - { - foreach (var route in routes) + new HttpCwsRoute("versions") { - AddRoute(route); - } - } + Name = "ReportVersions", + RouteHandler = new ReportVersionsRequestHandler() + }, + new HttpCwsRoute("appdebug") + { + Name = "AppDebug", + RouteHandler = new AppDebugRequestHandler() + }, + new HttpCwsRoute("devices") + { + Name = "DevList", + RouteHandler = new DevListRequestHandler() + }, + new HttpCwsRoute("deviceCommands/{deviceKey}") + { + Name = "DevJson", + RouteHandler = new DevJsonRequestHandler() + }, + new HttpCwsRoute("deviceProperties/{deviceKey}") + { + Name = "DevProps", + RouteHandler = new DevPropsRequestHandler() + }, + new HttpCwsRoute("deviceMethods/{deviceKey}") + { + Name = "DevMethods", + RouteHandler = new DevMethodsRequestHandler() + }, + new HttpCwsRoute("deviceFeedbacks/{deviceKey}") + { + Name = "GetFeedbacksForDeviceKey", + RouteHandler = new GetFeedbacksForDeviceRequestHandler() + }, + new HttpCwsRoute("deviceStreamDebug") + { + Name = "SetDeviceStreamDebug", + RouteHandler = new SetDeviceStreamDebugRequestHandler() + }, + new HttpCwsRoute("disableAllStreamDebug") + { + Name = "DisableAllStreamDebug", + RouteHandler = new DisableAllStreamDebugRequestHandler() + }, + new HttpCwsRoute("config") + { + Name = "ShowConfig", + RouteHandler = new ShowConfigRequestHandler() + }, + new HttpCwsRoute("types") + { + Name = "GetTypes", + RouteHandler = new GetTypesRequestHandler() + }, + new HttpCwsRoute("types/{filter}") + { + Name = "GetTypesByFilter", + RouteHandler = new GetTypesByFilterRequestHandler() + }, + new HttpCwsRoute("joinMap/{bridgeKey}") + { + Name = "GetJoinMapsForBridgeKey", + RouteHandler = new GetJoinMapForBridgeKeyRequestHandler() + }, + new HttpCwsRoute("joinMap/{bridgeKey}/{deviceKey}") + { + Name = "GetJoinMapsForDeviceKey", + RouteHandler = new GetJoinMapForDeviceKeyRequestHandler() + }, + new HttpCwsRoute("debugSession") + { + Name = "DebugSession", + RouteHandler = new DebugSessionRequestHandler() + }, + new HttpCwsRoute("doNotLoadConfigOnNextBoot") + { + Name = "DoNotLoadConfigOnNextBoot", + RouteHandler = new DoNotLoadConfigOnNextBootRequestHandler() + }, + new HttpCwsRoute("restartProgram") + { + Name = "Restart Program", + RouteHandler = new RestartProgramRequestHandler() + }, + new HttpCwsRoute("loadConfig") + { + Name = "Load Config", + RouteHandler = new LoadConfigRequestHandler() + }, + new HttpCwsRoute("tielines") + { + Name = "Get TieLines", + RouteHandler = new GetTieLinesRequestHandler() + }, + new HttpCwsRoute("device/{deviceKey}/routingPorts") + { + Name = "Get Routing Ports for a device", + RouteHandler = new GetRoutingPortsHandler() + }, + }; - /// - /// Initializes the CWS class - /// - public override void Initialize() + AddRoute(routes); + } + + /// + /// Add a single route to the API. MUST be done during the activation phase + /// + /// + public void AddRoute(HttpCwsRoute route) + { + _server.AddRoute(route); + } + + /// + /// Add a collection of routes to the API. MUST be done during the activation phase + /// + /// + public void AddRoute(List routes) + { + foreach (var route in routes) + { + AddRoute(route); + } + } + + /// + /// Initializes the CWS class + /// + public override void Initialize() { - AddRoute(new HttpCwsRoute("apiPaths") { - Name = "GetPaths", - RouteHandler = new GetRoutesHandler(_server.GetRouteCollection(), BasePath) - }); + AddRoute(new HttpCwsRoute("apiPaths") { + Name = "GetPaths", + RouteHandler = new GetRoutesHandler(_server.GetRouteCollection(), BasePath) + }); - // If running on an appliance - if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) + // If running on an appliance + if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) { /* WEBSERVER [ON | OFF | TIMEOUT | MAXSESSIONSPERUSER ] @@ -253,11 +253,11 @@ namespace PepperDash.Essentials.Core.Web CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var hostname = CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server - ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}" - : $"https://{currentIp}/cws{BasePath}"; + var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server + ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}" + : $"https://{currentIp}/cws{BasePath}"; Debug.LogMessage(LogEventLevel.Information, this, "Server:{path:l}", path); @@ -274,5 +274,4 @@ namespace PepperDash.Essentials.Core.Web } Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50)); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs index d0610ede..d15cbc49 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs @@ -3,8 +3,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Core.Web -{ +namespace PepperDash.Essentials.Core.Web; + public class EssentialsWebApiFactory : EssentialsDeviceFactory { public EssentialsWebApiFactory() @@ -22,5 +22,4 @@ namespace PepperDash.Essentials.Core.Web Debug.LogMessage(LogEventLevel.Debug, "Factory failed to create new Essentials Web API Server"); return null; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs index d5f5af36..14fbd32a 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs @@ -5,8 +5,8 @@ using System.Text; using Crestron.SimplSharp.WebScripting; using PepperDash.Core; -namespace PepperDash.Essentials.Core.Web -{ +namespace PepperDash.Essentials.Core.Web; + public static class EssentialsWebApiHelpers { public static string GetRequestBody(this HttpCwsRequest request) @@ -22,8 +22,8 @@ namespace PepperDash.Essentials.Core.Web { return new { - assembly.Name, - assembly.Version + assembly.Name, + assembly.Version }; } @@ -31,7 +31,7 @@ namespace PepperDash.Essentials.Core.Web { return new { - device.Key, + device.Key, Name = (device is IKeyName) ? (device as IKeyName).Name : "---" @@ -83,5 +83,4 @@ namespace PepperDash.Essentials.Core.Web CType = device.Value.Type == null ? "---": device.Value.Type.ToString() }; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs index 7af4c631..090ebf8c 100644 --- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Web -{ +namespace PepperDash.Essentials.Core.Web; + public class EssentialsWebApiPropertiesConfig { [JsonProperty("basePath")] public string BasePath { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs index 0b7497d2..05ade982 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs @@ -6,8 +6,8 @@ using System; using Serilog.Events; using Newtonsoft.Json.Converters; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class AppDebugRequestHandler : WebApiBaseRequestHandler { /// @@ -80,7 +80,6 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers public class AppDebug { [JsonProperty("minimumLevel", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] - public LogEventLevel MinimumLevel { get; set; } - } -} \ No newline at end of file + [JsonConverter(typeof(StringEnumConverter))] + public LogEventLevel MinimumLevel { get; set; } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs index fcc36893..7d7e26cb 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs @@ -12,89 +12,88 @@ using System.Text; using System.Threading.Tasks; using PepperDash.Essentials.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ - public class DebugSessionRequestHandler : WebApiBaseRequestHandler - { - private readonly DebugWebsocketSink _sink = new DebugWebsocketSink(); +namespace PepperDash.Essentials.Core.Web.RequestHandlers; - public DebugSessionRequestHandler() - : base(true) +public class DebugSessionRequestHandler : WebApiBaseRequestHandler +{ + private readonly DebugWebsocketSink _sink = new DebugWebsocketSink(); + + public DebugSessionRequestHandler() + : base(true) + { + } + + /// + /// Gets details for a debug session + /// + /// + protected override void HandleGet(Crestron.SimplSharp.WebScripting.HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) { - } - - /// - /// Gets details for a debug session - /// - /// - protected override void HandleGet(Crestron.SimplSharp.WebScripting.HttpCwsContext context) - { - var routeData = context.Request.RouteData; - if (routeData == null) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); - - return; - } - - try - { - var ip = CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - - var port = 0; - - if (!_sink.IsRunning) - { - Debug.LogMessage(LogEventLevel.Information, "Starting WS Server"); - // Generate a random port within a specified range - port = new Random().Next(65435, 65535); - // Start the WS Server - _sink.StartServerAndSetPort(port); - Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); - } - - var url = _sink.Url; - - object data = new - { - url = _sink.Url - }; - - Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url); - - // Return the port number with the full url of the WS Server - var res = JsonConvert.SerializeObject(data); - - context.Response.ContentType = "application/json"; - context.Response.ContentEncoding = Encoding.UTF8; - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; - context.Response.Write(res, false); - context.Response.End(); - } - catch (Exception e) - { - Debug.LogMessage(LogEventLevel.Information, "Error: {0}", e); - } - } - - /// - /// Stops a debug session - /// - /// - protected override void HandlePost(HttpCwsContext context) - { - _sink.StopServer(); - - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; context.Response.End(); - Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped"); + return; } + try + { + var ip = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + + var port = 0; + + if (!_sink.IsRunning) + { + Debug.LogMessage(LogEventLevel.Information, "Starting WS Server"); + // Generate a random port within a specified range + port = new Random().Next(65435, 65535); + // Start the WS Server + _sink.StartServerAndSetPort(port); + Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); + } + + var url = _sink.Url; + + object data = new + { + url = _sink.Url + }; + + Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url); + + // Return the port number with the full url of the WS Server + var res = JsonConvert.SerializeObject(data); + + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = Encoding.UTF8; + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.Write(res, false); + context.Response.End(); + } + catch (Exception e) + { + Debug.LogMessage(LogEventLevel.Information, "Error: {0}", e); + } } + + /// + /// Stops a debug session + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + _sink.StopServer(); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.End(); + + Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped"); + } + } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs index add30634..34d8b446 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugWebsocketSink.cs @@ -1,42 +1,41 @@ using System; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class DebugWebsocketSink { - public class DebugWebsocketSink + private bool _isRunning; + private string _url; + + public bool IsRunning => _isRunning; + public string Url => _url; + + public void StartServerAndSetPort(int port) { - private bool _isRunning; - private string _url; - - public bool IsRunning => _isRunning; - public string Url => _url; - - public void StartServerAndSetPort(int port) + try { - try - { - _url = $"ws://localhost:{port}"; - _isRunning = true; - // Implement actual server startup logic here - } - catch (Exception ex) - { - _isRunning = false; - throw new Exception($"Failed to start debug websocket server: {ex.Message}"); - } + _url = $"ws://localhost:{port}"; + _isRunning = true; + // Implement actual server startup logic here } - - public void StopServer() + catch (Exception ex) { - try - { - // Implement actual server shutdown logic here - _isRunning = false; - _url = null; - } - catch (Exception ex) - { - throw new Exception($"Failed to stop debug websocket server: {ex.Message}"); - } + _isRunning = false; + throw new Exception($"Failed to start debug websocket server: {ex.Message}"); + } + } + + public void StopServer() + { + try + { + // Implement actual server shutdown logic here + _isRunning = false; + _url = null; + } + catch (Exception ex) + { + throw new Exception($"Failed to stop debug websocket server: {ex.Message}"); } } } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs index 3320de7e..24ad97bc 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs @@ -1,8 +1,8 @@ using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DefaultRequestHandler : WebApiBaseRequestHandler { /// @@ -114,5 +114,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs index d14ffb83..f0cefb1c 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs @@ -5,8 +5,8 @@ using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using Serilog.Events; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DevJsonRequestHandler : WebApiBaseRequestHandler { /// @@ -26,25 +26,25 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers /// protected override void HandlePost(HttpCwsContext context) { - var routeData = context.Request.RouteData; + var routeData = context.Request.RouteData; - if(routeData == null) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); + if(routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); - return; - } + return; + } - if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); + if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); - return; - } + return; + } if (context.Request.ContentLength < 0) { @@ -68,11 +68,11 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers try { - var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey}; + var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey}; - JsonConvert.PopulateObject(data, daw); + JsonConvert.PopulateObject(data, daw); - Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw); + Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw); DeviceJsonApi.DoDeviceAction(daw); @@ -86,9 +86,8 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; - context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false); + context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false); context.Response.End(); } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs index a83685fb..25eca5af 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs @@ -3,8 +3,8 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DevListRequestHandler : WebApiBaseRequestHandler { /// @@ -47,5 +47,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs index 263eb161..844f9b69 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs @@ -4,8 +4,8 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DevMethodsRequestHandler : WebApiBaseRequestHandler { /// @@ -25,18 +25,18 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers /// protected override void HandleGet(HttpCwsContext context) { - var routeData = context.Request.RouteData; - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting DevMethods: {@routeData}", routeData); - if (routeData == null) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); + var routeData = context.Request.RouteData; + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting DevMethods: {@routeData}", routeData); + if (routeData == null) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); - return; - } + return; + } - object deviceObj; + object deviceObj; if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) { context.Response.StatusCode = 400; @@ -51,13 +51,13 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers if (device == null) { context.Response.StatusCode = 404; - context.Response.StatusDescription = "Device Not Found"; - context.Response.End(); + context.Response.StatusDescription = "Device Not Found"; + context.Response.End(); - return; + return; } - var deviceMethods = DeviceJsonApi.GetMethods(device.Key); + var deviceMethods = DeviceJsonApi.GetMethods(device.Key); if (deviceMethods == null || deviceMethods.ToLower().Contains("no device")) { context.Response.StatusCode = 404; @@ -74,5 +74,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(deviceMethods, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs index c00e47c2..1968f091 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs @@ -3,8 +3,8 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DevPropsRequestHandler : WebApiBaseRequestHandler { /// @@ -18,59 +18,58 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers { } - /// - /// Handles GET method requests - /// - /// - protected override void HandleGet(HttpCwsContext context) + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + var routeData = context.Request.RouteData; + if (routeData == null) { - var routeData = context.Request.RouteData; - if (routeData == null) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); - - return; - } - - object deviceObj; - if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); - - return; - } - - var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()); - - if (device == null) - { - context.Response.StatusCode = 404; - context.Response.StatusDescription = "Device Not Found"; - context.Response.End(); - - return; - } - - var deviceProperties = DeviceJsonApi.GetProperties(device.Key); - if (deviceProperties == null || deviceProperties.ToLower().Contains("no device")) - { - context.Response.StatusCode = 404; - context.Response.StatusDescription = "Not Found"; - context.Response.End(); - - return; - } - - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; - context.Response.ContentType = "application/json"; - context.Response.ContentEncoding = Encoding.UTF8; - context.Response.Write(deviceProperties, false); + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; context.Response.End(); + + return; } + + object deviceObj; + if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + + return; + } + + var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()); + + if (device == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Device Not Found"; + context.Response.End(); + + return; + } + + var deviceProperties = DeviceJsonApi.GetProperties(device.Key); + if (deviceProperties == null || deviceProperties.ToLower().Contains("no device")) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); + + return; + } + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = Encoding.UTF8; + context.Response.Write(deviceProperties, false); + context.Response.End(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs index 0e682d6c..db40603c 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs @@ -1,8 +1,8 @@ using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DisableAllStreamDebugRequestHandler : WebApiBaseRequestHandler { /// @@ -28,5 +28,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.StatusDescription = "OK"; context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs index fdcad73c..d5dee2dd 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs @@ -3,8 +3,8 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class DoNotLoadConfigOnNextBootRequestHandler : WebApiBaseRequestHandler { /// @@ -27,7 +27,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers var data = new Data { DoNotLoadConfigOnNextBoot = Debug.DoNotLoadConfigOnNextBoot - }; + }; var body = JsonConvert.SerializeObject(data, Formatting.Indented); @@ -80,5 +80,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers { [JsonProperty("doNotLoadConfigOnNextBoot", NullValueHandling = NullValueHandling.Ignore)] public bool DoNotLoadConfigOnNextBoot { get; set; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs index 5dd5495c..2cc40c26 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs @@ -3,8 +3,8 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler { /// @@ -98,5 +98,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs index f2362f4b..2504d3d9 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs @@ -4,8 +4,8 @@ using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class GetJoinMapForBridgeKeyRequestHandler : WebApiBaseRequestHandler { /// @@ -74,5 +74,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs index 6c669189..228d6c2e 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs @@ -3,8 +3,8 @@ using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Bridges; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class GetJoinMapForDeviceKeyRequestHandler : WebApiBaseRequestHandler { /// @@ -91,5 +91,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs index 2ba9cb33..c86777b3 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs @@ -3,50 +3,49 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetRoutesHandler:WebApiBaseRequestHandler { - public class GetRoutesHandler:WebApiBaseRequestHandler - { - private HttpCwsRouteCollection routeCollection; - private string basePath; + private HttpCwsRouteCollection routeCollection; + private string basePath; - public GetRoutesHandler(HttpCwsRouteCollection routeCollection, string basePath) { - this.routeCollection = routeCollection; - this.basePath = basePath; - } - - protected override void HandleGet(HttpCwsContext context) - { - var currentIp = CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - - var hostname = CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - - var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server - ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{basePath}" - : $"https://{currentIp}/cws{basePath}"; - - var response = JsonConvert.SerializeObject(new RoutesResponseObject() - { - Url = path, - Routes = routeCollection - }); - - context.Response.StatusCode = 200; - context.Response.ContentType = "application/json"; - context.Response.Headers.Add("Content-Type", "application/json"); - context.Response.Write(response, false); - context.Response.End(); - } + public GetRoutesHandler(HttpCwsRouteCollection routeCollection, string basePath) { + this.routeCollection = routeCollection; + this.basePath = basePath; } - public class RoutesResponseObject + protected override void HandleGet(HttpCwsContext context) { - [JsonProperty("url")] - public string Url { set; get; } + var currentIp = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - [JsonProperty("routes")] - public HttpCwsRouteCollection Routes { get; set; } + var hostname = CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + + var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server + ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{basePath}" + : $"https://{currentIp}/cws{basePath}"; + + var response = JsonConvert.SerializeObject(new RoutesResponseObject() + { + Url = path, + Routes = routeCollection + }); + + context.Response.StatusCode = 200; + context.Response.ContentType = "application/json"; + context.Response.Headers.Add("Content-Type", "application/json"); + context.Response.Write(response, false); + context.Response.End(); } } + +public class RoutesResponseObject +{ + [JsonProperty("url")] + public string Url { set; get; } + + [JsonProperty("routes")] + public HttpCwsRouteCollection Routes { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs index 6e033f06..2350fe5a 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs @@ -5,66 +5,65 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetRoutingPortsHandler : WebApiBaseRequestHandler { - public class GetRoutingPortsHandler : WebApiBaseRequestHandler + public GetRoutingPortsHandler() : base(true) { } + + protected override void HandleGet(HttpCwsContext context) { - public GetRoutingPortsHandler() : base(true) { } + var routeData = context.Request.RouteData; - protected override void HandleGet(HttpCwsContext context) + if (routeData == null) { - var routeData = context.Request.RouteData; - - if (routeData == null) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); - return; - } - - if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) - { - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Bad Request"; - context.Response.End(); - return; - } - - var device = DeviceManager.GetDeviceForKey(deviceKey.ToString()); - - if (device == null) - { - context.Response.StatusCode = 404; - context.Response.StatusDescription = "Device Not Found"; - context.Response.End(); - return; - } - - var inputPorts = (device as IRoutingInputs)?.InputPorts; - var outputPorts = (device as IRoutingOutputs)?.OutputPorts; - - var response = JsonConvert.SerializeObject( new ReturnValue - { - InputPorts = inputPorts?.Select(p => p.Key).ToList(), - OutputPorts = outputPorts?.Select(p => p.Key).ToList() - }); - - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; - context.Response.ContentType = "application/json"; - context.Response.ContentEncoding = Encoding.UTF8; - context.Response.Write(response, false); + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; context.Response.End(); - + return; } - } - internal class ReturnValue { - [JsonProperty("inputPorts", NullValueHandling = NullValueHandling.Ignore)] - public List InputPorts { get; set; } + if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) + { + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Bad Request"; + context.Response.End(); + return; + } + + var device = DeviceManager.GetDeviceForKey(deviceKey.ToString()); + + if (device == null) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Device Not Found"; + context.Response.End(); + return; + } + + var inputPorts = (device as IRoutingInputs)?.InputPorts; + var outputPorts = (device as IRoutingOutputs)?.OutputPorts; + + var response = JsonConvert.SerializeObject( new ReturnValue + { + InputPorts = inputPorts?.Select(p => p.Key).ToList(), + OutputPorts = outputPorts?.Select(p => p.Key).ToList() + }); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = Encoding.UTF8; + context.Response.Write(response, false); + context.Response.End(); - [JsonProperty("outputPorts", NullValueHandling = NullValueHandling.Ignore)] - public List OutputPorts { get; set; } } } + +internal class ReturnValue { + [JsonProperty("inputPorts", NullValueHandling = NullValueHandling.Ignore)] + public List InputPorts { get; set; } + + [JsonProperty("outputPorts", NullValueHandling = NullValueHandling.Ignore)] + public List OutputPorts { get; set; } +} diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs index fb1db4e7..c1eabdac 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs @@ -4,30 +4,29 @@ using PepperDash.Core.Web.RequestHandlers; using System.Linq; using System.Text; -namespace PepperDash.Essentials.Core.Web.RequestHandlers +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + +public class GetTieLinesRequestHandler : WebApiBaseRequestHandler { - public class GetTieLinesRequestHandler : WebApiBaseRequestHandler + public GetTieLinesRequestHandler() : base(true) { } + + protected override void HandleGet(HttpCwsContext context) { - public GetTieLinesRequestHandler() : base(true) { } - - protected override void HandleGet(HttpCwsContext context) + var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new { - var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new - { - sourceKey = tl.SourcePort.ParentDevice.Key, - sourcePort = tl.SourcePort.Key, - destinationKey = tl.DestinationPort.ParentDevice.Key, - destinationPort = tl.DestinationPort.Key, - type = tl.Type.ToString(), - })); + sourceKey = tl.SourcePort.ParentDevice.Key, + sourcePort = tl.SourcePort.Key, + destinationKey = tl.DestinationPort.ParentDevice.Key, + destinationPort = tl.DestinationPort.Key, + type = tl.Type.ToString(), + })); - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; - context.Response.ContentType = "application/json"; - context.Response.ContentEncoding = Encoding.UTF8; - context.Response.Write(tieLineString, false); - context.Response.End(); + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; + context.Response.ContentType = "application/json"; + context.Response.ContentEncoding = Encoding.UTF8; + context.Response.Write(tieLineString, false); + context.Response.End(); - } } } diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs index 637c533c..3a8159fd 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs @@ -3,8 +3,8 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class GetTypesByFilterRequestHandler : WebApiBaseRequestHandler { /// @@ -64,5 +64,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs index 564cb00d..d1a20098 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs @@ -3,8 +3,8 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class GetTypesRequestHandler : WebApiBaseRequestHandler { /// @@ -54,5 +54,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs index 61932f30..c5789166 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs @@ -4,8 +4,8 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class LoadConfigRequestHandler : WebApiBaseRequestHandler { /// @@ -28,12 +28,11 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers var message = ""; var cs = Global.ControlSystem as ILoadConfig; if(cs != null) - cs.GoWithLoad(); - - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; + cs.GoWithLoad(); + + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; context.Response.Write(message, false); - context.Response.End(); - } - } -} \ No newline at end of file + context.Response.End(); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs index 3447a1eb..8e4c0a56 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs @@ -3,8 +3,8 @@ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class ReportVersionsRequestHandler : WebApiBaseRequestHandler { /// @@ -45,5 +45,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(js, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs index 0bb568f6..baeeace5 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs @@ -4,8 +4,8 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class RestartProgramRequestHandler : WebApiBaseRequestHandler { /// @@ -29,10 +29,9 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers if(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) CrestronConsole.SendControlSystemCommand($"progres -p:{InitialParametersClass.ApplicationNumber}", ref message); - context.Response.StatusCode = 200; - context.Response.StatusDescription = "OK"; + context.Response.StatusCode = 200; + context.Response.StatusDescription = "OK"; context.Response.Write(message, false); - context.Response.End(); - } - } -} \ No newline at end of file + context.Response.End(); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs index fa20145c..11ea1cc4 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs @@ -4,8 +4,8 @@ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler { /// @@ -119,23 +119,23 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers return; } - if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device)) - { - context.Response.StatusCode = 404; - context.Response.StatusDescription = "Not Found"; - context.Response.End(); + if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device)) + { + context.Response.StatusCode = 404; + context.Response.StatusDescription = "Not Found"; + context.Response.End(); - return; - } + return; + } - eStreamDebuggingSetting debugSetting; + eStreamDebuggingSetting debugSetting; try { debugSetting = (eStreamDebuggingSetting) Enum.Parse(typeof (eStreamDebuggingSetting), body.Setting, true); } catch (Exception ex) { - Debug.LogMessage(ex, "Exception handling set debug request"); + Debug.LogMessage(ex, "Exception handling set debug request"); context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); @@ -161,7 +161,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers } catch (Exception ex) { - Debug.LogMessage(ex, "Exception handling set debug request"); + Debug.LogMessage(ex, "Exception handling set debug request"); context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); @@ -209,5 +209,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers Setting = null; Timeout = 15; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs index 65af1d06..0395e34f 100644 --- a/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs +++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs @@ -3,8 +3,8 @@ using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Config; -namespace PepperDash.Essentials.Core.Web.RequestHandlers -{ +namespace PepperDash.Essentials.Core.Web.RequestHandlers; + public class ShowConfigRequestHandler : WebApiBaseRequestHandler { /// @@ -33,5 +33,4 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers context.Response.Write(config, false); context.Response.End(); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs index 150b7818..289e0356 100644 --- a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs +++ b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs @@ -10,40 +10,40 @@ using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common -{ +namespace PepperDash.Essentials.Devices.Common; + /// /// Represents and audio endpoint /// public class GenericAudioOut : EssentialsDevice, IRoutingSink { - public RoutingInputPort CurrentInputPort => AnyAudioIn; + public RoutingInputPort CurrentInputPort => AnyAudioIn; - public event SourceInfoChangeHandler CurrentSourceChange; + public event SourceInfoChangeHandler CurrentSourceChange; - public string CurrentSourceInfoKey { get; set; } - public SourceListItem CurrentSourceInfo + public string CurrentSourceInfoKey { get; set; } + public SourceListItem CurrentSourceInfo + { + get { - get - { - return _CurrentSourceInfo; - } - set - { - if (value == _CurrentSourceInfo) return; - - var handler = CurrentSourceChange; - - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); - - _CurrentSourceInfo = value; - - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); - } + return _CurrentSourceInfo; } - SourceListItem _CurrentSourceInfo; + set + { + if (value == _CurrentSourceInfo) return; + + var handler = CurrentSourceChange; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); + + _CurrentSourceInfo = value; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); + } + } + SourceListItem _CurrentSourceInfo; public RoutingInputPort AnyAudioIn { get; private set; } @@ -102,20 +102,18 @@ namespace PepperDash.Essentials.Devices.Common } - public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory +public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory +{ + public GenericAudioOutWithVolumeFactory() { - public GenericAudioOutWithVolumeFactory() - { - TypeNames = new List() { "genericaudiooutwithvolume" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new GenericAudioOutWithVolumeFactory Device"); - var zone = dc.Properties.Value("zone"); - return new GenericAudioOutWithVolume(dc.Key, dc.Name, - dc.Properties.Value("volumeDeviceKey"), zone); - } + TypeNames = new List() { "genericaudiooutwithvolume" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new GenericAudioOutWithVolumeFactory Device"); + var zone = dc.Properties.Value("zone"); + return new GenericAudioOutWithVolume(dc.Key, dc.Name, + dc.Properties.Value("volumeDeviceKey"), zone); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs index 56998d46..4668f754 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs @@ -8,97 +8,96 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo { - public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo + + public event EventHandler CallStatusChange; + + public AudioCodecInfo CodecInfo { get; protected set; } + + #region IUsageTracking Members + + /// + /// This object can be added by outside users of this class to provide usage tracking + /// for various services + /// + public UsageTracking UsageTracker { get; set; } + + #endregion + + /// + /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected + /// + public bool IsInCall { - - public event EventHandler CallStatusChange; - - public AudioCodecInfo CodecInfo { get; protected set; } - - #region IUsageTracking Members - - /// - /// This object can be added by outside users of this class to provide usage tracking - /// for various services - /// - public UsageTracking UsageTracker { get; set; } - - #endregion - - /// - /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected - /// - public bool IsInCall + get { - get - { - bool value; + bool value; - if (ActiveCalls != null) - value = ActiveCalls.Any(c => c.IsActiveCall); - else - value = false; - return value; - } + if (ActiveCalls != null) + value = ActiveCalls.Any(c => c.IsActiveCall); + else + value = false; + return value; } - - // In most cases only a single call can be active - public List ActiveCalls { get; set; } - - public AudioCodecBase(string key, string name) - : base(key, name) - { - ActiveCalls = new List(); - } - - /// - /// Helper method to fire CallStatusChange event with old and new status - /// - protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) - { - call.Status = newStatus; - - OnCallStatusChange(call); - - } - - /// - /// - /// - /// - /// - /// - protected void OnCallStatusChange(CodecActiveCallItem item) - { - var handler = CallStatusChange; - if (handler != null) - handler(this, new CodecCallStatusItemChangeEventArgs(item)); - - if (UsageTracker != null) - { - if (IsInCall && !UsageTracker.UsageTrackingStarted) - UsageTracker.StartDeviceUsage(); - else if (UsageTracker.UsageTrackingStarted && !IsInCall) - UsageTracker.EndDeviceUsage(); - } - } - - #region IHasDialer Members - - public abstract void Dial(string number); - - public abstract void EndCall(CodecActiveCallItem activeCall); - - public abstract void EndAllCalls(); - - public abstract void AcceptCall(CodecActiveCallItem item); - - public abstract void RejectCall(CodecActiveCallItem item); - - public abstract void SendDtmf(string digit); - - #endregion } + + // In most cases only a single call can be active + public List ActiveCalls { get; set; } + + public AudioCodecBase(string key, string name) + : base(key, name) + { + ActiveCalls = new List(); + } + + /// + /// Helper method to fire CallStatusChange event with old and new status + /// + protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) + { + call.Status = newStatus; + + OnCallStatusChange(call); + + } + + /// + /// + /// + /// + /// + /// + protected void OnCallStatusChange(CodecActiveCallItem item) + { + var handler = CallStatusChange; + if (handler != null) + handler(this, new CodecCallStatusItemChangeEventArgs(item)); + + if (UsageTracker != null) + { + if (IsInCall && !UsageTracker.UsageTrackingStarted) + UsageTracker.StartDeviceUsage(); + else if (UsageTracker.UsageTrackingStarted && !IsInCall) + UsageTracker.EndDeviceUsage(); + } + } + + #region IHasDialer Members + + public abstract void Dial(string number); + + public abstract void EndCall(CodecActiveCallItem activeCall); + + public abstract void EndAllCalls(); + + public abstract void AcceptCall(CodecActiveCallItem item); + + public abstract void RejectCall(CodecActiveCallItem item); + + public abstract void SendDtmf(string digit); + + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs index e853c898..8d6a1778 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs @@ -4,21 +4,20 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.AudioCodec -{ - /// - /// Implements a common set of data about a codec - /// - public interface IAudioCodecInfo - { - AudioCodecInfo CodecInfo { get; } - } +namespace PepperDash.Essentials.Devices.Common.AudioCodec; - /// - /// Stores general information about a codec - /// - public abstract class AudioCodecInfo - { - public abstract string PhoneNumber { get; set; } - } +/// +/// Implements a common set of data about a codec +/// +public interface IAudioCodecInfo +{ + AudioCodecInfo CodecInfo { get; } +} + +/// +/// Stores general information about a codec +/// +public abstract class AudioCodecInfo +{ + public abstract string PhoneNumber { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs index b6fa079d..edefe5e1 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs @@ -6,18 +6,17 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.AudioCodec -{ - /// - /// For rooms that have audio codec - /// - public interface IHasAudioCodec:IHasInCallFeedback - { - AudioCodecBase AudioCodec { get; } +namespace PepperDash.Essentials.Devices.Common.AudioCodec; - ///// - ///// Make this more specific - ///// - //List ActiveCalls { get; } - } +/// +/// For rooms that have audio codec +/// +public interface IHasAudioCodec:IHasInCallFeedback +{ + AudioCodecBase AudioCodec { get; } + + ///// + ///// Make this more specific + ///// + //List ActiveCalls { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs index 502902b9..79915447 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs @@ -10,123 +10,121 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Devices.Common.Codec; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +public class MockAC : AudioCodecBase { - public class MockAC : AudioCodecBase + public MockAC(string key, string name, MockAcPropertiesConfig props) + : base(key, name) { - public MockAC(string key, string name, MockAcPropertiesConfig props) - : base(key, name) - { - CodecInfo = new MockAudioCodecInfo(); + CodecInfo = new MockAudioCodecInfo(); - CodecInfo.PhoneNumber = props.PhoneNumber; - } + CodecInfo.PhoneNumber = props.PhoneNumber; + } - public override void Dial(string number) + public override void Dial(string number) + { + if (!IsInCall) { - if (!IsInCall) + Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); + var call = new CodecActiveCallItem() { - Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); - var call = new CodecActiveCallItem() - { - Name = "Mock Outgoing Call", - Number = number, - Type = eCodecCallType.Audio, - Status = eCodecCallStatus.Connected, - Direction = eCodecCallDirection.Outgoing, - Id = "mockAudioCall-1" - }; + Name = "Mock Outgoing Call", + Number = number, + Type = eCodecCallType.Audio, + Status = eCodecCallStatus.Connected, + Direction = eCodecCallDirection.Outgoing, + Id = "mockAudioCall-1" + }; - ActiveCalls.Add(call); - - OnCallStatusChange(call); - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Already in call. Cannot dial new call."); - } - } - - public override void EndCall(CodecActiveCallItem call) - { - Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); - ActiveCalls.Remove(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - } - - public override void EndAllCalls() - { - Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); - for (int i = ActiveCalls.Count - 1; i >= 0; i--) - { - var call = ActiveCalls[i]; - ActiveCalls.Remove(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - } - } - - public override void AcceptCall(CodecActiveCallItem call) - { - Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); - } - - public override void RejectCall(CodecActiveCallItem call) - { - Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); - ActiveCalls.Remove(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - } - - public override void SendDtmf(string s) - { - Debug.LogMessage(LogEventLevel.Debug, this, "BEEP BOOP SendDTMF: {0}", s); - } - - /// - /// - /// - /// - public void TestIncomingAudioCall(string number) - { - Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", number); - var call = new CodecActiveCallItem() { Name = number, Id = number, Number = number, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming }; ActiveCalls.Add(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); - } + OnCallStatusChange(call); + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Already in call. Cannot dial new call."); + } } - public class MockAudioCodecInfo : AudioCodecInfo + public override void EndCall(CodecActiveCallItem call) { - string _phoneNumber; - - public override string PhoneNumber - { - get - { - return _phoneNumber; - } - set - { - _phoneNumber = value; - } - } + Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } - public class MockACFactory : EssentialsDeviceFactory + public override void EndAllCalls() { - public MockACFactory() + Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); + for (int i = ActiveCalls.Count - 1; i >= 0; i--) { - TypeNames = new List() { "mockac" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MockAc Device"); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); - return new AudioCodec.MockAC(dc.Key, dc.Name, props); + var call = ActiveCalls[i]; + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } } + public override void AcceptCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); + } + + public override void RejectCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); + } + + public override void SendDtmf(string s) + { + Debug.LogMessage(LogEventLevel.Debug, this, "BEEP BOOP SendDTMF: {0}", s); + } + + /// + /// + /// + /// + public void TestIncomingAudioCall(string number) + { + Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", number); + var call = new CodecActiveCallItem() { Name = number, Id = number, Number = number, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming }; + ActiveCalls.Add(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); + } + +} + +public class MockAudioCodecInfo : AudioCodecInfo +{ + string _phoneNumber; + + public override string PhoneNumber + { + get + { + return _phoneNumber; + } + set + { + _phoneNumber = value; + } + } +} + +public class MockACFactory : EssentialsDeviceFactory +{ + public MockACFactory() + { + TypeNames = new List() { "mockac" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MockAc Device"); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); + return new AudioCodec.MockAC(dc.Key, dc.Name, props); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs index c9d041eb..387d3bc1 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs @@ -8,11 +8,10 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec; + +public class MockAcPropertiesConfig { - public class MockAcPropertiesConfig - { - [JsonProperty("phoneNumber")] - public string PhoneNumber { get; set; } - } + [JsonProperty("phoneNumber")] + public string PhoneNumber { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs index c008e969..fe9015aa 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs @@ -19,64 +19,64 @@ using PepperDash.Essentials.Devices.Common.Codec; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +public enum eCameraCapabilities { - public enum eCameraCapabilities + None = 0, + Pan = 1, + Tilt = 2, + Zoom = 4, + Focus = 8 +} + +public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs + { + [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] + public eCameraControlMode ControlMode { get; protected set; } + + #region IRoutingOutputs Members + + [JsonIgnore] + public RoutingPortCollection OutputPorts { get; protected set; } + + #endregion + + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + public bool CanPan { - None = 0, - Pan = 1, - Tilt = 2, - Zoom = 4, - Focus = 8 + get + { + return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; + } + } + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + public bool CanTilt + { + get + { + return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; + } + } + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + public bool CanZoom + { + get + { + return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; + } + } + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + public bool CanFocus + { + get + { + return (Capabilities & eCameraCapabilities.Focus) == eCameraCapabilities.Focus; + } } - public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs - { - [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] - public eCameraControlMode ControlMode { get; protected set; } - - #region IRoutingOutputs Members - - [JsonIgnore] - public RoutingPortCollection OutputPorts { get; protected set; } - - #endregion - - [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] - public bool CanPan - { - get - { - return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; - } - } - [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] - public bool CanTilt - { - get - { - return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; - } - } - [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] - public bool CanZoom - { - get - { - return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; - } - } - [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] - public bool CanFocus - { - get - { - return (Capabilities & eCameraCapabilities.Focus) == eCameraCapabilities.Focus; - } - } - - // A bitmasked value to indicate the movement capabilites of this camera - protected eCameraCapabilities Capabilities { get; set; } + // A bitmasked value to indicate the movement capabilites of this camera + protected eCameraCapabilities Capabilities { get; set; } protected CameraBase(DeviceConfig config) : base(config) { @@ -86,199 +86,199 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } - protected CameraBase(string key, string name) : + protected CameraBase(string key, string name) : this (new DeviceConfig{Name = name, Key = key}) - { + { + } + + protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey, + EiscApiAdvanced bridge) + { + CameraControllerJoinMap joinMap = new CameraControllerJoinMap(joinStart); + + 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."); } - protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey, - EiscApiAdvanced bridge) + var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); + + if (customJoins != null) { - CameraControllerJoinMap joinMap = new CameraControllerJoinMap(joinStart); + joinMap.SetCustomJoinData(customJoins); + } - if (bridge != null) + Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + Debug.LogMessage(LogEventLevel.Information, "Linking to Bridge Type {0}", cameraDevice.GetType().Name.ToString()); + + var commMonitor = cameraDevice as ICommunicationMonitor; + commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); + + var ptzCamera = cameraDevice as IHasCameraPtzControl; + + if (ptzCamera != null) + { + trilist.SetBoolSigAction(joinMap.PanLeft.JoinNumber, (b) => { - 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."); - } - - var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); - - if (customJoins != null) - { - joinMap.SetCustomJoinData(customJoins); - } - - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - Debug.LogMessage(LogEventLevel.Information, "Linking to Bridge Type {0}", cameraDevice.GetType().Name.ToString()); - - var commMonitor = cameraDevice as ICommunicationMonitor; - commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig( - trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); - - var ptzCamera = cameraDevice as IHasCameraPtzControl; - - if (ptzCamera != null) - { - trilist.SetBoolSigAction(joinMap.PanLeft.JoinNumber, (b) => + if (b) { - if (b) - { - ptzCamera.PanLeft(); - } - else - { - ptzCamera.PanStop(); - } - }); - trilist.SetBoolSigAction(joinMap.PanRight.JoinNumber, (b) => - { - if (b) - { - ptzCamera.PanRight(); - } - else - { - ptzCamera.PanStop(); - } - }); - - trilist.SetBoolSigAction(joinMap.TiltUp.JoinNumber, (b) => - { - if (b) - { - ptzCamera.TiltUp(); - } - else - { - ptzCamera.TiltStop(); - } - }); - trilist.SetBoolSigAction(joinMap.TiltDown.JoinNumber, (b) => - { - if (b) - { - ptzCamera.TiltDown(); - } - else - { - ptzCamera.TiltStop(); - } - }); - - trilist.SetBoolSigAction(joinMap.ZoomIn.JoinNumber, (b) => - { - if (b) - { - ptzCamera.ZoomIn(); - } - else - { - ptzCamera.ZoomStop(); - } - }); - - trilist.SetBoolSigAction(joinMap.ZoomOut.JoinNumber, (b) => - { - if (b) - { - ptzCamera.ZoomOut(); - } - else - { - ptzCamera.ZoomStop(); - } - }); - } - - var powerCamera = cameraDevice as IHasPowerControl; - if (powerCamera != null) - { - trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => powerCamera.PowerOn()); - trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => powerCamera.PowerOff()); - - var powerFbCamera = powerCamera as IHasPowerControlWithFeedback; - if (powerFbCamera != null) - { - powerFbCamera.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); - powerFbCamera.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); + ptzCamera.PanLeft(); } - } - - if (cameraDevice is ICommunicationMonitor) - { - var monitoredCamera = cameraDevice as ICommunicationMonitor; - monitoredCamera.CommunicationMonitor.IsOnlineFeedback.LinkInputSig( - trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); - } - - if (cameraDevice is IHasCameraPresets) - { - // Set the preset lables when they change - var presetsCamera = cameraDevice as IHasCameraPresets; - presetsCamera.PresetsListHasChanged += new EventHandler((o, a) => + else { - SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); + ptzCamera.PanStop(); + } + }); + trilist.SetBoolSigAction(joinMap.PanRight.JoinNumber, (b) => + { + if (b) + { + ptzCamera.PanRight(); + } + else + { + ptzCamera.PanStop(); + } + }); + + trilist.SetBoolSigAction(joinMap.TiltUp.JoinNumber, (b) => + { + if (b) + { + ptzCamera.TiltUp(); + } + else + { + ptzCamera.TiltStop(); + } + }); + trilist.SetBoolSigAction(joinMap.TiltDown.JoinNumber, (b) => + { + if (b) + { + ptzCamera.TiltDown(); + } + else + { + ptzCamera.TiltStop(); + } + }); + + trilist.SetBoolSigAction(joinMap.ZoomIn.JoinNumber, (b) => + { + if (b) + { + ptzCamera.ZoomIn(); + } + else + { + ptzCamera.ZoomStop(); + } + }); + + trilist.SetBoolSigAction(joinMap.ZoomOut.JoinNumber, (b) => + { + if (b) + { + ptzCamera.ZoomOut(); + } + else + { + ptzCamera.ZoomStop(); + } + }); + } + + var powerCamera = cameraDevice as IHasPowerControl; + if (powerCamera != null) + { + trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => powerCamera.PowerOn()); + trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => powerCamera.PowerOff()); + + var powerFbCamera = powerCamera as IHasPowerControlWithFeedback; + if (powerFbCamera != null) + { + powerFbCamera.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); + powerFbCamera.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); + } + } + + if (cameraDevice is ICommunicationMonitor) + { + var monitoredCamera = cameraDevice as ICommunicationMonitor; + monitoredCamera.CommunicationMonitor.IsOnlineFeedback.LinkInputSig( + trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); + } + + if (cameraDevice is IHasCameraPresets) + { + // Set the preset lables when they change + var presetsCamera = cameraDevice as IHasCameraPresets; + presetsCamera.PresetsListHasChanged += new EventHandler((o, a) => + { + SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); + }); + + SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); + + for (int i = 0; i < joinMap.PresetRecallStart.JoinSpan; i++) + { + int tempNum = i; + + trilist.SetSigTrueAction((ushort) (joinMap.PresetRecallStart.JoinNumber + tempNum), () => + { + presetsCamera.PresetSelect(tempNum); }); + trilist.SetSigTrueAction((ushort) (joinMap.PresetSaveStart.JoinNumber + tempNum), () => + { + var label = trilist.GetString((ushort) (joinMap.PresetLabelStart.JoinNumber + tempNum)); + + presetsCamera.PresetStore(tempNum, label); + }); + } + trilist.OnlineStatusChange += (sender, args) => + { + if (!args.DeviceOnLine) + { return; } SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); - - for (int i = 0; i < joinMap.PresetRecallStart.JoinSpan; i++) - { - int tempNum = i; - - trilist.SetSigTrueAction((ushort) (joinMap.PresetRecallStart.JoinNumber + tempNum), () => - { - presetsCamera.PresetSelect(tempNum); - }); - trilist.SetSigTrueAction((ushort) (joinMap.PresetSaveStart.JoinNumber + tempNum), () => - { - var label = trilist.GetString((ushort) (joinMap.PresetLabelStart.JoinNumber + tempNum)); - - presetsCamera.PresetStore(tempNum, label); - }); - } - trilist.OnlineStatusChange += (sender, args) => - { - if (!args.DeviceOnLine) - { return; } - - SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); - }; - - } - } - private void SendCameraPresetNamesToApi(IHasCameraPresets presetsCamera, CameraControllerJoinMap joinMap, BasicTriList trilist) - { - for (int i = 1; i <= joinMap.NumberOfPresets.JoinNumber; i++) - { - int tempNum = i - 1; - - string label = ""; - - var preset = presetsCamera.Presets.FirstOrDefault(p => p.ID.Equals(i)); - - if (preset != null) - label = preset.Description; - - trilist.SetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum), label); - } - } - } - - - public class CameraPreset : PresetBase - { - public CameraPreset(int id, string description, bool isDefined, bool isDefinable) - : base(id, description, isDefined, isDefinable) - { + }; } } + private void SendCameraPresetNamesToApi(IHasCameraPresets presetsCamera, CameraControllerJoinMap joinMap, BasicTriList trilist) + { + for (int i = 1; i <= joinMap.NumberOfPresets.JoinNumber; i++) + { + int tempNum = i - 1; + + string label = ""; + + var preset = presetsCamera.Presets.FirstOrDefault(p => p.ID.Equals(i)); + + if (preset != null) + label = preset.Description; + + trilist.SetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum), label); + } + } + } + + +public class CameraPreset : PresetBase +{ + public CameraPreset(int id, string description, bool isDefined, bool isDefinable) + : base(id, description, isDefined, isDefinable) + { + + } +} public class CameraPropertiesConfig @@ -287,13 +287,12 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public ControlPropertiesConfig Control { get; set; } - [JsonProperty("supportsAutoMode")] - public bool SupportsAutoMode { get; set; } + [JsonProperty("supportsAutoMode")] + public bool SupportsAutoMode { get; set; } - [JsonProperty("supportsOffMode")] - public bool SupportsOffMode { get; set; } + [JsonProperty("supportsOffMode")] + public bool SupportsOffMode { get; set; } - [JsonProperty("presets")] - public List Presets { get; set; } - } -} \ No newline at end of file + [JsonProperty("presets")] + public List Presets { get; set; } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs index cbf53476..1f97f191 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs @@ -6,161 +6,156 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +public enum eCameraControlMode +{ + Manual = 0, + Off, + Auto +} + + +public interface IHasCameras { - public enum eCameraControlMode - { - Manual = 0, - Off, - Auto - } + event EventHandler CameraSelected; + List Cameras { get; } - public interface IHasCameras + CameraBase SelectedCamera { get; } + + StringFeedback SelectedCameraFeedback { get; } + + void SelectCamera(string key); +} + +/// +/// Aggregates far end cameras with near end cameras +/// +public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl +{ + +} + +/// +/// To be implmented on codecs that can disable their camera(s) to blank the near end video +/// +public interface IHasCameraOff +{ + BoolFeedback CameraIsOffFeedback { get; } + void CameraOff(); +} + +/// +/// Describes the ability to mute and unmute camera video +/// +public interface IHasCameraMute +{ + BoolFeedback CameraIsMutedFeedback { get; } + void CameraMuteOn(); + void CameraMuteOff(); + void CameraMuteToggle(); +} + +public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute +{ + event EventHandler VideoUnmuteRequested; +} + +public class CameraSelectedEventArgs : EventArgs +{ + public CameraBase SelectedCamera { get; private set; } + + public CameraSelectedEventArgs(CameraBase camera) { - event EventHandler CameraSelected; - - List Cameras { get; } - - CameraBase SelectedCamera { get; } - - StringFeedback SelectedCameraFeedback { get; } - - void SelectCamera(string key); + SelectedCamera = camera; } +} +public interface IHasFarEndCameraControl +{ + CameraBase FarEndCamera { get; } + + BoolFeedback ControllingFarEndCameraFeedback { get; } + +} + +/// +/// Used to decorate a camera as a far end +/// +public interface IAmFarEndCamera +{ + +} + +public interface IHasCameraControls +{ +} + +/// +/// Aggregates the pan, tilt and zoom interfaces +/// +public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl +{ /// - /// Aggregates far end cameras with near end cameras + /// Resets the camera position /// - public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl - { + void PositionHome(); +} - } +/// +/// Interface for camera pan control +/// +public interface IHasCameraPanControl : IHasCameraControls +{ + void PanLeft(); + void PanRight(); + void PanStop(); +} - /// - /// To be implmented on codecs that can disable their camera(s) to blank the near end video - /// - public interface IHasCameraOff - { - BoolFeedback CameraIsOffFeedback { get; } - void CameraOff(); - } +/// +/// Interface for camera tilt control +/// +public interface IHasCameraTiltControl : IHasCameraControls +{ + void TiltDown(); + void TiltUp(); + void TiltStop(); +} - /// - /// Describes the ability to mute and unmute camera video - /// - public interface IHasCameraMute - { - BoolFeedback CameraIsMutedFeedback { get; } - void CameraMuteOn(); - void CameraMuteOff(); - void CameraMuteToggle(); - } - - public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute - { - event EventHandler VideoUnmuteRequested; - } - - public class CameraSelectedEventArgs : EventArgs - { - public CameraBase SelectedCamera { get; private set; } - - public CameraSelectedEventArgs(CameraBase camera) - { - SelectedCamera = camera; - } - } - - public interface IHasFarEndCameraControl - { - CameraBase FarEndCamera { get; } - - BoolFeedback ControllingFarEndCameraFeedback { get; } - - } - - /// - /// Used to decorate a camera as a far end - /// - public interface IAmFarEndCamera - { - - } - - public interface IHasCameraControls - { - } - - /// - /// Aggregates the pan, tilt and zoom interfaces - /// - public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl - { - /// - /// Resets the camera position - /// - void PositionHome(); - } - - /// - /// Interface for camera pan control - /// - public interface IHasCameraPanControl : IHasCameraControls - { - void PanLeft(); - void PanRight(); - void PanStop(); - } - - /// - /// Interface for camera tilt control - /// - public interface IHasCameraTiltControl : IHasCameraControls - { - void TiltDown(); - void TiltUp(); - void TiltStop(); - } - - /// - /// Interface for camera zoom control - /// - public interface IHasCameraZoomControl : IHasCameraControls - { - void ZoomIn(); - void ZoomOut(); - void ZoomStop(); - } - - /// - /// Interface for camera focus control - /// - public interface IHasCameraFocusControl : IHasCameraControls - { - void FocusNear(); - void FocusFar(); - void FocusStop(); - - void TriggerAutoFocus(); - } - - public interface IHasAutoFocusMode - { - void SetFocusModeAuto(); - void SetFocusModeManual(); - void ToggleFocusMode(); - } - - public interface IHasCameraAutoMode : IHasCameraControls - { - void CameraAutoModeOn(); - void CameraAutoModeOff(); - void CameraAutoModeToggle(); - BoolFeedback CameraAutoModeIsOnFeedback { get; } - } +/// +/// Interface for camera zoom control +/// +public interface IHasCameraZoomControl : IHasCameraControls +{ + void ZoomIn(); + void ZoomOut(); + void ZoomStop(); +} +/// +/// Interface for camera focus control +/// +public interface IHasCameraFocusControl : IHasCameraControls +{ + void FocusNear(); + void FocusFar(); + void FocusStop(); + void TriggerAutoFocus(); +} +public interface IHasAutoFocusMode +{ + void SetFocusModeAuto(); + void SetFocusModeManual(); + void ToggleFocusMode(); +} +public interface IHasCameraAutoMode : IHasCameraControls +{ + void CameraAutoModeOn(); + void CameraAutoModeOff(); + void CameraAutoModeToggle(); + BoolFeedback CameraAutoModeIsOnFeedback { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs index 384d60a3..9c07a1ea 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs @@ -17,103 +17,103 @@ using System.Reflection; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Cameras -{ +namespace PepperDash.Essentials.Devices.Common.Cameras; + public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode { - private readonly CameraViscaPropertiesConfig PropertiesConfig; + private readonly CameraViscaPropertiesConfig PropertiesConfig; public IBasicCommunication Communication { get; private set; } public StatusMonitorBase CommunicationMonitor { get; private set; } - /// - /// Used to store the actions to parse inquiry responses as the inquiries are sent - /// - private readonly CrestronQueue> InquiryResponseQueue; + /// + /// Used to store the actions to parse inquiry responses as the inquiries are sent + /// + private readonly CrestronQueue> InquiryResponseQueue; - /// - /// Camera ID (Default 1) - /// - public byte ID = 0x01; - public byte ResponseID; + /// + /// Camera ID (Default 1) + /// + public byte ID = 0x01; + public byte ResponseID; public byte PanSpeedSlow = 0x10; public byte TiltSpeedSlow = 0x10; - public byte PanSpeedFast = 0x13; - public byte TiltSpeedFast = 0x13; + public byte PanSpeedFast = 0x13; + public byte TiltSpeedFast = 0x13; - // private bool IsMoving; + // private bool IsMoving; private bool IsZooming; - bool _powerIsOn; + bool _powerIsOn; public bool PowerIsOn + { + get { - get + return _powerIsOn; + } + private set + { + if (value != _powerIsOn) { - return _powerIsOn; - } - private set - { - if (value != _powerIsOn) - { - _powerIsOn = value; - PowerIsOnFeedback.FireUpdate(); - CameraIsOffFeedback.FireUpdate(); - } + _powerIsOn = value; + PowerIsOnFeedback.FireUpdate(); + CameraIsOffFeedback.FireUpdate(); } } + } - const byte ZoomInCmd = 0x02; - const byte ZoomOutCmd = 0x03; - const byte ZoomStopCmd = 0x00; + const byte ZoomInCmd = 0x02; + const byte ZoomOutCmd = 0x03; + const byte ZoomStopCmd = 0x00; - /// - /// Used to determine when to move the camera at a faster speed if a direction is held - /// - CTimer SpeedTimer; - // TODO: Implment speed timer for PTZ controls + /// + /// Used to determine when to move the camera at a faster speed if a direction is held + /// + CTimer SpeedTimer; + // TODO: Implment speed timer for PTZ controls - long FastSpeedHoldTimeMs = 2000; + long FastSpeedHoldTimeMs = 2000; byte[] IncomingBuffer = new byte[] { }; public BoolFeedback PowerIsOnFeedback { get; private set; } - public CameraVisca(string key, string name, IBasicCommunication comm, CameraViscaPropertiesConfig props) : + public CameraVisca(string key, string name, IBasicCommunication comm, CameraViscaPropertiesConfig props) : base(key, name) { - InquiryResponseQueue = new CrestronQueue>(15); + InquiryResponseQueue = new CrestronQueue>(15); - Presets = props.Presets; + Presets = props.Presets; - PropertiesConfig = props; + PropertiesConfig = props; - ID = (byte)(props.Id + 0x80); - ResponseID = (byte)((props.Id * 0x10) + 0x80); + ID = (byte)(props.Id + 0x80); + ResponseID = (byte)((props.Id * 0x10) + 0x80); - SetupCameraSpeeds(); + SetupCameraSpeeds(); - OutputPorts.Add(new RoutingOutputPort("videoOut", eRoutingSignalType.Video, eRoutingPortConnectionType.None, null, this, true)); + OutputPorts.Add(new RoutingOutputPort("videoOut", eRoutingSignalType.Video, eRoutingPortConnectionType.None, null, this, true)); - // Default to all capabilties - Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; - - Communication = comm; - if (comm is ISocketStatus socket) - { - // This instance uses IP control - socket.ConnectionChange += new EventHandler(Socket_ConnectionChange); - } - else - { - // This instance uses RS-232 control - } + // Default to all capabilties + Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; + + Communication = comm; + if (comm is ISocketStatus socket) + { + // This instance uses IP control + socket.ConnectionChange += new EventHandler(Socket_ConnectionChange); + } + else + { + // This instance uses RS-232 control + } - Communication.BytesReceived += new EventHandler(Communication_BytesReceived); + Communication.BytesReceived += new EventHandler(Communication_BytesReceived); PowerIsOnFeedback = new BoolFeedback(() => { return PowerIsOn; }); - CameraIsOffFeedback = new BoolFeedback(() => { return !PowerIsOn; }); + CameraIsOffFeedback = new BoolFeedback(() => { return !PowerIsOn; }); if (props.CommunicationMonitorProperties != null) { @@ -127,35 +127,35 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } - /// - /// Sets up camera speed values based on config - /// - void SetupCameraSpeeds() + /// + /// Sets up camera speed values based on config + /// + void SetupCameraSpeeds() + { + if (PropertiesConfig.FastSpeedHoldTimeMs > 0) { - if (PropertiesConfig.FastSpeedHoldTimeMs > 0) - { - FastSpeedHoldTimeMs = PropertiesConfig.FastSpeedHoldTimeMs; - } - - if (PropertiesConfig.PanSpeedSlow > 0) - { - PanSpeedSlow = (byte)PropertiesConfig.PanSpeedSlow; - } - if (PropertiesConfig.PanSpeedFast > 0) - { - PanSpeedFast = (byte)PropertiesConfig.PanSpeedFast; - } - - if (PropertiesConfig.TiltSpeedSlow > 0) - { - TiltSpeedSlow = (byte)PropertiesConfig.TiltSpeedSlow; - } - if (PropertiesConfig.TiltSpeedFast > 0) - { - TiltSpeedFast = (byte)PropertiesConfig.TiltSpeedFast; - } + FastSpeedHoldTimeMs = PropertiesConfig.FastSpeedHoldTimeMs; } + if (PropertiesConfig.PanSpeedSlow > 0) + { + PanSpeedSlow = (byte)PropertiesConfig.PanSpeedSlow; + } + if (PropertiesConfig.PanSpeedFast > 0) + { + PanSpeedFast = (byte)PropertiesConfig.PanSpeedFast; + } + + if (PropertiesConfig.TiltSpeedSlow > 0) + { + TiltSpeedSlow = (byte)PropertiesConfig.TiltSpeedSlow; + } + if (PropertiesConfig.TiltSpeedFast > 0) + { + TiltSpeedFast = (byte)PropertiesConfig.TiltSpeedFast; + } + } + public override bool CustomActivate() { Communication.Connect(); @@ -200,250 +200,250 @@ namespace PepperDash.Essentials.Devices.Common.Cameras void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) { - var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length]; + var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length]; - try + try + { + // This is probably not thread-safe buffering + // Append the incoming bytes with whatever is in the buffer + IncomingBuffer.CopyTo(newBytes, 0); + e.Bytes.CopyTo(newBytes, IncomingBuffer.Length); + if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1 + Debug.LogMessage(LogEventLevel.Verbose, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes)); + + byte[] message = new byte[] { }; + + // Search for the delimiter 0xFF character + for (int i = 0; i < newBytes.Length; i++) { - // This is probably not thread-safe buffering - // Append the incoming bytes with whatever is in the buffer - IncomingBuffer.CopyTo(newBytes, 0); - e.Bytes.CopyTo(newBytes, IncomingBuffer.Length); - if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1 - Debug.LogMessage(LogEventLevel.Verbose, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes)); - - byte[] message = new byte[] { }; - - // Search for the delimiter 0xFF character - for (int i = 0; i < newBytes.Length; i++) + if (newBytes[i] == 0xFF) { - if (newBytes[i] == 0xFF) - { - // i will be the index of the delmiter character - message = newBytes.Take(i).ToArray(); - // Skip over what we just took and save the rest for next time - newBytes = newBytes.Skip(i).ToArray(); - } + // i will be the index of the delmiter character + message = newBytes.Take(i).ToArray(); + // Skip over what we just took and save the rest for next time + newBytes = newBytes.Skip(i).ToArray(); + } + } + + if (message.Length > 0) + { + // Check for matching ID + if (message[0] != ResponseID) + { + return; } - if (message.Length > 0) + switch (message[1]) { - // Check for matching ID - if (message[0] != ResponseID) - { - return; - } + case 0x40: + { + // ACK received + Debug.LogMessage(LogEventLevel.Verbose, this, "ACK Received"); + break; + } + case 0x50: + { - switch (message[1]) - { - case 0x40: + if (message[2] == 0xFF) { - // ACK received - Debug.LogMessage(LogEventLevel.Verbose, this, "ACK Received"); - break; + // Completion received + Debug.LogMessage(LogEventLevel.Verbose, this, "Completion Received"); } - case 0x50: + else { - - if (message[2] == 0xFF) + // Inquiry response received. Dequeue the next response handler and invoke it + if (InquiryResponseQueue.Count > 0) { - // Completion received - Debug.LogMessage(LogEventLevel.Verbose, this, "Completion Received"); + var inquiryAction = InquiryResponseQueue.Dequeue(); + + inquiryAction.Invoke(message.Skip(2).ToArray()); } else { - // Inquiry response received. Dequeue the next response handler and invoke it - if (InquiryResponseQueue.Count > 0) - { - var inquiryAction = InquiryResponseQueue.Dequeue(); - - inquiryAction.Invoke(message.Skip(2).ToArray()); - } - else - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Response Queue is empty. Nothing to dequeue."); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Response Queue is empty. Nothing to dequeue."); } - - break; } - case 0x60: + + break; + } + case 0x60: + { + // Error message + + switch (message[2]) { - // Error message - - switch (message[2]) - { - case 0x01: - { - // Message Length Error - Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Message Length Error"); - break; - } - case 0x02: - { - // Syntax Error - Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Syntax Error"); - break; - } - case 0x03: - { - // Command Buffer Full - Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command Buffer Full"); - break; - } - case 0x04: - { - // Command Cancelled - Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command Cancelled"); - break; - } - case 0x05: - { - // No Socket - Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: No Socket"); - break; - } - case 0x41: - { - // Command not executable - Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command not executable"); - break; - } - } - break; + case 0x01: + { + // Message Length Error + Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Message Length Error"); + break; + } + case 0x02: + { + // Syntax Error + Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Syntax Error"); + break; + } + case 0x03: + { + // Command Buffer Full + Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command Buffer Full"); + break; + } + case 0x04: + { + // Command Cancelled + Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command Cancelled"); + break; + } + case 0x05: + { + // No Socket + Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: No Socket"); + break; + } + case 0x41: + { + // Command not executable + Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command not executable"); + break; + } } - } - - if (message == new byte[] { ResponseID, 0x50, 0x02, 0xFF }) - { - PowerIsOn = true; - } - else if (message == new byte[] { ResponseID, 0x50, 0x03, 0xFF }) - { - PowerIsOn = false; - } + break; + } + } + if (message == new byte[] { ResponseID, 0x50, 0x02, 0xFF }) + { + PowerIsOn = true; + } + else if (message == new byte[] { ResponseID, 0x50, 0x03, 0xFF }) + { + PowerIsOn = false; } } - catch (Exception err) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error parsing feedback: {0}", err); - } - finally - { - // Save whatever partial message is here - IncomingBuffer = newBytes; - } - } - /// - /// Sends a pan/tilt command. If the command is not for fastSpeed then it starts a timer to initiate fast speed. - /// - /// - /// + } + catch (Exception err) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Error parsing feedback: {0}", err); + } + finally + { + // Save whatever partial message is here + IncomingBuffer = newBytes; + } + } + + /// + /// Sends a pan/tilt command. If the command is not for fastSpeed then it starts a timer to initiate fast speed. + /// + /// + /// private void SendPanTiltCommand (byte[] cmd, bool fastSpeedEnabled) { - SendBytes(GetPanTiltCommand(cmd, fastSpeedEnabled)); + SendBytes(GetPanTiltCommand(cmd, fastSpeedEnabled)); - if (!fastSpeedEnabled) - { - if (SpeedTimer != null) - { - StopSpeedTimer(); - } - - // Start the timer to send fast speed if still moving after FastSpeedHoldTime elapses - SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs); - } - - } - - private void StopSpeedTimer() + if (!fastSpeedEnabled) { if (SpeedTimer != null) { - SpeedTimer.Stop(); - SpeedTimer.Dispose(); - SpeedTimer = null; - } - } - - /// - /// Generates the pan/tilt command with either slow or fast speed - /// - /// - /// - /// - private byte[] GetPanTiltCommand(byte[] cmd, bool fastSpeed) - { - byte panSpeed; - byte tiltSpeed; - - if (!fastSpeed) - { - panSpeed = PanSpeedSlow; - tiltSpeed = TiltSpeedSlow; - } - else - { - panSpeed = PanSpeedFast; - tiltSpeed = TiltSpeedFast; + StopSpeedTimer(); } - var temp = new byte[] { ID, 0x01, 0x06, 0x01, panSpeed, tiltSpeed }; - int length = temp.Length + cmd.Length + 1; - - byte[] sum = new byte[length]; - temp.CopyTo(sum, 0); - cmd.CopyTo(sum, temp.Length); - sum[length - 1] = 0xFF; - - return sum; + // Start the timer to send fast speed if still moving after FastSpeedHoldTime elapses + SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs); } + } - void SendPowerQuery() + private void StopSpeedTimer() + { + if (SpeedTimer != null) { - SendBytes(new byte[] { ID, 0x09, 0x04, 0x00, 0xFF }); - InquiryResponseQueue.Enqueue(HandlePowerResponse); + SpeedTimer.Stop(); + SpeedTimer.Dispose(); + SpeedTimer = null; + } + } + + /// + /// Generates the pan/tilt command with either slow or fast speed + /// + /// + /// + /// + private byte[] GetPanTiltCommand(byte[] cmd, bool fastSpeed) + { + byte panSpeed; + byte tiltSpeed; + + if (!fastSpeed) + { + panSpeed = PanSpeedSlow; + tiltSpeed = TiltSpeedSlow; } + else + { + panSpeed = PanSpeedFast; + tiltSpeed = TiltSpeedFast; + } + + var temp = new byte[] { ID, 0x01, 0x06, 0x01, panSpeed, tiltSpeed }; + int length = temp.Length + cmd.Length + 1; + + byte[] sum = new byte[length]; + temp.CopyTo(sum, 0); + cmd.CopyTo(sum, temp.Length); + sum[length - 1] = 0xFF; + + return sum; + } + + + void SendPowerQuery() + { + SendBytes(new byte[] { ID, 0x09, 0x04, 0x00, 0xFF }); + InquiryResponseQueue.Enqueue(HandlePowerResponse); + } public void PowerOn() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x02, 0xFF }); - SendPowerQuery(); + SendPowerQuery(); } - void HandlePowerResponse(byte[] response) + void HandlePowerResponse(byte[] response) + { + switch (response[0]) { - switch (response[0]) - { - case 0x02: - { - PowerIsOn = true; - break; - } - case 0x03: - { - PowerIsOn = false; - break; - } - } + case 0x02: + { + PowerIsOn = true; + break; + } + case 0x03: + { + PowerIsOn = false; + break; + } } + } public void PowerOff() { SendBytes(new byte[] {ID, 0x01, 0x04, 0x00, 0x03, 0xFF}); - SendPowerQuery(); - } + SendPowerQuery(); + } - public void PowerToggle() - { - if (PowerIsOnFeedback.BoolValue) - PowerOff(); - else - PowerOn(); - } + public void PowerToggle() + { + if (PowerIsOnFeedback.BoolValue) + PowerOff(); + else + PowerOn(); + } public void PanLeft() { @@ -452,27 +452,27 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } public void PanRight() { - SendPanTiltCommand(new byte[] { 0x02, 0x03 }, false); + SendPanTiltCommand(new byte[] { 0x02, 0x03 }, false); // IsMoving = true; } - public void PanStop() - { - Stop(); - } + public void PanStop() + { + Stop(); + } public void TiltDown() { - SendPanTiltCommand(new byte[] { 0x03, 0x02 }, false); + SendPanTiltCommand(new byte[] { 0x03, 0x02 }, false); // IsMoving = true; } public void TiltUp() { - SendPanTiltCommand(new byte[] { 0x03, 0x01 }, false); + SendPanTiltCommand(new byte[] { 0x03, 0x01 }, false); // IsMoving = true; } - public void TiltStop() - { - Stop(); - } + public void TiltStop() + { + Stop(); + } private void SendZoomCommand (byte cmd) { @@ -482,38 +482,38 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public void ZoomIn() { - SendZoomCommand(ZoomInCmd); + SendZoomCommand(ZoomInCmd); IsZooming = true; } public void ZoomOut() { - SendZoomCommand(ZoomOutCmd); + SendZoomCommand(ZoomOutCmd); IsZooming = true; } - public void ZoomStop() - { - Stop(); - } + public void ZoomStop() + { + Stop(); + } public void Stop() { if (IsZooming) { - SendZoomCommand(ZoomStopCmd); + SendZoomCommand(ZoomStopCmd); IsZooming = false; } else { - StopSpeedTimer(); - SendPanTiltCommand(new byte[] { 0x03, 0x03 }, false); + StopSpeedTimer(); + SendPanTiltCommand(new byte[] { 0x03, 0x03 }, false); // IsMoving = false; } } - public void PositionHome() - { - SendBytes(new byte[] { ID, 0x01, 0x06, 0x02, PanSpeedFast, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }); - SendBytes(new byte[] { ID, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF }); - } + public void PositionHome() + { + SendBytes(new byte[] { ID, 0x01, 0x06, 0x02, PanSpeedFast, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }); + SendBytes(new byte[] { ID, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF }); + } public void RecallPreset(int presetNumber) { SendBytes(new byte[] {ID, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF} ); @@ -523,9 +523,9 @@ namespace PepperDash.Essentials.Devices.Common.Cameras SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF }); } - #region IHasCameraPresets Members + #region IHasCameraPresets Members - public event EventHandler PresetsListHasChanged; + public event EventHandler PresetsListHasChanged; protected void OnPresetsListHasChanged() { @@ -536,162 +536,160 @@ namespace PepperDash.Essentials.Devices.Common.Cameras handler.Invoke(this, EventArgs.Empty); } - public List Presets { get; private set; } + public List Presets { get; private set; } - public void PresetSelect(int preset) - { - RecallPreset(preset); - } - - public void PresetStore(int preset, string description) - { - SavePreset(preset); - } - - - #endregion - - #region IHasCameraFocusControl Members - - public void FocusNear() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x03, 0xFF }); - } - - public void FocusFar() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x02, 0xFF }); - } - - public void FocusStop() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x00, 0xFF }); - } - - public void TriggerAutoFocus() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x18, 0x01, 0xFF }); - SendAutoFocusQuery(); - } - - #endregion - - #region IHasAutoFocus Members - - public void SetFocusModeAuto() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x02, 0xFF }); - SendAutoFocusQuery(); - } - - public void SetFocusModeManual() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x03, 0xFF }); - SendAutoFocusQuery(); - } - - public void ToggleFocusMode() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x10, 0xFF }); - SendAutoFocusQuery(); - } - - #endregion - - void SendAutoFocusQuery() - { - SendBytes(new byte[] { ID, 0x09, 0x04, 0x38, 0xFF }); - InquiryResponseQueue.Enqueue(HandleAutoFocusResponse); - } - - void HandleAutoFocusResponse(byte[] response) - { - switch (response[0]) - { - case 0x02: - { - // Auto Mode - PowerIsOn = true; - break; - } - case 0x03: - { - // Manual Mode - PowerIsOn = false; - break; - } - } - } - - #region IHasCameraOff Members - - public BoolFeedback CameraIsOffFeedback { get; private set; } - - - public void CameraOff() - { - PowerOff(); - } - - #endregion - } - - public class CameraViscaFactory : EssentialsDeviceFactory + public void PresetSelect(int preset) { - public CameraViscaFactory() - { - TypeNames = new List() { "cameravisca" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new CameraVisca Device"); - var comm = CommFactory.CreateCommForDevice(dc); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject( - dc.Properties.ToString()); - return new Cameras.CameraVisca(dc.Key, dc.Name, comm, props); - } + RecallPreset(preset); } - - public class CameraViscaPropertiesConfig : CameraPropertiesConfig + public void PresetStore(int preset, string description) { - /// - /// Control ID of the camera (1-7) - /// - [JsonProperty("id")] - public uint Id { get; set; } - - /// - /// Slow Pan speed (0-18) - /// - [JsonProperty("panSpeedSlow")] - public uint PanSpeedSlow { get; set; } - - /// - /// Fast Pan speed (0-18) - /// - [JsonProperty("panSpeedFast")] - public uint PanSpeedFast { get; set; } - - /// - /// Slow tilt speed (0-18) - /// - [JsonProperty("tiltSpeedSlow")] - public uint TiltSpeedSlow { get; set; } - - /// - /// Fast tilt speed (0-18) - /// - [JsonProperty("tiltSpeedFast")] - public uint TiltSpeedFast { get; set; } - - /// - /// Time a button must be held before fast speed is engaged (Milliseconds) - /// - [JsonProperty("fastSpeedHoldTimeMs")] - public uint FastSpeedHoldTimeMs { get; set; } - + SavePreset(preset); } + + #endregion + + #region IHasCameraFocusControl Members + + public void FocusNear() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x03, 0xFF }); + } + + public void FocusFar() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x02, 0xFF }); + } + + public void FocusStop() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x00, 0xFF }); + } + + public void TriggerAutoFocus() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x18, 0x01, 0xFF }); + SendAutoFocusQuery(); + } + + #endregion + + #region IHasAutoFocus Members + + public void SetFocusModeAuto() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x02, 0xFF }); + SendAutoFocusQuery(); + } + + public void SetFocusModeManual() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x03, 0xFF }); + SendAutoFocusQuery(); + } + + public void ToggleFocusMode() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x10, 0xFF }); + SendAutoFocusQuery(); + } + + #endregion + + void SendAutoFocusQuery() + { + SendBytes(new byte[] { ID, 0x09, 0x04, 0x38, 0xFF }); + InquiryResponseQueue.Enqueue(HandleAutoFocusResponse); + } + + void HandleAutoFocusResponse(byte[] response) + { + switch (response[0]) + { + case 0x02: + { + // Auto Mode + PowerIsOn = true; + break; + } + case 0x03: + { + // Manual Mode + PowerIsOn = false; + break; + } + } + } + + #region IHasCameraOff Members + + public BoolFeedback CameraIsOffFeedback { get; private set; } + + + public void CameraOff() + { + PowerOff(); + } + + #endregion +} + +public class CameraViscaFactory : EssentialsDeviceFactory +{ + public CameraViscaFactory() + { + TypeNames = new List() { "cameravisca" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new CameraVisca Device"); + var comm = CommFactory.CreateCommForDevice(dc); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject( + dc.Properties.ToString()); + return new Cameras.CameraVisca(dc.Key, dc.Name, comm, props); + } +} + + +public class CameraViscaPropertiesConfig : CameraPropertiesConfig +{ + /// + /// Control ID of the camera (1-7) + /// + [JsonProperty("id")] + public uint Id { get; set; } + + /// + /// Slow Pan speed (0-18) + /// + [JsonProperty("panSpeedSlow")] + public uint PanSpeedSlow { get; set; } + + /// + /// Fast Pan speed (0-18) + /// + [JsonProperty("panSpeedFast")] + public uint PanSpeedFast { get; set; } + + /// + /// Slow tilt speed (0-18) + /// + [JsonProperty("tiltSpeedSlow")] + public uint TiltSpeedSlow { get; set; } + + /// + /// Fast tilt speed (0-18) + /// + [JsonProperty("tiltSpeedFast")] + public uint TiltSpeedFast { get; set; } + + /// + /// Time a button must be held before fast speed is engaged (Milliseconds) + /// + [JsonProperty("fastSpeedHoldTimeMs")] + public uint FastSpeedHoldTimeMs { get; set; } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs index a8e8983d..2f973c3f 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs @@ -4,19 +4,18 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +/// +/// Describes a camera with preset functionality +/// +public interface IHasCameraPresets { - /// - /// Describes a camera with preset functionality - /// - public interface IHasCameraPresets - { - event EventHandler PresetsListHasChanged; + event EventHandler PresetsListHasChanged; - List Presets { get; } + List Presets { get; } - void PresetSelect(int preset); + void PresetSelect(int preset); - void PresetStore(int preset, string description); - } + void PresetStore(int preset, string description); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs index f3f164bd..6ec7de16 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs @@ -6,90 +6,89 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Devices.Common.Codec.Cisco +namespace PepperDash.Essentials.Devices.Common.Codec.Cisco; + +/// +/// Describes the available tracking modes for a Cisco codec's Presenter Track feature. +/// +public enum ePresenterTrackMode { /// - /// Describes the available tracking modes for a Cisco codec's Presenter Track feature. + /// Presenter Track is turned off. /// - public enum ePresenterTrackMode - { - /// - /// Presenter Track is turned off. - /// - Off, - /// - /// Presenter Track follows the speaker's movements. - /// - Follow, - /// - /// Presenter Track is set to background mode, where it tracks the speaker but does not actively follow. - /// - Background, - /// - /// Presenter Track is set to persistent mode, where it maintains a fixed position or focus on the speaker. - /// - Persistent - } + Off, + /// + /// Presenter Track follows the speaker's movements. + /// + Follow, + /// + /// Presenter Track is set to background mode, where it tracks the speaker but does not actively follow. + /// + Background, + /// + /// Presenter Track is set to persistent mode, where it maintains a fixed position or focus on the speaker. + /// + Persistent +} +/// +/// Describes the Presenter Track controls for a Cisco codec. +/// +public interface IPresenterTrack : IKeyed +{ + /// + /// + /// + bool PresenterTrackAvailability { get; } + /// - /// Describes the Presenter Track controls for a Cisco codec. + /// Feedback indicating whether Presenter Track is available. /// - public interface IPresenterTrack : IKeyed - { - /// - /// - /// - bool PresenterTrackAvailability { get; } + BoolFeedback PresenterTrackAvailableFeedback { get; } - /// - /// Feedback indicating whether Presenter Track is available. - /// - BoolFeedback PresenterTrackAvailableFeedback { get; } + /// + /// Feedback indicating the current status of Presenter Track is off + /// + BoolFeedback PresenterTrackStatusOffFeedback { get; } - /// - /// Feedback indicating the current status of Presenter Track is off - /// - BoolFeedback PresenterTrackStatusOffFeedback { get; } + /// + /// Feedback indicating the current status of Presenter Track is follow + /// + BoolFeedback PresenterTrackStatusFollowFeedback { get; } - /// - /// Feedback indicating the current status of Presenter Track is follow - /// - BoolFeedback PresenterTrackStatusFollowFeedback { get; } + /// + /// Feedback indicating the current status of Presenter Track is background + /// + BoolFeedback PresenterTrackStatusBackgroundFeedback { get; } - /// - /// Feedback indicating the current status of Presenter Track is background - /// - BoolFeedback PresenterTrackStatusBackgroundFeedback { get; } + /// + /// Feedback indicating the current status of Presenter Track is persistent + /// + BoolFeedback PresenterTrackStatusPersistentFeedback { get; } - /// - /// Feedback indicating the current status of Presenter Track is persistent - /// - BoolFeedback PresenterTrackStatusPersistentFeedback { get; } + /// + /// Indicates the current status of Presenter Track. + /// + bool PresenterTrackStatus { get; } - /// - /// Indicates the current status of Presenter Track. - /// - bool PresenterTrackStatus { get; } + /// + /// Turns off Presenter Track. + /// + void PresenterTrackOff(); - /// - /// Turns off Presenter Track. - /// - void PresenterTrackOff(); + /// + /// Turns on Presenter Track in follow mode. + /// + void PresenterTrackFollow(); - /// - /// Turns on Presenter Track in follow mode. - /// - void PresenterTrackFollow(); + /// + /// Turns on Presenter Track in background mode. + /// + void PresenterTrackBackground(); - /// - /// Turns on Presenter Track in background mode. - /// - void PresenterTrackBackground(); - - /// - /// Turns on Presenter Track in persistent mode. - /// - void PresenterTrackPersistent(); - } + /// + /// Turns on Presenter Track in persistent mode. + /// + void PresenterTrackPersistent(); } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs index 83735183..f00af25b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs @@ -6,35 +6,34 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Devices.Common.Codec.Cisco +namespace PepperDash.Essentials.Devices.Common.Codec.Cisco; + +/// +/// Describes the available tracking modes for a Cisco codec +/// +public interface ISpeakerTrack : IKeyed { /// - /// Describes the available tracking modes for a Cisco codec + /// Indicates whether Speaker Track is available on the codec. /// - public interface ISpeakerTrack : IKeyed - { - /// - /// Indicates whether Speaker Track is available on the codec. - /// - bool SpeakerTrackAvailability { get; } + bool SpeakerTrackAvailability { get; } - /// - /// - /// - BoolFeedback SpeakerTrackAvailableFeedback { get; } + /// + /// + /// + BoolFeedback SpeakerTrackAvailableFeedback { get; } - /// - /// Feedback indicating the current status of Speaker Track is off - /// - bool SpeakerTrackStatus { get; } + /// + /// Feedback indicating the current status of Speaker Track is off + /// + bool SpeakerTrackStatus { get; } - /// - /// Turns Speaker Track off - /// - void SpeakerTrackOff(); - /// - /// Turns Speaker Track on - /// - void SpeakerTrackOn(); - } + /// + /// Turns Speaker Track off + /// + void SpeakerTrackOff(); + /// + /// Turns Speaker Track on + /// + void SpeakerTrackOn(); } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs b/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs index a8b8d563..1a034c8e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs @@ -9,67 +9,66 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public class CodecActiveCallItem { - public class CodecActiveCallItem - { [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string Name { get; set; } + public string Name { get; set; } - [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] - public string Number { get; set; } + [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] + public string Number { get; set; } - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] - public eCodecCallType Type { get; set; } + public eCodecCallType Type { get; set; } - [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] - public eCodecCallStatus Status { get; set; } + public eCodecCallStatus Status { get; set; } - [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] - public eCodecCallDirection Direction { get; set; } + public eCodecCallDirection Direction { get; set; } - [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] - public string Id { get; set; } + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string Id { get; set; } - [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] - public bool IsOnHold { get; set; } + [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] + public bool IsOnHold { get; set; } - [JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)] - public TimeSpan Duration { get; set; } + [JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)] + public TimeSpan Duration { get; set; } - //public object CallMetaData { get; set; } - - /// - /// Returns true when this call is any status other than - /// Unknown, Disconnected, Disconnecting - /// - [JsonProperty("isActiveCall", NullValueHandling = NullValueHandling.Ignore)] - public bool IsActiveCall - { - get - { - return !(Status == eCodecCallStatus.Disconnected - || Status == eCodecCallStatus.Disconnecting - || Status == eCodecCallStatus.Idle - || Status == eCodecCallStatus.Unknown); - } - } - } + //public object CallMetaData { get; set; } /// - /// + /// Returns true when this call is any status other than + /// Unknown, Disconnected, Disconnecting /// - public class CodecCallStatusItemChangeEventArgs : EventArgs + [JsonProperty("isActiveCall", NullValueHandling = NullValueHandling.Ignore)] + public bool IsActiveCall { - public CodecActiveCallItem CallItem { get; private set; } - - public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item) + get { - CallItem = item; + return !(Status == eCodecCallStatus.Disconnected + || Status == eCodecCallStatus.Disconnecting + || Status == eCodecCallStatus.Idle + || Status == eCodecCallStatus.Unknown); } } +} + +/// +/// +/// +public class CodecCallStatusItemChangeEventArgs : EventArgs +{ + public CodecActiveCallItem CallItem { get; private set; } + + public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item) + { + CallItem = item; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs b/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs index fefb4b09..a9fcdf94 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs @@ -5,27 +5,26 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Devices.Common.Codec -{ - /// - /// Describes a cisco codec device that can allow configuration of cameras - /// - public interface ICiscoCodecCameraConfig - { - void SetCameraAssignedSerialNumber(uint cameraId, string serialNumber); +namespace PepperDash.Essentials.Devices.Common.Codec; - void SetCameraName(uint videoConnectorId, string name); +/// +/// Describes a cisco codec device that can allow configuration of cameras +/// +public interface ICiscoCodecCameraConfig +{ + void SetCameraAssignedSerialNumber(uint cameraId, string serialNumber); - void SetInputSourceType(uint videoConnectorId, eCiscoCodecInputSourceType sourceType); - } + void SetCameraName(uint videoConnectorId, string name); - public enum eCiscoCodecInputSourceType - { - PC, - camera, - document_camera, - mediaplayer, - other, - whiteboard - } + void SetInputSourceType(uint videoConnectorId, eCiscoCodecInputSourceType sourceType); +} + +public enum eCiscoCodecInputSourceType +{ + PC, + camera, + document_camera, + mediaplayer, + other, + whiteboard } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs index 78211841..a29215b7 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs @@ -4,20 +4,19 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Codec -{ - public interface IHasCallHold - { - /// - /// Put the specified call on hold - /// - /// - void HoldCall(CodecActiveCallItem activeCall); +namespace PepperDash.Essentials.Devices.Common.Codec; - /// - /// Resume the specified call - /// - /// - void ResumeCall(CodecActiveCallItem activeCall); - } +public interface IHasCallHold +{ + /// + /// Put the specified call on hold + /// + /// + void HoldCall(CodecActiveCallItem activeCall); + + /// + /// Resume the specified call + /// + /// + void ResumeCall(CodecActiveCallItem activeCall); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs index 7bb9b924..70d96e9b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs @@ -6,40 +6,39 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Describes a device that has Do Not Disturb mode capability +/// +public interface IHasDoNotDisturbMode { /// - /// Describes a device that has Do Not Disturb mode capability + /// Indictes whether Do Not Disturb mode is on (Activated) /// - public interface IHasDoNotDisturbMode - { - /// - /// Indictes whether Do Not Disturb mode is on (Activated) - /// - BoolFeedback DoNotDisturbModeIsOnFeedback { get; } + BoolFeedback DoNotDisturbModeIsOnFeedback { get; } - /// - /// Activates Do Not Disturb mode - /// - void ActivateDoNotDisturbMode(); + /// + /// Activates Do Not Disturb mode + /// + void ActivateDoNotDisturbMode(); - /// - /// Deactivates Do Not Disturb mode - /// - void DeactivateDoNotDisturbMode(); + /// + /// Deactivates Do Not Disturb mode + /// + void DeactivateDoNotDisturbMode(); - /// - /// Toggles Do Not Disturb mode - /// - void ToggleDoNotDisturbMode(); - } + /// + /// Toggles Do Not Disturb mode + /// + void ToggleDoNotDisturbMode(); +} - public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode - { - /// - /// Activates Do Not Disturb mode with a timeout - /// - /// - void ActivateDoNotDisturbMode(int timeout); - } +public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode +{ + /// + /// Activates Do Not Disturb mode with a timeout + /// + /// + void ActivateDoNotDisturbMode(int timeout); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs index 1ea6b09b..b13bce1e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs @@ -6,17 +6,15 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; -namespace PepperDash.Essentials.Devices.Common.Codec -{ +namespace PepperDash.Essentials.Devices.Common.Codec; + public interface IHasExternalSourceSwitching { bool ExternalSourceListEnabled { get; } - string ExternalSourceInputPort { get; } + string ExternalSourceInputPort { get; } void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type); void SetExternalSourceState(string key, eExternalSourceMode mode); void ClearExternalSources(); - void SetSelectedSource(string key); + void SetSelectedSource(string key); Action RunRouteAction { set;} - } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs index a5e118df..f705fc50 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs @@ -4,38 +4,37 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public enum eCodecCallDirection { - public enum eCodecCallDirection - { - Unknown = 0, Incoming, Outgoing - } + Unknown = 0, Incoming, Outgoing +} - public class CodecCallDirection +public class CodecCallDirection +{ + /// + /// Takes the Cisco call type and converts to the matching enum + /// + /// + /// + public static eCodecCallDirection ConvertToDirectionEnum(string s) { - /// - /// Takes the Cisco call type and converts to the matching enum - /// - /// - /// - public static eCodecCallDirection ConvertToDirectionEnum(string s) + switch (s.ToLower()) { - switch (s.ToLower()) - { - case "incoming": - { - return eCodecCallDirection.Incoming; - } - case "outgoing": - { - return eCodecCallDirection.Outgoing; - } - default: - return eCodecCallDirection.Unknown; - } - + case "incoming": + { + return eCodecCallDirection.Incoming; + } + case "outgoing": + { + return eCodecCallDirection.Outgoing; + } + default: + return eCodecCallDirection.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs index 610d928b..2a462775 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs @@ -4,86 +4,85 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public enum eCodecCallStatus { - public enum eCodecCallStatus + Unknown = 0, + Connected, + Connecting, + Dialing, + Disconnected, + Disconnecting, + EarlyMedia, + Idle, + OnHold, + Ringing, + Preserved, + RemotePreserved, +} + + +public class CodecCallStatus +{ + + /// + /// Takes the Cisco call type and converts to the matching enum + /// + /// + /// + public static eCodecCallStatus ConvertToStatusEnum(string s) { - Unknown = 0, - Connected, - Connecting, - Dialing, - Disconnected, - Disconnecting, - EarlyMedia, - Idle, - OnHold, - Ringing, - Preserved, - RemotePreserved, - } - - - public class CodecCallStatus - { - - /// - /// Takes the Cisco call type and converts to the matching enum - /// - /// - /// - public static eCodecCallStatus ConvertToStatusEnum(string s) + switch (s) { - switch (s) - { - case "Connected": - { - return eCodecCallStatus.Connected; - } - case "Connecting": - { - return eCodecCallStatus.Connecting; - } - case "Dialling": - { - return eCodecCallStatus.Dialing; - } - case "Disconnected": - { - return eCodecCallStatus.Disconnected; - } - case "Disconnecting": - { - return eCodecCallStatus.Disconnecting; - } - case "EarlyMedia": - { - return eCodecCallStatus.EarlyMedia; - } - case "Idle": - { - return eCodecCallStatus.Idle; - } - case "OnHold": - { - return eCodecCallStatus.OnHold; - } - case "Ringing": - { - return eCodecCallStatus.Ringing; - } - case "Preserved": - { - return eCodecCallStatus.Preserved; - } - case "RemotePreserved": - { - return eCodecCallStatus.RemotePreserved; - } - default: - return eCodecCallStatus.Unknown; - } - + case "Connected": + { + return eCodecCallStatus.Connected; + } + case "Connecting": + { + return eCodecCallStatus.Connecting; + } + case "Dialling": + { + return eCodecCallStatus.Dialing; + } + case "Disconnected": + { + return eCodecCallStatus.Disconnected; + } + case "Disconnecting": + { + return eCodecCallStatus.Disconnecting; + } + case "EarlyMedia": + { + return eCodecCallStatus.EarlyMedia; + } + case "Idle": + { + return eCodecCallStatus.Idle; + } + case "OnHold": + { + return eCodecCallStatus.OnHold; + } + case "Ringing": + { + return eCodecCallStatus.Ringing; + } + case "Preserved": + { + return eCodecCallStatus.Preserved; + } + case "RemotePreserved": + { + return eCodecCallStatus.RemotePreserved; + } + default: + return eCodecCallStatus.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs index dbab015b..ccadae10 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs @@ -4,51 +4,50 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public enum eCodecCallType { - public enum eCodecCallType - { - Unknown = 0, - Audio, - Video, - AudioCanEscalate, - ForwardAllCall - } + Unknown = 0, + Audio, + Video, + AudioCanEscalate, + ForwardAllCall +} - public class CodecCallType - { +public class CodecCallType +{ - /// - /// Takes the Cisco call type and converts to the matching enum - /// - /// - /// - public static eCodecCallType ConvertToTypeEnum(string s) + /// + /// Takes the Cisco call type and converts to the matching enum + /// + /// + /// + public static eCodecCallType ConvertToTypeEnum(string s) + { + switch (s) { - switch (s) - { - case "Audio": - { - return eCodecCallType.Audio; - } - case "Video": - { - return eCodecCallType.Video; - } - case "AudioCanEscalate": - { - return eCodecCallType.AudioCanEscalate; - } - case "ForwardAllCall": - { - return eCodecCallType.ForwardAllCall; - } - default: - return eCodecCallType.Unknown; - } - + case "Audio": + { + return eCodecCallType.Audio; + } + case "Video": + { + return eCodecCallType.Video; + } + case "AudioCanEscalate": + { + return eCodecCallType.AudioCanEscalate; + } + case "ForwardAllCall": + { + return eCodecCallType.ForwardAllCall; + } + default: + return eCodecCallType.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs index f163a864..5885adb5 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs @@ -4,39 +4,38 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public enum eMeetingPrivacy { - public enum eMeetingPrivacy - { - Unknown = 0, - Public, - Private - } + Unknown = 0, + Public, + Private +} - public class CodecCallPrivacy +public class CodecCallPrivacy +{ + /// + /// Takes the Cisco privacy type and converts to the matching enum + /// + /// + /// + public static eMeetingPrivacy ConvertToDirectionEnum(string s) { - /// - /// Takes the Cisco privacy type and converts to the matching enum - /// - /// - /// - public static eMeetingPrivacy ConvertToDirectionEnum(string s) + switch (s.ToLower()) { - switch (s.ToLower()) - { - case "public": - { - return eMeetingPrivacy.Public; - } - case "private": - { - return eMeetingPrivacy.Private; - } - default: - return eMeetingPrivacy.Unknown; - } - + case "public": + { + return eMeetingPrivacy.Public; + } + case "private": + { + return eMeetingPrivacy.Private; + } + default: + return eMeetingPrivacy.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs index d61f7d26..654d3d6e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs @@ -6,13 +6,12 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec -{ - /// - /// Defines minimum volume controls for a codec device with dialing capabilities - /// - public interface ICodecAudio : IBasicVolumeWithFeedback, IPrivacy - { +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Defines minimum volume controls for a codec device with dialing capabilities +/// +public interface ICodecAudio : IBasicVolumeWithFeedback, IPrivacy +{ - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs index 50c1b2c9..73cdd49c 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs @@ -4,23 +4,22 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public interface IHasCallFavorites { - public interface IHasCallFavorites - { - CodecCallFavorites CallFavorites { get; } - } + CodecCallFavorites CallFavorites { get; } +} - /// - /// Represents favorites entries for a codec device - /// - public class CodecCallFavorites - { - public List Favorites { get; set; } +/// +/// Represents favorites entries for a codec device +/// +public class CodecCallFavorites +{ + public List Favorites { get; set; } - public CodecCallFavorites() - { - Favorites = new List(); - } + public CodecCallFavorites() + { + Favorites = new List(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs index 5291a393..2a3e9bbf 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs @@ -7,132 +7,131 @@ using PepperDash.Essentials.Devices.Common.VideoCodec; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + + +public interface IHasCallHistory { + CodecCallHistory CallHistory { get; } - public interface IHasCallHistory + void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry); +} + +public enum eCodecOccurrenceType +{ + Unknown = 0, + Placed = 1, + Received = 2, + NoAnswer = 3, +} + +/// +/// Represents the recent call history for a codec device +/// +public class CodecCallHistory +{ + public event EventHandler RecentCallsListHasChanged; + + public List RecentCalls { get; private set; } + + /// + /// Item that gets added to the list when there are no recent calls in history + /// + CallHistoryEntry ListEmptyEntry; + + public CodecCallHistory() { - CodecCallHistory CallHistory { get; } + ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" }; - void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry); + RecentCalls = new List(); + + RecentCalls.Add(ListEmptyEntry); } - public enum eCodecOccurrenceType + void OnRecentCallsListChange() { - Unknown = 0, - Placed = 1, - Received = 2, - NoAnswer = 3, + var handler = RecentCallsListHasChanged; + if (handler != null) + { + handler(this, new EventArgs()); + } + } + + public void RemoveEntry(CallHistoryEntry entry) + { + RecentCalls.Remove(entry); + OnRecentCallsListChange(); } /// - /// Represents the recent call history for a codec device + /// Generic call history entry, not device specific /// - public class CodecCallHistory + public class CallHistoryEntry : CodecActiveCallItem { - public event EventHandler RecentCallsListHasChanged; + [JsonConverter(typeof(IsoDateTimeConverter))] + [JsonProperty("startTime")] + public DateTime StartTime { get; set; } + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("occurrenceType")] + public eCodecOccurrenceType OccurrenceType { get; set; } + [JsonProperty("occurrenceHistoryId")] + public string OccurrenceHistoryId { get; set; } + } - public List RecentCalls { get; private set; } + /// + /// Converts a list of call history entries returned by a Cisco codec to the generic list type + /// + /// + /// + public void ConvertCiscoCallHistoryToGeneric(List entries) + { + var genericEntries = new List(); - /// - /// Item that gets added to the list when there are no recent calls in history - /// - CallHistoryEntry ListEmptyEntry; - - public CodecCallHistory() + foreach (CiscoCallHistory.Entry entry in entries) { - ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" }; - RecentCalls = new List(); - - RecentCalls.Add(ListEmptyEntry); - } - - void OnRecentCallsListChange() - { - var handler = RecentCallsListHasChanged; - if (handler != null) + genericEntries.Add(new CallHistoryEntry() { - handler(this, new EventArgs()); - } + Name = entry.DisplayName.Value, + Number = entry.CallbackNumber.Value, + StartTime = entry.LastOccurrenceStartTime.Value, + OccurrenceHistoryId = entry.LastOccurrenceHistoryId.Value, + OccurrenceType = ConvertToOccurenceTypeEnum(entry.OccurrenceType.Value) + }); } - public void RemoveEntry(CallHistoryEntry entry) + // Check if list is empty and if so, add an item to display No Recent Calls + if(genericEntries.Count == 0) + genericEntries.Add(ListEmptyEntry); + + RecentCalls = genericEntries; + OnRecentCallsListChange(); + } + + /// + /// Takes the Cisco occurence type and converts it to the matching enum + /// + /// + public eCodecOccurrenceType ConvertToOccurenceTypeEnum(string s) + { + switch (s) { - RecentCalls.Remove(entry); - OnRecentCallsListChange(); - } - - /// - /// Generic call history entry, not device specific - /// - public class CallHistoryEntry : CodecActiveCallItem - { - [JsonConverter(typeof(IsoDateTimeConverter))] - [JsonProperty("startTime")] - public DateTime StartTime { get; set; } - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("occurrenceType")] - public eCodecOccurrenceType OccurrenceType { get; set; } - [JsonProperty("occurrenceHistoryId")] - public string OccurrenceHistoryId { get; set; } - } - - /// - /// Converts a list of call history entries returned by a Cisco codec to the generic list type - /// - /// - /// - public void ConvertCiscoCallHistoryToGeneric(List entries) - { - var genericEntries = new List(); - - foreach (CiscoCallHistory.Entry entry in entries) - { - - genericEntries.Add(new CallHistoryEntry() + case "Placed": { - Name = entry.DisplayName.Value, - Number = entry.CallbackNumber.Value, - StartTime = entry.LastOccurrenceStartTime.Value, - OccurrenceHistoryId = entry.LastOccurrenceHistoryId.Value, - OccurrenceType = ConvertToOccurenceTypeEnum(entry.OccurrenceType.Value) - }); - } - - // Check if list is empty and if so, add an item to display No Recent Calls - if(genericEntries.Count == 0) - genericEntries.Add(ListEmptyEntry); - - RecentCalls = genericEntries; - OnRecentCallsListChange(); - } - - /// - /// Takes the Cisco occurence type and converts it to the matching enum - /// - /// - public eCodecOccurrenceType ConvertToOccurenceTypeEnum(string s) - { - switch (s) - { - case "Placed": - { - return eCodecOccurrenceType.Placed; - } - case "Received": - { - return eCodecOccurrenceType.Received; - } - case "NoAnswer": - { - return eCodecOccurrenceType.NoAnswer; - } - default: - return eCodecOccurrenceType.Unknown; - } - + return eCodecOccurrenceType.Placed; + } + case "Received": + { + return eCodecOccurrenceType.Received; + } + case "NoAnswer": + { + return eCodecOccurrenceType.NoAnswer; + } + default: + return eCodecOccurrenceType.Unknown; } } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs index f3c28243..cdbdc766 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs @@ -8,17 +8,15 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +public interface IHasContentSharing { - public interface IHasContentSharing - { - BoolFeedback SharingContentIsOnFeedback { get; } - StringFeedback SharingSourceFeedback { get; } + BoolFeedback SharingContentIsOnFeedback { get; } + StringFeedback SharingSourceFeedback { get; } - bool AutoShareContentWhileInCall { get; } - - void StartSharing(); - void StopSharing(); - } + bool AutoShareContentWhileInCall { get; } + void StartSharing(); + void StopSharing(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs index bce2dee3..7668e120 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs @@ -6,25 +6,23 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +/// +/// Requirements for a device that has dialing capabilities +/// +public interface IHasDialer { - /// - /// Requirements for a device that has dialing capabilities - /// - public interface IHasDialer - { - // Add requirements for Dialer functionality + // Add requirements for Dialer functionality - event EventHandler CallStatusChange; + event EventHandler CallStatusChange; - void Dial(string number); - void EndCall(CodecActiveCallItem activeCall); - void EndAllCalls(); - void AcceptCall(CodecActiveCallItem item); - void RejectCall(CodecActiveCallItem item); - void SendDtmf(string digit); - - bool IsInCall { get; } - } + void Dial(string number); + void EndCall(CodecActiveCallItem activeCall); + void EndAllCalls(); + void AcceptCall(CodecActiveCallItem item); + void RejectCall(CodecActiveCallItem item); + void SendDtmf(string digit); + bool IsInCall { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs index 6a4e62fe..1c021815 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs @@ -14,233 +14,233 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.VideoCodec; -namespace PepperDash.Essentials.Devices.Common.Codec -{ +namespace PepperDash.Essentials.Devices.Common.Codec; + /// /// Defines the API for codecs with a directory /// - public interface IHasDirectory - { - event EventHandler DirectoryResultReturned; +public interface IHasDirectory +{ + event EventHandler DirectoryResultReturned; - CodecDirectory DirectoryRoot { get; } + CodecDirectory DirectoryRoot { get; } - CodecDirectory CurrentDirectoryResult { get; } + CodecDirectory CurrentDirectoryResult { get; } - CodecPhonebookSyncState PhonebookSyncState { get; } + CodecPhonebookSyncState PhonebookSyncState { get; } - void SearchDirectory(string searchString); + void SearchDirectory(string searchString); - void GetDirectoryFolderContents(string folderId); + void GetDirectoryFolderContents(string folderId); - void SetCurrentDirectoryToRoot(); + void SetCurrentDirectoryToRoot(); - void GetDirectoryParentFolderContents(); + void GetDirectoryParentFolderContents(); - BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; } - } + BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; } +} - public interface IHasDirectoryHistoryStack : IHasDirectory - { - Stack DirectoryBrowseHistoryStack { get; } - } +public interface IHasDirectoryHistoryStack : IHasDirectory +{ + Stack DirectoryBrowseHistoryStack { get; } +} /// /// /// - public class DirectoryEventArgs : EventArgs - { - public CodecDirectory Directory { get; set; } - public bool DirectoryIsOnRoot { get; set; } - } +public class DirectoryEventArgs : EventArgs +{ + public CodecDirectory Directory { get; set; } + public bool DirectoryIsOnRoot { get; set; } +} /// /// Represents a codec directory /// - public class CodecDirectory - { - /// - /// Represents the contents of the directory - /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data - /// +public class CodecDirectory +{ + /// + /// Represents the contents of the directory + /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data + /// [JsonIgnore] - public List CurrentDirectoryResults { get; private set; } + public List CurrentDirectoryResults { get; private set; } - [JsonProperty("contacts")] - public List Contacts + [JsonProperty("contacts")] + public List Contacts + { + get { - get - { - return CurrentDirectoryResults.OfType().Cast().ToList(); - } + return CurrentDirectoryResults.OfType().Cast().ToList(); } + } - [JsonProperty("folders")] - public List Folders + [JsonProperty("folders")] + public List Folders + { + get { - get - { - return CurrentDirectoryResults.OfType().Cast().ToList(); - } + return CurrentDirectoryResults.OfType().Cast().ToList(); } - - /// - /// Used to store the ID of the current folder for CurrentDirectoryResults - /// - [JsonProperty("resultsFolderId")] - public string ResultsFolderId { get; set; } - - public CodecDirectory() - { - CurrentDirectoryResults = new List(); - } - - /// - /// Adds folders to the directory - /// - /// - public void AddFoldersToDirectory(List folders) - { - if(folders != null) - CurrentDirectoryResults.AddRange(folders); - - SortDirectory(); - } - - /// - /// Adds contacts to the directory - /// - /// - public void AddContactsToDirectory(List contacts) - { - if(contacts != null) - CurrentDirectoryResults.AddRange(contacts); - - SortDirectory(); - } - - /// - /// Filters the CurrentDirectoryResults by the predicate - /// - /// - public void FilterContacts(Func predicate) - { - CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList(); - } - - /// - /// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically - /// - private void SortDirectory() - { - var sortedFolders = new List(); - - sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder)); - - sortedFolders.OrderBy(f => f.Name); - - var sortedContacts = new List(); - - sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact)); - - sortedFolders.OrderBy(c => c.Name); - - CurrentDirectoryResults.Clear(); - - CurrentDirectoryResults.AddRange(sortedFolders); - - CurrentDirectoryResults.AddRange(sortedContacts); - } - } /// - /// Used to decorate a contact to indicate it can be invided to a meeting + /// Used to store the ID of the current folder for CurrentDirectoryResults /// - public interface IInvitableContact + [JsonProperty("resultsFolderId")] + public string ResultsFolderId { get; set; } + + public CodecDirectory() { - bool IsInvitableContact { get; } + CurrentDirectoryResults = new List(); } - public class InvitableDirectoryContact : DirectoryContact, IInvitableContact + /// + /// Adds folders to the directory + /// + /// + public void AddFoldersToDirectory(List folders) { - [JsonProperty("isInvitableContact")] - public bool IsInvitableContact + if(folders != null) + CurrentDirectoryResults.AddRange(folders); + + SortDirectory(); + } + + /// + /// Adds contacts to the directory + /// + /// + public void AddContactsToDirectory(List contacts) + { + if(contacts != null) + CurrentDirectoryResults.AddRange(contacts); + + SortDirectory(); + } + + /// + /// Filters the CurrentDirectoryResults by the predicate + /// + /// + public void FilterContacts(Func predicate) + { + CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList(); + } + + /// + /// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically + /// + private void SortDirectory() + { + var sortedFolders = new List(); + + sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder)); + + sortedFolders.OrderBy(f => f.Name); + + var sortedContacts = new List(); + + sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact)); + + sortedFolders.OrderBy(c => c.Name); + + CurrentDirectoryResults.Clear(); + + CurrentDirectoryResults.AddRange(sortedFolders); + + CurrentDirectoryResults.AddRange(sortedContacts); + } + +} + +/// +/// Used to decorate a contact to indicate it can be invided to a meeting +/// +public interface IInvitableContact +{ + bool IsInvitableContact { get; } +} + +public class InvitableDirectoryContact : DirectoryContact, IInvitableContact +{ + [JsonProperty("isInvitableContact")] + public bool IsInvitableContact + { + get { - get - { - return this is IInvitableContact; - } + return this is IInvitableContact; } } +} /// /// Represents an item in the directory /// - public class DirectoryItem : ICloneable +public class DirectoryItem : ICloneable +{ + public object Clone() { - public object Clone() - { - return this.MemberwiseClone(); - } + return this.MemberwiseClone(); + } - [JsonProperty("folderId")] - public string FolderId { get; set; } + [JsonProperty("folderId")] + public string FolderId { get; set; } [JsonProperty("name")] - public string Name { get; set; } + public string Name { get; set; } - [JsonProperty("parentFolderId")] - public string ParentFolderId { get; set; } - } + [JsonProperty("parentFolderId")] + public string ParentFolderId { get; set; } +} /// /// Represents a folder type DirectoryItem /// - public class DirectoryFolder : DirectoryItem - { +public class DirectoryFolder : DirectoryItem +{ [JsonProperty("contacts")] - public List Contacts { get; set; } + public List Contacts { get; set; } - public DirectoryFolder() - { - Contacts = new List(); - } + public DirectoryFolder() + { + Contacts = new List(); } +} /// /// Represents a contact type DirectoryItem /// - public class DirectoryContact : DirectoryItem - { +public class DirectoryContact : DirectoryItem +{ [JsonProperty("contactId")] - public string ContactId { get; set; } + public string ContactId { get; set; } [JsonProperty("title")] - public string Title { get; set; } + public string Title { get; set; } [JsonProperty("contactMethods")] - public List ContactMethods { get; set; } + public List ContactMethods { get; set; } - public DirectoryContact() - { - ContactMethods = new List(); - } + public DirectoryContact() + { + ContactMethods = new List(); } +} /// /// Represents a method of contact for a contact /// - public class ContactMethod - { +public class ContactMethod +{ [JsonProperty("contactMethodId")] - public string ContactMethodId { get; set; } + public string ContactMethodId { get; set; } [JsonProperty("number")] - public string Number { get; set; } - + public string Number { get; set; } + [JsonProperty("device")] [JsonConverter(typeof(StringEnumConverter))] public eContactMethodDevice Device { get; set; } @@ -248,27 +248,26 @@ namespace PepperDash.Essentials.Devices.Common.Codec [JsonProperty("callType")] [JsonConverter(typeof(StringEnumConverter))] public eContactMethodCallType CallType { get; set; } - } +} /// /// /// - public enum eContactMethodDevice - { - Unknown = 0, - Mobile, - Other, - Telephone, - Video - } +public enum eContactMethodDevice +{ + Unknown = 0, + Mobile, + Other, + Telephone, + Video +} /// /// /// - public enum eContactMethodCallType - { - Unknown = 0, - Audio, - Video - } +public enum eContactMethodCallType +{ + Unknown = 0, + Audio, + Video } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs index 602d65e3..dff7203f 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs @@ -11,262 +11,260 @@ using PepperDash.Core; using Newtonsoft.Json; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec; + +[Flags] +public enum eMeetingEventChangeType { - [Flags] - public enum eMeetingEventChangeType + Unknown = 0, + MeetingStartWarning = 1, + MeetingStart = 2, + MeetingEndWarning = 4, + MeetingEnd = 8 +} + +public interface IHasScheduleAwareness +{ + CodecScheduleAwareness CodecSchedule { get; } + + void GetSchedule(); +} + +public class CodecScheduleAwareness +{ + List _meetings; + + public event EventHandler MeetingEventChange; + + public event EventHandler MeetingsListHasChanged; + + private int _meetingWarningMinutes = 5; + + //private Meeting _previousChangedMeeting; + + //private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown; + + public int MeetingWarningMinutes { - Unknown = 0, - MeetingStartWarning = 1, - MeetingStart = 2, - MeetingEndWarning = 4, - MeetingEnd = 8 - } - - public interface IHasScheduleAwareness - { - CodecScheduleAwareness CodecSchedule { get; } - - void GetSchedule(); - } - - public class CodecScheduleAwareness - { - List _meetings; - - public event EventHandler MeetingEventChange; - - public event EventHandler MeetingsListHasChanged; - - private int _meetingWarningMinutes = 5; - - //private Meeting _previousChangedMeeting; - - //private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown; - - public int MeetingWarningMinutes - { - get { return _meetingWarningMinutes; } - set { _meetingWarningMinutes = value; } - } - - /// - /// Setter triggers MeetingsListHasChanged event - /// - public List Meetings - { - get - { - return _meetings; - } - set - { - _meetings = value; - MeetingsListHasChanged?.Invoke(this, new EventArgs()); - } - } - - private readonly CTimer _scheduleChecker; - - public CodecScheduleAwareness() - { - Meetings = new List(); - - _scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000); - } - - public CodecScheduleAwareness(long pollTime) - { - Meetings = new List(); - - _scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime); - } - - /// - /// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting - /// - /// - /// - private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) - { - Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType); - if (changeType != (changeType & meeting.NotifiedChangeTypes)) - { - // Add this change type to the NotifiedChangeTypes - meeting.NotifiedChangeTypes |= changeType; - MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); - } - else - { - Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType); - } - } - - - /// - /// Checks the schedule to see if any MeetingEventChange updates should be fired - /// - /// - private void CheckSchedule(object o) - { - // Iterate the meeting list and check if any meeting need to do anything - - const double meetingTimeEpsilon = 0.05; - foreach (var m in Meetings) - { - var changeType = eMeetingEventChangeType.Unknown; - - if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); - changeType = eMeetingEventChangeType.MeetingStartWarning; - } - else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart"); - changeType = eMeetingEventChangeType.MeetingStart; - } - else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds); - changeType = eMeetingEventChangeType.MeetingEndWarning; - } - else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd"); - changeType = eMeetingEventChangeType.MeetingEnd; - } - - if (changeType != eMeetingEventChangeType.Unknown) - { - OnMeetingChange(changeType, m); - } - } - - } + get { return _meetingWarningMinutes; } + set { _meetingWarningMinutes = value; } } /// - /// Generic class to represent a meeting (Cisco or Polycom OBTP or Fusion) - /// - public class Meeting + /// Setter triggers MeetingsListHasChanged event + /// + public List Meetings { - [JsonProperty("minutesBeforeMeeting")] - public int MinutesBeforeMeeting; + get + { + return _meetings; + } + set + { + _meetings = value; + MeetingsListHasChanged?.Invoke(this, new EventArgs()); + } + } - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("organizer")] - public string Organizer { get; set; } - [JsonProperty("title")] - public string Title { get; set; } - [JsonProperty("agenda")] - public string Agenda { get; set; } + private readonly CTimer _scheduleChecker; - [JsonProperty("meetingWarningMinutes")] - public TimeSpan MeetingWarningMinutes + public CodecScheduleAwareness() + { + Meetings = new List(); + + _scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000); + } + + public CodecScheduleAwareness(long pollTime) + { + Meetings = new List(); + + _scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime); + } + + /// + /// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting + /// + /// + /// + private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) + { + Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType); + if (changeType != (changeType & meeting.NotifiedChangeTypes)) { - get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); } + // Add this change type to the NotifiedChangeTypes + meeting.NotifiedChangeTypes |= changeType; + MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); } - [JsonProperty("timeToMeetingStart")] - public TimeSpan TimeToMeetingStart + else { - get + Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType); + } + } + + + /// + /// Checks the schedule to see if any MeetingEventChange updates should be fired + /// + /// + private void CheckSchedule(object o) + { + // Iterate the meeting list and check if any meeting need to do anything + + const double meetingTimeEpsilon = 0.05; + foreach (var m in Meetings) + { + var changeType = eMeetingEventChangeType.Unknown; + + if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start { - return StartTime - DateTime.Now; + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); + changeType = eMeetingEventChangeType.MeetingStartWarning; + } + else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart"); + changeType = eMeetingEventChangeType.MeetingStart; + } + else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds); + changeType = eMeetingEventChangeType.MeetingEndWarning; + } + else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd"); + changeType = eMeetingEventChangeType.MeetingEnd; + } + + if (changeType != eMeetingEventChangeType.Unknown) + { + OnMeetingChange(changeType, m); } } - [JsonProperty("timeToMeetingEnd")] - public TimeSpan TimeToMeetingEnd + + } +} + +/// +/// Generic class to represent a meeting (Cisco or Polycom OBTP or Fusion) +/// +public class Meeting +{ + [JsonProperty("minutesBeforeMeeting")] + public int MinutesBeforeMeeting; + + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("organizer")] + public string Organizer { get; set; } + [JsonProperty("title")] + public string Title { get; set; } + [JsonProperty("agenda")] + public string Agenda { get; set; } + + [JsonProperty("meetingWarningMinutes")] + public TimeSpan MeetingWarningMinutes + { + get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); } + } + [JsonProperty("timeToMeetingStart")] + public TimeSpan TimeToMeetingStart + { + get { - get - { - return EndTime - DateTime.Now; - } + return StartTime - DateTime.Now; } - [JsonProperty("startTime")] - public DateTime StartTime { get; set; } - [JsonProperty("endTime")] - public DateTime EndTime { get; set; } - [JsonProperty("duration")] - public TimeSpan Duration + } + [JsonProperty("timeToMeetingEnd")] + public TimeSpan TimeToMeetingEnd + { + get { - get - { - return EndTime - StartTime; - } + return EndTime - DateTime.Now; } - [JsonProperty("privacy")] - public eMeetingPrivacy Privacy { get; set; } - [JsonProperty("joinable")] - public bool Joinable + } + [JsonProperty("startTime")] + public DateTime StartTime { get; set; } + [JsonProperty("endTime")] + public DateTime EndTime { get; set; } + [JsonProperty("duration")] + public TimeSpan Duration + { + get { - get - { - var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now - && DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds); - //Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable); - return joinable; - } + return EndTime - StartTime; } + } + [JsonProperty("privacy")] + public eMeetingPrivacy Privacy { get; set; } + [JsonProperty("joinable")] + public bool Joinable + { + get + { + var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now + && DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds); + //Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable); + return joinable; + } + } [JsonProperty("dialable")] public bool Dialable { get; set; } - //public string ConferenceNumberToDial { get; set; } - [JsonProperty("conferencePassword")] - public string ConferencePassword { get; set; } - [JsonProperty("isOneButtonToPushMeeting")] - public bool IsOneButtonToPushMeeting { get; set; } + //public string ConferenceNumberToDial { get; set; } + [JsonProperty("conferencePassword")] + public string ConferencePassword { get; set; } + [JsonProperty("isOneButtonToPushMeeting")] + public bool IsOneButtonToPushMeeting { get; set; } - [JsonProperty("calls")] - public List Calls { get; private set; } + [JsonProperty("calls")] + public List Calls { get; private set; } - /// - /// Tracks the change types that have already been notified for - /// - [JsonIgnore] - public eMeetingEventChangeType NotifiedChangeTypes { get; set; } + /// + /// Tracks the change types that have already been notified for + /// + [JsonIgnore] + public eMeetingEventChangeType NotifiedChangeTypes { get; set; } - [JsonIgnore] private readonly int _joinableCooldownSeconds; + [JsonIgnore] private readonly int _joinableCooldownSeconds; - public Meeting() - { - Calls = new List(); - _joinableCooldownSeconds = 300; - } - - public Meeting(int joinableCooldownSeconds) - { - Calls = new List(); - _joinableCooldownSeconds = joinableCooldownSeconds; - } - - - - #region Overrides of Object - - public override string ToString() - { - return String.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime); - } - - #endregion - } - - public class Call + public Meeting() { - public string Number { get; set; } - public string Protocol { get; set; } - public string CallRate { get; set; } - public string CallType { get; set; } + Calls = new List(); + _joinableCooldownSeconds = 300; } - public class MeetingEventArgs : EventArgs + public Meeting(int joinableCooldownSeconds) { - public eMeetingEventChangeType ChangeType { get; set; } - public Meeting Meeting { get; set; } + Calls = new List(); + _joinableCooldownSeconds = joinableCooldownSeconds; } + + + #region Overrides of Object + + public override string ToString() + { + return String.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime); + } + + #endregion +} + +public class Call +{ + public string Number { get; set; } + public string Protocol { get; set; } + public string CallRate { get; set; } + public string CallType { get; set; } +} + +public class MeetingEventArgs : EventArgs +{ + public eMeetingEventChangeType ChangeType { get; set; } + public Meeting Meeting { get; set; } } diff --git a/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs b/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs index 078dc9e7..ff9ccac0 100644 --- a/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs @@ -8,15 +8,15 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.Devices.Common.DSP -{ +namespace PepperDash.Essentials.Devices.Common.DSP; + public abstract class DspBase : EssentialsDevice, ILevelControls { public Dictionary LevelControlPoints { get; private set; } - public Dictionary DialerControlPoints { get; private set; } + public Dictionary DialerControlPoints { get; private set; } - public Dictionary SwitcherControlPoints { get; private set; } + public Dictionary SwitcherControlPoints { get; private set; } public DspBase(string key, string name) : base(key, name) @@ -47,40 +47,38 @@ namespace PepperDash.Essentials.Devices.Common.DSP public abstract class DspControlPoint :IKeyed { - public string Key { get; } + public string Key { get; } - protected DspControlPoint(string key) => Key = key; + protected DspControlPoint(string key) => Key = key; } - public abstract class DspLevelControlPoint :DspControlPoint, IBasicVolumeWithFeedback +public abstract class DspLevelControlPoint :DspControlPoint, IBasicVolumeWithFeedback +{ + public BoolFeedback MuteFeedback { get; } + public IntFeedback VolumeLevelFeedback { get; } + + protected DspLevelControlPoint(string key, Func muteFeedbackFunc, Func volumeLevelFeedbackFunc) : base(key) { - public BoolFeedback MuteFeedback { get; } - public IntFeedback VolumeLevelFeedback { get; } - - protected DspLevelControlPoint(string key, Func muteFeedbackFunc, Func volumeLevelFeedbackFunc) : base(key) - { - MuteFeedback = new BoolFeedback(muteFeedbackFunc); - VolumeLevelFeedback = new IntFeedback(volumeLevelFeedbackFunc); - } - - public abstract void MuteOff(); - public abstract void MuteOn(); - public abstract void MuteToggle(); - public abstract void SetVolume(ushort level); - public abstract void VolumeDown(bool pressRelease); - public abstract void VolumeUp(bool pressRelease); + MuteFeedback = new BoolFeedback(muteFeedbackFunc); + VolumeLevelFeedback = new IntFeedback(volumeLevelFeedbackFunc); } + public abstract void MuteOff(); + public abstract void MuteOn(); + public abstract void MuteToggle(); + public abstract void SetVolume(ushort level); + public abstract void VolumeDown(bool pressRelease); + public abstract void VolumeUp(bool pressRelease); +} - public abstract class DspDialerBase:DspControlPoint + +public abstract class DspDialerBase:DspControlPoint { - protected DspDialerBase(string key) : base(key) { } + protected DspDialerBase(string key) : base(key) { } } // Main program // VTC // ATC - // Mics, unusual - -} \ No newline at end of file + // Mics, unusual \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs index d7e19d00..3308bc0e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs @@ -9,17 +9,17 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Displays -{ - public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced +namespace PepperDash.Essentials.Devices.Common.Displays; + +public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced { public IrOutputPortController IrPort { get; private set; } public ushort IrPulseTime { get; set; } - protected Func PowerIsOnFeedbackFunc - { - get { return () => _PowerIsOn; } - } + protected Func PowerIsOnFeedbackFunc + { + get { return () => _PowerIsOn; } + } protected override Func IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } @@ -29,7 +29,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays get { return () => _IsWarmingUp; } } - bool _PowerIsOn; + bool _PowerIsOn; bool _IsWarmingUp; bool _IsCoolingDown; @@ -101,18 +101,18 @@ namespace PepperDash.Essentials.Devices.Common.Displays public override void PowerOn() { IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime); - _PowerIsOn = true; + _PowerIsOn = true; } public override void PowerOff() { - _PowerIsOn = false; + _PowerIsOn = false; IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime); } public override void PowerToggle() { - _PowerIsOn = false; + _PowerIsOn = false; IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime); } @@ -166,7 +166,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// A delegate containing the input selector method to call public override void ExecuteSwitch(object inputSelector) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString()); + Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString()); Action finishSwitch = () => { @@ -199,26 +199,24 @@ namespace PepperDash.Essentials.Devices.Common.Displays } } - public class BasicIrDisplayFactory : EssentialsDeviceFactory +public class BasicIrDisplayFactory : EssentialsDeviceFactory +{ + public BasicIrDisplayFactory() { - public BasicIrDisplayFactory() - { - TypeNames = new List() { "basicirdisplay" }; - } - - 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; - } + TypeNames = new List() { "basicirdisplay" }; } + 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; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 24d55c2e..8f1fae45 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -11,60 +11,60 @@ using System.Collections.Generic; using System.Linq; using Feedback = PepperDash.Essentials.Core.Feedback; -namespace PepperDash.Essentials.Devices.Common.Displays -{ - public abstract class DisplayBase : EssentialsDevice, IDisplay +namespace PepperDash.Essentials.Devices.Common.Displays; + +public abstract class DisplayBase : EssentialsDevice, IDisplay { - private RoutingInputPort _currentInputPort; - public RoutingInputPort CurrentInputPort + private RoutingInputPort _currentInputPort; + public RoutingInputPort CurrentInputPort + { + get { - get - { - return _currentInputPort; - } - - protected set - { - if (_currentInputPort == value) return; - - _currentInputPort = value; - - InputChanged?.Invoke(this, _currentInputPort); - } + return _currentInputPort; } - public event InputChangedEventHandler InputChanged; - - public event SourceInfoChangeHandler CurrentSourceChange; - - public string CurrentSourceInfoKey { get; set; } - public SourceListItem CurrentSourceInfo + protected set { - get - { - return _CurrentSourceInfo; - } - set - { - if (value == _CurrentSourceInfo) return; + if (_currentInputPort == value) return; - var handler = CurrentSourceChange; + _currentInputPort = value; - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); - - _CurrentSourceInfo = value; - - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); - } + InputChanged?.Invoke(this, _currentInputPort); } - SourceListItem _CurrentSourceInfo; + } + + public event InputChangedEventHandler InputChanged; + + public event SourceInfoChangeHandler CurrentSourceChange; + + public string CurrentSourceInfoKey { get; set; } + public SourceListItem CurrentSourceInfo + { + get + { + return _CurrentSourceInfo; + } + set + { + if (value == _CurrentSourceInfo) return; + + var handler = CurrentSourceChange; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); + + _CurrentSourceInfo = value; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); + } + } + SourceListItem _CurrentSourceInfo; public BoolFeedback IsCoolingDownFeedback { get; protected set; } public BoolFeedback IsWarmingUpFeedback { get; private set; } - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } public uint WarmupTime { get; set; } public uint CooldownTime { get; set; } @@ -75,7 +75,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// abstract protected Func IsCoolingDownFeedbackFunc { get; } abstract protected Func IsWarmingUpFeedbackFunc { get; } - + protected CTimer WarmupTimer; protected CTimer CooldownTimer; @@ -100,11 +100,11 @@ namespace PepperDash.Essentials.Devices.Common.Displays public abstract void PowerOff(); public abstract void PowerToggle(); - public virtual FeedbackCollection Feedbacks + public virtual FeedbackCollection Feedbacks { get { - return new FeedbackCollection + return new FeedbackCollection { IsCoolingDownFeedback, IsWarmingUpFeedback @@ -117,12 +117,12 @@ namespace PepperDash.Essentials.Devices.Common.Displays protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { - var joinMap = new DisplayControllerJoinMap(joinStart); + var joinMap = new DisplayControllerJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { @@ -268,21 +268,21 @@ namespace PepperDash.Essentials.Devices.Common.Displays volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); } - } +} - public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback +public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback { - public StringFeedback CurrentInputFeedback { get; private set; } + public StringFeedback CurrentInputFeedback { get; private set; } - abstract protected Func CurrentInputFeedbackFunc { get; } + abstract protected Func CurrentInputFeedbackFunc { get; } - public BoolFeedback PowerIsOnFeedback { get; protected set; } + public BoolFeedback PowerIsOnFeedback { get; protected set; } - abstract protected Func PowerIsOnFeedbackFunc { get; } + abstract protected Func PowerIsOnFeedbackFunc { get; } - public static MockDisplay DefaultDisplay - { + public static MockDisplay DefaultDisplay + { get { if (_DefaultDisplay == null) @@ -295,41 +295,40 @@ namespace PepperDash.Essentials.Devices.Common.Displays public TwoWayDisplayBase(string key, string name) : base(key, name) { - CurrentInputFeedback = new StringFeedback(CurrentInputFeedbackFunc); + CurrentInputFeedback = new StringFeedback(CurrentInputFeedbackFunc); WarmupTime = 7000; CooldownTime = 15000; - PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); + PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); - Feedbacks.Add(CurrentInputFeedback); - Feedbacks.Add(PowerIsOnFeedback); + Feedbacks.Add(CurrentInputFeedback); + Feedbacks.Add(PowerIsOnFeedback); - PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; + PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; } - void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) + void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) + { + if (UsageTracker != null) { - if (UsageTracker != null) - { - if (PowerIsOnFeedback.BoolValue) - UsageTracker.StartDeviceUsage(); - else - UsageTracker.EndDeviceUsage(); - } + if (PowerIsOnFeedback.BoolValue) + UsageTracker.StartDeviceUsage(); + else + UsageTracker.EndDeviceUsage(); } + } - public event EventHandler NumericSwitchChange; + public event EventHandler NumericSwitchChange; - /// - /// Raise an event when the status of a switch object changes. - /// - /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType - protected void OnSwitchChange(RoutingNumericEventArgs e) - { - var newEvent = NumericSwitchChange; - if (newEvent != null) newEvent(this, e); - } - } -} \ No newline at end of file + /// + /// Raise an event when the status of a switch object changes. + /// + /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType + protected void OnSwitchChange(RoutingNumericEventArgs e) + { + var newEvent = NumericSwitchChange; + if (newEvent != null) newEvent(this, e); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs b/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs index ce7113e1..81540294 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs @@ -4,14 +4,12 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Displays -{ - public interface IInputHdmi1 { void InputHdmi1(); } - public interface IInputHdmi2 { void InputHdmi2(); } - public interface IInputHdmi3 { void InputHdmi3(); } - public interface IInputHdmi4 { void InputHdmi4(); } - public interface IInputDisplayPort1 { void InputDisplayPort1(); } - public interface IInputDisplayPort2 { void InputDisplayPort2(); } - public interface IInputVga1 { void InputVga1(); } +namespace PepperDash.Essentials.Devices.Displays; -} \ No newline at end of file +public interface IInputHdmi1 { void InputHdmi1(); } +public interface IInputHdmi2 { void InputHdmi2(); } +public interface IInputHdmi3 { void InputHdmi3(); } +public interface IInputHdmi4 { void InputHdmi4(); } +public interface IInputDisplayPort1 { void InputDisplayPort1(); } +public interface IInputDisplayPort2 { void InputDisplayPort2(); } +public interface IInputVga1 { void InputVga1(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index f972c1e6..56bdbc41 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -10,58 +10,58 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Displays -{ - public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback +namespace PepperDash.Essentials.Devices.Common.Displays; + +public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback { - public ISelectableItems Inputs { get; private set; } + public ISelectableItems Inputs { get; private set; } bool _PowerIsOn; bool _IsWarmingUp; bool _IsCoolingDown; - protected override Func PowerIsOnFeedbackFunc + protected override Func PowerIsOnFeedbackFunc + { + get { - get - { - return () => - { - return _PowerIsOn; - }; - } } + return () => + { + return _PowerIsOn; + }; + } } protected override Func IsCoolingDownFeedbackFunc + { + get { - get + return () => { - return () => - { - return _IsCoolingDown; - }; - } + return _IsCoolingDown; + }; } + } protected override Func IsWarmingUpFeedbackFunc + { + get { - get + return () => { - return () => - { - return _IsWarmingUp; - }; - } + return _IsWarmingUp; + }; } - protected override Func CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } } + } + protected override Func CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } } - int VolumeHeldRepeatInterval = 200; - ushort VolumeInterval = 655; + 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 + Inputs = new MockDisplayInputs + { + Items = new Dictionary { { "HDMI1", new MockDisplayInput ( "HDMI1", "HDMI 1",this ) }, { "HDMI2", new MockDisplayInput ("HDMI2", "HDMI 2",this ) }, @@ -69,11 +69,11 @@ 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(); - - 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); @@ -88,8 +88,8 @@ namespace PepperDash.Essentials.Devices.Common.Displays VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; }); MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted); - WarmupTime = 10000; - CooldownTime = 10000; + WarmupTime = 10000; + CooldownTime = 10000; } public override void PowerOn() @@ -123,8 +123,8 @@ namespace PepperDash.Essentials.Devices.Common.Displays Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this); _IsCoolingDown = false; IsCoolingDownFeedback.InvokeFireUpdate(); - _PowerIsOn = false; - PowerIsOnFeedback.InvokeFireUpdate(); + _PowerIsOn = false; + PowerIsOnFeedback.InvokeFireUpdate(); }, CooldownTime); } } @@ -139,43 +139,43 @@ namespace PepperDash.Essentials.Devices.Common.Displays public override void ExecuteSwitch(object selector) { - try - { - Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector); + try + { + Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector); if (!_PowerIsOn) { PowerOn(); } - if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) - return; + if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) + return; - Debug.LogMessage(LogEventLevel.Verbose, "Selected input: {input}", this, input.Key); - input.Select(); + Debug.LogMessage(LogEventLevel.Verbose, "Selected input: {input}", this, input.Key); + input.Select(); - var inputPort = InputPorts.FirstOrDefault(port => - { - Debug.LogMessage(LogEventLevel.Verbose, "Checking input port {inputPort} with selector {portSelector} against {selector}", this, port, port.Selector, selector); - return port.Selector.ToString() == selector.ToString(); - }); - - if (inputPort == null) - { - Debug.LogMessage(LogEventLevel.Verbose, "Unable to find input port for selector {selector}", this, selector); - return; - } - - Debug.LogMessage(LogEventLevel.Verbose, "Setting current input port to {inputPort}", this, inputPort); - CurrentInputPort = inputPort; - } catch (Exception ex) + var inputPort = InputPorts.FirstOrDefault(port => { - Debug.LogMessage(ex, "Error making switch: {Exception}", this, ex); - } - } + Debug.LogMessage(LogEventLevel.Verbose, "Checking input port {inputPort} with selector {portSelector} against {selector}", this, port, port.Selector, selector); + return port.Selector.ToString() == selector.ToString(); + }); - public void SetInput(string selector) + 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; try @@ -185,24 +185,24 @@ namespace PepperDash.Essentials.Devices.Common.Displays catch { } - if (currentInput != null) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector); - currentInput.IsSelected = false; - } + if (currentInput != null) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector); + currentInput.IsSelected = false; + } if (!Inputs.Items.TryGetValue(selector, out var input)) - return; + return; input.IsSelected = true; Inputs.CurrentItem = selector; - } + } - #region IBasicVolumeWithFeedback Members + #region IBasicVolumeWithFeedback Members - public IntFeedback VolumeLevelFeedback { get; private set; } + public IntFeedback VolumeLevelFeedback { get; private set; } public void SetVolume(ushort level) { @@ -225,36 +225,36 @@ namespace PepperDash.Essentials.Devices.Common.Displays public BoolFeedback MuteFeedback { get; private set; } - #endregion + #endregion - #region IBasicVolumeControls Members + #region IBasicVolumeControls Members - public void VolumeUp(bool pressRelease) + 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); - } - //} + //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); - } - //} + //while (pressRelease) + //{ + Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease); + if (pressRelease) + { + var newLevel = _FakeVolumeLevel - VolumeInterval; + SetVolume((ushort)newLevel); + CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); + } + //} } public void MuteToggle() @@ -269,7 +269,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays { LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); } - } +} public class MockDisplayFactory : EssentialsDeviceFactory { @@ -283,5 +283,4 @@ namespace PepperDash.Essentials.Devices.Common.Displays Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device"); return new MockDisplay(dc.Key, dc.Name); } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs index 0380085f..2b723230 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs @@ -6,96 +6,95 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Devices.Common.Displays +namespace PepperDash.Essentials.Devices.Common.Displays; + +public class MockDisplayInputs : ISelectableItems { - public class MockDisplayInputs : ISelectableItems + private Dictionary _items; + + public Dictionary Items { - private Dictionary _items; - - public Dictionary Items + get { - get - { - return _items; - } - set - { - if (_items == value) - return; - - _items = value; - - ItemsUpdated?.Invoke(this, null); - } + return _items; } + set + { + if (_items == value) + return; - private string _currentItem; + _items = value; - public string CurrentItem - { - get - { - return _currentItem; - } - set - { - if (_currentItem == value) - return; - - _currentItem = value; - - CurrentItemChanged?.Invoke(this, null); - } + ItemsUpdated?.Invoke(this, null); } - - public event EventHandler ItemsUpdated; - public event EventHandler CurrentItemChanged; } - 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; - - public bool IsSelected + get { - get - { - return _isSelected; - } - set - { - if (_isSelected == value) - return; - - _isSelected = value; - - ItemUpdated?.Invoke(this, null); - } + return _isSelected; } - - public string Name { get; set; } - - public string Key { get; set; } - - public event EventHandler ItemUpdated; - - 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); } + } - 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; } } } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 1bb7f503..825988e6 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -11,256 +11,255 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Shades +namespace PepperDash.Essentials.Devices.Common.Shades; + +/// +/// Controls a single shade using three relays +/// +public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftControl { + readonly ScreenLiftControllerConfigProperties Config; + readonly ScreenLiftRelaysConfig RaiseRelayConfig; + readonly ScreenLiftRelaysConfig LowerRelayConfig; + readonly ScreenLiftRelaysConfig LatchedRelayConfig; + + Displays.DisplayBase DisplayDevice; + ISwitchedOutput RaiseRelay; + ISwitchedOutput LowerRelay; + ISwitchedOutput LatchedRelay; + + public bool InUpPosition + { + get { return _isInUpPosition; } + set + { + if (value == _isInUpPosition) return; + _isInUpPosition = value; + IsInUpPosition.FireUpdate(); + PositionChanged?.Invoke(this, new EventArgs()); + } + } + + private bool _isInUpPosition { get; set; } + public eScreenLiftControlType Type { get; private set; } + public eScreenLiftControlMode Mode { get; private set; } + + public string DisplayDeviceKey { get; private set; } + public BoolFeedback IsInUpPosition { get; private set; } + + public event EventHandler PositionChanged; + + public ScreenLiftController(string key, string name, ScreenLiftControllerConfigProperties config) + : base(key, name) + { + Config = config; + DisplayDeviceKey = Config.DisplayDeviceKey; + Mode = Config.Mode; + Type = Config.Type; + + IsInUpPosition = new BoolFeedback(() => _isInUpPosition); + + switch (Mode) + { + case eScreenLiftControlMode.momentary: + { + RaiseRelayConfig = Config.Relays["raise"]; + LowerRelayConfig = Config.Relays["lower"]; + break; + } + case eScreenLiftControlMode.latched: + { + LatchedRelayConfig = Config.Relays["latched"]; + break; + } + } + } + + private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + if (!DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift) + { + Raise(); + return; + } + if (DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.screen) + { + Raise(); + return; + } + } + + private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + if (DisplayDevice.IsWarmingUpFeedback.BoolValue) + { + Lower(); + } + } + + public override bool CustomActivate() + { + //Create ISwitchedOutput objects based on props + switch (Mode) + { + case eScreenLiftControlMode.momentary: + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}"); + RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey); + LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey); + break; + } + case eScreenLiftControlMode.latched: + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}"); + LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey); + break; + } + } + + Debug.LogMessage(LogEventLevel.Debug, this, $"Getting display with key {DisplayDeviceKey}"); + DisplayDevice = GetDisplayBaseFromDevice(DisplayDeviceKey); + + if (DisplayDevice != null) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Subscribing to {DisplayDeviceKey} feedbacks"); + + DisplayDevice.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; + DisplayDevice.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; + } + + return base.CustomActivate(); + } + + public void Raise() + { + if (RaiseRelay == null && LatchedRelay == null) return; + + Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}"); + + switch (Mode) + { + case eScreenLiftControlMode.momentary: + { + PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); + break; + } + case eScreenLiftControlMode.latched: + { + LatchedRelay.Off(); + break; + } + } + InUpPosition = true; + } + + public void Lower() + { + if (LowerRelay == null && LatchedRelay == null) return; + + Debug.LogMessage(LogEventLevel.Debug, this, $"Lowering {Type}"); + + switch (Mode) + { + case eScreenLiftControlMode.momentary: + { + PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); + break; + } + case eScreenLiftControlMode.latched: + { + LatchedRelay.On(); + break; + } + } + InUpPosition = false; + } + + void PulseOutput(ISwitchedOutput output, int pulseTime) + { + output.On(); + CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime); + } + /// - /// Controls a single shade using three relays + /// Attempts to get the port on teh specified device from config /// - public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftControl + /// + /// + ISwitchedOutput GetSwitchedOutputFromDevice(string relayKey) { - readonly ScreenLiftControllerConfigProperties Config; - readonly ScreenLiftRelaysConfig RaiseRelayConfig; - readonly ScreenLiftRelaysConfig LowerRelayConfig; - readonly ScreenLiftRelaysConfig LatchedRelayConfig; - - Displays.DisplayBase DisplayDevice; - ISwitchedOutput RaiseRelay; - ISwitchedOutput LowerRelay; - ISwitchedOutput LatchedRelay; - - public bool InUpPosition + var portDevice = DeviceManager.GetDeviceForKey(relayKey); + if (portDevice != null) { - get { return _isInUpPosition; } - set - { - if (value == _isInUpPosition) return; - _isInUpPosition = value; - IsInUpPosition.FireUpdate(); - PositionChanged?.Invoke(this, new EventArgs()); - } + return (portDevice as ISwitchedOutput); } - - private bool _isInUpPosition { get; set; } - public eScreenLiftControlType Type { get; private set; } - public eScreenLiftControlMode Mode { get; private set; } - - public string DisplayDeviceKey { get; private set; } - public BoolFeedback IsInUpPosition { get; private set; } - - public event EventHandler PositionChanged; - - public ScreenLiftController(string key, string name, ScreenLiftControllerConfigProperties config) - : base(key, name) + else { - Config = config; - DisplayDeviceKey = Config.DisplayDeviceKey; - Mode = Config.Mode; - Type = Config.Type; - - IsInUpPosition = new BoolFeedback(() => _isInUpPosition); - - switch (Mode) - { - case eScreenLiftControlMode.momentary: - { - RaiseRelayConfig = Config.Relays["raise"]; - LowerRelayConfig = Config.Relays["lower"]; - break; - } - case eScreenLiftControlMode.latched: - { - LatchedRelayConfig = Config.Relays["latched"]; - break; - } - } - } - - private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - if (!DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift) - { - Raise(); - return; - } - if (DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.screen) - { - Raise(); - return; - } - } - - private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - if (DisplayDevice.IsWarmingUpFeedback.BoolValue) - { - Lower(); - } - } - - public override bool CustomActivate() - { - //Create ISwitchedOutput objects based on props - switch (Mode) - { - case eScreenLiftControlMode.momentary: - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}"); - RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey); - LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey); - break; - } - case eScreenLiftControlMode.latched: - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}"); - LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey); - break; - } - } - - Debug.LogMessage(LogEventLevel.Debug, this, $"Getting display with key {DisplayDeviceKey}"); - DisplayDevice = GetDisplayBaseFromDevice(DisplayDeviceKey); - - if (DisplayDevice != null) - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Subscribing to {DisplayDeviceKey} feedbacks"); - - DisplayDevice.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; - DisplayDevice.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; - } - - return base.CustomActivate(); - } - - public void Raise() - { - if (RaiseRelay == null && LatchedRelay == null) return; - - Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}"); - - switch (Mode) - { - case eScreenLiftControlMode.momentary: - { - PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); - break; - } - case eScreenLiftControlMode.latched: - { - LatchedRelay.Off(); - break; - } - } - InUpPosition = true; - } - - public void Lower() - { - if (LowerRelay == null && LatchedRelay == null) return; - - Debug.LogMessage(LogEventLevel.Debug, this, $"Lowering {Type}"); - - switch (Mode) - { - case eScreenLiftControlMode.momentary: - { - PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); - break; - } - case eScreenLiftControlMode.latched: - { - LatchedRelay.On(); - break; - } - } - InUpPosition = false; - } - - void PulseOutput(ISwitchedOutput output, int pulseTime) - { - output.On(); - CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime); - } - - /// - /// Attempts to get the port on teh specified device from config - /// - /// - /// - ISwitchedOutput GetSwitchedOutputFromDevice(string relayKey) - { - var portDevice = DeviceManager.GetDeviceForKey(relayKey); - if (portDevice != null) - { - return (portDevice as ISwitchedOutput); - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay device with key '{0}'", relayKey); - return null; - } - } - - Displays.DisplayBase GetDisplayBaseFromDevice(string displayKey) - { - var displayDevice = DeviceManager.GetDeviceForKey(displayKey); - if (displayDevice != null) - { - return displayDevice as Displays.DisplayBase; - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get display device with key '{0}'", displayKey); - return null; - } - } - - } - - public class ScreenLiftControllerConfigProperties - { - [JsonProperty("displayDeviceKey")] - public string DisplayDeviceKey { get; set; } - - [JsonProperty("type")] - [JsonConverter(typeof(StringEnumConverter))] - public eScreenLiftControlType Type { get; set; } - - [JsonProperty("mode")] - [JsonConverter(typeof(StringEnumConverter))] - public eScreenLiftControlMode Mode { get; set; } - - [JsonProperty("relays")] - public Dictionary Relays { get; set; } - - } - public class ScreenLiftRelaysConfig - { - [JsonProperty("deviceKey")] - public string DeviceKey { get; set; } - - [JsonProperty("pulseTimeInMs")] - public int PulseTimeInMs { get; set; } - } - - public class ScreenLiftControllerFactory : EssentialsDeviceFactory - { - public ScreenLiftControllerFactory() - { - TypeNames = new List() { "screenliftcontroller" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); - - return new ScreenLiftController(dc.Key, dc.Name, props); + Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay device with key '{0}'", relayKey); + return null; } } - public enum eScreenLiftControlMode + Displays.DisplayBase GetDisplayBaseFromDevice(string displayKey) { - momentary, - latched + var displayDevice = DeviceManager.GetDeviceForKey(displayKey); + if (displayDevice != null) + { + return displayDevice as Displays.DisplayBase; + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get display device with key '{0}'", displayKey); + return null; + } } + +} + +public class ScreenLiftControllerConfigProperties +{ + [JsonProperty("displayDeviceKey")] + public string DisplayDeviceKey { get; set; } + + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public eScreenLiftControlType Type { get; set; } + + [JsonProperty("mode")] + [JsonConverter(typeof(StringEnumConverter))] + public eScreenLiftControlMode Mode { get; set; } + + [JsonProperty("relays")] + public Dictionary Relays { get; set; } + +} +public class ScreenLiftRelaysConfig +{ + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + [JsonProperty("pulseTimeInMs")] + public int PulseTimeInMs { get; set; } +} + +public class ScreenLiftControllerFactory : EssentialsDeviceFactory +{ + public ScreenLiftControllerFactory() + { + TypeNames = new List() { "screenliftcontroller" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); + + return new ScreenLiftController(dc.Key, dc.Name, props); + } +} + +public enum eScreenLiftControlMode +{ + momentary, + latched } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs index 618924cd..f6b99b09 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs @@ -5,56 +5,55 @@ using Serilog.Events; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.Devices.Common.Generic +namespace PepperDash.Essentials.Devices.Common.Generic; + +public class GenericSink : EssentialsDevice, IRoutingSinkWithInputPort { - public class GenericSink : EssentialsDevice, IRoutingSinkWithInputPort + public GenericSink(string key, string name) : base(key, name) { - public GenericSink(string key, string name) : base(key, name) - { - InputPorts = new RoutingPortCollection(); + InputPorts = new RoutingPortCollection(); - var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); + var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); - InputPorts.Add(inputPort); - } - - public RoutingPortCollection InputPorts { get; private set; } - - public string CurrentSourceInfoKey { get; set; } - - private SourceListItem _currentSource; - public SourceListItem CurrentSourceInfo { - get => _currentSource; - set { - if(value == _currentSource) - { - return; - } - - CurrentSourceChange?.Invoke(_currentSource, ChangeType.WillChange); - - _currentSource = value; - - CurrentSourceChange?.Invoke(_currentSource, ChangeType.DidChange); - } - } - - public RoutingInputPort CurrentInputPort => InputPorts[0]; - - public event SourceInfoChangeHandler CurrentSourceChange; + InputPorts.Add(inputPort); } - public class GenericSinkFactory : EssentialsDeviceFactory - { - public GenericSinkFactory() - { - TypeNames = new List() { "genericsink", "genericdestination" }; - } + public RoutingPortCollection InputPorts { get; private set; } - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Sink Device"); - return new GenericSink(dc.Key, dc.Name); + public string CurrentSourceInfoKey { get; set; } + + private SourceListItem _currentSource; + public SourceListItem CurrentSourceInfo { + get => _currentSource; + set { + if(value == _currentSource) + { + return; + } + + CurrentSourceChange?.Invoke(_currentSource, ChangeType.WillChange); + + _currentSource = value; + + CurrentSourceChange?.Invoke(_currentSource, ChangeType.DidChange); } } + + public RoutingInputPort CurrentInputPort => InputPorts[0]; + + public event SourceInfoChangeHandler CurrentSourceChange; +} + +public class GenericSinkFactory : EssentialsDeviceFactory +{ + public GenericSinkFactory() + { + TypeNames = new List() { "genericsink", "genericdestination" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Sink Device"); + return new GenericSink(dc.Key, dc.Name); + } } diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs index 3c6e57d2..ea5f497e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs @@ -11,18 +11,18 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common -{ +namespace PepperDash.Essentials.Devices.Common; + public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } - public GenericSource(string key, string name) + public GenericSource(string key, string name) : base(key, name) { - AnyOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + AnyOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts = new RoutingPortCollection { AnyOut }; } @@ -34,24 +34,23 @@ namespace PepperDash.Essentials.Devices.Common #endregion - #region IUsageTracking Members + #region IUsageTracking Members - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } - #endregion + #endregion } - public class GenericSourceFactory : EssentialsDeviceFactory +public class GenericSourceFactory : EssentialsDeviceFactory +{ + public GenericSourceFactory() { - public GenericSourceFactory() - { - TypeNames = new List() { "genericsource" }; - } + TypeNames = new List() { "genericsource" }; + } - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Source Device"); - return new GenericSource(dc.Key, dc.Name); - } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Source Device"); + return new GenericSource(dc.Key, dc.Name); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs b/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs index 6e1dc506..565f90ed 100644 --- a/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs @@ -14,61 +14,61 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Lighting; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Lighting +namespace PepperDash.Essentials.Devices.Common.Lighting; + +public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes { - public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes - { - #region ILightingScenes Members + #region ILightingScenes Members - public event EventHandler LightingSceneChange; + public event EventHandler LightingSceneChange; - public List LightingScenes { get; protected set; } + public List LightingScenes { get; protected set; } - public LightingScene CurrentLightingScene { get; protected set; } + public LightingScene CurrentLightingScene { get; protected set; } public IntFeedback CurrentLightingSceneFeedback { get; protected set; } - #endregion + #endregion - protected LightingBase(string key, string name) - : base(key, name) - { - LightingScenes = new List(); + protected LightingBase(string key, string name) + : base(key, name) + { + LightingScenes = new List(); - CurrentLightingScene = new LightingScene(); + CurrentLightingScene = new LightingScene(); //CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); }); - } + } - public abstract void SelectScene(LightingScene scene); + public abstract void SelectScene(LightingScene scene); - public void SimulateSceneSelect(string sceneName) + public void SimulateSceneSelect(string sceneName) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); + + var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName)); + + if (scene != null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); - - var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName)); - - if (scene != null) - { - CurrentLightingScene = scene; - OnLightingSceneChange(); - } + CurrentLightingScene = scene; + OnLightingSceneChange(); } + } - /// - /// Sets the IsActive property on each scene and fires the LightingSceneChange event - /// - protected void OnLightingSceneChange() + /// + /// Sets the IsActive property on each scene and fires the LightingSceneChange event + /// + protected void OnLightingSceneChange() + { + foreach (var scene in LightingScenes) { - foreach (var scene in LightingScenes) - { - if (scene == CurrentLightingScene) - scene.IsActive = true; + if (scene == CurrentLightingScene) + scene.IsActive = true; - else - scene.IsActive = false; - } - LightingSceneChange?.Invoke(this, new LightingSceneChangeEventArgs(CurrentLightingScene)); + else + scene.IsActive = false; } + LightingSceneChange?.Invoke(this, new LightingSceneChangeEventArgs(CurrentLightingScene)); + } protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) @@ -92,46 +92,45 @@ namespace PepperDash.Essentials.Devices.Common.Lighting return LinkLightingToApi(lightingDevice, trilist, joinMap); } - protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap) - { - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap) + { + Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - Debug.LogMessage(LogEventLevel.Information, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); + Debug.LogMessage(LogEventLevel.Information, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); - // GenericLighitng Actions & FeedBack - trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); + // GenericLighitng Actions & FeedBack + trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); - var sceneIndex = 0; - foreach (var scene in lightingDevice.LightingScenes) - { - var index = sceneIndex; + var sceneIndex = 0; + foreach (var scene in lightingDevice.LightingScenes) + { + var index = sceneIndex; - trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index])); - scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]); - trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; - trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; + trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index])); + scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]); + trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; + trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; - sceneIndex++; - } - - trilist.OnlineStatusChange += (sender, args) => - { - if (!args.DeviceOnLine) return; - - sceneIndex = 0; - foreach (var scene in lightingDevice.LightingScenes) - { - var index = sceneIndex; - - trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; - trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; - scene.IsActiveFeedback.FireUpdate(); - - sceneIndex++; - } - }; - - return joinMap; - } + sceneIndex++; } + + trilist.OnlineStatusChange += (sender, args) => + { + if (!args.DeviceOnLine) return; + + sceneIndex = 0; + foreach (var scene in lightingDevice.LightingScenes) + { + var index = sceneIndex; + + trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; + trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; + scene.IsActiveFeedback.FireUpdate(); + + sceneIndex++; + } + }; + + return joinMap; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs index 1af09f1c..19ee9410 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs @@ -1,15 +1,14 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Devices.Common.Room +namespace PepperDash.Essentials.Devices.Common.Room; + +public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy, + IEmergency, IMicrophonePrivacy { - public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy, - IEmergency, IMicrophonePrivacy - { - bool ExcludeFromGlobalFunctions { get; } + bool ExcludeFromGlobalFunctions { get; } - void RunRouteAction(string routeKey); + void RunRouteAction(string routeKey); - EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } - } + EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs index b7f1a619..fd80010c 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs @@ -4,23 +4,22 @@ using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Devices.Common.Room +namespace PepperDash.Essentials.Devices.Common.Room; + +public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback, + IRoomOccupancy, IEmergency, IMicrophonePrivacy { - public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback, - IRoomOccupancy, IEmergency, IMicrophonePrivacy - { - EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } + EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } - bool ExcludeFromGlobalFunctions { get; } + bool ExcludeFromGlobalFunctions { get; } - void RunRouteAction(string routeKey); + void RunRouteAction(string routeKey); - IHasScheduleAwareness ScheduleSource { get; } + IHasScheduleAwareness ScheduleSource { get; } - new BoolFeedback InCallFeedback { get; } + new BoolFeedback InCallFeedback { get; } - new BoolFeedback PrivacyModeIsOnFeedback { get; } + new BoolFeedback PrivacyModeIsOnFeedback { get; } - string DefaultCodecRouteString { get; } - } + string DefaultCodecRouteString { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs index e32be4c4..69f15d83 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs @@ -5,10 +5,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace PepperDash.Essentials.Devices.Common.Room +namespace PepperDash.Essentials.Devices.Common.Room; + +public interface IEssentialsRoomPropertiesConfig { - public interface IEssentialsRoomPropertiesConfig - { - EssentialsRoomPropertiesConfig PropertiesConfig { get; } - } + EssentialsRoomPropertiesConfig PropertiesConfig { get; } } diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs index 947be5d9..00b0348e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs @@ -6,17 +6,16 @@ using System.Collections.Generic; using TwoWayDisplayBase = PepperDash.Essentials.Devices.Common.Displays.TwoWayDisplayBase; -namespace PepperDash.Essentials.Devices.Common.Room +namespace PepperDash.Essentials.Devices.Common.Room; + +public interface IEssentialsTechRoom:IEssentialsRoom, ITvPresetsProvider,IBridgeAdvanced,IRunDirectRouteAction { - public interface IEssentialsTechRoom:IEssentialsRoom, ITvPresetsProvider,IBridgeAdvanced,IRunDirectRouteAction - { - EssentialsTechRoomConfig PropertiesConfig { get; } - Dictionary Tuners { get; } + EssentialsTechRoomConfig PropertiesConfig { get; } + Dictionary Tuners { get; } - Dictionary Displays { get; } + Dictionary Displays { get; } - void RoomPowerOn(); + void RoomPowerOn(); - void RoomPowerOff(); - } + void RoomPowerOff(); } diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs index 32885aec..808568de 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs @@ -16,41 +16,41 @@ using PepperDash.Essentials.Core.Presets; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common -{ - [Description("Wrapper class for an IR Set Top Box")] - public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider +namespace PepperDash.Essentials.Devices.Common; + +[Description("Wrapper class for an IR Set Top Box")] +public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider { public IrOutputPortController IrPort { get; private set; } public uint DisplayUiType { get { return DisplayUiConstants.TypeDirecTv; } } - public ushort IrPulseTime { get; set; } + public ushort IrPulseTime { get; set; } - public bool HasPresets { get; set; } - public bool HasDvr { get; set; } - public bool HasDpad { get; set; } - public bool HasNumeric { get; set; } + public bool HasPresets { get; set; } + public bool HasDvr { get; set; } + public bool HasDpad { get; set; } + public bool HasNumeric { get; set; } - public DevicePresetsModel TvPresets { get; private set; } + public DevicePresetsModel TvPresets { get; private set; } public IRSetTopBoxBase(string key, string name, IrOutputPortController portCont, - SetTopBoxPropertiesConfig props) + SetTopBoxPropertiesConfig props) : base(key, name) { IrPort = portCont; - IrPulseTime = 200; + IrPulseTime = 200; - if (props.IrPulseTime > 0) - { - IrPulseTime = (ushort)props.IrPulseTime; - } + if (props.IrPulseTime > 0) + { + IrPulseTime = (ushort)props.IrPulseTime; + } DeviceManager.AddDevice(portCont); - HasPresets = props.HasPresets; - HasDvr = props.HasDvr; - HasDpad = props.HasDpad; - HasNumeric = props.HasNumeric; + HasPresets = props.HasPresets; + HasDvr = props.HasDvr; + HasDpad = props.HasDpad; + HasNumeric = props.HasNumeric; HasKeypadAccessoryButton1 = true; KeypadAccessoryButton1Command = "Dash"; @@ -347,174 +347,172 @@ namespace PepperDash.Essentials.Devices.Common #endregion - #region IUsageTracking Members + #region IUsageTracking Members - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } - #endregion + #endregion - #region IPower Members + #region IPower Members - public void PowerOn() - { - IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime); - } + public void PowerOn() + { + IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime); + } - public void PowerOff() - { - IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime); - } + public void PowerOff() + { + IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime); + } - public void PowerToggle() - { - IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime); - } + public void PowerToggle() + { + IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime); + } - #endregion + #endregion public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { - var joinMap = new SetTopBoxControllerJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var joinMap = new SetTopBoxControllerJoinMap(joinStart); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); - if (bridge != null) + 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."); + } + + Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + Debug.LogMessage(LogEventLevel.Information, "Linking to SetTopBox: {0}", Name); + + trilist.OnlineStatusChange += new OnlineStatusChangeEventHandler((o, a) => + { + if (a.DeviceOnLine) { - bridge.AddJoinMap(Key, joinMap); + trilist.StringInput[joinMap.Name.JoinNumber].StringValue = Name; } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); - } - - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - Debug.LogMessage(LogEventLevel.Information, "Linking to SetTopBox: {0}", Name); - - trilist.OnlineStatusChange += new OnlineStatusChangeEventHandler((o, a) => - { - if (a.DeviceOnLine) - { - trilist.StringInput[joinMap.Name.JoinNumber].StringValue = Name; - } - }); + }); - var stbBase = this as ISetTopBoxControls; - if (stbBase != null) - { - trilist.BooleanInput[joinMap.HasDpad.JoinNumber].BoolValue = stbBase.HasDpad; - trilist.BooleanInput[joinMap.HasNumeric.JoinNumber].BoolValue = stbBase.HasNumeric; - trilist.BooleanInput[joinMap.HasDvr.JoinNumber].BoolValue = stbBase.HasDvr; - trilist.BooleanInput[joinMap.HasPresets.JoinNumber].BoolValue = stbBase.HasPresets; + var stbBase = this as ISetTopBoxControls; + if (stbBase != null) + { + trilist.BooleanInput[joinMap.HasDpad.JoinNumber].BoolValue = stbBase.HasDpad; + trilist.BooleanInput[joinMap.HasNumeric.JoinNumber].BoolValue = stbBase.HasNumeric; + trilist.BooleanInput[joinMap.HasDvr.JoinNumber].BoolValue = stbBase.HasDvr; + trilist.BooleanInput[joinMap.HasPresets.JoinNumber].BoolValue = stbBase.HasPresets; - trilist.SetBoolSigAction(joinMap.DvrList.JoinNumber, stbBase.DvrList); - trilist.SetBoolSigAction(joinMap.Replay.JoinNumber, stbBase.Replay); + trilist.SetBoolSigAction(joinMap.DvrList.JoinNumber, stbBase.DvrList); + trilist.SetBoolSigAction(joinMap.Replay.JoinNumber, stbBase.Replay); - trilist.SetStringSigAction(joinMap.LoadPresets.JoinNumber, stbBase.LoadPresets); - } + trilist.SetStringSigAction(joinMap.LoadPresets.JoinNumber, stbBase.LoadPresets); + } var stbPower = this as IHasPowerControl; - if (stbPower != null) - { - trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, stbPower.PowerOn); - trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, stbPower.PowerOff); - trilist.SetSigTrueAction(joinMap.PowerToggle.JoinNumber, stbPower.PowerToggle); - } + if (stbPower != null) + { + trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, stbPower.PowerOn); + trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, stbPower.PowerOff); + trilist.SetSigTrueAction(joinMap.PowerToggle.JoinNumber, stbPower.PowerToggle); + } var stbDPad = this as IDPad; - if (stbDPad != null) - { - trilist.SetBoolSigAction(joinMap.Up.JoinNumber, stbDPad.Up); - trilist.SetBoolSigAction(joinMap.Down.JoinNumber, stbDPad.Down); - trilist.SetBoolSigAction(joinMap.Left.JoinNumber, stbDPad.Left); - trilist.SetBoolSigAction(joinMap.Right.JoinNumber, stbDPad.Right); - trilist.SetBoolSigAction(joinMap.Select.JoinNumber, stbDPad.Select); - trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, stbDPad.Menu); - trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbDPad.Exit); - } + if (stbDPad != null) + { + trilist.SetBoolSigAction(joinMap.Up.JoinNumber, stbDPad.Up); + trilist.SetBoolSigAction(joinMap.Down.JoinNumber, stbDPad.Down); + trilist.SetBoolSigAction(joinMap.Left.JoinNumber, stbDPad.Left); + trilist.SetBoolSigAction(joinMap.Right.JoinNumber, stbDPad.Right); + trilist.SetBoolSigAction(joinMap.Select.JoinNumber, stbDPad.Select); + trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, stbDPad.Menu); + trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbDPad.Exit); + } var stbChannel = this as IChannel; - if (stbChannel != null) - { - trilist.SetBoolSigAction(joinMap.ChannelUp.JoinNumber, stbChannel.ChannelUp); - trilist.SetBoolSigAction(joinMap.ChannelDown.JoinNumber, stbChannel.ChannelDown); - trilist.SetBoolSigAction(joinMap.LastChannel.JoinNumber, stbChannel.LastChannel); - trilist.SetBoolSigAction(joinMap.Guide.JoinNumber, stbChannel.Guide); - trilist.SetBoolSigAction(joinMap.Info.JoinNumber, stbChannel.Info); - trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbChannel.Exit); - } + if (stbChannel != null) + { + trilist.SetBoolSigAction(joinMap.ChannelUp.JoinNumber, stbChannel.ChannelUp); + trilist.SetBoolSigAction(joinMap.ChannelDown.JoinNumber, stbChannel.ChannelDown); + trilist.SetBoolSigAction(joinMap.LastChannel.JoinNumber, stbChannel.LastChannel); + trilist.SetBoolSigAction(joinMap.Guide.JoinNumber, stbChannel.Guide); + trilist.SetBoolSigAction(joinMap.Info.JoinNumber, stbChannel.Info); + trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbChannel.Exit); + } var stbColor = this as IColor; - if (stbColor != null) - { - trilist.SetBoolSigAction(joinMap.Red.JoinNumber, stbColor.Red); - trilist.SetBoolSigAction(joinMap.Green.JoinNumber, stbColor.Green); - trilist.SetBoolSigAction(joinMap.Yellow.JoinNumber, stbColor.Yellow); - trilist.SetBoolSigAction(joinMap.Blue.JoinNumber, stbColor.Blue); - } + if (stbColor != null) + { + trilist.SetBoolSigAction(joinMap.Red.JoinNumber, stbColor.Red); + trilist.SetBoolSigAction(joinMap.Green.JoinNumber, stbColor.Green); + trilist.SetBoolSigAction(joinMap.Yellow.JoinNumber, stbColor.Yellow); + trilist.SetBoolSigAction(joinMap.Blue.JoinNumber, stbColor.Blue); + } var stbKeypad = this as ISetTopBoxNumericKeypad; - if (stbKeypad != null) - { - trilist.StringInput[joinMap.KeypadAccessoryButton1Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton1Label; - trilist.StringInput[joinMap.KeypadAccessoryButton2Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton2Label; + if (stbKeypad != null) + { + trilist.StringInput[joinMap.KeypadAccessoryButton1Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton1Label; + trilist.StringInput[joinMap.KeypadAccessoryButton2Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton2Label; - trilist.BooleanInput[joinMap.HasKeypadAccessoryButton1.JoinNumber].BoolValue = stbKeypad.HasKeypadAccessoryButton1; - trilist.BooleanInput[joinMap.HasKeypadAccessoryButton2.JoinNumber].BoolValue = stbKeypad.HasKeypadAccessoryButton2; + trilist.BooleanInput[joinMap.HasKeypadAccessoryButton1.JoinNumber].BoolValue = stbKeypad.HasKeypadAccessoryButton1; + trilist.BooleanInput[joinMap.HasKeypadAccessoryButton2.JoinNumber].BoolValue = stbKeypad.HasKeypadAccessoryButton2; - trilist.SetBoolSigAction(joinMap.Digit0.JoinNumber, stbKeypad.Digit0); - trilist.SetBoolSigAction(joinMap.Digit1.JoinNumber, stbKeypad.Digit1); - trilist.SetBoolSigAction(joinMap.Digit2.JoinNumber, stbKeypad.Digit2); - trilist.SetBoolSigAction(joinMap.Digit3.JoinNumber, stbKeypad.Digit3); - trilist.SetBoolSigAction(joinMap.Digit4.JoinNumber, stbKeypad.Digit4); - trilist.SetBoolSigAction(joinMap.Digit5.JoinNumber, stbKeypad.Digit5); - trilist.SetBoolSigAction(joinMap.Digit6.JoinNumber, stbKeypad.Digit6); - trilist.SetBoolSigAction(joinMap.Digit7.JoinNumber, stbKeypad.Digit7); - trilist.SetBoolSigAction(joinMap.Digit8.JoinNumber, stbKeypad.Digit8); - trilist.SetBoolSigAction(joinMap.Digit9.JoinNumber, stbKeypad.Digit9); - trilist.SetBoolSigAction(joinMap.KeypadAccessoryButton1Press.JoinNumber, stbKeypad.KeypadAccessoryButton1); - trilist.SetBoolSigAction(joinMap.KeypadAccessoryButton2Press.JoinNumber, stbKeypad.KeypadAccessoryButton1); - trilist.SetBoolSigAction(joinMap.Dash.JoinNumber, stbKeypad.Dash); - trilist.SetBoolSigAction(joinMap.KeypadEnter.JoinNumber, stbKeypad.KeypadEnter); - } + trilist.SetBoolSigAction(joinMap.Digit0.JoinNumber, stbKeypad.Digit0); + trilist.SetBoolSigAction(joinMap.Digit1.JoinNumber, stbKeypad.Digit1); + trilist.SetBoolSigAction(joinMap.Digit2.JoinNumber, stbKeypad.Digit2); + trilist.SetBoolSigAction(joinMap.Digit3.JoinNumber, stbKeypad.Digit3); + trilist.SetBoolSigAction(joinMap.Digit4.JoinNumber, stbKeypad.Digit4); + trilist.SetBoolSigAction(joinMap.Digit5.JoinNumber, stbKeypad.Digit5); + trilist.SetBoolSigAction(joinMap.Digit6.JoinNumber, stbKeypad.Digit6); + trilist.SetBoolSigAction(joinMap.Digit7.JoinNumber, stbKeypad.Digit7); + trilist.SetBoolSigAction(joinMap.Digit8.JoinNumber, stbKeypad.Digit8); + trilist.SetBoolSigAction(joinMap.Digit9.JoinNumber, stbKeypad.Digit9); + trilist.SetBoolSigAction(joinMap.KeypadAccessoryButton1Press.JoinNumber, stbKeypad.KeypadAccessoryButton1); + trilist.SetBoolSigAction(joinMap.KeypadAccessoryButton2Press.JoinNumber, stbKeypad.KeypadAccessoryButton1); + trilist.SetBoolSigAction(joinMap.Dash.JoinNumber, stbKeypad.Dash); + trilist.SetBoolSigAction(joinMap.KeypadEnter.JoinNumber, stbKeypad.KeypadEnter); + } var stbTransport = this as ITransport; - if (stbTransport != null) - { - trilist.SetBoolSigAction(joinMap.Play.JoinNumber, stbTransport.Play); - trilist.SetBoolSigAction(joinMap.Pause.JoinNumber, stbTransport.Pause); - trilist.SetBoolSigAction(joinMap.Rewind.JoinNumber, stbTransport.Rewind); - trilist.SetBoolSigAction(joinMap.FFwd.JoinNumber, stbTransport.FFwd); - trilist.SetBoolSigAction(joinMap.ChapMinus.JoinNumber, stbTransport.ChapMinus); - trilist.SetBoolSigAction(joinMap.ChapPlus.JoinNumber, stbTransport.ChapPlus); - trilist.SetBoolSigAction(joinMap.Stop.JoinNumber, stbTransport.Stop); - trilist.SetBoolSigAction(joinMap.Record.JoinNumber, stbTransport.Record); - } + if (stbTransport != null) + { + trilist.SetBoolSigAction(joinMap.Play.JoinNumber, stbTransport.Play); + trilist.SetBoolSigAction(joinMap.Pause.JoinNumber, stbTransport.Pause); + trilist.SetBoolSigAction(joinMap.Rewind.JoinNumber, stbTransport.Rewind); + trilist.SetBoolSigAction(joinMap.FFwd.JoinNumber, stbTransport.FFwd); + trilist.SetBoolSigAction(joinMap.ChapMinus.JoinNumber, stbTransport.ChapMinus); + trilist.SetBoolSigAction(joinMap.ChapPlus.JoinNumber, stbTransport.ChapPlus); + trilist.SetBoolSigAction(joinMap.Stop.JoinNumber, stbTransport.Stop); + trilist.SetBoolSigAction(joinMap.Record.JoinNumber, stbTransport.Record); + } } } - public class IRSetTopBoxBaseFactory : EssentialsDeviceFactory +public class IRSetTopBoxBaseFactory : EssentialsDeviceFactory +{ + public IRSetTopBoxBaseFactory() { - public IRSetTopBoxBaseFactory() - { - TypeNames = new List() { "settopbox" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new SetTopBox Device"); - var irCont = IRPortHelper.GetIrOutputPortController(dc); - var config = dc.Properties.ToObject(); - var stb = new IRSetTopBoxBase(dc.Key, dc.Name, irCont, config); - - var listName = dc.Properties.Value("presetsList"); - if (listName != null) - stb.LoadPresets(listName); - return stb; - - } + TypeNames = new List() { "settopbox" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new SetTopBox Device"); + var irCont = IRPortHelper.GetIrOutputPortController(dc); + var config = dc.Properties.ToObject(); + var stb = new IRSetTopBoxBase(dc.Key, dc.Name, irCont, config); + + var listName = dc.Properties.Value("presetsList"); + if (listName != null) + stb.LoadPresets(listName); + return stb; + + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs index 8faac507..35cfbf41 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs @@ -6,16 +6,15 @@ using Crestron.SimplSharp; using PepperDash.Core; -namespace PepperDash.Essentials.Devices.Common -{ - public class SetTopBoxPropertiesConfig : PepperDash.Essentials.Core.Config.SourceDevicePropertiesConfigBase - { - public bool HasPresets { get; set; } - public bool HasDvr { get; set; } - public bool HasDpad { get; set; } - public bool HasNumeric { get; set; } - public int IrPulseTime { get; set; } +namespace PepperDash.Essentials.Devices.Common; - public ControlPropertiesConfig Control { get; set; } - } +public class SetTopBoxPropertiesConfig : PepperDash.Essentials.Core.Config.SourceDevicePropertiesConfigBase +{ + public bool HasPresets { get; set; } + public bool HasDvr { get; set; } + public bool HasDpad { get; set; } + public bool HasNumeric { get; set; } + public int IrPulseTime { get; set; } + + public ControlPropertiesConfig Control { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs b/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs index 085517b2..58275954 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs @@ -7,122 +7,120 @@ using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.Shades; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Shades +namespace PepperDash.Essentials.Devices.Common.Shades; + +/// +/// Controls a single shade using three relays +/// +public class RelayControlledShade : ShadeBase, IShadesOpenCloseStop { + RelayControlledShadeConfigProperties Config; + + ISwitchedOutput OpenRelay; + ISwitchedOutput StopOrPresetRelay; + ISwitchedOutput CloseRelay; + + int RelayPulseTime; + + public string StopOrPresetButtonLabel { get; set; } + + public RelayControlledShade(string key, string name, RelayControlledShadeConfigProperties config) + : base(key, name) + { + Config = config; + + RelayPulseTime = Config.RelayPulseTime; + + StopOrPresetButtonLabel = Config.StopOrPresetLabel; + + } + + public override bool CustomActivate() + { + //Create ISwitchedOutput objects based on props + OpenRelay = GetSwitchedOutputFromDevice(Config.Relays.Open); + StopOrPresetRelay = GetSwitchedOutputFromDevice(Config.Relays.StopOrPreset); + CloseRelay = GetSwitchedOutputFromDevice(Config.Relays.Close); + + + return base.CustomActivate(); + } + + public override void Open() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Opening Shade: '{0}'", this.Name); + + PulseOutput(OpenRelay, RelayPulseTime); + } + + public override void Stop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Shade: '{0}'", this.Name); + + PulseOutput(StopOrPresetRelay, RelayPulseTime); + } + + public override void Close() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Closing Shade: '{0}'", this.Name); + + PulseOutput(CloseRelay, RelayPulseTime); + } + + void PulseOutput(ISwitchedOutput output, int pulseTime) + { + output.On(); + CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime); + } + /// - /// Controls a single shade using three relays + /// Attempts to get the port on teh specified device from config /// - public class RelayControlledShade : ShadeBase, IShadesOpenCloseStop + /// + /// + ISwitchedOutput GetSwitchedOutputFromDevice(IOPortConfig relayConfig) { - RelayControlledShadeConfigProperties Config; + var portDevice = DeviceManager.GetDeviceForKey(relayConfig.PortDeviceKey); - ISwitchedOutput OpenRelay; - ISwitchedOutput StopOrPresetRelay; - ISwitchedOutput CloseRelay; - - int RelayPulseTime; - - public string StopOrPresetButtonLabel { get; set; } - - public RelayControlledShade(string key, string name, RelayControlledShadeConfigProperties config) - : base(key, name) + if (portDevice != null) { - Config = config; - - RelayPulseTime = Config.RelayPulseTime; - - StopOrPresetButtonLabel = Config.StopOrPresetLabel; - + return (portDevice as ISwitchedOutputCollection).SwitchedOutputs[relayConfig.PortNumber]; } - - public override bool CustomActivate() + else { - //Create ISwitchedOutput objects based on props - OpenRelay = GetSwitchedOutputFromDevice(Config.Relays.Open); - StopOrPresetRelay = GetSwitchedOutputFromDevice(Config.Relays.StopOrPreset); - CloseRelay = GetSwitchedOutputFromDevice(Config.Relays.Close); - - - return base.CustomActivate(); - } - - public override void Open() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Opening Shade: '{0}'", this.Name); - - PulseOutput(OpenRelay, RelayPulseTime); - } - - public override void Stop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Shade: '{0}'", this.Name); - - PulseOutput(StopOrPresetRelay, RelayPulseTime); - } - - public override void Close() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Closing Shade: '{0}'", this.Name); - - PulseOutput(CloseRelay, RelayPulseTime); - } - - void PulseOutput(ISwitchedOutput output, int pulseTime) - { - output.On(); - CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime); - } - - /// - /// Attempts to get the port on teh specified device from config - /// - /// - /// - ISwitchedOutput GetSwitchedOutputFromDevice(IOPortConfig relayConfig) - { - var portDevice = DeviceManager.GetDeviceForKey(relayConfig.PortDeviceKey); - - if (portDevice != null) - { - return (portDevice as ISwitchedOutputCollection).SwitchedOutputs[relayConfig.PortNumber]; - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay on port '{0}' from device with key '{1}'", relayConfig.PortNumber, relayConfig.PortDeviceKey); - return null; - } - } - - } - - public class RelayControlledShadeConfigProperties - { - public int RelayPulseTime { get; set; } - public ShadeRelaysConfig Relays { get; set; } - public string StopOrPresetLabel { get; set; } - - public class ShadeRelaysConfig - { - public IOPortConfig Open { get; set; } - public IOPortConfig StopOrPreset { get; set; } - public IOPortConfig Close { get; set; } + Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay on port '{0}' from device with key '{1}'", relayConfig.PortNumber, relayConfig.PortDeviceKey); + return null; } } - public class RelayControlledShadeFactory : EssentialsDeviceFactory +} + +public class RelayControlledShadeConfigProperties +{ + public int RelayPulseTime { get; set; } + public ShadeRelaysConfig Relays { get; set; } + public string StopOrPresetLabel { get; set; } + + public class ShadeRelaysConfig { - public RelayControlledShadeFactory() - { - TypeNames = new List() { "relaycontrolledshade" }; - } + public IOPortConfig Open { get; set; } + public IOPortConfig StopOrPreset { get; set; } + public IOPortConfig Close { get; set; } + } +} - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); - - return new RelayControlledShade(dc.Key, dc.Name, props); - } +public class RelayControlledShadeFactory : EssentialsDeviceFactory +{ + public RelayControlledShadeFactory() + { + TypeNames = new List() { "relaycontrolledshade" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); + + return new RelayControlledShade(dc.Key, dc.Name, props); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs index 2c506750..f4a64a13 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs @@ -1,22 +1,21 @@ using PepperDash.Essentials.Core.Shades; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Shades +namespace PepperDash.Essentials.Devices.Common.Shades; + +public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop { - public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop + public ShadeBase(string key, string name) + : base(key, name) { - public ShadeBase(string key, string name) - : base(key, name) - { - } - - #region iShadesOpenClose Members - - public abstract void Open(); - public abstract void Stop(); - public abstract void Close(); - - #endregion } + + #region iShadesOpenClose Members + + public abstract void Open(); + public abstract void Stop(); + public abstract void Close(); + + #endregion } diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs index 43ce0abc..623d1751 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs @@ -5,70 +5,68 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Shades; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Shades +namespace PepperDash.Essentials.Devices.Common.Shades; + +/// +/// Class that contains the shades to be controlled in a room +/// +public class ShadeController : EssentialsDevice, IShades { - /// - /// Class that contains the shades to be controlled in a room - /// - public class ShadeController : EssentialsDevice, IShades + ShadeControllerConfigProperties Config; + + public List Shades { get; private set; } + + public ShadeController(string key, string name, ShadeControllerConfigProperties config) + : base(key, name) { - ShadeControllerConfigProperties Config; + Config = config; - public List Shades { get; private set; } + Shades = new List(); + } - public ShadeController(string key, string name, ShadeControllerConfigProperties config) - : base(key, name) + public override bool CustomActivate() + { + foreach (var shadeConfig in Config.Shades) { - Config = config; + var shade = DeviceManager.GetDeviceForKey(shadeConfig.Key) as ShadeBase; - Shades = new List(); - } - - public override bool CustomActivate() - { - foreach (var shadeConfig in Config.Shades) + if (shade != null) { - var shade = DeviceManager.GetDeviceForKey(shadeConfig.Key) as ShadeBase; - - if (shade != null) - { - AddShade(shade); - } + AddShade(shade); } - return base.CustomActivate(); - } - - void AddShade(IShadesOpenCloseStop shade) - { - Shades.Add(shade); } + return base.CustomActivate(); } - public class ShadeControllerConfigProperties + void AddShade(IShadesOpenCloseStop shade) { - public List Shades { get; set; } - - - public class ShadeConfig - { - public string Key { get; set; } - } + Shades.Add(shade); } +} - public class ShadeControllerFactory : EssentialsDeviceFactory +public class ShadeControllerConfigProperties +{ + public List Shades { get; set; } + + + public class ShadeConfig { - public ShadeControllerFactory() - { - TypeNames = new List() { "shadecontroller" }; - } + public string Key { get; set; } + } +} - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ShadeController Device"); - var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); - - return new ShadeController(dc.Key, dc.Name, props); - } +public class ShadeControllerFactory : EssentialsDeviceFactory +{ + public ShadeControllerFactory() + { + TypeNames = new List() { "shadecontroller" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ShadeController Device"); + var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); + + return new ShadeController(dc.Key, dc.Name, props); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs index 891f92b1..9bdec0a8 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs @@ -9,173 +9,171 @@ using PepperDash.Essentials.Devices.Common.Sources; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.SoftCodec +namespace PepperDash.Essentials.Devices.Common.SoftCodec; + +public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink { - public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink + + public RoutingInputPort AnyVideoIn { get; private set; } + + public RoutingInputPort CurrentInputPort => AnyVideoIn; + + #region IRoutingInputs Members + + public RoutingPortCollection InputPorts { get; private set; } + + #endregion + + public BlueJeansPc(string key, string name) + : base(key, name) { - - public RoutingInputPort AnyVideoIn { get; private set; } - - public RoutingInputPort CurrentInputPort => AnyVideoIn; - - #region IRoutingInputs Members - - public RoutingPortCollection InputPorts { get; private set; } - - #endregion - - public BlueJeansPc(string key, string name) - : base(key, name) + InputPorts = new RoutingPortCollection { - InputPorts = new RoutingPortCollection + (AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)) + }; + } + + #region IRunRouteAction Members + + public void RunRouteAction(string routeKey, string sourceListKey) + { + RunRouteAction(routeKey, sourceListKey, null); + } + + public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback) + { + CrestronInvoke.BeginInvoke(o => { - (AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)) - }; - } + Debug.LogMessage(LogEventLevel.Debug, this, "Run route action '{0}' on SourceList: {1}", routeKey, sourceListKey); - #region IRunRouteAction Members - - public void RunRouteAction(string routeKey, string sourceListKey) - { - RunRouteAction(routeKey, sourceListKey, null); - } - - public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback) - { - CrestronInvoke.BeginInvoke(o => + var dict = ConfigReader.ConfigObject.GetSourceListForKey(sourceListKey); + if (dict == null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Run route action '{0}' on SourceList: {1}", routeKey, sourceListKey); + Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Config source list '{0}' not found", sourceListKey); + return; + } - var dict = ConfigReader.ConfigObject.GetSourceListForKey(sourceListKey); - if (dict == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Config source list '{0}' not found", sourceListKey); - return; - } + // Try to get the list item by it's string key + if (!dict.ContainsKey(routeKey)) + { + Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: No item '{0}' found on config list '{1}'", + routeKey, sourceListKey); + return; + } - // Try to get the list item by it's string key - if (!dict.ContainsKey(routeKey)) - { - Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: No item '{0}' found on config list '{1}'", - routeKey, sourceListKey); - return; - } + var item = dict[routeKey]; - var item = dict[routeKey]; + foreach (var route in item.RouteList) + { + DoRoute(route); + } - foreach (var route in item.RouteList) - { - DoRoute(route); - } + // store the name and UI info for routes + if (item.SourceKey == "none") + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = null; + } + else if (item.SourceKey != null) + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = item; + } - // store the name and UI info for routes - if (item.SourceKey == "none") - { - CurrentSourceInfoKey = routeKey; - CurrentSourceInfo = null; - } - else if (item.SourceKey != null) - { - CurrentSourceInfoKey = routeKey; - CurrentSourceInfo = item; - } + // report back when done + if (successCallback != null) + successCallback(); + }); + } - // report back when done - if (successCallback != null) - successCallback(); - }); + #endregion + + /// + /// + /// + /// + /// + bool DoRoute(SourceRouteListItem route) + { + IRoutingSink dest = null; + + dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink; + + if (dest == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Cannot route, unknown destination '{0}'", route.DestinationKey); + return false; } - #endregion - - /// - /// - /// - /// - /// - bool DoRoute(SourceRouteListItem route) + if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase)) { - IRoutingSink dest = null; - - dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink; - - if (dest == null) + dest.ReleaseRoute(); + if (dest is IHasPowerControl) + (dest as IHasPowerControl).PowerOff(); + } + else + { + var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs; + if (source == null) { - Debug.LogMessage(LogEventLevel.Debug, this, "Cannot route, unknown destination '{0}'", route.DestinationKey); + Debug.LogMessage(LogEventLevel.Debug, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey); return false; } - - if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase)) - { - dest.ReleaseRoute(); - if (dest is IHasPowerControl) - (dest as IHasPowerControl).PowerOff(); - } - else - { - var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs; - if (source == null) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey); - return false; - } - dest.ReleaseAndMakeRoute(source, route.Type); - } - return true; + dest.ReleaseAndMakeRoute(source, route.Type); } - - - - #region IHasCurrentSourceInfoChange Members - - public string CurrentSourceInfoKey { get; set; } - - /// - /// The SourceListItem last run - containing names and icons - /// - public SourceListItem CurrentSourceInfo - { - get { return _CurrentSourceInfo; } - set - { - if (value == _CurrentSourceInfo) return; - - var handler = CurrentSourceChange; - // remove from in-use tracker, if so equipped - if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) - (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); - - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); - - _CurrentSourceInfo = value; - - // add to in-use tracking - if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) - (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); - } - } - SourceListItem _CurrentSourceInfo; - - public event SourceInfoChangeHandler CurrentSourceChange; - - #endregion + return true; } - public class BlueJeansPcFactory : EssentialsDeviceFactory + + + #region IHasCurrentSourceInfoChange Members + + public string CurrentSourceInfoKey { get; set; } + + /// + /// The SourceListItem last run - containing names and icons + /// + public SourceListItem CurrentSourceInfo { - public BlueJeansPcFactory() + get { return _CurrentSourceInfo; } + set { - TypeNames = new List() { "bluejeanspc" }; - } + if (value == _CurrentSourceInfo) return; - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BlueJeansPc Device"); - return new SoftCodec.BlueJeansPc(dc.Key, dc.Name); + var handler = CurrentSourceChange; + // remove from in-use tracker, if so equipped + if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) + (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); + + _CurrentSourceInfo = value; + + // add to in-use tracking + if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) + (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); } } + SourceListItem _CurrentSourceInfo; + public event SourceInfoChangeHandler CurrentSourceChange; + + #endregion +} + +public class BlueJeansPcFactory : EssentialsDeviceFactory +{ + public BlueJeansPcFactory() + { + TypeNames = new List() { "bluejeanspc" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BlueJeansPc Device"); + return new SoftCodec.BlueJeansPc(dc.Key, dc.Name); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index 84847f35..ba6e22c7 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -6,128 +6,127 @@ using Serilog.Events; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.Devices.Common.SoftCodec +namespace PepperDash.Essentials.Devices.Common.SoftCodec; + +public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitchingWithInputPort { - public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitchingWithInputPort - { - private RoutingInputPort _currentInputPort; + private RoutingInputPort _currentInputPort; - public RoutingInputPort CurrentInputPort { - get => _currentInputPort; - set - { - _currentInputPort = value; - - InputChanged?.Invoke(this, _currentInputPort); - } - } - - public GenericSoftCodec(string key, string name, GenericSoftCodecProperties props) : base(key, name) + public RoutingInputPort CurrentInputPort { + get => _currentInputPort; + set { - InputPorts = new RoutingPortCollection(); - OutputPorts = new RoutingPortCollection(); + _currentInputPort = value; - for(var i = 1; i <= props.OutputCount; i++) - { - var outputPort = new RoutingOutputPort($"output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); - - OutputPorts.Add(outputPort); - } - - for(var i = 1; i<= props.ContentInputCount; i++) - { - var inputPort = new RoutingInputPort($"contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); - - InputPorts.Add(inputPort); - } - - if (!props.HasCameraInputs) - { - return; - } - - for(var i = 1; i <=props.CameraInputCount; i++) - { - var cameraPort = new RoutingInputPort($"cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); - - InputPorts.Add(cameraPort); - } - } - - public RoutingPortCollection InputPorts { get; private set; } - - public RoutingPortCollection OutputPorts { get; private set; } - public string CurrentSourceInfoKey { get ; set; } - public SourceListItem CurrentSourceInfo - { - get - { - return _CurrentSourceInfo; - } - set - { - if (value == _CurrentSourceInfo) return; - - var handler = CurrentSourceChange; - - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); - - _CurrentSourceInfo = value; - - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); - } - } - - SourceListItem _CurrentSourceInfo; - - public event SourceInfoChangeHandler CurrentSourceChange; - public event InputChangedEventHandler InputChanged; - - public void ExecuteSwitch(object inputSelector) - { - var inputPort = InputPorts.FirstOrDefault(p => p.Selector == inputSelector); - - if(inputPort == null) - { - Debug.LogMessage(LogEventLevel.Warning, "No input port found for selector {inputSelector}", inputSelector); - return; - } - - CurrentInputPort = inputPort; + InputChanged?.Invoke(this, _currentInputPort); } } - public class GenericSoftCodecProperties + public GenericSoftCodec(string key, string name, GenericSoftCodecProperties props) : base(key, name) { - [JsonProperty("hasCameraInputs")] - public bool HasCameraInputs { get; set; } + InputPorts = new RoutingPortCollection(); + OutputPorts = new RoutingPortCollection(); - [JsonProperty("cameraInputCount")] - public int CameraInputCount { get; set; } + for(var i = 1; i <= props.OutputCount; i++) + { + var outputPort = new RoutingOutputPort($"output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); - [JsonProperty("contentInputCount")] - public int ContentInputCount { get; set; } + OutputPorts.Add(outputPort); + } - [JsonProperty("contentOutputCount")] - public int OutputCount { get; set; } + for(var i = 1; i<= props.ContentInputCount; i++) + { + var inputPort = new RoutingInputPort($"contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); + + InputPorts.Add(inputPort); + } + + if (!props.HasCameraInputs) + { + return; + } + + for(var i = 1; i <=props.CameraInputCount; i++) + { + var cameraPort = new RoutingInputPort($"cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); + + InputPorts.Add(cameraPort); + } } - public class GenericSoftCodecFactory: EssentialsDeviceFactory + public RoutingPortCollection InputPorts { get; private set; } + + public RoutingPortCollection OutputPorts { get; private set; } + public string CurrentSourceInfoKey { get ; set; } + public SourceListItem CurrentSourceInfo { - public GenericSoftCodecFactory() + get { - TypeNames = new List { "genericsoftcodec" }; + return _CurrentSourceInfo; + } + set + { + if (value == _CurrentSourceInfo) return; + + var handler = CurrentSourceChange; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); + + _CurrentSourceInfo = value; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); + } + } + + SourceListItem _CurrentSourceInfo; + + public event SourceInfoChangeHandler CurrentSourceChange; + public event InputChangedEventHandler InputChanged; + + public void ExecuteSwitch(object inputSelector) + { + var inputPort = InputPorts.FirstOrDefault(p => p.Selector == inputSelector); + + if(inputPort == null) + { + Debug.LogMessage(LogEventLevel.Warning, "No input port found for selector {inputSelector}", inputSelector); + return; } - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Generic SoftCodec Device"); - - var props = dc.Properties.ToObject(); - - return new GenericSoftCodec(dc.Key, dc.Name, props); - } + CurrentInputPort = inputPort; + } +} + +public class GenericSoftCodecProperties +{ + [JsonProperty("hasCameraInputs")] + public bool HasCameraInputs { get; set; } + + [JsonProperty("cameraInputCount")] + public int CameraInputCount { get; set; } + + [JsonProperty("contentInputCount")] + public int ContentInputCount { get; set; } + + [JsonProperty("contentOutputCount")] + public int OutputCount { get; set; } +} + +public class GenericSoftCodecFactory: EssentialsDeviceFactory +{ + public GenericSoftCodecFactory() + { + TypeNames = new List { "genericsoftcodec" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Generic SoftCodec Device"); + + var props = dc.Properties.ToObject(); + + return new GenericSoftCodec(dc.Key, dc.Name, props); } } diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs index 41ad7a43..ed906843 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs @@ -5,8 +5,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Sources -{ +namespace PepperDash.Essentials.Devices.Common.Sources; + public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } @@ -40,37 +40,35 @@ namespace PepperDash.Essentials.Devices.Common.Sources /// /// Passes through the VideoStatuses list /// - public FeedbackCollection Feedbacks + public FeedbackCollection Feedbacks { get - { - var newList = new FeedbackCollection(); - newList.AddRange(this.GetVideoStatuses().ToList()); - return newList; - } + { + var newList = new FeedbackCollection(); + newList.AddRange(this.GetVideoStatuses().ToList()); + return newList; + } } #endregion - #region IUsageTracking Members + #region IUsageTracking Members - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } - #endregion + #endregion } - public class InRoomPcFactory : EssentialsDeviceFactory +public class InRoomPcFactory : EssentialsDeviceFactory +{ + public InRoomPcFactory() { - public InRoomPcFactory() - { - TypeNames = new List() { "inroompc" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device"); - return new InRoomPc(dc.Key, dc.Name); - } + TypeNames = new List() { "inroompc" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device"); + return new InRoomPc(dc.Key, dc.Name); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs index 38898209..c9fa19d8 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs @@ -5,9 +5,9 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Sources -{ - public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking +namespace PepperDash.Essentials.Devices.Common.Sources; + +public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public string IconName { get; set; } @@ -33,10 +33,10 @@ namespace PepperDash.Essentials.Devices.Common.Sources () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); OutputPorts = new RoutingPortCollection - { - (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.None, 0, this)) - }; + { + (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.None, 0, this)) + }; } #region IHasFeedback Members @@ -44,36 +44,35 @@ namespace PepperDash.Essentials.Devices.Common.Sources /// /// Passes through the VideoStatuses list /// - public FeedbackCollection Feedbacks + public FeedbackCollection Feedbacks + { + get { - get - { - var newList = new FeedbackCollection(); - newList.AddRange(this.GetVideoStatuses().ToList()); - return newList; - } + var newList = new FeedbackCollection(); + newList.AddRange(this.GetVideoStatuses().ToList()); + return newList; } + } #endregion - #region IUsageTracking Members + #region IUsageTracking Members - public UsageTracking UsageTracker { get; set; } + public UsageTracking UsageTracker { get; set; } - #endregion + #endregion } - public class LaptopFactory : EssentialsDeviceFactory +public class LaptopFactory : EssentialsDeviceFactory +{ + public LaptopFactory() { - public LaptopFactory() - { - TypeNames = new List() { "laptop" }; - } + TypeNames = new List() { "laptop" }; + } - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Laptop Device"); - return new Laptop(dc.Key, dc.Name); - } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Laptop Device"); + return new Laptop(dc.Key, dc.Name); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs index a00fb5a2..ddd24c05 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs @@ -15,14 +15,14 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common -{ - [Description("Wrapper class for an IR-Controlled AppleTV")] +namespace PepperDash.Essentials.Devices.Common; + +[Description("Wrapper class for an IR-Controlled AppleTV")] public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs - { +{ public IrOutputPortController IrPort { get; private set; } - public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; + public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } public AppleTV(string key, string name, IrOutputPortController portCont) @@ -37,20 +37,20 @@ namespace PepperDash.Essentials.Devices.Common eRoutingPortConnectionType.DigitalAudio, null, this); OutputPorts = new RoutingPortCollection { HdmiOut, AnyAudioOut }; - PrintExpectedIrCommands(); + PrintExpectedIrCommands(); } - public void PrintExpectedIrCommands() + public void PrintExpectedIrCommands() + { + var cmds = typeof (AppleTvIrCommands).GetFields(BindingFlags.Public | BindingFlags.Static); + + foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType()) { - var cmds = typeof (AppleTvIrCommands).GetFields(BindingFlags.Public | BindingFlags.Static); - - foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType()) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Expected IR Function Name: {0}", value); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Expected IR Function Name: {0}", value); } + } - #region IDPad Members + #region IDPad Members public void Up(bool pressRelease) { @@ -98,7 +98,7 @@ namespace PepperDash.Essentials.Devices.Common public void Pause(bool pressRelease) { - IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); + IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); } /// @@ -161,61 +161,60 @@ namespace PepperDash.Essentials.Devices.Common public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { - var joinMap = new AppleTvJoinMap(joinStart); + var joinMap = new AppleTvJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(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."); - } + 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."); + } - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - Debug.LogMessage(LogEventLevel.Information, "Linking to Bridge Type {0}", GetType().Name); + Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + Debug.LogMessage(LogEventLevel.Information, "Linking to Bridge Type {0}", GetType().Name); - trilist.SetBoolSigAction(joinMap.UpArrow.JoinNumber, Up); - trilist.SetBoolSigAction(joinMap.DnArrow.JoinNumber, Down); - trilist.SetBoolSigAction(joinMap.LeftArrow.JoinNumber, Left); - trilist.SetBoolSigAction(joinMap.RightArrow.JoinNumber, Right); - trilist.SetBoolSigAction(joinMap.Select.JoinNumber, Select); - trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, Menu); - trilist.SetBoolSigAction(joinMap.PlayPause.JoinNumber, Play); + trilist.SetBoolSigAction(joinMap.UpArrow.JoinNumber, Up); + trilist.SetBoolSigAction(joinMap.DnArrow.JoinNumber, Down); + trilist.SetBoolSigAction(joinMap.LeftArrow.JoinNumber, Left); + trilist.SetBoolSigAction(joinMap.RightArrow.JoinNumber, Right); + trilist.SetBoolSigAction(joinMap.Select.JoinNumber, Select); + trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, Menu); + trilist.SetBoolSigAction(joinMap.PlayPause.JoinNumber, Play); } } - public class AppleTVFactory : EssentialsDeviceFactory +public class AppleTVFactory : EssentialsDeviceFactory +{ + public AppleTVFactory() { - public AppleTVFactory() - { - TypeNames = new List() { "appletv" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new AppleTV Device"); - var irCont = IRPortHelper.GetIrOutputPortController(dc); - return new AppleTV(dc.Key, dc.Name, irCont); - } + TypeNames = new List() { "appletv" }; } - public static class AppleTvIrCommands + public override EssentialsDevice BuildDevice(DeviceConfig dc) { - - public static string Up = "+"; - public static string Down = "-"; - public static string Left = IROutputStandardCommands.IROut_TRACK_MINUS; - public static string Right = IROutputStandardCommands.IROut_TRACK_PLUS; - public static string Enter = IROutputStandardCommands.IROut_ENTER; - public static string PlayPause = "PLAY/PAUSE"; - public static string Rewind = "REWIND"; - public static string Menu = "Menu"; - public static string FastForward = "FASTFORWARD"; + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new AppleTV Device"); + var irCont = IRPortHelper.GetIrOutputPortController(dc); + return new AppleTV(dc.Key, dc.Name, irCont); } +} + +public static class AppleTvIrCommands +{ + + public static string Up = "+"; + public static string Down = "-"; + public static string Left = IROutputStandardCommands.IROut_TRACK_MINUS; + public static string Right = IROutputStandardCommands.IROut_TRACK_PLUS; + public static string Enter = IROutputStandardCommands.IROut_ENTER; + public static string PlayPause = "PLAY/PAUSE"; + public static string Rewind = "REWIND"; + public static string Menu = "Menu"; + public static string FastForward = "FASTFORWARD"; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs index 213e5835..e607f382 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs @@ -11,9 +11,9 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common -{ - [Description("Wrapper class for an IR-Controlled Roku")] +namespace PepperDash.Essentials.Devices.Common; + +[Description("Wrapper class for an IR-Controlled Roku")] public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs { [Api] @@ -148,20 +148,18 @@ namespace PepperDash.Essentials.Devices.Common } - public class Roku2Factory : EssentialsDeviceFactory +public class Roku2Factory : EssentialsDeviceFactory +{ + public Roku2Factory() { - public Roku2Factory() - { - TypeNames = new List() { "roku" }; - } - - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Roku Device"); - var irCont = IRPortHelper.GetIrOutputPortController(dc); - return new Roku2(dc.Key, dc.Name, irCont); - - } + TypeNames = new List() { "roku" }; } + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Roku Device"); + var irCont = IRPortHelper.GetIrOutputPortController(dc); + return new Roku2(dc.Key, dc.Name, irCont); + + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs index 4fc07bd2..392f6555 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs @@ -4,94 +4,93 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +public class CiscoCallHistory { - public class CiscoCallHistory + public class CallbackNumber { - public class CallbackNumber - { - public string Value { get; set; } - } + public string Value { get; set; } + } - public class DisplayName - { - public string Value { get; set; } - } + public class DisplayName + { + public string Value { get; set; } + } - public class LastOccurrenceStartTime - { - public DateTime Value { get; set; } - } + public class LastOccurrenceStartTime + { + public DateTime Value { get; set; } + } - public class LastOccurrenceDaysAgo - { - public string Value { get; set; } - } + public class LastOccurrenceDaysAgo + { + public string Value { get; set; } + } - public class LastOccurrenceHistoryId - { - public string Value { get; set; } - } + public class LastOccurrenceHistoryId + { + public string Value { get; set; } + } - public class OccurrenceType - { - public string Value { get; set; } - } + public class OccurrenceType + { + public string Value { get; set; } + } - public class IsAcknowledged - { - public string Value { get; set; } - } + public class IsAcknowledged + { + public string Value { get; set; } + } - public class OccurrenceCount - { - public string Value { get; set; } - } + public class OccurrenceCount + { + public string Value { get; set; } + } - public class Entry - { - public string id { get; set; } - public CallbackNumber CallbackNumber { get; set; } - public DisplayName DisplayName { get; set; } - public LastOccurrenceStartTime LastOccurrenceStartTime { get; set; } - public LastOccurrenceDaysAgo LastOccurrenceDaysAgo { get; set; } - public LastOccurrenceHistoryId LastOccurrenceHistoryId { get; set; } - public OccurrenceType OccurrenceType { get; set; } - public IsAcknowledged IsAcknowledged { get; set; } - public OccurrenceCount OccurrenceCount { get; set; } - } + public class Entry + { + public string id { get; set; } + public CallbackNumber CallbackNumber { get; set; } + public DisplayName DisplayName { get; set; } + public LastOccurrenceStartTime LastOccurrenceStartTime { get; set; } + public LastOccurrenceDaysAgo LastOccurrenceDaysAgo { get; set; } + public LastOccurrenceHistoryId LastOccurrenceHistoryId { get; set; } + public OccurrenceType OccurrenceType { get; set; } + public IsAcknowledged IsAcknowledged { get; set; } + public OccurrenceCount OccurrenceCount { get; set; } + } - public class Offset - { - public string Value { get; set; } - } + public class Offset + { + public string Value { get; set; } + } - public class Limit - { - public string Value { get; set; } - } + public class Limit + { + public string Value { get; set; } + } - public class ResultInfo - { - public Offset Offset { get; set; } - public Limit Limit { get; set; } - } + public class ResultInfo + { + public Offset Offset { get; set; } + public Limit Limit { get; set; } + } - public class CallHistoryRecentsResult - { - public string status { get; set; } - public List Entry { get; set; } - public ResultInfo ResultInfo { get; set; } - } + public class CallHistoryRecentsResult + { + public string status { get; set; } + public List Entry { get; set; } + public ResultInfo ResultInfo { get; set; } + } - public class CommandResponse - { - public CallHistoryRecentsResult CallHistoryRecentsResult { get; set; } - } + public class CommandResponse + { + public CallHistoryRecentsResult CallHistoryRecentsResult { get; set; } + } - public class RootObject - { - public CommandResponse CommandResponse { get; set; } - } + public class RootObject + { + public CommandResponse CommandResponse { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs index a6531a40..c66f9fce 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs @@ -5,84 +5,83 @@ using System.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +/// +/// Interface for camera presets +/// +public interface IHasCodecRoomPresets { /// - /// Interface for camera presets + /// Event that is raised when the list of room presets has changed. /// - public interface IHasCodecRoomPresets - { - /// - /// Event that is raised when the list of room presets has changed. - /// - event EventHandler CodecRoomPresetsListHasChanged; - - /// - /// List of near end presets that can be recalled. - /// - List NearEndPresets { get; } - - /// - /// List of far end presets that can be recalled. - /// - List FarEndRoomPresets { get; } - - /// - /// Selects a near end preset by its ID. - /// - /// - void CodecRoomPresetSelect(int preset); - - /// - /// Stores a near end preset with the given ID and description. - /// - /// - /// - void CodecRoomPresetStore(int preset, string description); - - /// - /// Selects a far end preset by its ID. This is typically used to recall a preset that has been defined on the far end codec. - /// - /// - void SelectFarEndPreset(int preset); - } + event EventHandler CodecRoomPresetsListHasChanged; /// - /// Static class for converting non-generic RoomPresets to generic CameraPresets. + /// List of near end presets that can be recalled. /// - public static class RoomPresets - { - /// - /// Converts non-generic RoomPresets to generic CameraPresets - /// - /// - /// - public static List GetGenericPresets(this List presets) where TSource : ConvertiblePreset where TDestination : PresetBase - { - return - presets.Select(preset => preset.ConvertCodecPreset()) - .Where(newPreset => newPreset != null) - .Cast() - .ToList(); - } - } + List NearEndPresets { get; } /// - /// Represents a room preset on a video codec. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled. + /// List of far end presets that can be recalled. /// - public class CodecRoomPreset : PresetBase - { - /// - /// - /// - /// - /// - /// - /// - public CodecRoomPreset(int id, string description, bool def, bool isDef) - : base(id, description, def, isDef) - { + List FarEndRoomPresets { get; } + + /// + /// Selects a near end preset by its ID. + /// + /// + void CodecRoomPresetSelect(int preset); + + /// + /// Stores a near end preset with the given ID and description. + /// + /// + /// + void CodecRoomPresetStore(int preset, string description); + + /// + /// Selects a far end preset by its ID. This is typically used to recall a preset that has been defined on the far end codec. + /// + /// + void SelectFarEndPreset(int preset); +} + +/// +/// Static class for converting non-generic RoomPresets to generic CameraPresets. +/// +public static class RoomPresets +{ + /// + /// Converts non-generic RoomPresets to generic CameraPresets + /// + /// + /// + public static List GetGenericPresets(this List presets) where TSource : ConvertiblePreset where TDestination : PresetBase + { + return + presets.Select(preset => preset.ConvertCodecPreset()) + .Where(newPreset => newPreset != null) + .Cast() + .ToList(); + } +} + +/// +/// Represents a room preset on a video codec. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled. +/// +public class CodecRoomPreset : PresetBase +{ + /// + /// + /// + /// + /// + /// + /// + public CodecRoomPreset(int id, string description, bool def, bool isDef) + : base(id, description, def, isDef) + { - } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs index b68f280d..d33ec5c5 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs @@ -1,4 +1,3 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco -{ - enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; -} \ No newline at end of file +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; + +enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs index 1f96f5e1..5cff4cd6 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs @@ -1,4 +1,3 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco -{ - public enum eExternalSourceMode {Ready, NotReady, Hidden, Error} -} \ No newline at end of file +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; + +public enum eExternalSourceMode {Ready, NotReady, Hidden, Error} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs index 66ebe390..4bce7e27 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs @@ -1,4 +1,3 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco -{ - public enum eExternalSourceType {camera, desktop, document_camera, mediaplayer, PC, whiteboard, other} -} \ No newline at end of file +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; + +public enum eExternalSourceType {camera, desktop, document_camera, mediaplayer, PC, whiteboard, other} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs index 4c01d94e..90cdcb71 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs @@ -1,9 +1,8 @@ using PepperDash.Essentials.Core.Presets; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +public abstract class ConvertiblePreset { - public abstract class ConvertiblePreset - { - public abstract PresetBase ConvertCodecPreset(); - } + public abstract PresetBase ConvertCodecPreset(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs index 98a8e4f4..42f4b135 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs @@ -10,17 +10,16 @@ using PepperDash.Essentials.Core; using Newtonsoft.Json; -namespace PepperDash.Essentials.Devices.Common.VideoCodec -{ - /// - /// Defines the required elements for layout control - /// - public interface IHasCodecLayouts - { - StringFeedback LocalLayoutFeedback { get; } +namespace PepperDash.Essentials.Devices.Common.VideoCodec; - void LocalLayoutToggle(); +/// +/// Defines the required elements for layout control +/// +public interface IHasCodecLayouts +{ + StringFeedback LocalLayoutFeedback { get; } + + void LocalLayoutToggle(); void LocalLayoutToggleSingleProminent(); void MinMaxLayoutToggle(); - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs index 3b079b7d..36116fb2 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs @@ -6,21 +6,20 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +/// +/// Defines the requred elements for selfview control +/// +public interface IHasCodecSelfView { - /// - /// Defines the requred elements for selfview control - /// - public interface IHasCodecSelfView - { - BoolFeedback SelfviewIsOnFeedback { get; } + BoolFeedback SelfviewIsOnFeedback { get; } - bool ShowSelfViewByDefault { get; } + bool ShowSelfViewByDefault { get; } - void SelfViewModeOn(); + void SelfViewModeOn(); - void SelfViewModeOff(); + void SelfViewModeOff(); - void SelfViewModeToggle(); - } + void SelfViewModeToggle(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs index bde88b61..dfc55818 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs @@ -8,72 +8,71 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +/// +/// Describes a device that provides meeting information (like a ZoomRoom) +/// +public interface IHasMeetingInfo { - /// - /// Describes a device that provides meeting information (like a ZoomRoom) - /// - public interface IHasMeetingInfo - { - event EventHandler MeetingInfoChanged; + event EventHandler MeetingInfoChanged; - MeetingInfo MeetingInfo { get; } + MeetingInfo MeetingInfo { get; } +} + +/// +/// Represents the information about a meeting in progress +/// Currently used for Zoom meetings +/// +public class MeetingInfo +{ + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string Id { get; private set; } + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; private set; } + [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)] + public string Host { get; private set; } + [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] + public string Password { get; private set; } + [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)] + public string ShareStatus { get; private set; } + [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)] + public Boolean IsHost { get; private set; } + [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)] + public Boolean IsSharingMeeting { get; private set; } + [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)] + public Boolean WaitingForHost { get; private set; } + [JsonProperty("isLocked", NullValueHandling = NullValueHandling.Ignore)] + public Boolean IsLocked { get; private set; } + [JsonProperty("isRecording", NullValueHandling = NullValueHandling.Ignore)] + public Boolean IsRecording { get; private set; } + [JsonProperty("canRecord", NullValueHandling = NullValueHandling.Ignore)] + public Boolean CanRecord { get; private set; } + + + public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost, bool isLocked, bool isRecording, bool canRecord) + { + Id = id; + Name = name; + Host = host; + Password = password; + ShareStatus = shareStatus; + IsHost = isHost; + IsSharingMeeting = isSharingMeeting; + WaitingForHost = waitingForHost; + IsLocked = isLocked; + IsRecording = isRecording; + CanRecord = CanRecord; + } +} + +public class MeetingInfoEventArgs : EventArgs +{ + public MeetingInfo Info { get; private set; } + + public MeetingInfoEventArgs(MeetingInfo info) + { + Info = info; } - /// - /// Represents the information about a meeting in progress - /// Currently used for Zoom meetings - /// - public class MeetingInfo - { - [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] - public string Id { get; private set; } - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string Name { get; private set; } - [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)] - public string Host { get; private set; } - [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] - public string Password { get; private set; } - [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)] - public string ShareStatus { get; private set; } - [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)] - public Boolean IsHost { get; private set; } - [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)] - public Boolean IsSharingMeeting { get; private set; } - [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)] - public Boolean WaitingForHost { get; private set; } - [JsonProperty("isLocked", NullValueHandling = NullValueHandling.Ignore)] - public Boolean IsLocked { get; private set; } - [JsonProperty("isRecording", NullValueHandling = NullValueHandling.Ignore)] - public Boolean IsRecording { get; private set; } - [JsonProperty("canRecord", NullValueHandling = NullValueHandling.Ignore)] - public Boolean CanRecord { get; private set; } - - - public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost, bool isLocked, bool isRecording, bool canRecord) - { - Id = id; - Name = name; - Host = host; - Password = password; - ShareStatus = shareStatus; - IsHost = isHost; - IsSharingMeeting = isSharingMeeting; - WaitingForHost = waitingForHost; - IsLocked = isLocked; - IsRecording = isRecording; - CanRecord = CanRecord; - } - } - - public class MeetingInfoEventArgs : EventArgs - { - public MeetingInfo Info { get; private set; } - - public MeetingInfoEventArgs(MeetingInfo info) - { - Info = info; - } - - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs index 97fcb725..abdd6986 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs @@ -5,14 +5,13 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces -{ - public interface IHasMeetingLock - { - BoolFeedback MeetingIsLockedFeedback { get; } +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; - void LockMeeting(); - void UnLockMeeting(); - void ToggleMeetingLock(); - } +public interface IHasMeetingLock +{ + BoolFeedback MeetingIsLockedFeedback { get; } + + void LockMeeting(); + void UnLockMeeting(); + void ToggleMeetingLock(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs index b05362c3..daa3a4a4 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs @@ -5,25 +5,24 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +public interface IHasMeetingRecording { - public interface IHasMeetingRecording - { - BoolFeedback MeetingIsRecordingFeedback { get; } + BoolFeedback MeetingIsRecordingFeedback { get; } - void StartRecording(); - void StopRecording(); - void ToggleRecording(); - } + void StartRecording(); + void StopRecording(); + void ToggleRecording(); +} - public interface IHasMeetingRecordingWithPrompt : IHasMeetingRecording - { - BoolFeedback RecordConsentPromptIsVisible { get; } +public interface IHasMeetingRecordingWithPrompt : IHasMeetingRecording +{ + BoolFeedback RecordConsentPromptIsVisible { get; } - /// - /// Used to agree or disagree to the meeting being recorded when prompted - /// - /// - void RecordingPromptAcknowledgement(bool agree); - } + /// + /// Used to agree or disagree to the meeting being recorded when prompted + /// + /// + void RecordingPromptAcknowledgement(bool agree); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs index 98c94bdc..8b8d6d25 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces -{ +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + /// /// Describes a device that has call participants /// @@ -13,23 +13,23 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { CodecParticipants Participants { get; } - /// - /// Removes the participant from the meeting - /// - /// - void RemoveParticipant(int userId); + /// + /// Removes the participant from the meeting + /// + /// + void RemoveParticipant(int userId); - /// - /// Sets the participant as the new host - /// - /// - void SetParticipantAsHost(int userId); + /// + /// Sets the participant as the new host + /// + /// + void SetParticipantAsHost(int userId); - /// - /// Admits a participant from the waiting room - /// - /// - void AdmitParticipantFromWaitingRoom(int userId); + /// + /// Admits a participant from the waiting room + /// + /// + void AdmitParticipantFromWaitingRoom(int userId); } /// @@ -47,10 +47,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces /// public interface IHasParticipantAudioMute : IHasParticipantVideoMute { - /// - /// Mute audio of all participants - /// - void MuteAudioForAllParticipants(); + /// + /// Mute audio of all participants + /// + void MuteAudioForAllParticipants(); void MuteAudioForParticipant(int userId); void UnmuteAudioForParticipant(int userId); @@ -84,13 +84,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces } } - public Participant Host + public Participant Host + { + get { - get - { - return _currentParticipants.FirstOrDefault(p => p.IsHost); - } + return _currentParticipants.FirstOrDefault(p => p.IsHost); } + } public event EventHandler ParticipantsListHasChanged; @@ -116,7 +116,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { public int UserId { get; set; } public bool IsHost { get; set; } - public bool IsMyself { get; set; } + public bool IsMyself { get; set; } public string Name { get; set; } public bool CanMuteVideo { get; set; } public bool CanUnmuteVideo { get; set; } @@ -131,5 +131,4 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces // Initialize to -1 (no screen) ScreenIndexIsPinnedToFb = -1; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs index a620af1e..0c8b523b 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs @@ -1,18 +1,17 @@ -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces -{ - public interface IHasPresentationOnlyMeeting - { - void StartSharingOnlyMeeting(); - void StartSharingOnlyMeeting(eSharingMeetingMode displayMode); - void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration); - void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration, string password); - void StartNormalMeetingFromSharingOnlyMeeting(); - } +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; - public enum eSharingMeetingMode - { - None, - Laptop, - Ios, - } +public interface IHasPresentationOnlyMeeting +{ + void StartSharingOnlyMeeting(); + void StartSharingOnlyMeeting(eSharingMeetingMode displayMode); + void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration); + void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration, string password); + void StartNormalMeetingFromSharingOnlyMeeting(); +} + +public enum eSharingMeetingMode +{ + None, + Laptop, + Ios, } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs index d0ba25fd..3e88917a 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs @@ -1,14 +1,13 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.VideoCodec; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + +public interface IHasSelfviewPosition { - public interface IHasSelfviewPosition - { - StringFeedback SelfviewPipPositionFeedback { get; } + StringFeedback SelfviewPipPositionFeedback { get; } - void SelfviewPipPositionSet(CodecCommandWithLabel position); + void SelfviewPipPositionSet(CodecCommandWithLabel position); - void SelfviewPipPositionToggle(); - } + void SelfviewPipPositionToggle(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs index 4103fa0e..b00bc0b9 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs @@ -1,7 +1,7 @@ using PepperDash.Essentials.Devices.Common.VideoCodec; -namespace PepperDash.Essentials.Core.DeviceTypeInterfaces -{ +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces; + public interface IHasSelfviewSize { StringFeedback SelfviewPipSizeFeedback { get; } @@ -9,5 +9,4 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces void SelfviewPipSizeSet(CodecCommandWithLabel size); void SelfviewPipSizeToggle(); - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs index cc9dcd3d..22bdba57 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs @@ -6,29 +6,28 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +/// +/// Describes a device that has Standby Mode capability +/// +public interface IHasStandbyMode { - /// - /// Describes a device that has Standby Mode capability - /// - public interface IHasStandbyMode - { - BoolFeedback StandbyIsOnFeedback { get; } + BoolFeedback StandbyIsOnFeedback { get; } - void StandbyActivate(); + void StandbyActivate(); - void StandbyDeactivate(); - } + void StandbyDeactivate(); +} - /// - /// Describes a device that has Half Waek Mode capability - /// - public interface IHasHalfWakeMode : IHasStandbyMode - { - BoolFeedback HalfWakeModeIsOnFeedback { get; } +/// +/// Describes a device that has Half Waek Mode capability +/// +public interface IHasHalfWakeMode : IHasStandbyMode +{ + BoolFeedback HalfWakeModeIsOnFeedback { get; } - BoolFeedback EnteringStandbyModeFeedback { get; } + BoolFeedback EnteringStandbyModeFeedback { get; } - void HalfwakeActivate(); - } + void HalfwakeActivate(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs index 6af59534..ee160cb4 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs @@ -4,27 +4,26 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +/// +/// Describes the ability to start an ad-hoc meeting +/// +public interface IHasStartMeeting { /// - /// Describes the ability to start an ad-hoc meeting + /// The default meeting duration in minutes /// - public interface IHasStartMeeting - { - /// - /// The default meeting duration in minutes - /// - uint DefaultMeetingDurationMin { get; } + uint DefaultMeetingDurationMin { get; } - /// - /// Start an ad-hoc meeting for the specified duration - /// - /// - void StartMeeting(uint duration); + /// + /// Start an ad-hoc meeting for the specified duration + /// + /// + void StartMeeting(uint duration); - /// - /// Leaves a meeting without ending it - /// - void LeaveMeeting(); - } + /// + /// Leaves a meeting without ending it + /// + void LeaveMeeting(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs index d8494334..11817a94 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs @@ -6,8 +6,8 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.VideoCodec -{ +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + /// /// For rooms that have video codec /// @@ -15,10 +15,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { VideoCodecBase VideoCodec { get; } - ///// - ///// Make this more specific - ///// - //List ActiveCalls { get; } + ///// + ///// Make this more specific + ///// + //List ActiveCalls { get; } /// /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis @@ -30,5 +30,4 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// BoolFeedback IsSharingFeedback { get; } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs index b84db1e9..6b5fdecb 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs @@ -6,11 +6,10 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +public interface IJoinCalls { - public interface IJoinCalls - { - void JoinCall(CodecActiveCallItem activeCall); - void JoinAllCalls(); - } + void JoinCall(CodecActiveCallItem activeCall); + void JoinAllCalls(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs index 8f004086..39cbb46f 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs @@ -8,34 +8,33 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Devices.Common.Codec -{ - /// - /// Implements a common set of data about a codec - /// - public interface iVideoCodecInfo - { - VideoCodecInfo CodecInfo { get; } - } +namespace PepperDash.Essentials.Devices.Common.Codec; - /// - /// Stores general information about a codec - /// - public abstract class VideoCodecInfo - { - [JsonProperty("multiSiteOptionIsEnabled", NullValueHandling = NullValueHandling.Ignore)] - public abstract bool MultiSiteOptionIsEnabled { get; } - [JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)] - public abstract string IpAddress { get; } - [JsonProperty("sipPhoneNumber", NullValueHandling = NullValueHandling.Ignore)] - public abstract string SipPhoneNumber { get; } - [JsonProperty("e164Alias", NullValueHandling = NullValueHandling.Ignore)] - public abstract string E164Alias { get; } - [JsonProperty("h323Id", NullValueHandling = NullValueHandling.Ignore)] - public abstract string H323Id { get; } - [JsonProperty("sipUri", NullValueHandling = NullValueHandling.Ignore)] - public abstract string SipUri { get; } - [JsonProperty("autoAnswerEnabled", NullValueHandling = NullValueHandling.Ignore)] - public abstract bool AutoAnswerEnabled { get; } - } +/// +/// Implements a common set of data about a codec +/// +public interface iVideoCodecInfo +{ + VideoCodecInfo CodecInfo { get; } +} + +/// +/// Stores general information about a codec +/// +public abstract class VideoCodecInfo +{ + [JsonProperty("multiSiteOptionIsEnabled", NullValueHandling = NullValueHandling.Ignore)] + public abstract bool MultiSiteOptionIsEnabled { get; } + [JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)] + public abstract string IpAddress { get; } + [JsonProperty("sipPhoneNumber", NullValueHandling = NullValueHandling.Ignore)] + public abstract string SipPhoneNumber { get; } + [JsonProperty("e164Alias", NullValueHandling = NullValueHandling.Ignore)] + public abstract string E164Alias { get; } + [JsonProperty("h323Id", NullValueHandling = NullValueHandling.Ignore)] + public abstract string H323Id { get; } + [JsonProperty("sipUri", NullValueHandling = NullValueHandling.Ignore)] + public abstract string SipUri { get; } + [JsonProperty("autoAnswerEnabled", NullValueHandling = NullValueHandling.Ignore)] + public abstract bool AutoAnswerEnabled { get; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs index 41b70661..32eded61 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs @@ -9,411 +9,410 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +public static class MockVideoCodecDirectory { - public static class MockVideoCodecDirectory + public enum eFolderId { - public enum eFolderId - { - UnitedStates, - Canada, - NewYork, - Boston, - SanFrancisco, - Denver, - Austin, - Calgary - } - - - /// - /// Aggregates the directory items for all directories into a single directory for searching purposes - /// - public static CodecDirectory CompleteDirectory - { - get - { - var completeDirectory = new CodecDirectory(); - - completeDirectory.AddContactsToDirectory(DirectoryRoot.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(UnitedStatesFolderContents.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(CanadaFolderContents.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(NewYorkFolderContents.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(BostonFolderContents.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(DenverFolderContents.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(AustinFolderContents.CurrentDirectoryResults); - completeDirectory.AddContactsToDirectory(CalgaryFolderContents.CurrentDirectoryResults); - - return completeDirectory; - } - } - - public static CodecDirectory DirectoryRoot - { - get - { - var directory = new CodecDirectory(); - - directory.AddFoldersToDirectory - ( - new List() - { - new DirectoryFolder() - { - FolderId = eFolderId.UnitedStates.ToString(), - Name = "United States", - ParentFolderId = "", - Contacts = null - }, - new DirectoryFolder() - { - FolderId = eFolderId.Canada.ToString(), - Name = "Canada", - ParentFolderId = "", - Contacts = null - } - } - ); - - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - Name = "Corporate Bridge", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "c_1", - Number = "site.corp.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - public static CodecDirectory UnitedStatesFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.UnitedStates.ToString(); - directory.AddFoldersToDirectory - ( - new List() - { - new DirectoryFolder() - { - FolderId = eFolderId.NewYork.ToString(), - Name = "New York", - ParentFolderId = eFolderId.UnitedStates.ToString(), - Contacts = null - }, - new DirectoryFolder() - { - FolderId = eFolderId.Boston.ToString(), - Name = "Boston", - ParentFolderId = eFolderId.UnitedStates.ToString(), - Contacts = null - }, - new DirectoryFolder() - { - FolderId = eFolderId.SanFrancisco.ToString(), - Name = "San Francisco", - ParentFolderId = eFolderId.UnitedStates.ToString(), - Contacts = null - }, - new DirectoryFolder() - { - FolderId = eFolderId.Denver.ToString(), - Name = "Denver", - ParentFolderId = eFolderId.UnitedStates.ToString(), - Contacts = null - }, - new DirectoryFolder() - { - FolderId = eFolderId.Austin.ToString(), - Name = "Austin", - ParentFolderId = eFolderId.UnitedStates.ToString(), - Contacts = null - } - } - ); - - return directory; - } - } - - public static CodecDirectory NewYorkFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.NewYork.ToString(); - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - ContactId = "nyc_1", - Name = "Meeting Room", - Title = @"", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "nycmeetingroom.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - }, - new DirectoryContact() - { - ContactId = "nyc_2", - Name = "Sumanth Rayancha", - Title = @"CTO", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "srayancha.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - }, - new DirectoryContact() - { - ContactId = "nyc_3", - Name = "Justin Gordon", - Title = @"Software Developer", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "jgordon.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - public static CodecDirectory BostonFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Boston.ToString(); - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - ContactId = "bos_1", - Name = "Board Room", - Title = @"", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "bosboardroom.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - public static CodecDirectory SanFranciscoFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.SanFrancisco.ToString(); - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - ContactId = "sfo_1", - Name = "David Huselid", - Title = @"Cive President, COO", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "dhuselid.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - public static CodecDirectory DenverFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Denver.ToString(); - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - ContactId = "den_1", - Name = "Heath Volmer", - Title = @"Software Developer", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "hvolmer.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - public static CodecDirectory AustinFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Austin.ToString(); - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - ContactId = "atx_1", - Name = "Vincent Longano", - Title = @"Product Development Manager", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "vlongano.pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - public static CodecDirectory CanadaFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Canada.ToString(); - directory.AddFoldersToDirectory - ( - new List() - { - new DirectoryFolder() - { - FolderId = eFolderId.Calgary.ToString(), - Name = "Calgary", - ParentFolderId = eFolderId.Canada.ToString(), - Contacts = null - } - } - ); - - return directory; - } - } - - public static CodecDirectory CalgaryFolderContents - { - get - { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Calgary.ToString(); - directory.AddContactsToDirectory - ( - new List() - { - new DirectoryContact() - { - ContactId = "cdn_1", - Name = "Neil Dorin", - Title = @"Software Developer /SC", - ContactMethods = new List() - { - new ContactMethod() - { - ContactMethodId = "cid_1", - Number = "ndorin@pepperdash.com", - Device = eContactMethodDevice.Video, - CallType = eContactMethodCallType.Video - } - } - } - } - ); - - return directory; - } - } - - + UnitedStates, + Canada, + NewYork, + Boston, + SanFrancisco, + Denver, + Austin, + Calgary } + + + /// + /// Aggregates the directory items for all directories into a single directory for searching purposes + /// + public static CodecDirectory CompleteDirectory + { + get + { + var completeDirectory = new CodecDirectory(); + + completeDirectory.AddContactsToDirectory(DirectoryRoot.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(UnitedStatesFolderContents.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(CanadaFolderContents.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(NewYorkFolderContents.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(BostonFolderContents.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(DenverFolderContents.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(AustinFolderContents.CurrentDirectoryResults); + completeDirectory.AddContactsToDirectory(CalgaryFolderContents.CurrentDirectoryResults); + + return completeDirectory; + } + } + + public static CodecDirectory DirectoryRoot + { + get + { + var directory = new CodecDirectory(); + + directory.AddFoldersToDirectory + ( + new List() + { + new DirectoryFolder() + { + FolderId = eFolderId.UnitedStates.ToString(), + Name = "United States", + ParentFolderId = "", + Contacts = null + }, + new DirectoryFolder() + { + FolderId = eFolderId.Canada.ToString(), + Name = "Canada", + ParentFolderId = "", + Contacts = null + } + } + ); + + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + Name = "Corporate Bridge", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "c_1", + Number = "site.corp.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + public static CodecDirectory UnitedStatesFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.UnitedStates.ToString(); + directory.AddFoldersToDirectory + ( + new List() + { + new DirectoryFolder() + { + FolderId = eFolderId.NewYork.ToString(), + Name = "New York", + ParentFolderId = eFolderId.UnitedStates.ToString(), + Contacts = null + }, + new DirectoryFolder() + { + FolderId = eFolderId.Boston.ToString(), + Name = "Boston", + ParentFolderId = eFolderId.UnitedStates.ToString(), + Contacts = null + }, + new DirectoryFolder() + { + FolderId = eFolderId.SanFrancisco.ToString(), + Name = "San Francisco", + ParentFolderId = eFolderId.UnitedStates.ToString(), + Contacts = null + }, + new DirectoryFolder() + { + FolderId = eFolderId.Denver.ToString(), + Name = "Denver", + ParentFolderId = eFolderId.UnitedStates.ToString(), + Contacts = null + }, + new DirectoryFolder() + { + FolderId = eFolderId.Austin.ToString(), + Name = "Austin", + ParentFolderId = eFolderId.UnitedStates.ToString(), + Contacts = null + } + } + ); + + return directory; + } + } + + public static CodecDirectory NewYorkFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.NewYork.ToString(); + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + ContactId = "nyc_1", + Name = "Meeting Room", + Title = @"", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "nycmeetingroom.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + }, + new DirectoryContact() + { + ContactId = "nyc_2", + Name = "Sumanth Rayancha", + Title = @"CTO", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "srayancha.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + }, + new DirectoryContact() + { + ContactId = "nyc_3", + Name = "Justin Gordon", + Title = @"Software Developer", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "jgordon.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + public static CodecDirectory BostonFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.Boston.ToString(); + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + ContactId = "bos_1", + Name = "Board Room", + Title = @"", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "bosboardroom.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + public static CodecDirectory SanFranciscoFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.SanFrancisco.ToString(); + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + ContactId = "sfo_1", + Name = "David Huselid", + Title = @"Cive President, COO", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "dhuselid.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + public static CodecDirectory DenverFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.Denver.ToString(); + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + ContactId = "den_1", + Name = "Heath Volmer", + Title = @"Software Developer", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "hvolmer.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + public static CodecDirectory AustinFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.Austin.ToString(); + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + ContactId = "atx_1", + Name = "Vincent Longano", + Title = @"Product Development Manager", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "vlongano.pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + public static CodecDirectory CanadaFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.Canada.ToString(); + directory.AddFoldersToDirectory + ( + new List() + { + new DirectoryFolder() + { + FolderId = eFolderId.Calgary.ToString(), + Name = "Calgary", + ParentFolderId = eFolderId.Canada.ToString(), + Contacts = null + } + } + ); + + return directory; + } + } + + public static CodecDirectory CalgaryFolderContents + { + get + { + var directory = new CodecDirectory(); + + directory.ResultsFolderId = eFolderId.Calgary.ToString(); + directory.AddContactsToDirectory + ( + new List() + { + new DirectoryContact() + { + ContactId = "cdn_1", + Name = "Neil Dorin", + Title = @"Software Developer /SC", + ContactMethods = new List() + { + new ContactMethod() + { + ContactMethodId = "cid_1", + Number = "ndorin@pepperdash.com", + Device = eContactMethodDevice.Video, + CallType = eContactMethodCallType.Video + } + } + } + } + ); + + return directory; + } + } + + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs index 23023857..a607ab60 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs @@ -18,407 +18,407 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.VideoCodec -{ - public class MockVC : VideoCodecBase, IRoutingSource, IHasCallHistory, IHasScheduleAwareness, IHasCallFavorites, IHasDirectory, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets - { - public MockVcPropertiesConfig PropertiesConfig; +namespace PepperDash.Essentials.Devices.Common.VideoCodec; - public RoutingInputPort CodecOsdIn { get; private set; } - public RoutingInputPort HdmiIn1 { get; private set; } - public RoutingInputPort HdmiIn2 { get; private set; } - public RoutingOutputPort HdmiOut { get; private set; } +public class MockVC : VideoCodecBase, IRoutingSource, IHasCallHistory, IHasScheduleAwareness, IHasCallFavorites, IHasDirectory, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets +{ + public MockVcPropertiesConfig PropertiesConfig; + + public RoutingInputPort CodecOsdIn { get; private set; } + public RoutingInputPort HdmiIn1 { get; private set; } + public RoutingInputPort HdmiIn2 { get; private set; } + public RoutingOutputPort HdmiOut { get; private set; } public CodecCallFavorites CallFavorites { get; private set; } - /// - /// - /// - public MockVC(DeviceConfig config) - : base(config) - { - PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + /// + /// + /// + public MockVC(DeviceConfig config) + : base(config) + { + PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - CodecInfo = new MockCodecInfo(); + CodecInfo = new MockCodecInfo(); // Get favoritesw - if (PropertiesConfig.Favorites != null) + if (PropertiesConfig.Favorites != null) { CallFavorites = new CodecCallFavorites(); CallFavorites.Favorites = PropertiesConfig.Favorites; } - DirectoryBrowseHistory = new List(); + DirectoryBrowseHistory = new List(); - // Debug helpers - MuteFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Mute={0}", _IsMuted); - PrivacyModeIsOnFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Privacy={0}", _PrivacyModeIsOn); - SharingSourceFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "SharingSource={0}", _SharingSource); - VolumeLevelFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Volume={0}", _VolumeLevel); + // Debug helpers + MuteFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Mute={0}", _IsMuted); + PrivacyModeIsOnFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Privacy={0}", _PrivacyModeIsOn); + SharingSourceFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "SharingSource={0}", _SharingSource); + VolumeLevelFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Volume={0}", _VolumeLevel); - CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback(() => DirectoryBrowseHistory.Count > 0); + CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback(() => DirectoryBrowseHistory.Count > 0); - CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); + CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); - CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 0, this); - InputPorts.Add(CodecOsdIn); - HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 1, this); - InputPorts.Add(HdmiIn1); - HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 2, this); - InputPorts.Add(HdmiIn2); - HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); - OutputPorts.Add(HdmiOut); + CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 0, this); + InputPorts.Add(CodecOsdIn); + HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 1, this); + InputPorts.Add(HdmiIn1); + HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 2, this); + InputPorts.Add(HdmiIn2); + HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); + OutputPorts.Add(HdmiOut); - CallHistory = new CodecCallHistory(); - for (int i = 0; i < 10; i++) - { - var call = new CodecCallHistory.CallHistoryEntry(); - call.Name = "Call " + i; - call.Number = i + "@call.com"; - CallHistory.RecentCalls.Add(call); - } - // eventually fire history event here - - SetupCameras(); - - CreateOsdSource(); - - SetIsReady(); - } - - protected override Func MuteFeedbackFunc + CallHistory = new CodecCallHistory(); + for (int i = 0; i < 10; i++) { - get { return () => _IsMuted; } + var call = new CodecCallHistory.CallHistoryEntry(); + call.Name = "Call " + i; + call.Number = i + "@call.com"; + CallHistory.RecentCalls.Add(call); } - bool _IsMuted; + // eventually fire history event here - protected override Func PrivacyModeIsOnFeedbackFunc + SetupCameras(); + + CreateOsdSource(); + + SetIsReady(); + } + + protected override Func MuteFeedbackFunc + { + get { return () => _IsMuted; } + } + bool _IsMuted; + + protected override Func PrivacyModeIsOnFeedbackFunc + { + get { return () => _PrivacyModeIsOn; } + } + bool _PrivacyModeIsOn; + + protected override Func SharingSourceFeedbackFunc + { + get { return () => _SharingSource; } + } + string _SharingSource; + + protected override Func SharingContentIsOnFeedbackFunc + { + get { return () => _SharingIsOn; } + } + bool _SharingIsOn; + + protected override Func VolumeLevelFeedbackFunc + { + get { return () => _VolumeLevel; } + } + int _VolumeLevel; + + protected override Func StandbyIsOnFeedbackFunc + { + get { return () => _StandbyIsOn; } + } + bool _StandbyIsOn; + + /// + /// Creates the fake OSD source, and connects it's AudioVideo output to the CodecOsdIn input + /// to enable routing + /// + private void CreateOsdSource() + { + OsdSource = new DummyRoutingInputsDevice(Key + "[osd]"); + DeviceManager.AddDevice(OsdSource); + var tl = new TieLine(OsdSource.AudioVideoOutputPort, CodecOsdIn); + TieLineCollection.Default.Add(tl); + + //foreach(var input in Status.Video. + } + + /// + /// Dials, yo! + /// + public override void Dial(string number) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); + var call = new CodecActiveCallItem() { Name = number, Number = number, Id = number, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; + ActiveCalls.Add(call); + OnCallStatusChange(call); + //ActiveCallCountFeedback.FireUpdate(); + // Simulate 2-second ring, then connecting, then connected + new CTimer(o => { - get { return () => _PrivacyModeIsOn; } - } - bool _PrivacyModeIsOn; - - protected override Func SharingSourceFeedbackFunc - { - get { return () => _SharingSource; } - } - string _SharingSource; - - protected override Func SharingContentIsOnFeedbackFunc - { - get { return () => _SharingIsOn; } - } - bool _SharingIsOn; - - protected override Func VolumeLevelFeedbackFunc - { - get { return () => _VolumeLevel; } - } - int _VolumeLevel; - - protected override Func StandbyIsOnFeedbackFunc - { - get { return () => _StandbyIsOn; } - } - bool _StandbyIsOn; - - /// - /// Creates the fake OSD source, and connects it's AudioVideo output to the CodecOsdIn input - /// to enable routing - /// - private void CreateOsdSource() - { - OsdSource = new DummyRoutingInputsDevice(Key + "[osd]"); - DeviceManager.AddDevice(OsdSource); - var tl = new TieLine(OsdSource.AudioVideoOutputPort, CodecOsdIn); - TieLineCollection.Default.Add(tl); - - //foreach(var input in Status.Video. - } - - /// - /// Dials, yo! - /// - public override void Dial(string number) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); - var call = new CodecActiveCallItem() { Name = number, Number = number, Id = number, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; - ActiveCalls.Add(call); - OnCallStatusChange(call); - //ActiveCallCountFeedback.FireUpdate(); - // Simulate 2-second ring, then connecting, then connected - new CTimer(o => - { - call.Type = eCodecCallType.Video; - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); - new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); - }, 2000); - } - - public override void Dial(Meeting meeting) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Dial Meeting: {0}", meeting.Id); - var call = new CodecActiveCallItem() { Name = meeting.Title, Number = meeting.Id, Id = meeting.Id, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; - ActiveCalls.Add(call); - OnCallStatusChange(call); - - //ActiveCallCountFeedback.FireUpdate(); - // Simulate 2-second ring, then connecting, then connected - new CTimer(o => - { - call.Type = eCodecCallType.Video; - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); - new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); - }, 2000); - - } - - /// - /// - /// - public override void EndCall(CodecActiveCallItem call) - { - Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); - ActiveCalls.Remove(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - //ActiveCallCountFeedback.FireUpdate(); - } - - /// - /// - /// - public override void EndAllCalls() - { - Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); - for(int i = ActiveCalls.Count - 1; i >= 0; i--) - { - var call = ActiveCalls[i]; - ActiveCalls.Remove(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - } - //ActiveCallCountFeedback.FireUpdate(); - } - - /// - /// For a call from the test methods below - /// - public override void AcceptCall(CodecActiveCallItem call) - { - Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); + call.Type = eCodecCallType.Video; SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); - new CTimer(o => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); - // should already be in active list - } + new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); + }, 2000); + } - /// - /// For a call from the test methods below - /// - public override void RejectCall(CodecActiveCallItem call) + public override void Dial(Meeting meeting) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Dial Meeting: {0}", meeting.Id); + var call = new CodecActiveCallItem() { Name = meeting.Title, Number = meeting.Id, Id = meeting.Id, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; + ActiveCalls.Add(call); + OnCallStatusChange(call); + + //ActiveCallCountFeedback.FireUpdate(); + // Simulate 2-second ring, then connecting, then connected + new CTimer(o => { - Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); + call.Type = eCodecCallType.Video; + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); + new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); + }, 2000); + + } + + /// + /// + /// + public override void EndCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); + //ActiveCallCountFeedback.FireUpdate(); + } + + /// + /// + /// + public override void EndAllCalls() + { + Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); + for(int i = ActiveCalls.Count - 1; i >= 0; i--) + { + var call = ActiveCalls[i]; ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); - //ActiveCallCountFeedback.FireUpdate(); } + //ActiveCallCountFeedback.FireUpdate(); + } - /// - /// Makes horrible tones go out on the wire! - /// - /// - public override void SendDtmf(string s) - { - Debug.LogMessage(LogEventLevel.Debug, this, "SendDTMF: {0}", s); - } + /// + /// For a call from the test methods below + /// + public override void AcceptCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); + new CTimer(o => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); + // should already be in active list + } - /// - /// - /// - public override void StartSharing() - { - _SharingIsOn = true; - SharingContentIsOnFeedback.FireUpdate(); - } + /// + /// For a call from the test methods below + /// + public override void RejectCall(CodecActiveCallItem call) + { + Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); + ActiveCalls.Remove(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); + //ActiveCallCountFeedback.FireUpdate(); + } - /// - /// - /// - public override void StopSharing() - { - _SharingIsOn = false; - SharingContentIsOnFeedback.FireUpdate(); - } + /// + /// Makes horrible tones go out on the wire! + /// + /// + public override void SendDtmf(string s) + { + Debug.LogMessage(LogEventLevel.Debug, this, "SendDTMF: {0}", s); + } - public override void StandbyActivate() - { - _StandbyIsOn = true; - } + /// + /// + /// + public override void StartSharing() + { + _SharingIsOn = true; + SharingContentIsOnFeedback.FireUpdate(); + } - public override void StandbyDeactivate() - { - _StandbyIsOn = false; - } + /// + /// + /// + public override void StopSharing() + { + _SharingIsOn = false; + SharingContentIsOnFeedback.FireUpdate(); + } - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - throw new NotImplementedException(); - } + public override void StandbyActivate() + { + _StandbyIsOn = true; + } - /// - /// Called by routing to make it happen - /// - /// - public override void ExecuteSwitch(object selector) - { - Debug.LogMessage(LogEventLevel.Debug, this, "ExecuteSwitch: {0}", selector); - _SharingSource = selector.ToString(); - } + public override void StandbyDeactivate() + { + _StandbyIsOn = false; + } - /// - /// - /// - public override void MuteOff() - { - _IsMuted = false; - MuteFeedback.FireUpdate(); - } + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + throw new NotImplementedException(); + } - /// - /// - /// - public override void MuteOn() - { - _IsMuted = true; - MuteFeedback.FireUpdate(); - } + /// + /// Called by routing to make it happen + /// + /// + public override void ExecuteSwitch(object selector) + { + Debug.LogMessage(LogEventLevel.Debug, this, "ExecuteSwitch: {0}", selector); + _SharingSource = selector.ToString(); + } - /// - /// - /// - public override void MuteToggle() - { - _IsMuted = !_IsMuted; - MuteFeedback.FireUpdate(); - } - - /// - /// - /// - /// - public override void SetVolume(ushort level) - { - _VolumeLevel = level; - VolumeLevelFeedback.FireUpdate(); - } + /// + /// + /// + public override void MuteOff() + { + _IsMuted = false; + MuteFeedback.FireUpdate(); + } - /// - /// - /// - /// - public override void VolumeDown(bool pressRelease) - { - } + /// + /// + /// + public override void MuteOn() + { + _IsMuted = true; + MuteFeedback.FireUpdate(); + } - /// - /// - /// - /// - public override void VolumeUp(bool pressRelease) - { - } + /// + /// + /// + public override void MuteToggle() + { + _IsMuted = !_IsMuted; + MuteFeedback.FireUpdate(); + } + + /// + /// + /// + /// + public override void SetVolume(ushort level) + { + _VolumeLevel = level; + VolumeLevelFeedback.FireUpdate(); + } - /// - /// - /// - public override void PrivacyModeOn() - { - Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOn"); - if (_PrivacyModeIsOn) - return; - _PrivacyModeIsOn = true; - PrivacyModeIsOnFeedback.FireUpdate(); - } + /// + /// + /// + /// + public override void VolumeDown(bool pressRelease) + { + } - /// - /// - /// - public override void PrivacyModeOff() - { - Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOff"); - if (!_PrivacyModeIsOn) - return; - _PrivacyModeIsOn = false; - PrivacyModeIsOnFeedback.FireUpdate(); - } + /// + /// + /// + /// + public override void VolumeUp(bool pressRelease) + { + } - /// - /// - /// - public override void PrivacyModeToggle() - { - _PrivacyModeIsOn = !_PrivacyModeIsOn; - Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteToggle: {0}", _PrivacyModeIsOn); - PrivacyModeIsOnFeedback.FireUpdate(); - } + /// + /// + /// + public override void PrivacyModeOn() + { + Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOn"); + if (_PrivacyModeIsOn) + return; + _PrivacyModeIsOn = true; + PrivacyModeIsOnFeedback.FireUpdate(); + } - //******************************************************** - // SIMULATION METHODS + /// + /// + /// + public override void PrivacyModeOff() + { + Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOff"); + if (!_PrivacyModeIsOn) + return; + _PrivacyModeIsOn = false; + PrivacyModeIsOnFeedback.FireUpdate(); + } - /// - /// - /// - /// - public void TestIncomingVideoCall(string url) - { - Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingVideoCall from {0}", url); - var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type= eCodecCallType.Video, Direction = eCodecCallDirection.Incoming }; - ActiveCalls.Add(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); + /// + /// + /// + public override void PrivacyModeToggle() + { + _PrivacyModeIsOn = !_PrivacyModeIsOn; + Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteToggle: {0}", _PrivacyModeIsOn); + PrivacyModeIsOnFeedback.FireUpdate(); + } - //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); - - } + //******************************************************** + // SIMULATION METHODS - /// - /// - /// - /// - public void TestIncomingAudioCall(string url) - { - Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", url); - var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming }; - ActiveCalls.Add(call); - SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); + /// + /// + /// + /// + public void TestIncomingVideoCall(string url) + { + Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingVideoCall from {0}", url); + var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type= eCodecCallType.Video, Direction = eCodecCallDirection.Incoming }; + ActiveCalls.Add(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); - //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); - } - - /// - /// - /// - public void TestFarEndHangup() - { - Debug.LogMessage(LogEventLevel.Debug, this, "TestFarEndHangup"); - - } - - - #region IHasCallHistory Members - - public CodecCallHistory CallHistory { get; private set; } - - public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) - { + //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); - } + } - #endregion + /// + /// + /// + /// + public void TestIncomingAudioCall(string url) + { + Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", url); + var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming }; + ActiveCalls.Add(call); + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); + + //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); + } + + /// + /// + /// + public void TestFarEndHangup() + { + Debug.LogMessage(LogEventLevel.Debug, this, "TestFarEndHangup"); + + } + + + #region IHasCallHistory Members + + public CodecCallHistory CallHistory { get; private set; } + + public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) + { + + } + + #endregion #region IHasScheduleAwareness Members - public void GetSchedule() - { + public void GetSchedule() + { - } + } public CodecScheduleAwareness CodecSchedule { @@ -431,13 +431,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec for (int i = 0; i < 5; i++) { var m = new Meeting(); - m.MinutesBeforeMeeting = 5; - m.Id = i.ToString(); - m.Organizer = "Employee " + 1; + m.MinutesBeforeMeeting = 5; + m.Id = i.ToString(); + m.Organizer = "Employee " + 1; m.StartTime = DateTime.Now.AddMinutes(5).AddHours(i); m.EndTime = DateTime.Now.AddHours(i).AddMinutes(50); m.Title = "Meeting " + i; - m.Calls.Add(new Call() { Number = i + "meeting@fake.com"}); + m.Calls.Add(new Call() { Number = i + "meeting@fake.com"}); _CodecSchedule.Meetings.Add(m); } } @@ -448,403 +448,401 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec #endregion - #region IHasDirectory Members + #region IHasDirectory Members - public event EventHandler DirectoryResultReturned; + public event EventHandler DirectoryResultReturned; - public CodecDirectory DirectoryRoot + public CodecDirectory DirectoryRoot + { + get { - get - { - return MockVideoCodecDirectory.DirectoryRoot; - } + return MockVideoCodecDirectory.DirectoryRoot; } - - public CodecDirectory CurrentDirectoryResult - { - get - { - if (DirectoryBrowseHistory.Count > 0) - return DirectoryBrowseHistory[DirectoryBrowseHistory.Count - 1]; - else - return DirectoryRoot; - } - } - - public CodecPhonebookSyncState PhonebookSyncState - { - get - { - var syncState = new CodecPhonebookSyncState(Key + "PhonebookSync"); - - syncState.InitialPhonebookFoldersReceived(); - syncState.PhonebookRootEntriesReceived(); - syncState.SetPhonebookHasFolders(true); - syncState.SetNumberOfContacts(0); // just need to call this method for the sync to complete - - return syncState; - } - } - - public void SearchDirectory(string searchString) - { - var searchResults = new CodecDirectory(); - - searchResults.ResultsFolderId = "searchResult"; - - // Search mock directory for contacts that contain the search string, ignoring case - List matches = MockVideoCodecDirectory.CompleteDirectory.CurrentDirectoryResults.FindAll( - s => s is DirectoryContact && s.Name.ToLower().Contains(searchString.ToLower())); - - if (matches != null) - { - searchResults.AddContactsToDirectory(matches); - - DirectoryBrowseHistory.Add(searchResults); - } - - OnDirectoryResultReturned(searchResults); - } - - public void GetDirectoryFolderContents(string folderId) - { - var folderDirectory = new CodecDirectory(); - - if (folderId == MockVideoCodecDirectory.eFolderId.UnitedStates.ToString()) - folderDirectory = MockVideoCodecDirectory.UnitedStatesFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.Canada.ToString()) - folderDirectory = MockVideoCodecDirectory.CanadaFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.NewYork.ToString()) - folderDirectory = MockVideoCodecDirectory.NewYorkFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.Boston.ToString()) - folderDirectory = MockVideoCodecDirectory.BostonFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.SanFrancisco.ToString()) - folderDirectory = MockVideoCodecDirectory.SanFranciscoFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.Denver.ToString()) - folderDirectory = MockVideoCodecDirectory.DenverFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.Austin.ToString()) - folderDirectory = MockVideoCodecDirectory.AustinFolderContents; - else if (folderId == MockVideoCodecDirectory.eFolderId.Calgary.ToString()) - folderDirectory = MockVideoCodecDirectory.CalgaryFolderContents; - - DirectoryBrowseHistory.Add(folderDirectory); - - OnDirectoryResultReturned(folderDirectory); - } - - public void SetCurrentDirectoryToRoot() - { - DirectoryBrowseHistory.Clear(); - - OnDirectoryResultReturned(DirectoryRoot); - } - - public void GetDirectoryParentFolderContents() - { - var currentDirectory = new CodecDirectory(); - - if (DirectoryBrowseHistory.Count > 0) - { - var lastItemIndex = DirectoryBrowseHistory.Count - 1; - var parentDirectoryContents = DirectoryBrowseHistory[lastItemIndex]; - - DirectoryBrowseHistory.Remove(DirectoryBrowseHistory[lastItemIndex]); - - currentDirectory = parentDirectoryContents; - - } - else - { - currentDirectory = DirectoryRoot; - } - - OnDirectoryResultReturned(currentDirectory); - } - - public BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; private set; } - - public List DirectoryBrowseHistory { get; private set; } - - public void OnDirectoryResultReturned(CodecDirectory result) - { - CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); - - var handler = DirectoryResultReturned; - if (handler != null) - { - handler(this, new DirectoryEventArgs() - { - Directory = result, - DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue - }); - } - } - - #endregion - - void SetupCameras() - { - SupportsCameraAutoMode = true; - - SupportsCameraOff = false; - - Cameras = new List(); - - var internalCamera = new MockVCCamera(Key + "-camera1", "Near End", this); - - Cameras.Add(internalCamera); - - var farEndCamera = new MockFarEndVCCamera(Key + "-cameraFar", "Far End", this); - - Cameras.Add(farEndCamera); - - SelectedCameraFeedback = new StringFeedback(() => SelectedCamera.Key); - - ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); - - CameraAutoModeIsOnFeedback = new BoolFeedback(() => _CameraAutoModeIsOn); - - SupportsCameraAutoMode = true; - - CameraAutoModeIsOnFeedback.FireUpdate(); - - DeviceManager.AddDevice(internalCamera); - DeviceManager.AddDevice(farEndCamera); - - NearEndPresets = new List(15); // Fix the capacity to emulate Cisco - - if (PropertiesConfig.Presets != null && PropertiesConfig.Presets.Count > 0) - { - NearEndPresets = PropertiesConfig.Presets; - } - else - { - for (int i = 1; i <= NearEndPresets.Capacity; i++) - { - var label = string.Format("Near End Preset {0}", i); - NearEndPresets.Add(new CodecRoomPreset(i, label, true, false)); - } - } - - FarEndRoomPresets = new List(15); // Fix the capacity to emulate Cisco - - // Add the far end presets - for (int i = 1; i <= FarEndRoomPresets.Capacity; i++) - { - var label = string.Format("Far End Preset {0}", i); - FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); - } - - SelectedCamera = internalCamera; ; // call the method to select the camera and ensure the feedbacks get updated. - } - - #region IHasCameras Members - - public event EventHandler CameraSelected; - - public List Cameras { get; private set; } - - private CameraBase _selectedCamera; - - /// - /// Returns the selected camera - /// - public CameraBase SelectedCamera - { - get - { - return _selectedCamera; - } - private set - { - _selectedCamera = value; - SelectedCameraFeedback.FireUpdate(); - ControllingFarEndCameraFeedback.FireUpdate(); - - var handler = CameraSelected; - if (handler != null) - { - handler(this, new CameraSelectedEventArgs(SelectedCamera)); - } - } - } - - public StringFeedback SelectedCameraFeedback { get; private set; } - - public void SelectCamera(string key) - { - var camera = Cameras.FirstOrDefault(c => c.Key.ToLower().IndexOf(key.ToLower()) > -1); - if (camera != null) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Selected Camera with key: '{0}'", camera.Key); - SelectedCamera = camera; - } - else - Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to select camera with key: '{0}'", key); - } - - #endregion - - #region IHasFarEndCameraControl Members - - public CameraBase FarEndCamera { get; private set; } - - public BoolFeedback ControllingFarEndCameraFeedback { get; private set; } - - #endregion - - #region IHasCameraAutoMode Members - - private bool _CameraAutoModeIsOn; - - public void CameraAutoModeOn() - { - _CameraAutoModeIsOn = true; - CameraAutoModeIsOnFeedback.FireUpdate(); - } - - public void CameraAutoModeOff() - { - _CameraAutoModeIsOn = false; - CameraAutoModeIsOnFeedback.FireUpdate(); - } - - public void CameraAutoModeToggle() - { - if(_CameraAutoModeIsOn) - _CameraAutoModeIsOn = false; - else - _CameraAutoModeIsOn = true; - - CameraAutoModeIsOnFeedback.FireUpdate(); - - } - - public BoolFeedback CameraAutoModeIsOnFeedback {get; private set;} - - #endregion - - #region IHasCameraPresets Members - - public event EventHandler CodecRoomPresetsListHasChanged; - - public List NearEndPresets { get; private set; } - - public List FarEndRoomPresets { get; private set; } - - public void CodecRoomPresetSelect(int preset) - { - if (SelectedCamera is IAmFarEndCamera) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Far End Preset: {0}", preset); - } - else - { - Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Near End Preset: {0}", preset); - } - } - - public void CodecRoomPresetStore(int preset, string description) - { - var editPreset = NearEndPresets.FirstOrDefault(p => p.ID.Equals(preset)); - - if (editPreset != null) - { - editPreset.Defined = true; - editPreset.Description = description; - } - else - NearEndPresets.Add(new CodecRoomPreset(preset, description, true, true)); - - var handler = CodecRoomPresetsListHasChanged; - if (handler != null) - { - handler(this, new EventArgs()); - } - - // Update the config - SetConfig(Config); - } - - public void SelectFarEndPreset(int i) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Far End Preset: {0}", i); - } - - #endregion - - protected override void CustomSetConfig(DeviceConfig config) - { - PropertiesConfig.Presets = NearEndPresets; - - Config.Properties = JToken.FromObject(PropertiesConfig); - - ConfigWriter.UpdateDeviceConfig(config); - } - } + public CodecDirectory CurrentDirectoryResult + { + get + { + if (DirectoryBrowseHistory.Count > 0) + return DirectoryBrowseHistory[DirectoryBrowseHistory.Count - 1]; + else + return DirectoryRoot; + } + } + + public CodecPhonebookSyncState PhonebookSyncState + { + get + { + var syncState = new CodecPhonebookSyncState(Key + "PhonebookSync"); + + syncState.InitialPhonebookFoldersReceived(); + syncState.PhonebookRootEntriesReceived(); + syncState.SetPhonebookHasFolders(true); + syncState.SetNumberOfContacts(0); // just need to call this method for the sync to complete + + return syncState; + } + } + + public void SearchDirectory(string searchString) + { + var searchResults = new CodecDirectory(); + + searchResults.ResultsFolderId = "searchResult"; + + // Search mock directory for contacts that contain the search string, ignoring case + List matches = MockVideoCodecDirectory.CompleteDirectory.CurrentDirectoryResults.FindAll( + s => s is DirectoryContact && s.Name.ToLower().Contains(searchString.ToLower())); + + if (matches != null) + { + searchResults.AddContactsToDirectory(matches); + + DirectoryBrowseHistory.Add(searchResults); + } + + OnDirectoryResultReturned(searchResults); + } + + public void GetDirectoryFolderContents(string folderId) + { + var folderDirectory = new CodecDirectory(); + + if (folderId == MockVideoCodecDirectory.eFolderId.UnitedStates.ToString()) + folderDirectory = MockVideoCodecDirectory.UnitedStatesFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.Canada.ToString()) + folderDirectory = MockVideoCodecDirectory.CanadaFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.NewYork.ToString()) + folderDirectory = MockVideoCodecDirectory.NewYorkFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.Boston.ToString()) + folderDirectory = MockVideoCodecDirectory.BostonFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.SanFrancisco.ToString()) + folderDirectory = MockVideoCodecDirectory.SanFranciscoFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.Denver.ToString()) + folderDirectory = MockVideoCodecDirectory.DenverFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.Austin.ToString()) + folderDirectory = MockVideoCodecDirectory.AustinFolderContents; + else if (folderId == MockVideoCodecDirectory.eFolderId.Calgary.ToString()) + folderDirectory = MockVideoCodecDirectory.CalgaryFolderContents; + + DirectoryBrowseHistory.Add(folderDirectory); + + OnDirectoryResultReturned(folderDirectory); + } + + public void SetCurrentDirectoryToRoot() + { + DirectoryBrowseHistory.Clear(); + + OnDirectoryResultReturned(DirectoryRoot); + } + + public void GetDirectoryParentFolderContents() + { + var currentDirectory = new CodecDirectory(); + + if (DirectoryBrowseHistory.Count > 0) + { + var lastItemIndex = DirectoryBrowseHistory.Count - 1; + var parentDirectoryContents = DirectoryBrowseHistory[lastItemIndex]; + + DirectoryBrowseHistory.Remove(DirectoryBrowseHistory[lastItemIndex]); + + currentDirectory = parentDirectoryContents; + + } + else + { + currentDirectory = DirectoryRoot; + } + + OnDirectoryResultReturned(currentDirectory); + } + + public BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; private set; } + + public List DirectoryBrowseHistory { get; private set; } + + public void OnDirectoryResultReturned(CodecDirectory result) + { + CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); + + var handler = DirectoryResultReturned; + if (handler != null) + { + handler(this, new DirectoryEventArgs() + { + Directory = result, + DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue + }); + } + } + + #endregion + + void SetupCameras() + { + SupportsCameraAutoMode = true; + + SupportsCameraOff = false; + + Cameras = new List(); + + var internalCamera = new MockVCCamera(Key + "-camera1", "Near End", this); + + Cameras.Add(internalCamera); + + var farEndCamera = new MockFarEndVCCamera(Key + "-cameraFar", "Far End", this); + + Cameras.Add(farEndCamera); + + SelectedCameraFeedback = new StringFeedback(() => SelectedCamera.Key); + + ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); + + CameraAutoModeIsOnFeedback = new BoolFeedback(() => _CameraAutoModeIsOn); + + SupportsCameraAutoMode = true; + + CameraAutoModeIsOnFeedback.FireUpdate(); + + DeviceManager.AddDevice(internalCamera); + DeviceManager.AddDevice(farEndCamera); + + NearEndPresets = new List(15); // Fix the capacity to emulate Cisco + + if (PropertiesConfig.Presets != null && PropertiesConfig.Presets.Count > 0) + { + NearEndPresets = PropertiesConfig.Presets; + } + else + { + for (int i = 1; i <= NearEndPresets.Capacity; i++) + { + var label = string.Format("Near End Preset {0}", i); + NearEndPresets.Add(new CodecRoomPreset(i, label, true, false)); + } + } + + FarEndRoomPresets = new List(15); // Fix the capacity to emulate Cisco + + // Add the far end presets + for (int i = 1; i <= FarEndRoomPresets.Capacity; i++) + { + var label = string.Format("Far End Preset {0}", i); + FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); + } + + SelectedCamera = internalCamera; ; // call the method to select the camera and ensure the feedbacks get updated. + } + + #region IHasCameras Members + + public event EventHandler CameraSelected; + + public List Cameras { get; private set; } + + private CameraBase _selectedCamera; + /// - /// Implementation for the mock VC + /// Returns the selected camera /// - public class MockCodecInfo : VideoCodecInfo + public CameraBase SelectedCamera { - - public override bool MultiSiteOptionIsEnabled + get { - get { return true; } + return _selectedCamera; } - - public override string E164Alias + private set { - get { return "someE164alias"; } - } + _selectedCamera = value; + SelectedCameraFeedback.FireUpdate(); + ControllingFarEndCameraFeedback.FireUpdate(); - public override string H323Id - { - get { return "someH323Id"; } - } - - public override string IpAddress - { - get { return "xxx.xxx.xxx.xxx"; } - } - - public override string SipPhoneNumber - { - get { return "333-444-5555"; } - } - - public override string SipUri - { - get { return "mock@someurl.com"; } - } - - public override bool AutoAnswerEnabled - { - get { return _AutoAnswerEnabled; } - } - bool _AutoAnswerEnabled; - - public void SetAutoAnswer(bool value) - { - _AutoAnswerEnabled = value; + var handler = CameraSelected; + if (handler != null) + { + handler(this, new CameraSelectedEventArgs(SelectedCamera)); + } } } - public class MockVCFactory : EssentialsDeviceFactory - { - public MockVCFactory() - { - TypeNames = new List() { "mockvc" }; - } + public StringFeedback SelectedCameraFeedback { get; private set; } - public override EssentialsDevice BuildDevice(DeviceConfig dc) + public void SelectCamera(string key) + { + var camera = Cameras.FirstOrDefault(c => c.Key.ToLower().IndexOf(key.ToLower()) > -1); + if (camera != null) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MockVC Device"); - return new VideoCodec.MockVC(dc); + Debug.LogMessage(LogEventLevel.Verbose, this, "Selected Camera with key: '{0}'", camera.Key); + SelectedCamera = camera; + } + else + Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to select camera with key: '{0}'", key); + } + + #endregion + + #region IHasFarEndCameraControl Members + + public CameraBase FarEndCamera { get; private set; } + + public BoolFeedback ControllingFarEndCameraFeedback { get; private set; } + + #endregion + + #region IHasCameraAutoMode Members + + private bool _CameraAutoModeIsOn; + + public void CameraAutoModeOn() + { + _CameraAutoModeIsOn = true; + CameraAutoModeIsOnFeedback.FireUpdate(); + } + + public void CameraAutoModeOff() + { + _CameraAutoModeIsOn = false; + CameraAutoModeIsOnFeedback.FireUpdate(); + } + + public void CameraAutoModeToggle() + { + if(_CameraAutoModeIsOn) + _CameraAutoModeIsOn = false; + else + _CameraAutoModeIsOn = true; + + CameraAutoModeIsOnFeedback.FireUpdate(); + + } + + public BoolFeedback CameraAutoModeIsOnFeedback {get; private set;} + + #endregion + + #region IHasCameraPresets Members + + public event EventHandler CodecRoomPresetsListHasChanged; + + public List NearEndPresets { get; private set; } + + public List FarEndRoomPresets { get; private set; } + + public void CodecRoomPresetSelect(int preset) + { + if (SelectedCamera is IAmFarEndCamera) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Far End Preset: {0}", preset); + } + else + { + Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Near End Preset: {0}", preset); } } + public void CodecRoomPresetStore(int preset, string description) + { + var editPreset = NearEndPresets.FirstOrDefault(p => p.ID.Equals(preset)); + + if (editPreset != null) + { + editPreset.Defined = true; + editPreset.Description = description; + } + else + NearEndPresets.Add(new CodecRoomPreset(preset, description, true, true)); + + var handler = CodecRoomPresetsListHasChanged; + if (handler != null) + { + handler(this, new EventArgs()); + } + + // Update the config + SetConfig(Config); + } + + public void SelectFarEndPreset(int i) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Far End Preset: {0}", i); + } + + #endregion + + protected override void CustomSetConfig(DeviceConfig config) + { + PropertiesConfig.Presets = NearEndPresets; + + Config.Properties = JToken.FromObject(PropertiesConfig); + + ConfigWriter.UpdateDeviceConfig(config); + } + +} + +/// +/// Implementation for the mock VC +/// +public class MockCodecInfo : VideoCodecInfo +{ + + public override bool MultiSiteOptionIsEnabled + { + get { return true; } + } + + public override string E164Alias + { + get { return "someE164alias"; } + } + + public override string H323Id + { + get { return "someH323Id"; } + } + + public override string IpAddress + { + get { return "xxx.xxx.xxx.xxx"; } + } + + public override string SipPhoneNumber + { + get { return "333-444-5555"; } + } + + public override string SipUri + { + get { return "mock@someurl.com"; } + } + + public override bool AutoAnswerEnabled + { + get { return _AutoAnswerEnabled; } + } + bool _AutoAnswerEnabled; + + public void SetAutoAnswer(bool value) + { + _AutoAnswerEnabled = value; + } +} + +public class MockVCFactory : EssentialsDeviceFactory +{ + public MockVCFactory() + { + TypeNames = new List() { "mockvc" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MockVC Device"); + return new VideoCodec.MockVC(dc); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs index 3b4d5ab9..52c52036 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs @@ -9,199 +9,198 @@ using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.VideoCodec; using Serilog.Events; -namespace PepperDash.Essentials.Devices.Common.Cameras +namespace PepperDash.Essentials.Devices.Common.Cameras; + +public class MockVCCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl, IBridgeAdvanced { - public class MockVCCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl, IBridgeAdvanced + protected VideoCodecBase ParentCodec { get; private set; } + + + public MockVCCamera(string key, string name, VideoCodecBase codec) + : base(key, name) { - protected VideoCodecBase ParentCodec { get; private set; } + Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; - - public MockVCCamera(string key, string name, VideoCodecBase codec) - : base(key, name) - { - Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; - - ParentCodec = codec; - } - - #region IHasCameraPtzControl Members - - public void PositionHome() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); - } - - #endregion - - #region IHasCameraPanControl Members - - public void PanLeft() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); - } - - public void PanRight() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); - } - - public void PanStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); - } - - #endregion - - #region IHasCameraTiltControl Members - - public void TiltDown() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); - } - - public void TiltUp() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); - } - - public void TiltStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); - } - - #endregion - - #region IHasCameraZoomControl Members - - public void ZoomIn() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); - } - - public void ZoomOut() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); - } - - public void ZoomStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); - } - - #endregion - - #region IHasCameraFocusControl Members - - public void FocusNear() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Near"); - } - - public void FocusFar() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Far"); - } - - public void FocusStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Focus"); - } - - public void TriggerAutoFocus() - { - Debug.LogMessage(LogEventLevel.Debug, this, "AutoFocus Triggered"); - } - - #endregion - - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); - } + ParentCodec = codec; } - public class MockFarEndVCCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera, IBridgeAdvanced + #region IHasCameraPtzControl Members + + public void PositionHome() { - protected VideoCodecBase ParentCodec { get; private set; } + Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); + } + + #endregion + + #region IHasCameraPanControl Members + + public void PanLeft() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); + } + + public void PanRight() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); + } + + public void PanStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); + } + + #endregion + + #region IHasCameraTiltControl Members + + public void TiltDown() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); + } + + public void TiltUp() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); + } + + public void TiltStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); + } + + #endregion + + #region IHasCameraZoomControl Members + + public void ZoomIn() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); + } + + public void ZoomOut() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); + } + + public void ZoomStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); + } + + #endregion + + #region IHasCameraFocusControl Members + + public void FocusNear() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Near"); + } + + public void FocusFar() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Far"); + } + + public void FocusStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Focus"); + } + + public void TriggerAutoFocus() + { + Debug.LogMessage(LogEventLevel.Debug, this, "AutoFocus Triggered"); + } + + #endregion + + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); + } +} + +public class MockFarEndVCCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera, IBridgeAdvanced +{ + protected VideoCodecBase ParentCodec { get; private set; } - public MockFarEndVCCamera(string key, string name, VideoCodecBase codec) - : base(key, name) - { - Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom; + public MockFarEndVCCamera(string key, string name, VideoCodecBase codec) + : base(key, name) + { + Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom; - ParentCodec = codec; - } + ParentCodec = codec; + } - #region IHasCameraPtzControl Members + #region IHasCameraPtzControl Members - public void PositionHome() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); - } + public void PositionHome() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); + } - #endregion + #endregion - #region IHasCameraPanControl Members + #region IHasCameraPanControl Members - public void PanLeft() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); - } + public void PanLeft() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); + } - public void PanRight() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); - } + public void PanRight() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); + } - public void PanStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); - } + public void PanStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); + } - #endregion + #endregion - #region IHasCameraTiltControl Members + #region IHasCameraTiltControl Members - public void TiltDown() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); - } + public void TiltDown() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); + } - public void TiltUp() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); - } + public void TiltUp() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); + } - public void TiltStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); - } + public void TiltStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); + } - #endregion + #endregion - #region IHasCameraZoomControl Members + #region IHasCameraZoomControl Members - public void ZoomIn() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); - } + public void ZoomIn() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); + } - public void ZoomOut() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); - } + public void ZoomOut() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); + } - public void ZoomStop() - { - Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); - } + public void ZoomStop() + { + Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); + } - #endregion + #endregion - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); - } + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs index c1940c3a..bee6ec35 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs @@ -11,20 +11,19 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; -namespace PepperDash.Essentials.Devices.Common.VideoCodec +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + +public class MockVcPropertiesConfig { - public class MockVcPropertiesConfig + [JsonProperty("favorites")] + public List Favorites { get; set; } + + [JsonProperty("presets")] + public List Presets { get; set; } + + public MockVcPropertiesConfig() { - [JsonProperty("favorites")] - public List Favorites { get; set; } - - [JsonProperty("presets")] - public List Presets { get; set; } - - public MockVcPropertiesConfig() - { - Favorites = new List(); - Presets = new List(); - } + Favorites = new List(); + Presets = new List(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs index f5ff3c07..d4974d93 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs @@ -22,20 +22,20 @@ using Serilog.Events; using PepperDash.Essentials.Core.Routing; using System.Text; -namespace PepperDash.Essentials.Devices.Common.VideoCodec -{ +namespace PepperDash.Essentials.Devices.Common.VideoCodec; + public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode { private const int XSigEncoding = 28591; - protected const int MaxParticipants = 50; + protected const int MaxParticipants = 50; private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); - private readonly IHasDirectory _directoryCodec; - private readonly BasicTriList _directoryTrilist; - private readonly VideoCodecControllerJoinMap _directoryJoinmap; + private readonly IHasDirectory _directoryCodec; + private readonly BasicTriList _directoryTrilist; + private readonly VideoCodecControllerJoinMap _directoryJoinmap; - protected string _timeFormatSpecifier; + protected string _timeFormatSpecifier; protected string _dateFormatSpecifier; @@ -50,8 +50,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc); SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc); - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - MeetingsToDisplayFeedback = new IntFeedback(() => MeetingsToDisplay); + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + MeetingsToDisplayFeedback = new IntFeedback(() => MeetingsToDisplay); InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); @@ -77,8 +77,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public bool ShowSelfViewByDefault { get; protected set; } - public bool SupportsCameraOff { get; protected set; } - public bool SupportsCameraAutoMode { get; protected set; } + public bool SupportsCameraOff { get; protected set; } + public bool SupportsCameraAutoMode { get; protected set; } public bool IsReady { get; protected set; } @@ -87,10 +87,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec get { return new List - { - PrivacyModeIsOnFeedback, - SharingSourceFeedback - }; + { + PrivacyModeIsOnFeedback, + SharingSourceFeedback + }; } } @@ -161,7 +161,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public abstract void AcceptCall(CodecActiveCallItem call); public abstract void RejectCall(CodecActiveCallItem call); public abstract void SendDtmf(string s); - public virtual void SendDtmf(string s, CodecActiveCallItem call) { } + public virtual void SendDtmf(string s, CodecActiveCallItem call) { } #endregion @@ -216,9 +216,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// protected virtual void OnCallStatusChange(CodecActiveCallItem item) { - CallStatusChange?.Invoke(this, new CodecCallStatusItemChangeEventArgs(item)); + CallStatusChange?.Invoke(this, new CodecCallStatusItemChangeEventArgs(item)); - PrivacyModeIsOnFeedback.FireUpdate(); + PrivacyModeIsOnFeedback.FireUpdate(); if (AutoShareContentWhileInCall) { @@ -248,8 +248,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec try { IsReady = true; - IsReadyChange?.Invoke(this, new EventArgs()); - } + IsReadyChange?.Invoke(this, new EventArgs()); + } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error in SetIsReady() : {0}", e); @@ -263,7 +263,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public virtual void ListCalls() { - Debug.LogMessage(LogEventLevel.Debug, this, "Active Calls:"); + Debug.LogMessage(LogEventLevel.Debug, this, "Active Calls:"); var sb = new StringBuilder(); foreach (var c in ActiveCalls) @@ -331,16 +331,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecVolumeToApi(trilist, joinMap); - LinkVideoCodecInfoToApi(trilist, joinMap); + LinkVideoCodecInfoToApi(trilist, joinMap); - // Register for this event to link any functions that require the codec to be ready first - codec.IsReadyChange += (o, a) => + // Register for this event to link any functions that require the codec to be ready first + codec.IsReadyChange += (o, a) => + { + if (codec is IHasCodecCameras) { - if (codec is IHasCodecCameras) - { - LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); - } - }; + LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); + } + }; if (codec is ICommunicationMonitor) { @@ -401,10 +401,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); } - if (codec is IHasCallHistory) - { - LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); - } + if (codec is IHasCallHistory) + { + LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); + } trilist.OnlineStatusChange += (device, args) => { @@ -452,39 +452,39 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); } - if (codec is IHasCallHistory) - { - UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); - } + if (codec is IHasCallHistory) + { + UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); + } SharingContentIsOnFeedback.FireUpdate(); }; } - private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); - trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); - trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); - trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); - trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); - trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); - trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); + private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); + trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); + trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); - trilist.OnlineStatusChange += (o, a) => + trilist.OnlineStatusChange += (o, a) => + { + if (a.DeviceOnLine) { - if (a.DeviceOnLine) - { - trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); - trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); - trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); - trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); - trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); - trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); - trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); - } - }; - } + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); + trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); + trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); + } + }; + } private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -520,9 +520,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - if (!(codec is IHasCameraAutoMode autoCodec)) return; + if (!(codec is IHasCameraAutoMode autoCodec)) return; - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoCodec.CameraAutoModeIsOnFeedback.BoolValue); }; @@ -537,9 +537,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - if (!(codec is IHasCameraAutoMode autoModeCodec)) return; + if (!(codec is IHasCameraAutoMode autoModeCodec)) return; - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); } @@ -578,35 +578,35 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - // make sure to update the values when the EISC comes online - trilist.OnlineStatusChange += (sender, args) => + // make sure to update the values when the EISC comes online + trilist.OnlineStatusChange += (sender, args) => + { + if (sender.IsOnline) { - if (sender.IsOnline) - { - UpdateParticipantsXSig(codec, trilist, joinMap); - } - }; + UpdateParticipantsXSig(codec, trilist, joinMap); + } + }; - // set actions and update the values when the list changes + // set actions and update the values when the list changes codec.Participants.ParticipantsListHasChanged += (sender, args) => { - SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); + SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); - UpdateParticipantsXSig(codec, trilist, joinMap); + UpdateParticipantsXSig(codec, trilist, joinMap); }; - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.CurrentParticipants.JoinNumber, "\xFC"); - UpdateParticipantsXSig(codec, trilist, joinMap); - }; + // TODO [ ] Issue #868 + trilist.SetString(joinMap.CurrentParticipants.JoinNumber, "\xFC"); + UpdateParticipantsXSig(codec, trilist, joinMap); + }; } - private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { + private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { string participantsXSig; if (codec.Participants.CurrentParticipants.Count == 0) @@ -622,49 +622,49 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); - } + } - /// - /// Sets the actions for each participant in the list - /// - private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List currentParticipants) + /// + /// Sets the actions for each participant in the list + /// + private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List currentParticipants) + { + uint index = 0; // track the index of the participant in the + + foreach (var participant in currentParticipants) { - uint index = 0; // track the index of the participant in the + var p = participant; + if (index > MaxParticipants) break; - foreach (var participant in currentParticipants) + if (this is IHasParticipantAudioMute audioMuteCodec) { - var p = participant; - if (index > MaxParticipants) break; + trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index, + () => audioMuteCodec.ToggleAudioForParticipant(p.UserId)); - if (this is IHasParticipantAudioMute audioMuteCodec) - { - trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index, - () => audioMuteCodec.ToggleAudioForParticipant(p.UserId)); - - trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index, - () => audioMuteCodec.ToggleVideoForParticipant(p.UserId)); - } - - if (this is IHasParticipantPinUnpin pinCodec) - { - trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index, - () => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo)); - } - - index++; + trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index, + () => audioMuteCodec.ToggleVideoForParticipant(p.UserId)); } - // Clear out any previously set actions - while (index < MaxParticipants) + if (this is IHasParticipantPinUnpin pinCodec) { - trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); - trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); - trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); - - index++; + trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index, + () => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo)); } + + index++; } + // Clear out any previously set actions + while (index < MaxParticipants) + { + trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); + trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); + trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); + + index++; + } + } + private string UpdateParticipantsXSig(List currentParticipants) { const int maxParticipants = MaxParticipants; @@ -683,37 +683,37 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (meetingIndex >= maxParticipants * offset) break; - // Debug.LogMessage(LogEventLevel.Verbose, this, - //@"Updating Participant on xsig: - //Name: {0} (s{9}) - //AudioMute: {1} (d{10}) - //VideoMute: {2} (d{11}) - //CanMuteVideo: {3} (d{12}) - //CanUMuteVideo: {4} (d{13}) - //IsHost: {5} (d{14}) - //HandIsRaised: {6} (d{15}) - //IsPinned: {7} (d{16}) - //ScreenIndexIsPinnedTo: {8} (a{17}) - //", - // participant.Name, - // participant.AudioMuteFb, - // participant.VideoMuteFb, - // participant.CanMuteVideo, - // participant.CanUnmuteVideo, - // participant.IsHost, - // participant.HandIsRaisedFb, - // participant.IsPinnedFb, - // participant.ScreenIndexIsPinnedToFb, - // stringIndex + 1, - // digitalIndex + 1, - // digitalIndex + 2, - // digitalIndex + 3, - // digitalIndex + 4, - // digitalIndex + 5, - // digitalIndex + 6, - // digitalIndex + 7, - // analogIndex + 1 - // ); + // Debug.LogMessage(LogEventLevel.Verbose, this, + //@"Updating Participant on xsig: + //Name: {0} (s{9}) + //AudioMute: {1} (d{10}) + //VideoMute: {2} (d{11}) + //CanMuteVideo: {3} (d{12}) + //CanUMuteVideo: {4} (d{13}) + //IsHost: {5} (d{14}) + //HandIsRaised: {6} (d{15}) + //IsPinned: {7} (d{16}) + //ScreenIndexIsPinnedTo: {8} (a{17}) + //", + // participant.Name, + // participant.AudioMuteFb, + // participant.VideoMuteFb, + // participant.CanMuteVideo, + // participant.CanUnmuteVideo, + // participant.IsHost, + // participant.HandIsRaisedFb, + // participant.IsPinnedFb, + // participant.ScreenIndexIsPinnedToFb, + // stringIndex + 1, + // digitalIndex + 1, + // digitalIndex + 2, + // digitalIndex + 3, + // digitalIndex + 4, + // digitalIndex + 5, + // digitalIndex + 6, + // digitalIndex + 7, + // analogIndex + 1 + // ); //digitals @@ -722,10 +722,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo); tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo); tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost); - tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb); - tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb); + tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb); + tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb); - Debug.LogMessage(LogEventLevel.Verbose, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes())); + Debug.LogMessage(LogEventLevel.Verbose, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes())); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name); @@ -762,12 +762,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec analogIndex += maxAnalogs; } - var returnString = GetXSigString(tokenArray); + var returnString = GetXSigString(tokenArray); - //Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString))); + //Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString))); - return returnString; + return returnString; } private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) @@ -783,7 +783,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, b => AutoShareContentWhileInCall = b); } - private List _currentMeetings = new List(); + private List _currentMeetings = new List(); private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -795,21 +795,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec }); - for (uint i = 0; i < joinMap.DialMeetingStart.JoinSpan; i++) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Setting action to Dial Meeting {0} to digital join {1}", i + 1, joinMap.DialMeetingStart.JoinNumber + i); - var joinNumber = joinMap.DialMeetingStart.JoinNumber + i; - var mtg = i + 1; - var index = (int)i; + for (uint i = 0; i < joinMap.DialMeetingStart.JoinSpan; i++) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Setting action to Dial Meeting {0} to digital join {1}", i + 1, joinMap.DialMeetingStart.JoinNumber + i); + var joinNumber = joinMap.DialMeetingStart.JoinNumber + i; + var mtg = i + 1; + var index = (int)i; - trilist.SetSigFalseAction(joinNumber, () => - { - Debug.LogMessage(LogEventLevel.Debug, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", - mtg, joinMap.DialMeetingStart.JoinNumber + i, index, _currentMeetings[index].Id, _currentMeetings[index].Title); - if (_currentMeetings[index] != null) - Dial(_currentMeetings[index]); - }); - } + trilist.SetSigFalseAction(joinNumber, () => + { + Debug.LogMessage(LogEventLevel.Debug, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeetingStart.JoinNumber + i, index, _currentMeetings[index].Id, _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + } codec.CodecSchedule.MeetingsListHasChanged += (sender, args) => UpdateMeetingsList(codec, trilist, joinMap); codec.CodecSchedule.MeetingEventChange += (sender, args) => @@ -820,20 +820,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } }; - trilist.SetUShortSigAction(joinMap.MeetingsToDisplay.JoinNumber, m => MeetingsToDisplay = m); + trilist.SetUShortSigAction(joinMap.MeetingsToDisplay.JoinNumber, m => MeetingsToDisplay = m); + MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); + + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; + + // TODO [ ] Issue #868 + trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); + UpdateMeetingsList(codec, trilist, joinMap); + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); - - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; - - // TODO [ ] Issue #868 - trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); - UpdateMeetingsList(codec, trilist, joinMap); - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); - }; - } + }; + } private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -841,50 +841,50 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec _currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); - if (_currentMeetings.Count == 0) - { - var emptyXSigByteArray = XSigHelpers.ClearOutputs(); - var emptyXSigString = Encoding.GetEncoding(XSigEncoding) - .GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length); + if (_currentMeetings.Count == 0) + { + var emptyXSigByteArray = XSigHelpers.ClearOutputs(); + var emptyXSigString = Encoding.GetEncoding(XSigEncoding) + .GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length); - trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString); - return; - } + trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString); + return; + } var meetingsData = UpdateMeetingsListXSig(_currentMeetings); trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count); - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); - UpdateMeetingsListXSig(_currentMeetings); - }; + // TODO [ ] Issue #868 + trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); + UpdateMeetingsListXSig(_currentMeetings); + }; } - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set private int _meetingsToDisplay = 3; - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set protected int MeetingsToDisplay { get { return _meetingsToDisplay; } set { - _meetingsToDisplay = (ushort) (value == 0 ? 3 : value); - MeetingsToDisplayFeedback.FireUpdate(); + _meetingsToDisplay = (ushort) (value == 0 ? 3 : value); + MeetingsToDisplayFeedback.FireUpdate(); } } - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - public IntFeedback MeetingsToDisplayFeedback { get; set; } + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + public IntFeedback MeetingsToDisplayFeedback { get; set; } - private string UpdateMeetingsListXSig(List meetings) - { - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - //const int _meetingsToDisplay = 3; + private string UpdateMeetingsListXSig(List meetings) + { + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + //const int _meetingsToDisplay = 3; const int maxDigitals = 2; const int maxStrings = 7; const int offset = maxDigitals + maxStrings; @@ -907,7 +907,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec * End Time - 6 * Id - 7 */ - + foreach (var meeting in meetings) { @@ -928,10 +928,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); digitalIndex += maxDigitals; @@ -963,7 +963,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } return GetXSigString(tokenArray); - } + } private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) @@ -975,9 +975,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i, trilist, joinMap)); - //Special Change for protected directory clear + //Special Change for protected directory clear - trilist.SetBoolSigAction(joinMap.DirectoryClearSelected.JoinNumber, (b) => SelectDirectoryEntry(_directoryCodec, 0, _directoryTrilist, _directoryJoinmap)); + trilist.SetBoolSigAction(joinMap.DirectoryClearSelected.JoinNumber, (b) => SelectDirectoryEntry(_directoryCodec, 0, _directoryTrilist, _directoryJoinmap)); // Report feedback for number of contact methods for selected contact @@ -988,19 +988,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (codec.DirectoryRoot != null) { var contactsCount = codec.DirectoryRoot.CurrentDirectoryResults.Where(c => c.ParentFolderId.Equals("root")).ToList().Count; - trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)contactsCount); + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)contactsCount); Debug.LogMessage(LogEventLevel.Verbose, this, ">>> contactsCount: {0}", contactsCount); - var clearBytes = XSigHelpers.ClearOutputs(); + var clearBytes = XSigHelpers.ClearOutputs(); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, - codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, + codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); - Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); + Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); } codec.DirectoryResultReturned += (sender, args) => @@ -1017,53 +1017,53 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetString(joinMap.DirectoryEntries.JoinNumber, Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(args.Directory, - codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); - Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); + var directoryXSig = UpdateDirectoryXSig(args.Directory, + codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); + Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); }; - - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - var clearBytes = XSigHelpers.ClearOutputs(); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); - }; + var clearBytes = XSigHelpers.ClearOutputs(); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); + }; } private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - if (i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; + if (i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; _selectedDirectoryItem = i == 0 ? null : codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; - trilist.SetUshort(joinMap.DirectorySelectRowFeedback.JoinNumber, i); + trilist.SetUshort(joinMap.DirectorySelectRowFeedback.JoinNumber, i); - if (_selectedDirectoryItem == null) trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); + if (_selectedDirectoryItem == null) trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); if (_selectedDirectoryItem is DirectoryFolder) { codec.GetDirectoryFolderContents(_selectedDirectoryItem.FolderId); - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); - trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name); - trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); - trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); + trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); + trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); - return; + return; } - // not a folder. Clear this value - trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty); + // not a folder. Clear this value + trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty); - var selectedContact = _selectedDirectoryItem as DirectoryContact; + var selectedContact = _selectedDirectoryItem as DirectoryContact; - if (selectedContact != null && selectedContact.ContactMethods.Count >= 1) + if (selectedContact != null && selectedContact.ContactMethods.Count >= 1) { trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, true); } @@ -1072,105 +1072,105 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec selectedContact != null ? selectedContact.Name : string.Empty); // Allow auto dial of selected line. Always dials first contact method - if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) + if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) + { + if (_selectedDirectoryItem is IInvitableContact invitableEntry) { - if (_selectedDirectoryItem is IInvitableContact invitableEntry) - { - Dial(invitableEntry); - return; - } - - - trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, - selectedContact != null ? selectedContact.ContactMethods[0].Number : string.Empty); - - if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) return; - - Dial(entryToDial.ContactMethods[0].Number); + Dial(invitableEntry); + return; } - else + + + trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, + selectedContact != null ? selectedContact.ContactMethods[0].Number : string.Empty); + + if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) return; + + Dial(entryToDial.ContactMethods[0].Number); + } + else + { + // If auto dial is disabled... + + if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) { - // If auto dial is disabled... - - if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) - { - // Clear out values and actions from last selected item - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); - trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); - trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); - return; - } - - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); - - // Update the action to dial the selected contact method - trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => - { - if (u < 1 || u > entryToDial.ContactMethods.Count) return; - - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); - }); - - // Sets DirectoryDialSelectedLine join action to dial first contact method - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); - - var clearBytes = XSigHelpers.ClearOutputs(); - - trilist.SetString(joinMap.ContactMethods.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial); - - trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); + // Clear out values and actions from last selected item + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); + trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); + return; } + + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); + + // Update the action to dial the selected contact method + trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => + { + if (u < 1 || u > entryToDial.ContactMethods.Count) return; + + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); + }); + + // Sets DirectoryDialSelectedLine join action to dial first contact method + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); + + var clearBytes = XSigHelpers.ClearOutputs(); + + trilist.SetString(joinMap.ContactMethods.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial); + + trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); + } } - /// - /// Generates the XSig data representing the available contact methods for the selected DirectoryContact - /// - /// - /// - private string UpdateContactMethodsXSig(DirectoryContact contact) + /// + /// Generates the XSig data representing the available contact methods for the selected DirectoryContact + /// + /// + /// + private string UpdateContactMethodsXSig(DirectoryContact contact) + { + const int maxMethods = 10; + const int maxStrings = 3; + const int offset = maxStrings; + var stringIndex = 0; + var arrayIndex = 0; + // Create a new token array and set the size to the number of methods times the total number of signals + var tokenArray = new XSigToken[maxMethods * offset]; + + Debug.LogMessage(LogEventLevel.Verbose, this, "Creating XSIG token array with size {0}", maxMethods * offset); + + // TODO: Add code to generate XSig data + foreach (var method in contact.ContactMethods) { - const int maxMethods = 10; - const int maxStrings = 3; - const int offset = maxStrings; - var stringIndex = 0; - var arrayIndex = 0; - // Create a new token array and set the size to the number of methods times the total number of signals - var tokenArray = new XSigToken[maxMethods * offset]; + if (arrayIndex >= maxMethods * offset) + break; - Debug.LogMessage(LogEventLevel.Verbose, this, "Creating XSIG token array with size {0}", maxMethods * offset); - - // TODO: Add code to generate XSig data - foreach (var method in contact.ContactMethods) - { - if (arrayIndex >= maxMethods * offset) - break; - - //serials - tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number); - tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString()); - tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString()); + //serials + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString()); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString()); arrayIndex += offset; stringIndex += maxStrings; - } - - while (arrayIndex < maxMethods) - { - tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); - - arrayIndex += offset; - stringIndex += maxStrings; - } - - return GetXSigString(tokenArray); } + while (arrayIndex < maxMethods) + { + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); + + arrayIndex += offset; + stringIndex += maxStrings; + } + + return GetXSigString(tokenArray); + } + private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) { var xSigMaxIndex = 1023; @@ -1222,31 +1222,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //End All calls trilist.SetSigFalseAction(joinMap.EndAllCalls.JoinNumber, EndAllCalls); - //End a specific call, specified by index. Maximum 8 calls supported - for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) - { - var callIndex = i; + //End a specific call, specified by index. Maximum 8 calls supported + for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) + { + var callIndex = i; - trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => + trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => + { + + if (callIndex < 0 || callIndex >= ActiveCalls.Count) { + Debug.LogMessage(LogEventLevel.Verbose, this, "Cannot end call. No call found at index: {0}", callIndex); + return; + } - if (callIndex < 0 || callIndex >= ActiveCalls.Count) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Cannot end call. No call found at index: {0}", callIndex); - return; - } - - var call = ActiveCalls[callIndex]; - if (call != null) - { - EndCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[End Call] Unable to find call at index '{0}'", i); - } - }); - } + var call = ActiveCalls[callIndex]; + if (call != null) + { + EndCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[End Call] Unable to find call at index '{0}'", i); + } + }); + } trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); @@ -1258,18 +1258,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec Debug.LogMessage(LogEventLevel.Debug, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming); trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing); - if (args.CallItem.Direction == eCodecCallDirection.Incoming) - { - trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); - trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); - trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name); - trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number); - } - else - { - trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); - trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); - } + if (args.CallItem.Direction == eCodecCallDirection.Incoming) + { + trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); + trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); + trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number); + } + else + { + trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); + } trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); @@ -1277,76 +1277,76 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count); }; - if (this is IJoinCalls joinCodec) + if (this is IJoinCalls joinCodec) + { + trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); + + for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) { - trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); - - for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) - { - trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () => + trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () => + { + var call = ActiveCalls[i]; + if (call != null) { - var call = ActiveCalls[i]; - if (call != null) - { - joinCodec.JoinCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[Join Call] Unable to find call at index '{0}'", i); - } - }); - } + joinCodec.JoinCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[Join Call] Unable to find call at index '{0}'", i); + } + }); } + } - if (this is IHasCallHold holdCodec) + if (this is IHasCallHold holdCodec) + { + trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => { - trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => + foreach (var call in ActiveCalls) { - foreach (var call in ActiveCalls) - { - holdCodec.HoldCall(call); - } - }); - - for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) - { - var index = i; - - trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () => - { - if (index < 0 || index >= ActiveCalls.Count) return; - - var call = ActiveCalls[index]; - if (call != null) - { - holdCodec.HoldCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[Hold Call] Unable to find call at index '{0}'", i); - } - }); - - trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () => - { - if (index < 0 || index >= ActiveCalls.Count) return; - - var call = ActiveCalls[index]; - if (call != null) - { - holdCodec.ResumeCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[Resume Call] Unable to find call at index '{0}'", i); - } - }); + holdCodec.HoldCall(call); } + }); + + for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) + { + var index = i; + + trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () => + { + if (index < 0 || index >= ActiveCalls.Count) return; + + var call = ActiveCalls[index]; + if (call != null) + { + holdCodec.HoldCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[Hold Call] Unable to find call at index '{0}'", i); + } + }); + + trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () => + { + if (index < 0 || index >= ActiveCalls.Count) return; + + var call = ActiveCalls[index]; + if (call != null) + { + holdCodec.ResumeCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[Resume Call] Unable to find call at index '{0}'", i); + } + }); } + } - trilist.OnlineStatusChange += (device, args) => + trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; @@ -1362,7 +1362,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { const int maxCalls = 8; const int maxStrings = 6; - const int maxDigitals = 2; + const int maxDigitals = 2; const int offset = maxStrings + maxDigitals; var stringIndex = 0; var digitalIndex = maxStrings * maxCalls; @@ -1375,40 +1375,40 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (arrayIndex >= maxCalls * offset) break; //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); - if(call.Duration != null) - { - // May need to verify correct string format here - var dur = string.Format("{0:c}", call.Duration); - tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur); - } + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); + if(call.Duration != null) + { + // May need to verify correct string format here + var dur = string.Format("{0:c}", call.Duration); + tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur); + } arrayIndex += offset; stringIndex += maxStrings; - digitalIndex += maxDigitals; + digitalIndex += maxDigitals; } - while (arrayIndex < maxCalls * offset) + while (arrayIndex < maxCalls * offset) { //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); arrayIndex += offset; stringIndex += maxStrings; @@ -1420,55 +1420,55 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap)); } - /// - /// Sends the specified string as a DTMF command. - /// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine - /// Whther to send to a specific call index or to the last connected call - /// - /// - /// - /// - private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + /// + /// Sends the specified string as a DTMF command. + /// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine + /// Whther to send to a specific call index or to the last connected call + /// + /// + /// + /// + private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber)) { - if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber)) + SendDtmf(s); + } + else + { + var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); + if (callIndex > 0 && callIndex <= 8) { - SendDtmf(s); - } - else - { - var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); - if (callIndex > 0 && callIndex <= 8) + var call = ActiveCalls[callIndex - 1]; + if (call != null && call.IsActiveCall) { - var call = ActiveCalls[callIndex - 1]; - if (call != null && call.IsActiveCall) - { - SendDtmf(s, call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Warning: No call found at index {0} or call is not active.", callIndex); - } + SendDtmf(s, call); } else { - Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); + Debug.LogMessage(LogEventLevel.Information, this, "Warning: No call found at index {0} or call is not active.", callIndex); } } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); + } } + } private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -1484,31 +1484,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => { - if (codec is IHasCameraOff offCodec) - { - if (offCodec.CameraIsOffFeedback.BoolValue) - { - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - return; - } - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - return; - } - - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - }; - - - if (codec is IHasCameraOff offModeCodec) + if (codec is IHasCameraOff offCodec) { - if (offModeCodec.CameraIsOffFeedback.BoolValue) + if (offCodec.CameraIsOffFeedback.BoolValue) { trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); @@ -1516,13 +1494,35 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec return; } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); return; } + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + }; + + + if (codec is IHasCameraOff offModeCodec) + { + if (offModeCodec.CameraIsOffFeedback.BoolValue) + { + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + return; + } + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + return; + } + + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); } @@ -1542,9 +1542,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.TiltUp(); + if (b) camera.TiltUp(); else camera.TiltStop(); }); @@ -1552,27 +1552,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.TiltDown(); + if (b) camera.TiltDown(); else camera.TiltStop(); }); trilist.SetBoolSigAction(joinMap.CameraPanLeft.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.PanLeft(); + if (b) camera.PanLeft(); else camera.PanStop(); }); trilist.SetBoolSigAction(joinMap.CameraPanRight.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.PanRight(); + if (b) camera.PanRight(); else camera.PanStop(); }); @@ -1580,9 +1580,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.ZoomIn(); + if (b) camera.ZoomIn(); else camera.ZoomStop(); }); @@ -1590,83 +1590,83 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.ZoomOut(); + if (b) camera.ZoomOut(); else camera.ZoomStop(); }); - trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) => + trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + + if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; + + if (b) camera.FocusNear(); + else camera.FocusStop(); + }); + + trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; + + if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; + + if (b) camera.FocusFar(); + else camera.FocusStop(); + }); + + trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () => + { + if (codec.SelectedCamera == null) return; + + if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; + + camera.TriggerAutoFocus(); + }); + + // Camera count + trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count); + + // Camera names + for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) + { + //Check the count first + if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null) { - if (codec.SelectedCamera == null) return; - - if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; - - if (b) camera.FocusNear(); - else camera.FocusStop(); - }); - - trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; - - if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; - - if (b) camera.FocusFar(); - else camera.FocusStop(); - }); - - trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () => - { - if (codec.SelectedCamera == null) return; - - if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; - - camera.TriggerAutoFocus(); - }); - - // Camera count - trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count); - - // Camera names - for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) - { - //Check the count first - if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null) - { - trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); - } - else - { - trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, ""); - } + trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); } + else + { + trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, ""); + } + } //Camera Select trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => { - if (i > 0 && i <= codec.Cameras.Count) - { - codec.SelectCamera(codec.Cameras[i - 1].Key); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to select. No camera found at index {0}", i); - } + if (i > 0 && i <= codec.Cameras.Count) + { + codec.SelectCamera(codec.Cameras[i - 1].Key); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Unable to select. No camera found at index {0}", i); + } }); - // Set initial selected camera feedback - if (codec.SelectedCamera != null) - { - trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); - } + // Set initial selected camera feedback + if (codec.SelectedCamera != null) + { + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); + } codec.CameraSelected += (sender, args) => { var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); - trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); if (codec is IHasCodecRoomPresets) { @@ -1713,11 +1713,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec }); - // Far End Presets - trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) => - { - presetCodec.SelectFarEndPreset(i); - }); + // Far End Presets + trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) => + { + presetCodec.SelectFarEndPreset(i); + }); trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, @@ -1728,105 +1728,105 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); }); - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.CameraPresetNames.JoinNumber, "\xFC"); - SetCameraPresetNames(presetCodec.NearEndPresets); - }; + // TODO [ ] Issue #868 + trilist.SetString(joinMap.CameraPresetNames.JoinNumber, "\xFC"); + SetCameraPresetNames(presetCodec.NearEndPresets); + }; } - // Following fields only used for Bridging - private int _selectedRecentCallItemIndex; - private DirectoryItem _selectedDirectoryItem; + // Following fields only used for Bridging + private int _selectedRecentCallItemIndex; + private DirectoryItem _selectedDirectoryItem; - private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.CallHistory.RecentCallsListHasChanged += (o, a) => - { - UpdateCallHistory(codec, trilist, joinMap); - }; - - // Selected item action and feedback - trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => - { - if (u == 0 || u > codec.CallHistory.RecentCalls.Count) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Recent Call History index out of range"); - return; - } - - _selectedRecentCallItemIndex = (int)(u - 1); - trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); - - var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; - - if (_selectedRecentCallItem != null) - { - trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); - trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); - trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); - trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number)); - } - else - { - trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); - trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); - trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber); - } - }); - } - - - - private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - // Clear out selected item - _selectedRecentCallItemIndex = 0; - - trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0); - trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); - trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); - trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); - // - - trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count); - - // Update the call history joins - var maxItems = joinMap.RecentCallNamesStart.JoinSpan; - - // Create history - uint index = 0; - for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++) + private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.CallHistory.RecentCallsListHasChanged += (o, a) => { - trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name); - trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString()); - trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType); - //i++; - index = i; - } - - //foreach(var item in codec.CallHistory.RecentCalls) - //{ - // trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); - // trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); - // trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); - // i++; - //} + UpdateCallHistory(codec, trilist, joinMap); + }; - // Clears existing items - for (uint j = index; j < maxItems; j++) + // Selected item action and feedback + trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => { - trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty); - trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty); - trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0); - } - } + if (u == 0 || u > codec.CallHistory.RecentCalls.Count) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Recent Call History index out of range"); + return; + } - private string SetCameraPresetNames(IEnumerable presets) + _selectedRecentCallItemIndex = (int)(u - 1); + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); + + var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; + + if (_selectedRecentCallItem != null) + { + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); + trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); + trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number)); + } + else + { + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); + trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber); + } + }); + } + + + + private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + // Clear out selected item + _selectedRecentCallItemIndex = 0; + + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0); + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); + trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + // + + trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count); + + // Update the call history joins + var maxItems = joinMap.RecentCallNamesStart.JoinSpan; + + // Create history + uint index = 0; + for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++) + { + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString()); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType); + //i++; + index = i; + } + + //foreach(var item in codec.CallHistory.RecentCalls) + //{ + // trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); + // trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); + // trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); + // i++; + //} + + // Clears existing items + for (uint j = index; j < maxItems; j++) + { + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0); + } + } + + private string SetCameraPresetNames(IEnumerable presets) { return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); } @@ -1895,8 +1895,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (value == true) { - InitialSyncCompleted?.Invoke(this, new EventArgs()); - } + InitialSyncCompleted?.Invoke(this, new EventArgs()); + } _InitialSyncComplete = value; } } @@ -1971,21 +1971,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } } - /// - /// Represents a codec command that might need to have a friendly label applied for UI feedback purposes - /// - public class CodecCommandWithLabel +/// +/// Represents a codec command that might need to have a friendly label applied for UI feedback purposes +/// +public class CodecCommandWithLabel +{ + public string Command { get; private set; } + public string Label { get; private set; } + + public CodecCommandWithLabel(string command, string label) { - public string Command { get; private set; } - public string Label { get; private set; } - - public CodecCommandWithLabel(string command, string label) - { - Command = command; - Label = label; - } + Command = command; + Label = label; } +} - - -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs b/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs index e555f11f..4c8506fb 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs @@ -1,31 +1,30 @@ using Newtonsoft.Json; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + +public class SourceSelectMessageContent { - public class SourceSelectMessageContent - { - [JsonProperty("sourceListItemKey")] - public string SourceListItemKey { get; set; } - [JsonProperty("sourceListKey")] - public string SourceListKey { get; set; } - } - - public class DirectRoute - { - - [JsonProperty("sourceKey")] - public string SourceKey { get; set; } - [JsonProperty("destinationKey")] - public string DestinationKey { get; set; } - [JsonProperty("signalType")] - public eRoutingSignalType SignalType { get; set; } - } - - /// - /// - /// - /// - public delegate void PressAndHoldAction(bool b); + [JsonProperty("sourceListItemKey")] + public string SourceListItemKey { get; set; } + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } } + +public class DirectRoute +{ + + [JsonProperty("sourceKey")] + public string SourceKey { get; set; } + [JsonProperty("destinationKey")] + public string DestinationKey { get; set; } + [JsonProperty("signalType")] + public eRoutingSignalType SignalType { get; set; } +} + +/// +/// +/// +/// +public delegate void PressAndHoldAction(bool b); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs index cc09a637..8db472db 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs @@ -6,55 +6,54 @@ using PepperDash.Essentials.AppServer.Messengers; using System.Linq; using DisplayBase = PepperDash.Essentials.Devices.Common.Displays.DisplayBase; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class DisplayBaseMessenger : MessengerBase { - public class DisplayBaseMessenger : MessengerBase + private readonly DisplayBase display; + + public DisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device) { - private readonly DisplayBase display; + display = device; + } - public DisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device) + protected override void RegisterActions() + { + base.RegisterActions(); + + /*AddAction("/powerOn", (id, content) => display.PowerOn()); + AddAction("/powerOff", (id, content) => display.PowerOff()); + AddAction("/powerToggle", (id, content) => display.PowerToggle());*/ + + AddAction("/inputSelect", (id, content) => { - display = device; - } + var s = content.ToObject>(); - protected override void RegisterActions() + var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s.Value); + + if (inputPort == null) + { + this.LogWarning("No input named {inputName} found for {deviceKey}", s, display.Key); + return; + } + + display.ExecuteSwitch(inputPort.Selector); + }); + + AddAction("/inputs", (id, content) => { - base.RegisterActions(); + var inputsList = display.InputPorts.Select(p => p.Key).ToList(); - /*AddAction("/powerOn", (id, content) => display.PowerOn()); - AddAction("/powerOff", (id, content) => display.PowerOff()); - AddAction("/powerToggle", (id, content) => display.PowerToggle());*/ - - AddAction("/inputSelect", (id, content) => + var messageObject = new MobileControlMessage { - var s = content.ToObject>(); - - var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s.Value); - - if (inputPort == null) + Type = MessagePath + "/inputs", + Content = JToken.FromObject(new { - this.LogWarning("No input named {inputName} found for {deviceKey}", s, display.Key); - return; - } + inputKeys = inputsList, + }) + }; - display.ExecuteSwitch(inputPort.Selector); - }); - - AddAction("/inputs", (id, content) => - { - var inputsList = display.InputPorts.Select(p => p.Key).ToList(); - - var messageObject = new MobileControlMessage - { - Type = MessagePath + "/inputs", - Content = JToken.FromObject(new - { - inputKeys = inputsList, - }) - }; - - AppServerController.SendMessageObject(messageObject); - }); - } + AppServerController.SendMessageObject(messageObject); + }); } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs index 4ba89800..43c0a640 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs @@ -2,28 +2,27 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class IChannelMessenger : MessengerBase { - public class IChannelMessenger : MessengerBase + private readonly IChannel channelDevice; + + public IChannelMessenger(string key, string messagePath, IChannel device) : base(key, messagePath, device as IKeyName) { - private readonly IChannel channelDevice; + channelDevice = device; + } - public IChannelMessenger(string key, string messagePath, IChannel device) : base(key, messagePath, device as IKeyName) - { - channelDevice = device; - } + protected override void RegisterActions() + { + base.RegisterActions(); - protected override void RegisterActions() - { - base.RegisterActions(); + AddAction("/chanUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.ChannelUp(b))); - AddAction("/chanUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.ChannelUp(b))); - - AddAction("/chanDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.ChannelDown(b))); - AddAction("/lastChan", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.LastChannel(b))); - AddAction("/guide", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Guide(b))); - AddAction("/info", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Info(b))); - AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Exit(b))); - } + AddAction("/chanDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.ChannelDown(b))); + AddAction("/lastChan", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.LastChannel(b))); + AddAction("/guide", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Guide(b))); + AddAction("/info", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Info(b))); + AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Exit(b))); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs index 86df2590..b4c831ed 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs @@ -2,24 +2,23 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class IColorMessenger : MessengerBase { - public class IColorMessenger : MessengerBase + private readonly IColor colorDevice; + public IColorMessenger(string key, string messagePath, IColor device) : base(key, messagePath, device as IKeyName) { - private readonly IColor colorDevice; - public IColorMessenger(string key, string messagePath, IColor device) : base(key, messagePath, device as IKeyName) - { - colorDevice = device as IColor; - } + colorDevice = device as IColor; + } - protected override void RegisterActions() - { - base.RegisterActions(); + protected override void RegisterActions() + { + base.RegisterActions(); - AddAction("/red", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Red(b))); - AddAction("/green", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Green(b))); - AddAction("/yellow", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Yellow(b))); - AddAction("/blue", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Blue(b))); - } + AddAction("/red", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Red(b))); + AddAction("/green", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Green(b))); + AddAction("/yellow", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Yellow(b))); + AddAction("/blue", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Blue(b))); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs index 4af07703..e2b351a1 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs @@ -2,28 +2,27 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class IDPadMessenger : MessengerBase { - public class IDPadMessenger : MessengerBase + private readonly IDPad dpadDevice; + public IDPadMessenger(string key, string messagePath, IDPad device) : base(key, messagePath, device as IKeyName) { - private readonly IDPad dpadDevice; - public IDPadMessenger(string key, string messagePath, IDPad device) : base(key, messagePath, device as IKeyName) - { - dpadDevice = device; - } + dpadDevice = device; + } - protected override void RegisterActions() - { - base.RegisterActions(); + protected override void RegisterActions() + { + base.RegisterActions(); - AddAction("/up", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Up(b))); - AddAction("/down", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Down(b))); - AddAction("/left", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Left(b))); - AddAction("/right", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Right(b))); - AddAction("/select", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Select(b))); - AddAction("/menu", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Menu(b))); - AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Exit(b))); - } + AddAction("/up", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Up(b))); + AddAction("/down", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Down(b))); + AddAction("/left", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Left(b))); + AddAction("/right", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Right(b))); + AddAction("/select", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Select(b))); + AddAction("/menu", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Menu(b))); + AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Exit(b))); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs index 8e286979..f0e02c8a 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs @@ -2,23 +2,22 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class IDvrMessenger : MessengerBase { - public class IDvrMessenger : MessengerBase + private readonly IDvr dvrDevice; + public IDvrMessenger(string key, string messagePath, IDvr device) : base(key, messagePath, device as IKeyName) { - private readonly IDvr dvrDevice; - public IDvrMessenger(string key, string messagePath, IDvr device) : base(key, messagePath, device as IKeyName) - { - dvrDevice = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/dvrlist", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dvrDevice?.DvrList(b))); - AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dvrDevice?.Record(b))); - } - + dvrDevice = device; } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/dvrlist", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dvrDevice?.DvrList(b))); + AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dvrDevice?.Record(b))); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs index 39ed0e6f..16f29411 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs @@ -2,23 +2,22 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class IHasPowerMessenger : MessengerBase { - public class IHasPowerMessenger : MessengerBase + private readonly IHasPowerControl powerDevice; + public IHasPowerMessenger(string key, string messagePath, IHasPowerControl device) : base(key, messagePath, device as IKeyName) { - private readonly IHasPowerControl powerDevice; - public IHasPowerMessenger(string key, string messagePath, IHasPowerControl device) : base(key, messagePath, device as IKeyName) - { - powerDevice = device; - } + powerDevice = device; + } - protected override void RegisterActions() - { - base.RegisterActions(); + protected override void RegisterActions() + { + base.RegisterActions(); - AddAction("/powerOn", (id, content) => powerDevice?.PowerOn()); - AddAction("/powerOff", (id, content) => powerDevice?.PowerOff()); - AddAction("/powerToggle", (id, content) => powerDevice?.PowerToggle()); - } + AddAction("/powerOn", (id, content) => powerDevice?.PowerOn()); + AddAction("/powerOff", (id, content) => powerDevice?.PowerOff()); + AddAction("/powerToggle", (id, content) => powerDevice?.PowerToggle()); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs index 69b5bc9d..c40459ec 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs @@ -2,33 +2,32 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class INumericKeypadMessenger : MessengerBase { - public class INumericKeypadMessenger : MessengerBase + private readonly INumericKeypad keypadDevice; + public INumericKeypadMessenger(string key, string messagePath, INumericKeypad device) : base(key, messagePath, device as IKeyName) { - private readonly INumericKeypad keypadDevice; - public INumericKeypadMessenger(string key, string messagePath, INumericKeypad device) : base(key, messagePath, device as IKeyName) - { - keypadDevice = device; - } + keypadDevice = device; + } - protected override void RegisterActions() - { - base.RegisterActions(); + protected override void RegisterActions() + { + base.RegisterActions(); - AddAction("/num0", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit0(b))); - AddAction("/num1", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit1(b))); - AddAction("/num2", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit2(b))); - AddAction("/num3", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit3(b))); - AddAction("/num4", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit4(b))); - AddAction("/num5", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit5(b))); - AddAction("/num6", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit6(b))); - AddAction("/num7", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit7(b))); - AddAction("/num8", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit8(b))); - AddAction("/num9", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit9(b))); - AddAction("/numDash", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.KeypadAccessoryButton1(b))); - AddAction("/numEnter", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.KeypadAccessoryButton2(b))); - // Deal with the Accessory functions on the numpad later - } + AddAction("/num0", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit0(b))); + AddAction("/num1", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit1(b))); + AddAction("/num2", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit2(b))); + AddAction("/num3", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit3(b))); + AddAction("/num4", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit4(b))); + AddAction("/num5", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit5(b))); + AddAction("/num6", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit6(b))); + AddAction("/num7", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit7(b))); + AddAction("/num8", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit8(b))); + AddAction("/num9", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit9(b))); + AddAction("/numDash", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.KeypadAccessoryButton1(b))); + AddAction("/numEnter", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.KeypadAccessoryButton2(b))); + // Deal with the Accessory functions on the numpad later } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs index 0e7c227b..775ace5e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs @@ -2,38 +2,37 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class ISetTopBoxControlsMessenger : MessengerBase { - public class ISetTopBoxControlsMessenger : MessengerBase + private readonly ISetTopBoxControls stbDevice; + public ISetTopBoxControlsMessenger(string key, string messagePath, ISetTopBoxControls device) : base(key, messagePath, device as IKeyName) { - private readonly ISetTopBoxControls stbDevice; - public ISetTopBoxControlsMessenger(string key, string messagePath, ISetTopBoxControls device) : base(key, messagePath, device as IKeyName) - { - stbDevice = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendISetTopBoxControlsFullMessageObject()); - AddAction("/dvrList", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => stbDevice?.DvrList(b))); - AddAction("/replay", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => stbDevice?.Replay(b))); - } - /// - /// Helper method to build call status for vtc - /// - /// - private void SendISetTopBoxControlsFullMessageObject() - { - - PostStatusMessage(new SetTopBoxControlsState()); - - - } + stbDevice = device; } - public class SetTopBoxControlsState : DeviceStateMessageBase + protected override void RegisterActions() + { + base.RegisterActions(); + AddAction("/fullStatus", (id, content) => SendISetTopBoxControlsFullMessageObject()); + AddAction("/dvrList", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => stbDevice?.DvrList(b))); + AddAction("/replay", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => stbDevice?.Replay(b))); + } + /// + /// Helper method to build call status for vtc + /// + /// + private void SendISetTopBoxControlsFullMessageObject() { + PostStatusMessage(new SetTopBoxControlsState()); + + } +} + +public class SetTopBoxControlsState : DeviceStateMessageBase +{ + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs index 75f74418..0beb4f11 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs @@ -2,29 +2,28 @@ using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.MobileControl +namespace PepperDash.Essentials.Room.MobileControl; + +public class ITransportMessenger : MessengerBase { - public class ITransportMessenger : MessengerBase + private readonly ITransport transportDevice; + public ITransportMessenger(string key, string messagePath, ITransport device) : base(key, messagePath, device as IKeyName) { - private readonly ITransport transportDevice; - public ITransportMessenger(string key, string messagePath, ITransport device) : base(key, messagePath, device as IKeyName) - { - transportDevice = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/play", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Play(b))); - AddAction("/pause", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Pause(b))); - AddAction("/stop", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Stop(b))); - AddAction("/prevTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.ChapPlus(b))); - AddAction("/nextTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.ChapMinus(b))); - AddAction("/rewind", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Rewind(b))); - AddAction("/ffwd", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.FFwd(b))); - AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Record(b))); - } - + transportDevice = device; } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/play", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Play(b))); + AddAction("/pause", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Pause(b))); + AddAction("/stop", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Stop(b))); + AddAction("/prevTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.ChapPlus(b))); + AddAction("/nextTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.ChapMinus(b))); + AddAction("/rewind", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Rewind(b))); + AddAction("/ffwd", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.FFwd(b))); + AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Record(b))); + } + } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs index 9a42141e..c30100ae 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs @@ -4,113 +4,112 @@ using PepperDash.Essentials.Devices.Common.Codec; using System; using System.Linq; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Provides a messaging bridge for an AudioCodecBase device +/// +public class AudioCodecBaseMessenger : MessengerBase { /// - /// Provides a messaging bridge for an AudioCodecBase device + /// Device being bridged /// - public class AudioCodecBaseMessenger : MessengerBase + public AudioCodecBase Codec { get; private set; } + + /// + /// Constuctor + /// + /// + /// + /// + public AudioCodecBaseMessenger(string key, AudioCodecBase codec, string messagePath) + : base(key, messagePath, codec) { - /// - /// Device being bridged - /// - public AudioCodecBase Codec { get; private set; } + Codec = codec ?? throw new ArgumentNullException("codec"); + codec.CallStatusChange += Codec_CallStatusChange; + } - /// - /// Constuctor - /// - /// - /// - /// - public AudioCodecBaseMessenger(string key, AudioCodecBase codec, string messagePath) - : base(key, messagePath, codec) + protected override void RegisterActions() + + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject()); + AddAction("/dial", (id, content) => { - Codec = codec ?? throw new ArgumentNullException("codec"); - codec.CallStatusChange += Codec_CallStatusChange; - } + var msg = content.ToObject>(); - protected override void RegisterActions() + Codec.Dial(msg.Value); + }); + AddAction("/endCallById", (id, content) => { - base.RegisterActions(); + var msg = content.ToObject>(); - AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject()); - AddAction("/dial", (id, content) => - { - var msg = content.ToObject>(); + var call = GetCallWithId(msg.Value); + if (call != null) + Codec.EndCall(call); + }); - Codec.Dial(msg.Value); - }); - - AddAction("/endCallById", (id, content) => - { - var msg = content.ToObject>(); - - var call = GetCallWithId(msg.Value); - if (call != null) - Codec.EndCall(call); - }); - - AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); - AddAction("/dtmf", (id, content) => - { - var msg = content.ToObject>(); - - Codec.SendDtmf(msg.Value); - }); - - AddAction("/rejectById", (id, content) => - { - var msg = content.ToObject>(); - - var call = GetCallWithId(msg.Value); - - if (call != null) - Codec.RejectCall(call); - }); - - AddAction("/acceptById", (id, content) => - { - var msg = content.ToObject>(); - var call = GetCallWithId(msg.Value); - if (call != null) - Codec.AcceptCall(call); - }); - } - - /// - /// Helper to grab a call with string ID - /// - /// - /// - private CodecActiveCallItem GetCallWithId(string id) + AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); + AddAction("/dtmf", (id, content) => { - return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); - } + var msg = content.ToObject>(); - private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) + Codec.SendDtmf(msg.Value); + }); + + AddAction("/rejectById", (id, content) => { - SendAtcFullMessageObject(); - } + var msg = content.ToObject>(); - /// - /// Helper method to build call status for vtc - /// - /// - private void SendAtcFullMessageObject() + var call = GetCallWithId(msg.Value); + + if (call != null) + Codec.RejectCall(call); + }); + + AddAction("/acceptById", (id, content) => { - var info = Codec.CodecInfo; + var msg = content.ToObject>(); + var call = GetCallWithId(msg.Value); + if (call != null) + Codec.AcceptCall(call); + }); + } - PostStatusMessage(JToken.FromObject(new + /// + /// Helper to grab a call with string ID + /// + /// + /// + private CodecActiveCallItem GetCallWithId(string id) + { + return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); + } + + private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) + { + SendAtcFullMessageObject(); + } + + /// + /// Helper method to build call status for vtc + /// + /// + private void SendAtcFullMessageObject() + { + var info = Codec.CodecInfo; + + PostStatusMessage(JToken.FromObject(new + { + isInCall = Codec.IsInCall, + calls = Codec.ActiveCalls, + info = new { - isInCall = Codec.IsInCall, - calls = Codec.ActiveCalls, - info = new - { - phoneNumber = info.PhoneNumber - } - }) - ); - } + phoneNumber = info.PhoneNumber + } + }) + ); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs index 36a94781..69023213 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs @@ -4,201 +4,200 @@ using PepperDash.Essentials.Devices.Common.Cameras; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class CameraBaseMessenger : MessengerBase { - public class CameraBaseMessenger : MessengerBase + /// + /// Device being bridged + /// + public CameraBase Camera { get; set; } + + /// + /// Constructor + /// + /// + /// + /// + public CameraBaseMessenger(string key, CameraBase camera, string messagePath) + : base(key, messagePath, camera) { - /// - /// Device being bridged - /// - public CameraBase Camera { get; set; } + Camera = camera ?? throw new ArgumentNullException("camera"); - /// - /// Constructor - /// - /// - /// - /// - public CameraBaseMessenger(string key, CameraBase camera, string messagePath) - : base(key, messagePath, camera) + + if (Camera is IHasCameraPresets presetsCamera) { - Camera = camera ?? throw new ArgumentNullException("camera"); - - - if (Camera is IHasCameraPresets presetsCamera) - { - presetsCamera.PresetsListHasChanged += PresetsCamera_PresetsListHasChanged; - } - } - - private void PresetsCamera_PresetsListHasChanged(object sender, EventArgs e) - { - var presetList = new List(); - - if (Camera is IHasCameraPresets presetsCamera) - presetList = presetsCamera.Presets; - - PostStatusMessage(JToken.FromObject(new - { - presets = presetList - }) - ); - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject()); - - - if (Camera is IHasCameraPtzControl ptzCamera) - { - // Need to evaluate how to pass through these P&H actions. Need a method that takes a bool maybe? - AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - ptzCamera.TiltUp(); - return; - } - - ptzCamera.TiltStop(); - })); - AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - ptzCamera.TiltDown(); - return; - } - - ptzCamera.TiltStop(); - })); - AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - ptzCamera.PanLeft(); - return; - } - - ptzCamera.PanStop(); - })); - AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - ptzCamera.PanRight(); - return; - } - - ptzCamera.PanStop(); - })); - AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - ptzCamera.ZoomIn(); - return; - } - - ptzCamera.ZoomStop(); - })); - AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - ptzCamera.ZoomOut(); - return; - } - - ptzCamera.ZoomStop(); - })); - } - - if (Camera is IHasCameraAutoMode) - { - AddAction("/cameraModeAuto", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOn()); - - AddAction("/cameraModeManual", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOff()); - - } - - if (Camera is IHasPowerControl) - { - AddAction("/cameraModeOff", (id, content) => (Camera as IHasPowerControl).PowerOff()); - AddAction("/cameraModeManual", (id, content) => (Camera as IHasPowerControl).PowerOn()); - } - - - if (Camera is IHasCameraPresets presetsCamera) - { - for (int i = 1; i <= 6; i++) - { - var preset = i; - AddAction("/cameraPreset" + i, (id, content) => - { - var msg = content.ToObject>(); - - presetsCamera.PresetSelect(msg.Value); - }); - - } - } - } - - private void HandleCameraPressAndHold(JToken content, Action cameraAction) - { - var state = content.ToObject>(); - - var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); - if (timerHandler == null) - { - return; - } - - timerHandler(state.Value, cameraAction); - - cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); - } - - /// - /// Helper method to update the full status of the camera - /// - private void SendCameraFullMessageObject() - { - var presetList = new List(); - - if (Camera is IHasCameraPresets presetsCamera) - presetList = presetsCamera.Presets; - - PostStatusMessage(JToken.FromObject(new - { - cameraManualSupported = Camera is IHasCameraControls, - cameraAutoSupported = Camera is IHasCameraAutoMode, - cameraOffSupported = Camera is IHasCameraOff, - cameraMode = GetCameraMode(), - hasPresets = Camera is IHasCameraPresets, - presets = presetList - }) - ); - } - - /// - /// Computes the current camera mode - /// - /// - private string GetCameraMode() - { - string m; - if (Camera is IHasCameraAutoMode && (Camera as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.BoolValue) - m = eCameraControlMode.Auto.ToString().ToLower(); - else if (Camera is IHasPowerControlWithFeedback && !(Camera as IHasPowerControlWithFeedback).PowerIsOnFeedback.BoolValue) - m = eCameraControlMode.Off.ToString().ToLower(); - else - m = eCameraControlMode.Manual.ToString().ToLower(); - return m; + presetsCamera.PresetsListHasChanged += PresetsCamera_PresetsListHasChanged; } } + + private void PresetsCamera_PresetsListHasChanged(object sender, EventArgs e) + { + var presetList = new List(); + + if (Camera is IHasCameraPresets presetsCamera) + presetList = presetsCamera.Presets; + + PostStatusMessage(JToken.FromObject(new + { + presets = presetList + }) + ); + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject()); + + + if (Camera is IHasCameraPtzControl ptzCamera) + { + // Need to evaluate how to pass through these P&H actions. Need a method that takes a bool maybe? + AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + ptzCamera.TiltUp(); + return; + } + + ptzCamera.TiltStop(); + })); + AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + ptzCamera.TiltDown(); + return; + } + + ptzCamera.TiltStop(); + })); + AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + ptzCamera.PanLeft(); + return; + } + + ptzCamera.PanStop(); + })); + AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + ptzCamera.PanRight(); + return; + } + + ptzCamera.PanStop(); + })); + AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + ptzCamera.ZoomIn(); + return; + } + + ptzCamera.ZoomStop(); + })); + AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + ptzCamera.ZoomOut(); + return; + } + + ptzCamera.ZoomStop(); + })); + } + + if (Camera is IHasCameraAutoMode) + { + AddAction("/cameraModeAuto", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOn()); + + AddAction("/cameraModeManual", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOff()); + + } + + if (Camera is IHasPowerControl) + { + AddAction("/cameraModeOff", (id, content) => (Camera as IHasPowerControl).PowerOff()); + AddAction("/cameraModeManual", (id, content) => (Camera as IHasPowerControl).PowerOn()); + } + + + if (Camera is IHasCameraPresets presetsCamera) + { + for (int i = 1; i <= 6; i++) + { + var preset = i; + AddAction("/cameraPreset" + i, (id, content) => + { + var msg = content.ToObject>(); + + presetsCamera.PresetSelect(msg.Value); + }); + + } + } + } + + private void HandleCameraPressAndHold(JToken content, Action cameraAction) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; + } + + timerHandler(state.Value, cameraAction); + + cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); + } + + /// + /// Helper method to update the full status of the camera + /// + private void SendCameraFullMessageObject() + { + var presetList = new List(); + + if (Camera is IHasCameraPresets presetsCamera) + presetList = presetsCamera.Presets; + + PostStatusMessage(JToken.FromObject(new + { + cameraManualSupported = Camera is IHasCameraControls, + cameraAutoSupported = Camera is IHasCameraAutoMode, + cameraOffSupported = Camera is IHasCameraOff, + cameraMode = GetCameraMode(), + hasPresets = Camera is IHasCameraPresets, + presets = presetList + }) + ); + } + + /// + /// Computes the current camera mode + /// + /// + private string GetCameraMode() + { + string m; + if (Camera is IHasCameraAutoMode && (Camera as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.BoolValue) + m = eCameraControlMode.Auto.ToString().ToLower(); + else if (Camera is IHasPowerControlWithFeedback && !(Camera as IHasPowerControlWithFeedback).PowerIsOnFeedback.BoolValue) + m = eCameraControlMode.Off.ToString().ToLower(); + else + m = eCameraControlMode.Manual.ToString().ToLower(); + return m; + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs index c588195e..58ea373d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs @@ -4,87 +4,86 @@ using PepperDash.Core; using PepperDash.Essentials.Core.DeviceInfo; using System.Timers; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Facilitates communication of device information by providing mechanisms for status updates and device +/// information reporting. +/// +/// The class integrates with an to manage device-specific information. It uses a debounce timer to limit the +/// frequency of updates, ensuring efficient communication. The timer is initialized with a 1-second interval and +/// is disabled by default. This class also subscribes to device information change events and provides actions for +/// reporting full device status and triggering updates. +public class DeviceInfoMessenger : MessengerBase { + private readonly IDeviceInfoProvider _deviceInfoProvider; + + private readonly Timer debounceTimer; + /// - /// Facilitates communication of device information by providing mechanisms for status updates and device - /// information reporting. - /// - /// The class integrates with an to manage device-specific information. It uses a debounce timer to limit the - /// frequency of updates, ensuring efficient communication. The timer is initialized with a 1-second interval and - /// is disabled by default. This class also subscribes to device information change events and provides actions for - /// reporting full device status and triggering updates. - public class DeviceInfoMessenger : MessengerBase + /// Initializes a new instance of the class, which facilitates communication + /// of device information. + /// + /// The messenger uses a debounce timer to limit the frequency of certain operations. The + /// timer is initialized with a 1-second interval and is disabled by default. + /// A unique identifier for the messenger instance. + /// The path used for sending and receiving messages. + /// An implementation of that provides device-specific information. + public DeviceInfoMessenger(string key, string messagePath, IDeviceInfoProvider device) : base(key, messagePath, device as Device) { - private readonly IDeviceInfoProvider _deviceInfoProvider; + _deviceInfoProvider = device; - private readonly Timer debounceTimer; - - /// - /// Initializes a new instance of the class, which facilitates communication - /// of device information. - /// - /// The messenger uses a debounce timer to limit the frequency of certain operations. The - /// timer is initialized with a 1-second interval and is disabled by default. - /// A unique identifier for the messenger instance. - /// The path used for sending and receiving messages. - /// An implementation of that provides device-specific information. - public DeviceInfoMessenger(string key, string messagePath, IDeviceInfoProvider device) : base(key, messagePath, device as Device) - { - _deviceInfoProvider = device; - - debounceTimer = new Timer(1000) - { - Enabled = false, - AutoReset = false - }; - - debounceTimer.Elapsed += DebounceTimer_Elapsed; - } - - private void DebounceTimer_Elapsed(object sender, ElapsedEventArgs e) + debounceTimer = new Timer(1000) { - PostStatusMessage(JToken.FromObject(new - { - deviceInfo = _deviceInfoProvider.DeviceInfo - })); - } + Enabled = false, + AutoReset = false + }; + + debounceTimer.Elapsed += DebounceTimer_Elapsed; + } + + private void DebounceTimer_Elapsed(object sender, ElapsedEventArgs e) + { + PostStatusMessage(JToken.FromObject(new + { + deviceInfo = _deviceInfoProvider.DeviceInfo + })); + } - /// - /// Registers actions and event handlers for device information updates and status reporting. - /// - /// This method sets up actions for handling device status updates and reporting full - /// device status. It also subscribes to the event to - /// trigger debounced updates when the device information changes. - protected override void RegisterActions() - { - base.RegisterActions(); - - _deviceInfoProvider.DeviceInfoChanged += (o, a) => - { - debounceTimer.Stop(); - debounceTimer.Start(); - }; - - AddAction("/fullStatus", (id, context) => PostStatusMessage(new DeviceInfoStateMessage - { - DeviceInfo = _deviceInfoProvider.DeviceInfo - })); - - AddAction("/update", (id, context) => _deviceInfoProvider.UpdateDeviceInfo()); - } - } - /// - /// Represents a message containing the state information of a device, including detailed device information. - /// - /// This class is used to encapsulate the state of a device along with its associated - /// information. It extends to provide additional details about the - /// device. - public class DeviceInfoStateMessage : DeviceStateMessageBase + /// Registers actions and event handlers for device information updates and status reporting. + /// + /// This method sets up actions for handling device status updates and reporting full + /// device status. It also subscribes to the event to + /// trigger debounced updates when the device information changes. + protected override void RegisterActions() { - [JsonProperty("deviceInfo")] - public DeviceInfo DeviceInfo { get; set; } + base.RegisterActions(); + + _deviceInfoProvider.DeviceInfoChanged += (o, a) => + { + debounceTimer.Stop(); + debounceTimer.Start(); + }; + + AddAction("/fullStatus", (id, context) => PostStatusMessage(new DeviceInfoStateMessage + { + DeviceInfo = _deviceInfoProvider.DeviceInfo + })); + + AddAction("/update", (id, context) => _deviceInfoProvider.UpdateDeviceInfo()); } } + +/// +/// Represents a message containing the state information of a device, including detailed device information. +/// +/// This class is used to encapsulate the state of a device along with its associated +/// information. It extends to provide additional details about the +/// device. +public class DeviceInfoStateMessage : DeviceStateMessageBase +{ + [JsonProperty("deviceInfo")] + public DeviceInfo DeviceInfo { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs index 91b87a83..3eff389d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs @@ -7,94 +7,93 @@ using PepperDash.Essentials.Core.Presets; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class DevicePresetsModelMessenger : MessengerBase { - public class DevicePresetsModelMessenger : MessengerBase + private readonly ITvPresetsProvider _presetsDevice; + + public DevicePresetsModelMessenger(string key, string messagePath, ITvPresetsProvider presetsDevice) + : base(key, messagePath, presetsDevice as Device) { - private readonly ITvPresetsProvider _presetsDevice; - - public DevicePresetsModelMessenger(string key, string messagePath, ITvPresetsProvider presetsDevice) - : base(key, messagePath, presetsDevice as Device) - { - _presetsDevice = presetsDevice; - } - - private void SendPresets() - { - PostStatusMessage(new PresetStateMessage - { - Favorites = _presetsDevice.TvPresets.PresetsList - }); - } - - private void RecallPreset(ISetTopBoxNumericKeypad device, string channel) - { - _presetsDevice.TvPresets.Dial(channel, device); - } - - private void SavePresets(List presets) - { - _presetsDevice.TvPresets.UpdatePresets(presets); - } - - - #region Overrides of MessengerBase - - protected override void RegisterActions() - - { - AddAction("/fullStatus", (id, content) => - { - this.LogInformation("getting full status for client {id}", id); - try - { - SendPresets(); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception sending preset full status", this); - } - }); - - AddAction("/recall", (id, content) => - { - var p = content.ToObject(); - - - if (!(DeviceManager.GetDeviceForKey(p.DeviceKey) is ISetTopBoxNumericKeypad dev)) - { - this.LogDebug("Unable to find device with key {0}", p.DeviceKey); - return; - } - - RecallPreset(dev, p.Preset.Channel); - }); - - AddAction("/save", (id, content) => - { - var presets = content.ToObject>(); - - SavePresets(presets); - }); - - _presetsDevice.TvPresets.PresetsSaved += (p) => SendPresets(); - } - - #endregion + _presetsDevice = presetsDevice; } - public class PresetChannelMessage + private void SendPresets() { - [JsonProperty("preset")] - public PresetChannel Preset; - - [JsonProperty("deviceKey")] - public string DeviceKey; + PostStatusMessage(new PresetStateMessage + { + Favorites = _presetsDevice.TvPresets.PresetsList + }); } - public class PresetStateMessage : DeviceStateMessageBase + private void RecallPreset(ISetTopBoxNumericKeypad device, string channel) { - [JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)] - public List Favorites { get; set; } = new List(); + _presetsDevice.TvPresets.Dial(channel, device); } + + private void SavePresets(List presets) + { + _presetsDevice.TvPresets.UpdatePresets(presets); + } + + + #region Overrides of MessengerBase + + protected override void RegisterActions() + + { + AddAction("/fullStatus", (id, content) => + { + this.LogInformation("getting full status for client {id}", id); + try + { + SendPresets(); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception sending preset full status", this); + } + }); + + AddAction("/recall", (id, content) => + { + var p = content.ToObject(); + + + if (!(DeviceManager.GetDeviceForKey(p.DeviceKey) is ISetTopBoxNumericKeypad dev)) + { + this.LogDebug("Unable to find device with key {0}", p.DeviceKey); + return; + } + + RecallPreset(dev, p.Preset.Channel); + }); + + AddAction("/save", (id, content) => + { + var presets = content.ToObject>(); + + SavePresets(presets); + }); + + _presetsDevice.TvPresets.PresetsSaved += (p) => SendPresets(); + } + + #endregion +} + +public class PresetChannelMessage +{ + [JsonProperty("preset")] + public PresetChannel Preset; + + [JsonProperty("deviceKey")] + public string DeviceKey; +} + +public class PresetStateMessage : DeviceStateMessageBase +{ + [JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)] + public List Favorites { get; set; } = new List(); } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs index 22f837c3..8e0015c7 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs @@ -5,168 +5,167 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class DeviceVolumeMessenger : MessengerBase { - public class DeviceVolumeMessenger : MessengerBase + private readonly IBasicVolumeWithFeedback _localDevice; + + public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeWithFeedback device) + : base(key, messagePath, device as IKeyName) { - private readonly IBasicVolumeWithFeedback _localDevice; + _localDevice = device; + } - public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeWithFeedback device) - : base(key, messagePath, device as IKeyName) + private void SendStatus() + { + try { - _localDevice = device; + var messageObj = new VolumeStateMessage + { + Volume = new Volume + { + Level = _localDevice?.VolumeLevelFeedback.IntValue ?? -1, + Muted = _localDevice?.MuteFeedback.BoolValue ?? false, + HasMute = true, // assume all devices have mute for now + } + }; + + if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) + { + messageObj.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString(); + messageObj.Volume.Units = volumeAdvanced.Units; + } + + PostStatusMessage(messageObj); } - - private void SendStatus() + catch (Exception ex) { + Debug.LogMessage(ex, "Exception sending full status", this); + } + } + + #region Overrides of MessengerBase + + + protected override void RegisterActions() + { + AddAction("/fullStatus", (id, content) => SendStatus()); + + AddAction("/level", (id, content) => + { + var volume = content.ToObject>(); + + _localDevice.SetVolume(volume.Value); + }); + + AddAction("/muteToggle", (id, content) => + { + _localDevice.MuteToggle(); + }); + + AddAction("/muteOn", (id, content) => + { + _localDevice.MuteOn(); + }); + + AddAction("/muteOff", (id, content) => + { + _localDevice.MuteOff(); + }); + + AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume up with {value}", DeviceKey, b); try { - var messageObj = new VolumeStateMessage - { - Volume = new Volume - { - Level = _localDevice?.VolumeLevelFeedback.IntValue ?? -1, - Muted = _localDevice?.MuteFeedback.BoolValue ?? false, - HasMute = true, // assume all devices have mute for now - } - }; - - if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) - { - messageObj.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString(); - messageObj.Volume.Units = volumeAdvanced.Units; - } - - PostStatusMessage(messageObj); + _localDevice.VolumeUp(b); } catch (Exception ex) { - Debug.LogMessage(ex, "Exception sending full status", this); + Debug.LogMessage(ex, "Got exception during volume up: {Exception}", null, ex); } - } - - #region Overrides of MessengerBase + })); - protected override void RegisterActions() + + AddAction("/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { - AddAction("/fullStatus", (id, content) => SendStatus()); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume down with {value}", DeviceKey, b); - AddAction("/level", (id, content) => + try { - var volume = content.ToObject>(); - - _localDevice.SetVolume(volume.Value); - }); - - AddAction("/muteToggle", (id, content) => + _localDevice.VolumeDown(b); + } + catch (Exception ex) { - _localDevice.MuteToggle(); - }); + Debug.LogMessage(ex, "Got exception during volume down: {Exception}", null, ex); + } + })); - AddAction("/muteOn", (id, content) => - { - _localDevice.MuteOn(); - }); - - AddAction("/muteOff", (id, content) => - { - _localDevice.MuteOff(); - }); - - AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume up with {value}", DeviceKey, b); - try - { - _localDevice.VolumeUp(b); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Got exception during volume up: {Exception}", null, ex); - } - })); - - - - AddAction("/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume down with {value}", DeviceKey, b); - - try - { - _localDevice.VolumeDown(b); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Got exception during volume down: {Exception}", null, ex); - } - })); - - _localDevice.MuteFeedback.OutputChange += (sender, args) => - { - PostStatusMessage(JToken.FromObject( - new - { - volume = new - { - muted = args.BoolValue - } - }) - ); - }; - - _localDevice.VolumeLevelFeedback.OutputChange += (sender, args) => - { - var rawValue = ""; - if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) - { - rawValue = volumeAdvanced.RawVolumeLevel.ToString(); - } - - var message = new - { - volume = new + _localDevice.MuteFeedback.OutputChange += (sender, args) => + { + PostStatusMessage(JToken.FromObject( + new { - level = args.IntValue, - rawValue - } - }; + volume = new + { + muted = args.BoolValue + } + }) + ); + }; - PostStatusMessage(JToken.FromObject(message)); + _localDevice.VolumeLevelFeedback.OutputChange += (sender, args) => + { + var rawValue = ""; + if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) + { + rawValue = volumeAdvanced.RawVolumeLevel.ToString(); + } + + var message = new + { + volume = new + { + level = args.IntValue, + rawValue + } }; + PostStatusMessage(JToken.FromObject(message)); + }; - } - #endregion } - public class VolumeStateMessage : DeviceStateMessageBase - { - [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] - public Volume Volume { get; set; } - } + #endregion +} - public class Volume - { - [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] - public int? Level { get; set; } +public class VolumeStateMessage : DeviceStateMessageBase +{ + [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] + public Volume Volume { get; set; } +} - [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasMute { get; set; } +public class Volume +{ + [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] + public int? Level { get; set; } - [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] - public bool? Muted { get; set; } + [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasMute { get; set; } - [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] - public string Label { get; set; } + [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] + public bool? Muted { get; set; } - [JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)] - public string RawValue { get; set; } + [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] + public string Label { get; set; } - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("units", NullValueHandling = NullValueHandling.Ignore)] - public eVolumeLevelUnits? Units { get; set; } - } + [JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)] + public string RawValue { get; set; } + + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("units", NullValueHandling = NullValueHandling.Ignore)] + public eVolumeLevelUnits? Units { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs index 64624bfa..c76b9adc 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs @@ -1,25 +1,24 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class GenericMessenger : MessengerBase { - public class GenericMessenger : MessengerBase + public GenericMessenger(string key, EssentialsDevice device, string messagePath) : base(key, messagePath, device) { - public GenericMessenger(string key, EssentialsDevice device, string messagePath) : base(key, messagePath, device) - { - } + } - protected override void RegisterActions() - { - base.RegisterActions(); + protected override void RegisterActions() + { + base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); - } + AddAction("/fullStatus", (id, content) => SendFullStatus()); + } - private void SendFullStatus() - { - var state = new DeviceStateMessageBase(); + private void SendFullStatus() + { + var state = new DeviceStateMessageBase(); - PostStatusMessage(state); - } + PostStatusMessage(state); } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs index 5ab81832..013e8047 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs @@ -4,71 +4,69 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class ICommunicationMonitorMessenger : MessengerBase { - public class ICommunicationMonitorMessenger : MessengerBase + private readonly ICommunicationMonitor _communicationMonitor; + + public ICommunicationMonitorMessenger(string key, string messagePath, ICommunicationMonitor device) : base(key, messagePath, device as IKeyName) { - private readonly ICommunicationMonitor _communicationMonitor; + _communicationMonitor = device; + } - public ICommunicationMonitorMessenger(string key, string messagePath, ICommunicationMonitor device) : base(key, messagePath, device as IKeyName) + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => { - _communicationMonitor = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => + PostStatusMessage(new CommunicationMonitorState { - PostStatusMessage(new CommunicationMonitorState + CommunicationMonitor = new CommunicationMonitorProps { - CommunicationMonitor = new CommunicationMonitorProps - { - IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, - Status = _communicationMonitor.CommunicationMonitor.Status - } - }); + IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, + Status = _communicationMonitor.CommunicationMonitor.Status + } }); + }); - _communicationMonitor.CommunicationMonitor.StatusChange += (sender, args) => + _communicationMonitor.CommunicationMonitor.StatusChange += (sender, args) => + { + PostStatusMessage(JToken.FromObject(new { - PostStatusMessage(JToken.FromObject(new + commMonitor = new CommunicationMonitorProps { - commMonitor = new CommunicationMonitorProps - { - IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, - Status = _communicationMonitor.CommunicationMonitor.Status - } - })); - }; - } + IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, + Status = _communicationMonitor.CommunicationMonitor.Status + } + })); + }; } +} - /// - /// Represents the state of the communication monitor - /// - public class CommunicationMonitorState : DeviceStateMessageBase - { - [JsonProperty("commMonitor", NullValueHandling = NullValueHandling.Ignore)] - public CommunicationMonitorProps CommunicationMonitor { get; set; } - - } - - public class CommunicationMonitorProps - { /// - /// For devices that implement ICommunicationMonitor, reports the online status of the device - /// - [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsOnline { get; set; } - - /// - /// For devices that implement ICommunicationMonitor, reports the online status of the device - /// - [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] - public MonitorStatus Status { get; set; } - - } +/// +/// Represents the state of the communication monitor +/// +public class CommunicationMonitorState : DeviceStateMessageBase +{ + [JsonProperty("commMonitor", NullValueHandling = NullValueHandling.Ignore)] + public CommunicationMonitorProps CommunicationMonitor { get; set; } + +} + +public class CommunicationMonitorProps +{ /// + /// For devices that implement ICommunicationMonitor, reports the online status of the device + /// + [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsOnline { get; set; } + + /// + /// For devices that implement ICommunicationMonitor, reports the online status of the device + /// + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public MonitorStatus Status { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs index e40cd8eb..f4c8513e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs @@ -3,48 +3,47 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IDspPresetsMessenger : MessengerBase { - public class IDspPresetsMessenger : MessengerBase + private readonly IDspPresets device; + + public IDspPresetsMessenger(string key, string messagePath, IDspPresets device) + : base(key, messagePath, device as IKeyName) { - private readonly IDspPresets device; - - public IDspPresetsMessenger(string key, string messagePath, IDspPresets device) - : base(key, messagePath, device as IKeyName) - { - this.device = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => - { - var message = new IHasDspPresetsStateMessage - { - Presets = device.Presets - }; - - PostStatusMessage(message); - }); - - AddAction("/recallPreset", (id, content) => - { - var presetKey = content.ToObject(); - - - if (!string.IsNullOrEmpty(presetKey)) - { - device.RecallPreset(presetKey); - } - }); - } + this.device = device; } - public class IHasDspPresetsStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("presets")] - public Dictionary Presets { get; set; } + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => + { + var message = new IHasDspPresetsStateMessage + { + Presets = device.Presets + }; + + PostStatusMessage(message); + }); + + AddAction("/recallPreset", (id, content) => + { + var presetKey = content.ToObject(); + + + if (!string.IsNullOrEmpty(presetKey)) + { + device.RecallPreset(presetKey); + } + }); } } + +public class IHasDspPresetsStateMessage : DeviceStateMessageBase +{ + [JsonProperty("presets")] + public Dictionary Presets { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs index 1752b567..20a6ec92 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs @@ -6,204 +6,201 @@ using PepperDash.Essentials.Core; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Provides messaging functionality for managing room combination scenarios and partition states in an instance. Enables external systems to interact with the room combiner via +/// predefined actions and status updates. +/// +/// This class facilitates communication with an by +/// exposing actions for toggling modes, managing partitions, and setting room combination scenarios. It also +/// listens for feedback changes and broadcasts status updates to connected systems. Typical usage involves +/// registering actions for external commands and handling feedback events to synchronize state changes. +public class IEssentialsRoomCombinerMessenger : MessengerBase { + private readonly IEssentialsRoomCombiner _roomCombiner; + /// - /// Provides messaging functionality for managing room combination scenarios and partition states in an instance. Enables external systems to interact with the room combiner via - /// predefined actions and status updates. - /// - /// This class facilitates communication with an by - /// exposing actions for toggling modes, managing partitions, and setting room combination scenarios. It also - /// listens for feedback changes and broadcasts status updates to connected systems. Typical usage involves - /// registering actions for external commands and handling feedback events to synchronize state changes. - public class IEssentialsRoomCombinerMessenger : MessengerBase + /// Initializes a new instance of the class, which facilitates + /// messaging for an instance. + /// + /// This class is designed to enable communication and interaction with an through the specified messaging path. Ensure that the parameter is not null when creating an instance. + /// The unique key identifying this messenger instance. + /// The path used for messaging operations. + /// The instance associated with this messenger. + public IEssentialsRoomCombinerMessenger(string key, string messagePath, IEssentialsRoomCombiner roomCombiner) + : base(key, messagePath, roomCombiner as IKeyName) { - private readonly IEssentialsRoomCombiner _roomCombiner; + _roomCombiner = roomCombiner; + } - /// - /// Initializes a new instance of the class, which facilitates - /// messaging for an instance. - /// - /// This class is designed to enable communication and interaction with an through the specified messaging path. Ensure that the parameter is not null when creating an instance. - /// The unique key identifying this messenger instance. - /// The path used for messaging operations. - /// The instance associated with this messenger. - public IEssentialsRoomCombinerMessenger(string key, string messagePath, IEssentialsRoomCombiner roomCombiner) - : base(key, messagePath, roomCombiner as IKeyName) + /// + /// Registers actions and event handlers for managing room combination scenarios and partition states. + /// + /// This method sets up various actions that can be triggered via specific endpoints, + /// such as toggling modes, setting room combination scenarios, and managing partition states. It also + /// subscribes to feedback events to update the status when changes occur in room combination scenarios or + /// partition states. + protected override void RegisterActions() + { + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/setAutoMode", (id, content) => { - _roomCombiner = roomCombiner; - } + _roomCombiner.SetAutoMode(); + }); - /// - /// Registers actions and event handlers for managing room combination scenarios and partition states. - /// - /// This method sets up various actions that can be triggered via specific endpoints, - /// such as toggling modes, setting room combination scenarios, and managing partition states. It also - /// subscribes to feedback events to update the status when changes occur in room combination scenarios or - /// partition states. - protected override void RegisterActions() + AddAction("/setManualMode", (id, content) => { - AddAction("/fullStatus", (id, content) => SendFullStatus()); + _roomCombiner.SetManualMode(); + }); - AddAction("/setAutoMode", (id, content) => + AddAction("/toggleMode", (id, content) => + { + _roomCombiner.ToggleMode(); + }); + + AddAction("/togglePartitionState", (id, content) => + { + try { - _roomCombiner.SetAutoMode(); - }); + var partitionKey = content.ToObject(); - AddAction("/setManualMode", (id, content) => + _roomCombiner.TogglePartitionState(partitionKey); + } + catch (Exception e) { - _roomCombiner.SetManualMode(); - }); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Error toggling partition state: {e}", this); + } + }); - AddAction("/toggleMode", (id, content) => + AddAction("/setRoomCombinationScenario", (id, content) => + { + try { - _roomCombiner.ToggleMode(); - }); + var scenarioKey = content.ToObject(); - AddAction("/togglePartitionState", (id, content) => + _roomCombiner.SetRoomCombinationScenario(scenarioKey); + } + catch (Exception e) { - try - { - var partitionKey = content.ToObject(); + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Error toggling partition state: {e}", this); + } + }); - _roomCombiner.TogglePartitionState(partitionKey); - } - catch (Exception e) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Error toggling partition state: {e}", this); - } - }); + _roomCombiner.RoomCombinationScenarioChanged += (sender, args) => + { + SendFullStatus(); + }; - AddAction("/setRoomCombinationScenario", (id, content) => + _roomCombiner.IsInAutoModeFeedback.OutputChange += (sender, args) => + { + var message = new { - try - { - var scenarioKey = content.ToObject(); - - _roomCombiner.SetRoomCombinationScenario(scenarioKey); - } - catch (Exception e) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Error toggling partition state: {e}", this); - } - }); - - _roomCombiner.RoomCombinationScenarioChanged += (sender, args) => - { - SendFullStatus(); + isInAutoMode = _roomCombiner.IsInAutoModeFeedback.BoolValue }; - _roomCombiner.IsInAutoModeFeedback.OutputChange += (sender, args) => + PostStatusMessage(JToken.FromObject(message)); + }; + + foreach (var partition in _roomCombiner.Partitions) + { + partition.PartitionPresentFeedback.OutputChange += (sender, args) => { var message = new { - isInAutoMode = _roomCombiner.IsInAutoModeFeedback.BoolValue + partitions = _roomCombiner.Partitions }; PostStatusMessage(JToken.FromObject(message)); }; - - foreach (var partition in _roomCombiner.Partitions) - { - partition.PartitionPresentFeedback.OutputChange += (sender, args) => - { - var message = new - { - partitions = _roomCombiner.Partitions - }; - - PostStatusMessage(JToken.FromObject(message)); - }; - } - } - - private void SendFullStatus() - { - try - { - var rooms = new List(); - - foreach (var room in _roomCombiner.Rooms) - { - rooms.Add(new RoomCombinerRoom { Key = room.Key, Name = room.Name }); - } - - var message = new IEssentialsRoomCombinerStateMessage - { - DisableAutoMode = _roomCombiner.DisableAutoMode, - IsInAutoMode = _roomCombiner.IsInAutoMode, - CurrentScenario = _roomCombiner.CurrentScenario, - Rooms = rooms, - RoomCombinationScenarios = _roomCombiner.RoomCombinationScenarios, - Partitions = _roomCombiner.Partitions - }; - - PostStatusMessage(message); - } - catch (Exception e) - { - this.LogException(e, "Error sending full status"); - } - } - - private class RoomCombinerRoom : IKeyName - { - [JsonProperty("key")] - public string Key { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } } } + private void SendFullStatus() + { + try + { + var rooms = new List(); + + foreach (var room in _roomCombiner.Rooms) + { + rooms.Add(new RoomCombinerRoom { Key = room.Key, Name = room.Name }); + } + + var message = new IEssentialsRoomCombinerStateMessage + { + DisableAutoMode = _roomCombiner.DisableAutoMode, + IsInAutoMode = _roomCombiner.IsInAutoMode, + CurrentScenario = _roomCombiner.CurrentScenario, + Rooms = rooms, + RoomCombinationScenarios = _roomCombiner.RoomCombinationScenarios, + Partitions = _roomCombiner.Partitions + }; + + PostStatusMessage(message); + } + catch (Exception e) + { + this.LogException(e, "Error sending full status"); + } + } + + private class RoomCombinerRoom : IKeyName + { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + } +} + +/// +/// Represents the state message for a room combiner system, providing information about the current configuration, +/// operational mode, and associated rooms, partitions, and scenarios. +/// +/// This class is used to encapsulate the state of a room combiner system, including its current +/// mode of operation, active room combination scenario, and the list of rooms and partitions involved. It is +/// typically serialized and transmitted to communicate the state of the system. +public class IEssentialsRoomCombinerStateMessage : DeviceStateMessageBase +{ + /// + /// Gets or sets a value indicating whether automatic mode is disabled. + /// + [JsonProperty("disableAutoMode", NullValueHandling = NullValueHandling.Ignore)] + public bool DisableAutoMode { get; set; } + /// - /// Represents the state message for a room combiner system, providing information about the current configuration, - /// operational mode, and associated rooms, partitions, and scenarios. + /// Gets or sets a value indicating whether the system is operating in automatic mode. /// - /// This class is used to encapsulate the state of a room combiner system, including its current - /// mode of operation, active room combination scenario, and the list of rooms and partitions involved. It is - /// typically serialized and transmitted to communicate the state of the system. - public class IEssentialsRoomCombinerStateMessage : DeviceStateMessageBase - { - /// - /// Gets or sets a value indicating whether automatic mode is disabled. - /// - [JsonProperty("disableAutoMode", NullValueHandling = NullValueHandling.Ignore)] - public bool DisableAutoMode { get; set; } + [JsonProperty("isInAutoMode", NullValueHandling = NullValueHandling.Ignore)] + public bool IsInAutoMode { get; set; } - /// - /// Gets or sets a value indicating whether the system is operating in automatic mode. - /// - [JsonProperty("isInAutoMode", NullValueHandling = NullValueHandling.Ignore)] - public bool IsInAutoMode { get; set; } + /// + /// Gets or sets the current room combination scenario. + /// + [JsonProperty("currentScenario", NullValueHandling = NullValueHandling.Ignore)] + public IRoomCombinationScenario CurrentScenario { get; set; } - /// - /// Gets or sets the current room combination scenario. - /// - [JsonProperty("currentScenario", NullValueHandling = NullValueHandling.Ignore)] - public IRoomCombinationScenario CurrentScenario { get; set; } - - /// - /// Gets or sets the collection of rooms associated with the entity. - /// - [JsonProperty("rooms", NullValueHandling = NullValueHandling.Ignore)] - public List Rooms { get; set; } - - /// - /// Gets or sets the collection of room combination scenarios. - /// - [JsonProperty("roomCombinationScenarios", NullValueHandling = NullValueHandling.Ignore)] - public List RoomCombinationScenarios { get; set; } - - /// - /// Gets or sets the collection of partition controllers. - /// - [JsonProperty("partitions", NullValueHandling = NullValueHandling.Ignore)] - public List Partitions { get; set; } - } + /// + /// Gets or sets the collection of rooms associated with the entity. + /// + [JsonProperty("rooms", NullValueHandling = NullValueHandling.Ignore)] + public List Rooms { get; set; } + /// + /// Gets or sets the collection of room combination scenarios. + /// + [JsonProperty("roomCombinationScenarios", NullValueHandling = NullValueHandling.Ignore)] + public List RoomCombinationScenarios { get; set; } + /// + /// Gets or sets the collection of partition controllers. + /// + [JsonProperty("partitions", NullValueHandling = NullValueHandling.Ignore)] + public List Partitions { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs index 24f1f461..ebf9a2d2 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs @@ -3,55 +3,54 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IHasCurrentSourceInfoMessenger : MessengerBase { - public class IHasCurrentSourceInfoMessenger : MessengerBase + private readonly IHasCurrentSourceInfoChange sourceDevice; + public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName) { - private readonly IHasCurrentSourceInfoChange sourceDevice; - public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName) - { - sourceDevice = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => - { - var message = new CurrentSourceStateMessage - { - CurrentSourceKey = sourceDevice.CurrentSourceInfoKey, - CurrentSource = sourceDevice.CurrentSourceInfo - }; - - PostStatusMessage(message); - }); - - sourceDevice.CurrentSourceChange += (sender, e) => - { - switch (e) - { - case ChangeType.DidChange: - { - PostStatusMessage(JToken.FromObject(new - { - currentSourceKey = string.IsNullOrEmpty(sourceDevice.CurrentSourceInfoKey) ? string.Empty : sourceDevice.CurrentSourceInfoKey, - currentSource = sourceDevice.CurrentSourceInfo - })); - break; - } - } - }; - } + sourceDevice = device; } - public class CurrentSourceStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] - public string CurrentSourceKey { get; set; } + base.RegisterActions(); - [JsonProperty("currentSource")] - public SourceListItem CurrentSource { get; set; } + AddAction("/fullStatus", (id, content) => + { + var message = new CurrentSourceStateMessage + { + CurrentSourceKey = sourceDevice.CurrentSourceInfoKey, + CurrentSource = sourceDevice.CurrentSourceInfo + }; + + PostStatusMessage(message); + }); + + sourceDevice.CurrentSourceChange += (sender, e) => + { + switch (e) + { + case ChangeType.DidChange: + { + PostStatusMessage(JToken.FromObject(new + { + currentSourceKey = string.IsNullOrEmpty(sourceDevice.CurrentSourceInfoKey) ? string.Empty : sourceDevice.CurrentSourceInfoKey, + currentSource = sourceDevice.CurrentSourceInfo + })); + break; + } + } + }; } } + +public class CurrentSourceStateMessage : DeviceStateMessageBase +{ + [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] + public string CurrentSourceKey { get; set; } + + [JsonProperty("currentSource")] + public SourceListItem CurrentSource { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs index 8eb693d5..35d3489c 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs @@ -5,97 +5,95 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers -{ - public class IHasInputsMessenger : MessengerBase - { - private readonly IHasInputs itemDevice; +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IHasInputsMessenger : MessengerBase +{ + private readonly IHasInputs itemDevice; - /// - /// Constructs a messenger for a device that implements IHasInputs - /// - /// - /// - /// - public IHasInputsMessenger(string key, string messagePath, IHasInputs device) : base(key, messagePath, device) + /// + /// Constructs a messenger for a device that implements IHasInputs + /// + /// + /// + /// + public IHasInputsMessenger(string key, string messagePath, IHasInputs device) : base(key, messagePath, device) + { + itemDevice = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, context) => { - itemDevice = device; - } + SendFullStatus(); + }); - protected override void RegisterActions() + itemDevice.Inputs.ItemsUpdated += (sender, args) => { - base.RegisterActions(); + SendFullStatus(); + }; - AddAction("/fullStatus", (id, context) => + itemDevice.Inputs.CurrentItemChanged += (sender, args) => + { + SendFullStatus(); + }; + + foreach (var input in itemDevice.Inputs.Items) + { + var key = input.Key; + var localItem = input.Value; + + AddAction($"/{key}", (id, content) => { - SendFullStatus(); + localItem.Select(); }); - itemDevice.Inputs.ItemsUpdated += (sender, args) => + localItem.ItemUpdated += (sender, args) => { SendFullStatus(); }; - - itemDevice.Inputs.CurrentItemChanged += (sender, args) => - { - SendFullStatus(); - }; - - foreach (var input in itemDevice.Inputs.Items) - { - var key = input.Key; - var localItem = input.Value; - - AddAction($"/{key}", (id, content) => - { - localItem.Select(); - }); - - localItem.ItemUpdated += (sender, args) => - { - SendFullStatus(); - }; - } } + } - private void SendFullStatus() + private void SendFullStatus() + { + try { - try - { - this.LogInformation("Sending full status"); + this.LogInformation("Sending full status"); - var stateObject = new IHasInputsStateMessage + var stateObject = new IHasInputsStateMessage + { + Inputs = new Inputs { - Inputs = new Inputs - { - Items = itemDevice.Inputs.Items, - CurrentItem = itemDevice.Inputs.CurrentItem - } - }; + Items = itemDevice.Inputs.Items, + CurrentItem = itemDevice.Inputs.CurrentItem + } + }; - PostStatusMessage(stateObject); - } - catch (Exception e) - { - this.LogError("Error sending full status: {0}", e.Message); - } + PostStatusMessage(stateObject); + } + catch (Exception e) + { + this.LogError("Error sending full status: {0}", e.Message); } } - - public class IHasInputsStateMessage : DeviceStateMessageBase - { - [JsonProperty("inputs")] - public Inputs Inputs { get; set; } - } - - public class Inputs - { - [JsonProperty("items")] - public Dictionary Items { get; set; } - - [JsonProperty("currentItem")] - public TKey CurrentItem { get; set; } - } - +} + +public class IHasInputsStateMessage : DeviceStateMessageBase +{ + [JsonProperty("inputs")] + public Inputs Inputs { get; set; } +} + +public class Inputs +{ + [JsonProperty("items")] + public Dictionary Items { get; set; } + + [JsonProperty("currentItem")] + public TKey CurrentItem { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs index 7fb39c8c..ae7ecd5f 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs @@ -3,50 +3,49 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IHasPowerControlWithFeedbackMessenger : MessengerBase { - public class IHasPowerControlWithFeedbackMessenger : MessengerBase + private readonly IHasPowerControlWithFeedback _powerControl; + + public IHasPowerControlWithFeedbackMessenger(string key, string messagePath, IHasPowerControlWithFeedback powerControl) + : base(key, messagePath, powerControl as IKeyName) { - private readonly IHasPowerControlWithFeedback _powerControl; - - public IHasPowerControlWithFeedbackMessenger(string key, string messagePath, IHasPowerControlWithFeedback powerControl) - : base(key, messagePath, powerControl as IKeyName) - { - _powerControl = powerControl; - } - - public void SendFullStatus() - { - var messageObj = new PowerControlWithFeedbackStateMessage - { - PowerState = _powerControl.PowerIsOnFeedback.BoolValue - }; - - PostStatusMessage(messageObj); - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - _powerControl.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; ; - } - - private void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs args) - { - PostStatusMessage(JToken.FromObject(new - { - powerState = args.BoolValue - }) - ); - } + _powerControl = powerControl; } - public class PowerControlWithFeedbackStateMessage : DeviceStateMessageBase + public void SendFullStatus() { - [JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] - public bool? PowerState { get; set; } + var messageObj = new PowerControlWithFeedbackStateMessage + { + PowerState = _powerControl.PowerIsOnFeedback.BoolValue + }; + + PostStatusMessage(messageObj); + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + _powerControl.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; ; + } + + private void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs args) + { + PostStatusMessage(JToken.FromObject(new + { + powerState = args.BoolValue + }) + ); } } + +public class PowerControlWithFeedbackStateMessage : DeviceStateMessageBase +{ + [JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] + public bool? PowerState { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs index 80481470..b658bcf2 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs @@ -5,77 +5,76 @@ using PepperDash.Essentials.Devices.Common.Codec; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IHasScheduleAwarenessMessenger : MessengerBase { - public class IHasScheduleAwarenessMessenger : MessengerBase + public IHasScheduleAwareness ScheduleSource { get; private set; } + + public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath) + : base(key, messagePath, scheduleSource as IKeyName) { - public IHasScheduleAwareness ScheduleSource { get; private set; } + ScheduleSource = scheduleSource ?? throw new ArgumentNullException("scheduleSource"); + ScheduleSource.CodecSchedule.MeetingsListHasChanged += new EventHandler(CodecSchedule_MeetingsListHasChanged); + ScheduleSource.CodecSchedule.MeetingEventChange += new EventHandler(CodecSchedule_MeetingEventChange); + } - public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath) - : base(key, messagePath, scheduleSource as IKeyName) - { - ScheduleSource = scheduleSource ?? throw new ArgumentNullException("scheduleSource"); - ScheduleSource.CodecSchedule.MeetingsListHasChanged += new EventHandler(CodecSchedule_MeetingsListHasChanged); - ScheduleSource.CodecSchedule.MeetingEventChange += new EventHandler(CodecSchedule_MeetingEventChange); - } + protected override void RegisterActions() + { + AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject()); + } - protected override void RegisterActions() + private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) + { + PostStatusMessage(JToken.FromObject(new MeetingChangeMessage { - AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject()); - } - - private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) - { - PostStatusMessage(JToken.FromObject(new MeetingChangeMessage + MeetingChange = new MeetingChange { - MeetingChange = new MeetingChange - { - ChangeType = e.ChangeType.ToString(), - Meeting = e.Meeting - } - }) - ); - } + ChangeType = e.ChangeType.ToString(), + Meeting = e.Meeting + } + }) + ); + } - private void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) + private void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) + { + SendFullScheduleObject(); + } + + /// + /// Helper method to send the full schedule data + /// + private void SendFullScheduleObject() + { + PostStatusMessage(new FullScheduleMessage { - SendFullScheduleObject(); - } - - /// - /// Helper method to send the full schedule data - /// - private void SendFullScheduleObject() - { - PostStatusMessage(new FullScheduleMessage - { - Meetings = ScheduleSource.CodecSchedule.Meetings, - MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes - }); - } + Meetings = ScheduleSource.CodecSchedule.Meetings, + MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes + }); } +} - public class FullScheduleMessage : DeviceStateMessageBase - { - [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] - public List Meetings { get; set; } +public class FullScheduleMessage : DeviceStateMessageBase +{ + [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] + public List Meetings { get; set; } - [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] - public int MeetingWarningMinutes { get; set; } - } + [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] + public int MeetingWarningMinutes { get; set; } +} - public class MeetingChangeMessage - { - [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] - public MeetingChange MeetingChange { get; set; } - } +public class MeetingChangeMessage +{ + [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] + public MeetingChange MeetingChange { get; set; } +} - public class MeetingChange - { - [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] - public string ChangeType { get; set; } +public class MeetingChange +{ + [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] + public string ChangeType { get; set; } - [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] - public Meeting Meeting { get; set; } - } + [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] + public Meeting Meeting { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs index c44ec9ae..09265530 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs @@ -3,41 +3,40 @@ using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IHumiditySensorMessenger : MessengerBase { - public class IHumiditySensorMessenger : MessengerBase + private readonly IHumiditySensor device; + + public IHumiditySensorMessenger(string key, IHumiditySensor device, string messagePath) + : base(key, messagePath, device as IKeyName) { - private readonly IHumiditySensor device; - - public IHumiditySensorMessenger(string key, IHumiditySensor device, string messagePath) - : base(key, messagePath, device as IKeyName) - { - this.device = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - device.HumidityFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); - } - - private void SendFullStatus() - { - var state = new IHumiditySensorStateMessage - { - Humidity = string.Format("{0}%", device.HumidityFeedback.UShortValue) - }; - - PostStatusMessage(state); - } + this.device = device; } - public class IHumiditySensorStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("humidity")] - public string Humidity { get; set; } + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + device.HumidityFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); + } + + private void SendFullStatus() + { + var state = new IHumiditySensorStateMessage + { + Humidity = string.Format("{0}%", device.HumidityFeedback.UShortValue) + }; + + PostStatusMessage(state); } } + +public class IHumiditySensorStateMessage : DeviceStateMessageBase +{ + [JsonProperty("humidity")] + public string Humidity { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs index 4fd3515a..b06a5c4a 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs @@ -5,87 +5,86 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class ILevelControlsMessenger : MessengerBase { - public class ILevelControlsMessenger : MessengerBase + private ILevelControls levelControlsDevice; + public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as IKeyName) { - private ILevelControls levelControlsDevice; - public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as IKeyName) - { - levelControlsDevice = device; - } + levelControlsDevice = device; + } - protected override void RegisterActions() - { - base.RegisterActions(); + protected override void RegisterActions() + { + base.RegisterActions(); - AddAction("/fullStatus", (id, context) => + AddAction("/fullStatus", (id, context) => + { + var message = new LevelControlStateMessage { - var message = new LevelControlStateMessage - { - Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue }) - }; + Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue }) + }; - PostStatusMessage(message); + PostStatusMessage(message); + }); + + foreach (var levelControl in levelControlsDevice.LevelControlPoints) + { + // reassigning here just in case of lambda closure issues + var key = levelControl.Key; + var control = levelControl.Value; + + AddAction($"/{key}/level", (id, content) => + { + var request = content.ToObject>(); + + control.SetVolume(request.Value); }); - foreach (var levelControl in levelControlsDevice.LevelControlPoints) + AddAction($"/{key}/muteToggle", (id, content) => { - // reassigning here just in case of lambda closure issues - var key = levelControl.Key; - var control = levelControl.Value; + control.MuteToggle(); + }); - AddAction($"/{key}/level", (id, content) => + AddAction($"/{key}/muteOn", (id, content) => control.MuteOn()); + + AddAction($"/{key}/muteOff", (id, content) => control.MuteOff()); + + AddAction($"/{key}/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => control.VolumeUp(b))); + + AddAction($"/{key}/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => control.VolumeDown(b))); + + control.VolumeLevelFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new + { + levelControls = new Dictionary { - var request = content.ToObject>(); + {key, new Volume{Level = a.IntValue} } + } + })); - control.SetVolume(request.Value); - }); - - AddAction($"/{key}/muteToggle", (id, content) => + control.MuteFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new + { + levelControls = new Dictionary { - control.MuteToggle(); - }); - - AddAction($"/{key}/muteOn", (id, content) => control.MuteOn()); - - AddAction($"/{key}/muteOff", (id, content) => control.MuteOff()); - - AddAction($"/{key}/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => control.VolumeUp(b))); - - AddAction($"/{key}/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => control.VolumeDown(b))); - - control.VolumeLevelFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new - { - levelControls = new Dictionary - { - {key, new Volume{Level = a.IntValue} } - } - })); - - control.MuteFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new - { - levelControls = new Dictionary - { - {key, new Volume{Muted = a.BoolValue} } - } - })); - } + {key, new Volume{Muted = a.BoolValue} } + } + })); } } - - public class LevelControlStateMessage : DeviceStateMessageBase - { - [JsonProperty("levelControls")] - public Dictionary Levels { get; set; } - } - - public class LevelControlRequestMessage - { - [JsonProperty("key")] - public string Key { get; set; } - - [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] - public ushort? Level { get; set; } - } +} + +public class LevelControlStateMessage : DeviceStateMessageBase +{ + [JsonProperty("levelControls")] + public Dictionary Levels { get; set; } +} + +public class LevelControlRequestMessage +{ + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] + public ushort? Level { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs index 2a9669f1..cdad6989 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs @@ -8,161 +8,160 @@ using System; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Messenger for devices that implment IMatrixRouting +/// +public class IMatrixRoutingMessenger : MessengerBase { - /// - /// Messenger for devices that implment IMatrixRouting - /// - public class IMatrixRoutingMessenger : MessengerBase + private readonly IMatrixRouting matrixDevice; + public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName) { - private readonly IMatrixRouting matrixDevice; - public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName) + matrixDevice = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => { - matrixDevice = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => + try { - try + Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count); + var message = new MatrixStateMessage { - Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count); - var message = new MatrixStateMessage - { - Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)), - Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)), - }; - - - PostStatusMessage(message); - } - catch (Exception e) - { - Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e); - } - }); - - AddAction("/route", (id, content) => - { - var request = content.ToObject(); - - matrixDevice.Route(request.InputKey, request.OutputKey, request.RouteType); - }); - - foreach (var output in matrixDevice.OutputSlots) - { - var key = output.Key; - var outputSlot = output.Value; - - outputSlot.OutputSlotChanged += (sender, args) => - { - PostStatusMessage(JToken.FromObject(new - { - outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)) - })); + Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)), + Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)), }; - } - foreach (var input in matrixDevice.InputSlots) + + PostStatusMessage(message); + } + catch (Exception e) { - var key = input.Key; - var inputSlot = input.Value; - - inputSlot.VideoSyncChanged += (sender, args) => - { - PostStatusMessage(JToken.FromObject(new - { - inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)) - })); - }; + Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e); } - } - } + }); - public class MatrixStateMessage : DeviceStateMessageBase - { - [JsonProperty("outputs")] - public Dictionary Outputs; - - [JsonProperty("inputs")] - public Dictionary Inputs; - } - - public class RoutingInput - { - private IRoutingInputSlot _input; - - [JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)] - public string TxDeviceKey => _input?.TxDeviceKey; - - [JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)] - public int? SlotNumber => _input?.SlotNumber; - - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - [JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)] - public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes; - - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string Name => _input?.Name; - - [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsOnline => _input?.IsOnline.BoolValue; - - [JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)] - - public bool? VideoSyncDetected => _input?.VideoSyncDetected; - - [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] - public string Key => _input?.Key; - - public RoutingInput(IRoutingInputSlot input) + AddAction("/route", (id, content) => { - _input = input; - } - } + var request = content.ToObject(); - public class RoutingOutput - { - private IRoutingOutputSlot _output; + matrixDevice.Route(request.InputKey, request.OutputKey, request.RouteType); + }); - - public RoutingOutput(IRoutingOutputSlot output) + foreach (var output in matrixDevice.OutputSlots) { - _output = output; + var key = output.Key; + var outputSlot = output.Value; + + outputSlot.OutputSlotChanged += (sender, args) => + { + PostStatusMessage(JToken.FromObject(new + { + outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)) + })); + }; } - [JsonProperty("rxDeviceKey")] - public string RxDeviceKey => _output.RxDeviceKey; + foreach (var input in matrixDevice.InputSlots) + { + var key = input.Key; + var inputSlot = input.Value; - [JsonProperty("currentRoutes")] - public Dictionary CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value)); - - [JsonProperty("slotNumber")] - public int SlotNumber => _output.SlotNumber; - - [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - [JsonProperty("supportedSignalTypes")] - public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes; - - [JsonProperty("name")] - public string Name => _output.Name; - - [JsonProperty("key")] - public string Key => _output.Key; - } - - public class MatrixRouteRequest - { - [JsonProperty("outputKey")] - public string OutputKey { get; set; } - - [JsonProperty("inputKey")] - public string InputKey { get; set; } - - [JsonProperty("routeType")] - public eRoutingSignalType RouteType { get; set; } + inputSlot.VideoSyncChanged += (sender, args) => + { + PostStatusMessage(JToken.FromObject(new + { + inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)) + })); + }; + } } } + +public class MatrixStateMessage : DeviceStateMessageBase +{ + [JsonProperty("outputs")] + public Dictionary Outputs; + + [JsonProperty("inputs")] + public Dictionary Inputs; +} + +public class RoutingInput +{ + private IRoutingInputSlot _input; + + [JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)] + public string TxDeviceKey => _input?.TxDeviceKey; + + [JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)] + public int? SlotNumber => _input?.SlotNumber; + + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + [JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)] + public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes; + + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name => _input?.Name; + + [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsOnline => _input?.IsOnline.BoolValue; + + [JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)] + + public bool? VideoSyncDetected => _input?.VideoSyncDetected; + + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key => _input?.Key; + + public RoutingInput(IRoutingInputSlot input) + { + _input = input; + } +} + +public class RoutingOutput +{ + private IRoutingOutputSlot _output; + + + public RoutingOutput(IRoutingOutputSlot output) + { + _output = output; + } + + [JsonProperty("rxDeviceKey")] + public string RxDeviceKey => _output.RxDeviceKey; + + [JsonProperty("currentRoutes")] + public Dictionary CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value)); + + [JsonProperty("slotNumber")] + public int SlotNumber => _output.SlotNumber; + + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + [JsonProperty("supportedSignalTypes")] + public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes; + + [JsonProperty("name")] + public string Name => _output.Name; + + [JsonProperty("key")] + public string Key => _output.Key; +} + +public class MatrixRouteRequest +{ + [JsonProperty("outputKey")] + public string OutputKey { get; set; } + + [JsonProperty("inputKey")] + public string InputKey { get; set; } + + [JsonProperty("routeType")] + public eRoutingSignalType RouteType { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs index a66a8586..cc114794 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs @@ -5,74 +5,73 @@ using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IProjectorScreenLiftControlMessenger : MessengerBase { - public class IProjectorScreenLiftControlMessenger : MessengerBase + private readonly IProjectorScreenLiftControl device; + + public IProjectorScreenLiftControlMessenger(string key, string messagePath, IProjectorScreenLiftControl screenLiftDevice) + : base(key, messagePath, screenLiftDevice as IKeyName) { - private readonly IProjectorScreenLiftControl device; - - public IProjectorScreenLiftControlMessenger(string key, string messagePath, IProjectorScreenLiftControl screenLiftDevice) - : base(key, messagePath, screenLiftDevice as IKeyName) - { - device = screenLiftDevice; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - AddAction("/raise", (id, content) => - { - - device.Raise(); - - }); - - AddAction("/lower", (id, content) => - { - - device.Lower(); - - }); - - device.PositionChanged += Device_PositionChanged; - - } - - private void Device_PositionChanged(object sender, EventArgs e) - { - var state = new - { - inUpPosition = device.InUpPosition - }; - PostStatusMessage(JToken.FromObject(state)); - } - - private void SendFullStatus() - { - var state = new ScreenLiftStateMessage - { - InUpPosition = device.InUpPosition, - Type = device.Type, - DisplayDeviceKey = device.DisplayDeviceKey - }; - - PostStatusMessage(state); - } + device = screenLiftDevice; } - public class ScreenLiftStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("inUpPosition", NullValueHandling = NullValueHandling.Ignore)] - public bool? InUpPosition { get; set; } + base.RegisterActions(); - [JsonProperty("displayDeviceKey", NullValueHandling = NullValueHandling.Ignore)] - public string DisplayDeviceKey { get; set; } + AddAction("/fullStatus", (id, content) => SendFullStatus()); - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] - public eScreenLiftControlType Type { get; set; } + AddAction("/raise", (id, content) => + { + + device.Raise(); + + }); + + AddAction("/lower", (id, content) => + { + + device.Lower(); + + }); + + device.PositionChanged += Device_PositionChanged; + + } + + private void Device_PositionChanged(object sender, EventArgs e) + { + var state = new + { + inUpPosition = device.InUpPosition + }; + PostStatusMessage(JToken.FromObject(state)); + } + + private void SendFullStatus() + { + var state = new ScreenLiftStateMessage + { + InUpPosition = device.InUpPosition, + Type = device.Type, + DisplayDeviceKey = device.DisplayDeviceKey + }; + + PostStatusMessage(state); } } + +public class ScreenLiftStateMessage : DeviceStateMessageBase +{ + [JsonProperty("inUpPosition", NullValueHandling = NullValueHandling.Ignore)] + public bool? InUpPosition { get; set; } + + [JsonProperty("displayDeviceKey", NullValueHandling = NullValueHandling.Ignore)] + public string DisplayDeviceKey { get; set; } + + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + public eScreenLiftControlType Type { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs index 8ca6668b..e4ac3e5c 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs @@ -5,80 +5,79 @@ using PepperDash.Essentials.Core; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class RunRouteActionMessenger : MessengerBase { - public class RunRouteActionMessenger : MessengerBase + /// + /// Device being bridged + /// + public IRunRouteAction RoutingDevice { get; private set; } + + public RunRouteActionMessenger(string key, IRunRouteAction routingDevice, string messagePath) + : base(key, messagePath, routingDevice as IKeyName) { - /// - /// Device being bridged - /// - public IRunRouteAction RoutingDevice { get; private set; } + RoutingDevice = routingDevice ?? throw new ArgumentNullException("routingDevice"); - public RunRouteActionMessenger(string key, IRunRouteAction routingDevice, string messagePath) - : base(key, messagePath, routingDevice as IKeyName) + + if (RoutingDevice is IRoutingSink routingSink) { - RoutingDevice = routingDevice ?? throw new ArgumentNullException("routingDevice"); - - - if (RoutingDevice is IRoutingSink routingSink) - { - routingSink.CurrentSourceChange += RoutingSink_CurrentSourceChange; - } - } - - private void RoutingSink_CurrentSourceChange(SourceListItem info, ChangeType type) - { - SendRoutingFullMessageObject(); - } - - protected override void RegisterActions() - { - AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject()); - - AddAction("/source", (id, content) => - { - var c = content.ToObject(); - // assume no sourceListKey - var sourceListKey = string.Empty; - - if (!string.IsNullOrEmpty(c.SourceListKey)) - { - // Check for source list in content of message - sourceListKey = c.SourceListKey; - } - - RoutingDevice.RunRouteAction(c.SourceListItemKey, sourceListKey); - }); - - if (RoutingDevice is IRoutingSink sinkDevice) - { - sinkDevice.CurrentSourceChange += (o, a) => SendRoutingFullMessageObject(); - } - } - - /// - /// Helper method to update full status of the routing device - /// - private void SendRoutingFullMessageObject() - { - if (RoutingDevice is IRoutingSink sinkDevice) - { - var sourceKey = sinkDevice.CurrentSourceInfoKey; - - if (string.IsNullOrEmpty(sourceKey)) - sourceKey = "none"; - - PostStatusMessage(new RoutingStateMessage - { - SelectedSourceKey = sourceKey - }); - } + routingSink.CurrentSourceChange += RoutingSink_CurrentSourceChange; } } - public class RoutingStateMessage : DeviceStateMessageBase + private void RoutingSink_CurrentSourceChange(SourceListItem info, ChangeType type) { - [JsonProperty("selectedSourceKey")] - public string SelectedSourceKey { get; set; } + SendRoutingFullMessageObject(); } + + protected override void RegisterActions() + { + AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject()); + + AddAction("/source", (id, content) => + { + var c = content.ToObject(); + // assume no sourceListKey + var sourceListKey = string.Empty; + + if (!string.IsNullOrEmpty(c.SourceListKey)) + { + // Check for source list in content of message + sourceListKey = c.SourceListKey; + } + + RoutingDevice.RunRouteAction(c.SourceListItemKey, sourceListKey); + }); + + if (RoutingDevice is IRoutingSink sinkDevice) + { + sinkDevice.CurrentSourceChange += (o, a) => SendRoutingFullMessageObject(); + } + } + + /// + /// Helper method to update full status of the routing device + /// + private void SendRoutingFullMessageObject() + { + if (RoutingDevice is IRoutingSink sinkDevice) + { + var sourceKey = sinkDevice.CurrentSourceInfoKey; + + if (string.IsNullOrEmpty(sourceKey)) + sourceKey = "none"; + + PostStatusMessage(new RoutingStateMessage + { + SelectedSourceKey = sourceKey + }); + } + } +} + +public class RoutingStateMessage : DeviceStateMessageBase +{ + [JsonProperty("selectedSourceKey")] + public string SelectedSourceKey { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs index d7c4a59f..04747dbc 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs @@ -5,91 +5,89 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers -{ - public class ISelectableItemsMessenger : MessengerBase - { - private readonly ISelectableItems itemDevice; +namespace PepperDash.Essentials.AppServer.Messengers; - private readonly string _propName; +public class ISelectableItemsMessenger : MessengerBase +{ + private readonly ISelectableItems itemDevice; - /// - /// Constructs a messenger for a device that implements ISelectableItems - /// - /// - /// - /// - /// - public ISelectableItemsMessenger(string key, string messagePath, ISelectableItems device, string propName) : base(key, messagePath, device as IKeyName) + private readonly string _propName; + + /// + /// Constructs a messenger for a device that implements ISelectableItems + /// + /// + /// + /// + /// + public ISelectableItemsMessenger(string key, string messagePath, ISelectableItems device, string propName) : base(key, messagePath, device as IKeyName) + { + itemDevice = device; + _propName = propName; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, context) => { - itemDevice = device; - _propName = propName; - } + SendFullStatus(); + }); - protected override void RegisterActions() + itemDevice.ItemsUpdated += (sender, args) => { - base.RegisterActions(); + SendFullStatus(); + }; - AddAction("/fullStatus", (id, context) => + itemDevice.CurrentItemChanged += (sender, args) => + { + SendFullStatus(); + }; + + foreach (var input in itemDevice.Items) + { + var key = input.Key; + var localItem = input.Value; + + AddAction($"/{key}", (id, content) => { - SendFullStatus(); + localItem.Select(); }); - itemDevice.ItemsUpdated += (sender, args) => + localItem.ItemUpdated += (sender, args) => { SendFullStatus(); }; - - itemDevice.CurrentItemChanged += (sender, args) => - { - SendFullStatus(); - }; - - foreach (var input in itemDevice.Items) - { - var key = input.Key; - var localItem = input.Value; - - AddAction($"/{key}", (id, content) => - { - localItem.Select(); - }); - - localItem.ItemUpdated += (sender, args) => - { - SendFullStatus(); - }; - } - } - - private void SendFullStatus() - { - try - { - this.LogInformation("Sending full status"); - - var stateObject = new ISelectableItemsStateMessage - { - Items = itemDevice.Items, - CurrentItem = itemDevice.CurrentItem - }; - - PostStatusMessage(stateObject); - } - catch (Exception e) - { - this.LogError("Error sending full status: {0}", e.Message); - } } } - public class ISelectableItemsStateMessage : DeviceStateMessageBase + private void SendFullStatus() { - [JsonProperty("items")] - public Dictionary Items { get; set; } + try + { + this.LogInformation("Sending full status"); - [JsonProperty("currentItem")] - public TKey CurrentItem { get; set; } + var stateObject = new ISelectableItemsStateMessage + { + Items = itemDevice.Items, + CurrentItem = itemDevice.CurrentItem + }; + + PostStatusMessage(stateObject); + } + catch (Exception e) + { + this.LogError("Error sending full status: {0}", e.Message); + } } - +} + +public class ISelectableItemsStateMessage : DeviceStateMessageBase +{ + [JsonProperty("items")] + public Dictionary Items { get; set; } + + [JsonProperty("currentItem")] + public TKey CurrentItem { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs index ca5fc3d3..23adcef8 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs @@ -3,91 +3,90 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IShutdownPromptTimerMessenger : MessengerBase { - public class IShutdownPromptTimerMessenger : MessengerBase + private readonly IShutdownPromptTimer _room; + + public IShutdownPromptTimerMessenger(string key, string messagePath, IShutdownPromptTimer room) + : base(key, messagePath, room as IKeyName) { - private readonly IShutdownPromptTimer _room; - - public IShutdownPromptTimerMessenger(string key, string messagePath, IShutdownPromptTimer room) - : base(key, messagePath, room as IKeyName) - { - _room = room; - } - - protected override void RegisterActions() - { - AddAction("/status", (id, content) => - { - SendFullStatus(); - }); - - AddAction("/setShutdownPromptSeconds", (id, content) => - { - var response = content.ToObject(); - - _room.SetShutdownPromptSeconds(response); - - SendFullStatus(); - }); - - AddAction("/shutdownStart", (id, content) => _room.StartShutdown(eShutdownType.Manual)); - - AddAction("/shutdownEnd", (id, content) => _room.ShutdownPromptTimer.Finish()); - - AddAction("/shutdownCancel", (id, content) => _room.ShutdownPromptTimer.Cancel()); - - - _room.ShutdownPromptTimer.HasStarted += (sender, args) => - { - PostEventMessage("timerStarted"); - }; - - _room.ShutdownPromptTimer.HasFinished += (sender, args) => - { - PostEventMessage("timerFinished"); - }; - - _room.ShutdownPromptTimer.WasCancelled += (sender, args) => - { - PostEventMessage("timerCancelled"); - }; - - _room.ShutdownPromptTimer.SecondsRemainingFeedback.OutputChange += (sender, args) => - { - var status = new - { - secondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, - percentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue - }; - - PostStatusMessage(JToken.FromObject(status)); - }; - } - - private void SendFullStatus() - { - var status = new IShutdownPromptTimerStateMessage - { - ShutdownPromptSeconds = _room.ShutdownPromptTimer.SecondsToCount, - SecondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, - PercentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue - }; - - PostStatusMessage(status); - } + _room = room; } - - public class IShutdownPromptTimerStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("secondsRemaining")] - public int SecondsRemaining { get; set; } + AddAction("/status", (id, content) => + { + SendFullStatus(); + }); - [JsonProperty("percentageRemaining")] - public int PercentageRemaining { get; set; } + AddAction("/setShutdownPromptSeconds", (id, content) => + { + var response = content.ToObject(); - [JsonProperty("shutdownPromptSeconds")] - public int ShutdownPromptSeconds { get; set; } + _room.SetShutdownPromptSeconds(response); + + SendFullStatus(); + }); + + AddAction("/shutdownStart", (id, content) => _room.StartShutdown(eShutdownType.Manual)); + + AddAction("/shutdownEnd", (id, content) => _room.ShutdownPromptTimer.Finish()); + + AddAction("/shutdownCancel", (id, content) => _room.ShutdownPromptTimer.Cancel()); + + + _room.ShutdownPromptTimer.HasStarted += (sender, args) => + { + PostEventMessage("timerStarted"); + }; + + _room.ShutdownPromptTimer.HasFinished += (sender, args) => + { + PostEventMessage("timerFinished"); + }; + + _room.ShutdownPromptTimer.WasCancelled += (sender, args) => + { + PostEventMessage("timerCancelled"); + }; + + _room.ShutdownPromptTimer.SecondsRemainingFeedback.OutputChange += (sender, args) => + { + var status = new + { + secondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, + percentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue + }; + + PostStatusMessage(JToken.FromObject(status)); + }; + } + + private void SendFullStatus() + { + var status = new IShutdownPromptTimerStateMessage + { + ShutdownPromptSeconds = _room.ShutdownPromptTimer.SecondsToCount, + SecondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, + PercentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue + }; + + PostStatusMessage(status); } } + + +public class IShutdownPromptTimerStateMessage : DeviceStateMessageBase +{ + [JsonProperty("secondsRemaining")] + public int SecondsRemaining { get; set; } + + [JsonProperty("percentageRemaining")] + public int PercentageRemaining { get; set; } + + [JsonProperty("shutdownPromptSeconds")] + public int ShutdownPromptSeconds { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs index f49d189d..a5d5f7e2 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs @@ -3,56 +3,55 @@ using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class ISwitchedOutputMessenger : MessengerBase { - public class ISwitchedOutputMessenger : MessengerBase + + private readonly ISwitchedOutput device; + + public ISwitchedOutputMessenger(string key, ISwitchedOutput device, string messagePath) + : base(key, messagePath, device as IKeyName) { - - private readonly ISwitchedOutput device; - - public ISwitchedOutputMessenger(string key, ISwitchedOutput device, string messagePath) - : base(key, messagePath, device as IKeyName) - { - this.device = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - AddAction("/on", (id, content) => - { - - device.On(); - - }); - - AddAction("/off", (id, content) => - { - - device.Off(); - - }); - - device.OutputIsOnFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); - } - - private void SendFullStatus() - { - var state = new ISwitchedOutputStateMessage - { - IsOn = device.OutputIsOnFeedback.BoolValue - }; - - PostStatusMessage(state); - } + this.device = device; } - public class ISwitchedOutputStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("isOn")] - public bool IsOn { get; set; } + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/on", (id, content) => + { + + device.On(); + + }); + + AddAction("/off", (id, content) => + { + + device.Off(); + + }); + + device.OutputIsOnFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); + } + + private void SendFullStatus() + { + var state = new ISwitchedOutputStateMessage + { + IsOn = device.OutputIsOnFeedback.BoolValue + }; + + PostStatusMessage(state); } } + +public class ISwitchedOutputStateMessage : DeviceStateMessageBase +{ + [JsonProperty("isOn")] + public bool IsOn { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs index 5b15d7ab..8f64c9d5 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs @@ -2,87 +2,85 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class ITechPasswordMessenger : MessengerBase { - public class ITechPasswordMessenger : MessengerBase + private readonly ITechPassword _room; + + public ITechPasswordMessenger(string key, string messagePath, ITechPassword room) + : base(key, messagePath, room as IKeyName) { - private readonly ITechPassword _room; - - public ITechPasswordMessenger(string key, string messagePath, ITechPassword room) - : base(key, messagePath, room as IKeyName) - { - _room = room; - } - - protected override void RegisterActions() - { - - AddAction("/status", (id, content) => - { - SendFullStatus(); - }); - - AddAction("/validateTechPassword", (id, content) => - { - var password = content.Value("password"); - - _room.ValidateTechPassword(password); - }); - - AddAction("/setTechPassword", (id, content) => - { - var response = content.ToObject(); - - _room.SetTechPassword(response.OldPassword, response.NewPassword); - }); - - _room.TechPasswordChanged += (sender, args) => - { - PostEventMessage("passwordChangedSuccessfully"); - }; - - _room.TechPasswordValidateResult += (sender, args) => - { - var evt = new ITechPasswordEventMessage - { - IsValid = args.IsValid - }; - - PostEventMessage(evt, "passwordValidationResult"); - }; - } - - private void SendFullStatus() - { - var status = new ITechPasswordStateMessage - { - TechPasswordLength = _room.TechPasswordLength - }; - - PostStatusMessage(status); - } - + _room = room; } - public class ITechPasswordStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("techPasswordLength", NullValueHandling = NullValueHandling.Ignore)] - public int? TechPasswordLength { get; set; } + + AddAction("/status", (id, content) => + { + SendFullStatus(); + }); + + AddAction("/validateTechPassword", (id, content) => + { + var password = content.Value("password"); + + _room.ValidateTechPassword(password); + }); + + AddAction("/setTechPassword", (id, content) => + { + var response = content.ToObject(); + + _room.SetTechPassword(response.OldPassword, response.NewPassword); + }); + + _room.TechPasswordChanged += (sender, args) => + { + PostEventMessage("passwordChangedSuccessfully"); + }; + + _room.TechPasswordValidateResult += (sender, args) => + { + var evt = new ITechPasswordEventMessage + { + IsValid = args.IsValid + }; + + PostEventMessage(evt, "passwordValidationResult"); + }; } - public class ITechPasswordEventMessage : DeviceEventMessageBase + private void SendFullStatus() { - [JsonProperty("isValid", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsValid { get; set; } - } + var status = new ITechPasswordStateMessage + { + TechPasswordLength = _room.TechPasswordLength + }; - internal class SetTechPasswordContent - { - [JsonProperty("oldPassword")] - public string OldPassword { get; set; } - - [JsonProperty("newPassword")] - public string NewPassword { get; set; } + PostStatusMessage(status); } } + +public class ITechPasswordStateMessage : DeviceStateMessageBase +{ + [JsonProperty("techPasswordLength", NullValueHandling = NullValueHandling.Ignore)] + public int? TechPasswordLength { get; set; } +} + +public class ITechPasswordEventMessage : DeviceEventMessageBase +{ + [JsonProperty("isValid", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsValid { get; set; } +} + +internal class SetTechPasswordContent +{ + [JsonProperty("oldPassword")] + public string OldPassword { get; set; } + + [JsonProperty("newPassword")] + public string NewPassword { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs index 6f7371c1..84c34969 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs @@ -3,59 +3,58 @@ using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class ITemperatureSensorMessenger : MessengerBase { - public class ITemperatureSensorMessenger : MessengerBase + private readonly ITemperatureSensor device; + + public ITemperatureSensorMessenger(string key, ITemperatureSensor device, string messagePath) + : base(key, messagePath, device as IKeyName) { - private readonly ITemperatureSensor device; - - public ITemperatureSensorMessenger(string key, ITemperatureSensor device, string messagePath) - : base(key, messagePath, device as IKeyName) - { - this.device = device; - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - AddAction("/setTemperatureUnitsToCelcius", (id, content) => - { - device.SetTemperatureFormat(true); - }); - - AddAction("/setTemperatureUnitsToFahrenheit", (id, content) => - { - device.SetTemperatureFormat(false); - }); - - device.TemperatureFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); - device.TemperatureInCFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); - } - - private void SendFullStatus() - { - // format the temperature to a string with one decimal place - var tempString = string.Format("{0}.{1}", device.TemperatureFeedback.UShortValue / 10, device.TemperatureFeedback.UShortValue % 10); - - var state = new ITemperatureSensorStateMessage - { - Temperature = tempString, - TemperatureInCelsius = device.TemperatureInCFeedback.BoolValue - }; - - PostStatusMessage(state); - } + this.device = device; } - public class ITemperatureSensorStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("temperature")] - public string Temperature { get; set; } + base.RegisterActions(); - [JsonProperty("temperatureInCelsius")] - public bool TemperatureInCelsius { get; set; } + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/setTemperatureUnitsToCelcius", (id, content) => + { + device.SetTemperatureFormat(true); + }); + + AddAction("/setTemperatureUnitsToFahrenheit", (id, content) => + { + device.SetTemperatureFormat(false); + }); + + device.TemperatureFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); + device.TemperatureInCFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); + } + + private void SendFullStatus() + { + // format the temperature to a string with one decimal place + var tempString = string.Format("{0}.{1}", device.TemperatureFeedback.UShortValue / 10, device.TemperatureFeedback.UShortValue % 10); + + var state = new ITemperatureSensorStateMessage + { + Temperature = tempString, + TemperatureInCelsius = device.TemperatureInCFeedback.BoolValue + }; + + PostStatusMessage(state); } } + +public class ITemperatureSensorStateMessage : DeviceStateMessageBase +{ + [JsonProperty("temperature")] + public string Temperature { get; set; } + + [JsonProperty("temperatureInCelsius")] + public bool TemperatureInCelsius { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs index 8ae91d36..ccb1a70b 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs @@ -4,67 +4,66 @@ using PepperDash.Essentials.Core.Lighting; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class ILightingScenesMessenger : MessengerBase { - public class ILightingScenesMessenger : MessengerBase + private ILightingScenes lightingScenesDevice; + + public ILightingScenesMessenger(string key, ILightingScenes device, string messagePath) + : base(key, messagePath, device as IKeyName) { - private ILightingScenes lightingScenesDevice; + lightingScenesDevice = device ?? throw new ArgumentNullException("device"); - public ILightingScenesMessenger(string key, ILightingScenes device, string messagePath) - : base(key, messagePath, device as IKeyName) - { - lightingScenesDevice = device ?? throw new ArgumentNullException("device"); - - lightingScenesDevice.LightingSceneChange += new EventHandler(LightingDevice_LightingSceneChange); - } - - private void LightingDevice_LightingSceneChange(object sender, LightingSceneChangeEventArgs e) - { - var state = new LightingBaseStateMessage - { - CurrentLightingScene = e.CurrentLightingScene - }; - - PostStatusMessage(state); - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - AddAction("/selectScene", (id, content) => - { - var s = content.ToObject(); - lightingScenesDevice.SelectScene(s); - }); - - if(!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic)) - return; - - lightingScenesDynamic.LightingScenesUpdated += (s, e) => SendFullStatus(); - } - - - private void SendFullStatus() - { - var state = new LightingBaseStateMessage - { - Scenes = lightingScenesDevice.LightingScenes, - CurrentLightingScene = lightingScenesDevice.CurrentLightingScene - }; - - PostStatusMessage(state); - } + lightingScenesDevice.LightingSceneChange += new EventHandler(LightingDevice_LightingSceneChange); } - public class LightingBaseStateMessage : DeviceStateMessageBase + private void LightingDevice_LightingSceneChange(object sender, LightingSceneChangeEventArgs e) { - [JsonProperty("scenes", NullValueHandling = NullValueHandling.Ignore)] - public List Scenes { get; set; } + var state = new LightingBaseStateMessage + { + CurrentLightingScene = e.CurrentLightingScene + }; - [JsonProperty("currentLightingScene", NullValueHandling = NullValueHandling.Ignore)] - public LightingScene CurrentLightingScene { get; set; } + PostStatusMessage(state); } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/selectScene", (id, content) => + { + var s = content.ToObject(); + lightingScenesDevice.SelectScene(s); + }); + + if(!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic)) + return; + + lightingScenesDynamic.LightingScenesUpdated += (s, e) => SendFullStatus(); + } + + + private void SendFullStatus() + { + var state = new LightingBaseStateMessage + { + Scenes = lightingScenesDevice.LightingScenes, + CurrentLightingScene = lightingScenesDevice.CurrentLightingScene + }; + + PostStatusMessage(state); + } +} + +public class LightingBaseStateMessage : DeviceStateMessageBase +{ + [JsonProperty("scenes", NullValueHandling = NullValueHandling.Ignore)] + public List Scenes { get; set; } + + [JsonProperty("currentLightingScene", NullValueHandling = NullValueHandling.Ignore)] + public LightingScene CurrentLightingScene { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs index c3a612bc..03a69c04 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs @@ -8,286 +8,284 @@ using System; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Provides a messaging bridge +/// +public abstract class MessengerBase : EssentialsDevice, IMobileControlMessenger +{ + protected IKeyName _device; + + private readonly List _deviceInterfaces; + + private readonly Dictionary> _actions = new Dictionary>(); + + public string DeviceKey => _device?.Key ?? ""; + + /// + /// + /// + + public IMobileControl AppServerController { get; private set; } + + public string MessagePath { get; private set; } + + /// + /// + /// + /// + /// + protected MessengerBase(string key, string messagePath) + : base(key) + { + Key = key; + + if (string.IsNullOrEmpty(messagePath)) + throw new ArgumentException("messagePath must not be empty or null"); + + MessagePath = messagePath; + } + + protected MessengerBase(string key, string messagePath, IKeyName device) + : this(key, messagePath) + { + _device = device; + + _deviceInterfaces = GetInterfaces(_device as Device); + } + + /// + /// Gets the interfaces implmented on the device + /// + /// + /// + private List GetInterfaces(Device device) + { + return device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); + } + + /// + /// Registers this messenger with appserver controller + /// + /// + public void RegisterWithAppServer(IMobileControl appServerController) + { + AppServerController = appServerController ?? throw new ArgumentNullException("appServerController"); + + AppServerController.AddAction(this, HandleMessage); + + RegisterActions(); + } + + private void HandleMessage(string path, string id, JToken content) + { + // replace base path with empty string. Should leave something like /fullStatus + var route = path.Replace(MessagePath, string.Empty); + + if (!_actions.TryGetValue(route, out var action)) + { + return; + } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Executing action for path {path}", this, path); + + action(id, content); + } + + protected void AddAction(string path, Action action) + { + if (_actions.ContainsKey(path)) + { + //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Messenger {Key} already has action registered at {path}", this); + return; + } + + _actions.Add(path, action); + } + + public List GetActionPaths() + { + return _actions.Keys.ToList(); + } + + protected void RemoveAction(string path) + { + if (!_actions.ContainsKey(path)) + { + return; + } + + _actions.Remove(path); + } + + /// + /// Implemented in extending classes. Wire up API calls and feedback here + /// + /// + protected virtual void RegisterActions() + { + + } + + /// + /// Helper for posting status message + /// + /// + /// + protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null) + { + try + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + if (_device == null) + { + throw new ArgumentNullException("device"); + } + + message.SetInterfaces(_deviceInterfaces); + + message.Key = _device.Key; + + message.Name = _device.Name; + + var token = JToken.FromObject(message); + + PostStatusMessage(token, MessagePath, clientId); + } + catch (Exception ex) + { + this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients"); + } + } + + protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null) + { + try + { + //Debug.Console(2, this, "*********************Setting DeviceStateMessageProperties on MobileControlResponseMessage"); + deviceState.SetInterfaces(_deviceInterfaces); + + deviceState.Key = _device.Key; + + deviceState.Name = _device.Name; + + deviceState.MessageBasePath = MessagePath; + + var token = JToken.FromObject(deviceState); + + PostStatusMessage(token, type, clientId); + } + catch (Exception ex) + { + this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients"); + } + } + + protected void PostStatusMessage(JToken content, string type = "", string clientId = null) + { + try + { + AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception posting status message", this); + } + } + + protected void PostEventMessage(DeviceEventMessageBase message) + { + message.Key = _device.Key; + + message.Name = _device.Name; + + AppServerController?.SendMessageObject(new MobileControlMessage + { + Type = $"/event{MessagePath}/{message.EventType}", + Content = JToken.FromObject(message), + }); + } + + protected void PostEventMessage(DeviceEventMessageBase message, string eventType) + { + message.Key = _device.Key; + + message.Name = _device.Name; + + message.EventType = eventType; + + AppServerController?.SendMessageObject(new MobileControlMessage + { + Type = $"/event{MessagePath}/{eventType}", + Content = JToken.FromObject(message), + }); + } + + protected void PostEventMessage(string eventType) + { + AppServerController?.SendMessageObject(new MobileControlMessage + { + Type = $"/event{MessagePath}/{eventType}", + Content = JToken.FromObject(new { }), + }); + } + +} + +public abstract class DeviceMessageBase { /// - /// Provides a messaging bridge + /// The device key /// - public abstract class MessengerBase : EssentialsDevice, IMobileControlMessenger - { - protected IKeyName _device; - - private readonly List _deviceInterfaces; - - private readonly Dictionary> _actions = new Dictionary>(); - - public string DeviceKey => _device?.Key ?? ""; - - /// - /// - /// - - public IMobileControl AppServerController { get; private set; } - - public string MessagePath { get; private set; } - - /// - /// - /// - /// - /// - protected MessengerBase(string key, string messagePath) - : base(key) - { - Key = key; - - if (string.IsNullOrEmpty(messagePath)) - throw new ArgumentException("messagePath must not be empty or null"); - - MessagePath = messagePath; - } - - protected MessengerBase(string key, string messagePath, IKeyName device) - : this(key, messagePath) - { - _device = device; - - _deviceInterfaces = GetInterfaces(_device as Device); - } - - /// - /// Gets the interfaces implmented on the device - /// - /// - /// - private List GetInterfaces(Device device) - { - return device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); - } - - /// - /// Registers this messenger with appserver controller - /// - /// - public void RegisterWithAppServer(IMobileControl appServerController) - { - AppServerController = appServerController ?? throw new ArgumentNullException("appServerController"); - - AppServerController.AddAction(this, HandleMessage); - - RegisterActions(); - } - - private void HandleMessage(string path, string id, JToken content) - { - // replace base path with empty string. Should leave something like /fullStatus - var route = path.Replace(MessagePath, string.Empty); - - if (!_actions.TryGetValue(route, out var action)) - { - return; - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Executing action for path {path}", this, path); - - action(id, content); - } - - protected void AddAction(string path, Action action) - { - if (_actions.ContainsKey(path)) - { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Messenger {Key} already has action registered at {path}", this); - return; - } - - _actions.Add(path, action); - } - - public List GetActionPaths() - { - return _actions.Keys.ToList(); - } - - protected void RemoveAction(string path) - { - if (!_actions.ContainsKey(path)) - { - return; - } - - _actions.Remove(path); - } - - /// - /// Implemented in extending classes. Wire up API calls and feedback here - /// - /// - protected virtual void RegisterActions() - { - - } - - /// - /// Helper for posting status message - /// - /// - /// - protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null) - { - try - { - if (message == null) - { - throw new ArgumentNullException("message"); - } - - if (_device == null) - { - throw new ArgumentNullException("device"); - } - - message.SetInterfaces(_deviceInterfaces); - - message.Key = _device.Key; - - message.Name = _device.Name; - - var token = JToken.FromObject(message); - - PostStatusMessage(token, MessagePath, clientId); - } - catch (Exception ex) - { - this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients"); - } - } - - protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null) - { - try - { - //Debug.Console(2, this, "*********************Setting DeviceStateMessageProperties on MobileControlResponseMessage"); - deviceState.SetInterfaces(_deviceInterfaces); - - deviceState.Key = _device.Key; - - deviceState.Name = _device.Name; - - deviceState.MessageBasePath = MessagePath; - - var token = JToken.FromObject(deviceState); - - PostStatusMessage(token, type, clientId); - } - catch (Exception ex) - { - this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients"); - } - } - - protected void PostStatusMessage(JToken content, string type = "", string clientId = null) - { - try - { - AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception posting status message", this); - } - } - - protected void PostEventMessage(DeviceEventMessageBase message) - { - message.Key = _device.Key; - - message.Name = _device.Name; - - AppServerController?.SendMessageObject(new MobileControlMessage - { - Type = $"/event{MessagePath}/{message.EventType}", - Content = JToken.FromObject(message), - }); - } - - protected void PostEventMessage(DeviceEventMessageBase message, string eventType) - { - message.Key = _device.Key; - - message.Name = _device.Name; - - message.EventType = eventType; - - AppServerController?.SendMessageObject(new MobileControlMessage - { - Type = $"/event{MessagePath}/{eventType}", - Content = JToken.FromObject(message), - }); - } - - protected void PostEventMessage(string eventType) - { - AppServerController?.SendMessageObject(new MobileControlMessage - { - Type = $"/event{MessagePath}/{eventType}", - Content = JToken.FromObject(new { }), - }); - } - - } - - public abstract class DeviceMessageBase - { - /// - /// The device key - /// - [JsonProperty("key")] - public string Key { get; set; } - - /// - /// The device name - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// The type of the message class - /// - [JsonProperty("messageType")] - public string MessageType => GetType().Name; - - [JsonProperty("messageBasePath")] - public string MessageBasePath { get; set; } - } + [JsonProperty("key")] + public string Key { get; set; } /// - /// Base class for state messages that includes the type of message and the implmented interfaces + /// The device name /// - public class DeviceStateMessageBase : DeviceMessageBase - { - /// - /// The interfaces implmented by the device sending the messsage - /// - [JsonProperty("interfaces")] - public List Interfaces { get; private set; } - - public void SetInterfaces(List interfaces) - { - Interfaces = interfaces; - } - } + [JsonProperty("name")] + public string Name { get; set; } /// - /// Base class for event messages that include the type of message and an event type + /// The type of the message class /// - public abstract class DeviceEventMessageBase : DeviceMessageBase - { - /// - /// The event type - /// - [JsonProperty("eventType")] - public string EventType { get; set; } - } + [JsonProperty("messageType")] + public string MessageType => GetType().Name; + [JsonProperty("messageBasePath")] + public string MessageBasePath { get; set; } +} + +/// +/// Base class for state messages that includes the type of message and the implmented interfaces +/// +public class DeviceStateMessageBase : DeviceMessageBase +{ + /// + /// The interfaces implmented by the device sending the messsage + /// + [JsonProperty("interfaces")] + public List Interfaces { get; private set; } + + public void SetInterfaces(List interfaces) + { + Interfaces = interfaces; + } +} + +/// +/// Base class for event messages that include the type of message and an event type +/// +public abstract class DeviceEventMessageBase : DeviceMessageBase +{ + /// + /// The event type + /// + [JsonProperty("eventType")] + public string EventType { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs index 9ec2a4e4..f6b518e5 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs @@ -4,113 +4,112 @@ using PepperDash.Core; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public static class PressAndHoldHandler { - public static class PressAndHoldHandler + private const long ButtonHeartbeatInterval = 1000; + + private static readonly Dictionary _pushedActions = new Dictionary(); + + private static readonly Dictionary>> _pushedActionHandlers; + + static PressAndHoldHandler() { - private const long ButtonHeartbeatInterval = 1000; - - private static readonly Dictionary _pushedActions = new Dictionary(); - - private static readonly Dictionary>> _pushedActionHandlers; - - static PressAndHoldHandler() + _pushedActionHandlers = new Dictionary>> { - _pushedActionHandlers = new Dictionary>> - { - {"pressed", AddTimer }, - {"held", ResetTimer }, - {"released", StopTimer } - }; + {"pressed", AddTimer }, + {"held", ResetTimer }, + {"released", StopTimer } + }; + } + + private static void AddTimer(string deviceKey, Action action) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to add timer for {deviceKey}", deviceKey); + + if (_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} already exists", deviceKey); + return; } - private static void AddTimer(string deviceKey, Action action) + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Adding timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + + action(true); + + cancelTimer = new CTimer(o => { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to add timer for {deviceKey}", deviceKey); - - if (_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} already exists", deviceKey); - return; - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Adding timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); - - action(true); - - cancelTimer = new CTimer(o => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer expired for {deviceKey}", deviceKey); - - action(false); - - _pushedActions.Remove(deviceKey); - }, ButtonHeartbeatInterval); - - _pushedActions.Add(deviceKey, cancelTimer); - } - - private static void ResetTimer(string deviceKey, Action action) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to reset timer for {deviceKey}", deviceKey); - - if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} not found", deviceKey); - return; - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Resetting timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); - - cancelTimer.Reset(ButtonHeartbeatInterval); - } - - private static void StopTimer(string deviceKey, Action action) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to stop timer for {deviceKey}", deviceKey); - - if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} not found", deviceKey); - return; - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Stopping timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer expired for {deviceKey}", deviceKey); action(false); - cancelTimer.Stop(); + _pushedActions.Remove(deviceKey); - } + }, ButtonHeartbeatInterval); - public static Action> GetPressAndHoldHandler(string value) + _pushedActions.Add(deviceKey, cancelTimer); + } + + private static void ResetTimer(string deviceKey, Action action) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to reset timer for {deviceKey}", deviceKey); + + if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting press and hold handler for {value}", value); - - if (!_pushedActionHandlers.TryGetValue(value, out Action> handler)) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Press and hold handler for {value} not found", value); - return null; - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Got handler for {value}", value); - - return handler; + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} not found", deviceKey); + return; } - public static void HandlePressAndHold(string deviceKey, JToken content, Action action) + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Resetting timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + + cancelTimer.Reset(ButtonHeartbeatInterval); + } + + private static void StopTimer(string deviceKey, Action action) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to stop timer for {deviceKey}", deviceKey); + + if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { - var msg = content.ToObject>(); - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Handling press and hold message of {type} for {deviceKey}", msg.Value, deviceKey); - - var timerHandler = GetPressAndHoldHandler(msg.Value); - - if (timerHandler == null) - { - return; - } - - timerHandler(deviceKey, action); + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} not found", deviceKey); + return; } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Stopping timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + + action(false); + cancelTimer.Stop(); + _pushedActions.Remove(deviceKey); + } + + public static Action> GetPressAndHoldHandler(string value) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting press and hold handler for {value}", value); + + if (!_pushedActionHandlers.TryGetValue(value, out Action> handler)) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Press and hold handler for {value} not found", value); + return null; + } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Got handler for {value}", value); + + return handler; + } + + public static void HandlePressAndHold(string deviceKey, JToken content, Action action) + { + var msg = content.ToObject>(); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Handling press and hold message of {type} for {deviceKey}", msg.Value, deviceKey); + + var timerHandler = GetPressAndHoldHandler(msg.Value); + + if (timerHandler == null) + { + return; + } + + timerHandler(deviceKey, action); } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs index b8f5feff..845934dc 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs @@ -6,71 +6,70 @@ using PepperDash.Essentials.Room.Config; using System; using System.Collections.Generic; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class RoomEventScheduleMessenger : MessengerBase { - public class RoomEventScheduleMessenger : MessengerBase + private readonly IRoomEventSchedule _room; + + + public RoomEventScheduleMessenger(string key, string messagePath, IRoomEventSchedule room) + : base(key, messagePath, room as IKeyName) { - private readonly IRoomEventSchedule _room; + _room = room; + } + #region Overrides of MessengerBase - public RoomEventScheduleMessenger(string key, string messagePath, IRoomEventSchedule room) - : base(key, messagePath, room as IKeyName) + protected override void RegisterActions() + { + AddAction("/saveScheduledEvents", (id, content) => SaveScheduledEvents(content.ToObject>())); + AddAction("/status", (id, content) => { - _room = room; - } + var events = _room.GetScheduledEvents(); - #region Overrides of MessengerBase + SendFullStatus(events); + }); - protected override void RegisterActions() + _room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents); + } + + #endregion + + private void SaveScheduledEvents(List events) + { + foreach (var evt in events) { - AddAction("/saveScheduledEvents", (id, content) => SaveScheduledEvents(content.ToObject>())); - AddAction("/status", (id, content) => - { - var events = _room.GetScheduledEvents(); - - SendFullStatus(events); - }); - - _room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents); - } - - #endregion - - private void SaveScheduledEvents(List events) - { - foreach (var evt in events) - { - SaveScheduledEvent(evt); - } - } - - private void SaveScheduledEvent(ScheduledEventConfig eventConfig) - { - try - { - _room.AddOrUpdateScheduledEvent(eventConfig); - } - catch (Exception ex) - { - this.LogException(ex,"Exception saving event"); - } - } - - private void SendFullStatus(List events) - { - - var message = new RoomEventScheduleStateMessage - { - ScheduleEvents = events, - }; - - PostStatusMessage(message); + SaveScheduledEvent(evt); } } - public class RoomEventScheduleStateMessage : DeviceStateMessageBase + private void SaveScheduledEvent(ScheduledEventConfig eventConfig) { - [JsonProperty("scheduleEvents")] - public List ScheduleEvents { get; set; } + try + { + _room.AddOrUpdateScheduledEvent(eventConfig); + } + catch (Exception ex) + { + this.LogException(ex,"Exception saving event"); + } } + + private void SendFullStatus(List events) + { + + var message = new RoomEventScheduleStateMessage + { + ScheduleEvents = events, + }; + + PostStatusMessage(message); + } +} + +public class RoomEventScheduleStateMessage : DeviceStateMessageBase +{ + [JsonProperty("scheduleEvents")] + public List ScheduleEvents { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs index ff41670a..13d1bcfb 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs @@ -3,98 +3,97 @@ using PepperDash.Core; using PepperDash.Essentials.Core.Shades; using System; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class IShadesOpenCloseStopMessenger : MessengerBase { - public class IShadesOpenCloseStopMessenger : MessengerBase + private readonly IShadesOpenCloseStop device; + + public IShadesOpenCloseStopMessenger(string key, IShadesOpenCloseStop shades, string messagePath) + : base(key, messagePath, shades as IKeyName) { - private readonly IShadesOpenCloseStop device; + device = shades; + } - public IShadesOpenCloseStopMessenger(string key, IShadesOpenCloseStop shades, string messagePath) - : base(key, messagePath, shades as IKeyName) + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/shadeUp", (id, content) => + { + + device.Open(); + + }); + + AddAction("/shadeDown", (id, content) => + { + + device.Close(); + + }); + + var stopDevice = device; + if (stopDevice != null) { - device = shades; + AddAction("/stopOrPreset", (id, content) => + { + stopDevice.Stop(); + }); } - protected override void RegisterActions() + if (device is IShadesOpenClosedFeedback feedbackDevice) { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - AddAction("/shadeUp", (id, content) => - { - - device.Open(); - - }); - - AddAction("/shadeDown", (id, content) => - { - - device.Close(); - - }); - - var stopDevice = device; - if (stopDevice != null) - { - AddAction("/stopOrPreset", (id, content) => - { - stopDevice.Stop(); - }); - } - - if (device is IShadesOpenClosedFeedback feedbackDevice) - { - feedbackDevice.ShadeIsOpenFeedback.OutputChange += new EventHandler(ShadeIsOpenFeedback_OutputChange); - feedbackDevice.ShadeIsClosedFeedback.OutputChange += new EventHandler(ShadeIsClosedFeedback_OutputChange); - } - } - - private void ShadeIsOpenFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) - { - var state = new ShadeBaseStateMessage - { - IsOpen = e.BoolValue - }; - - PostStatusMessage(state); - } - - private void ShadeIsClosedFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) - { - var state = new ShadeBaseStateMessage - { - IsClosed = e.BoolValue - }; - - PostStatusMessage(state); - } - - - private void SendFullStatus() - { - var state = new ShadeBaseStateMessage(); - - if (device is IShadesOpenClosedFeedback feedbackDevice) - { - state.IsOpen = feedbackDevice.ShadeIsOpenFeedback.BoolValue; - state.IsClosed = feedbackDevice.ShadeIsClosedFeedback.BoolValue; - } - - PostStatusMessage(state); + feedbackDevice.ShadeIsOpenFeedback.OutputChange += new EventHandler(ShadeIsOpenFeedback_OutputChange); + feedbackDevice.ShadeIsClosedFeedback.OutputChange += new EventHandler(ShadeIsClosedFeedback_OutputChange); } } - public class ShadeBaseStateMessage : DeviceStateMessageBase + private void ShadeIsOpenFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) { - [JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)] - public string MiddleButtonLabel { get; set; } + var state = new ShadeBaseStateMessage + { + IsOpen = e.BoolValue + }; - [JsonProperty("isOpen", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsOpen { get; set; } - - [JsonProperty("isClosed", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsClosed { get; set; } + PostStatusMessage(state); } + + private void ShadeIsClosedFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) + { + var state = new ShadeBaseStateMessage + { + IsClosed = e.BoolValue + }; + + PostStatusMessage(state); + } + + + private void SendFullStatus() + { + var state = new ShadeBaseStateMessage(); + + if (device is IShadesOpenClosedFeedback feedbackDevice) + { + state.IsOpen = feedbackDevice.ShadeIsOpenFeedback.BoolValue; + state.IsClosed = feedbackDevice.ShadeIsClosedFeedback.BoolValue; + } + + PostStatusMessage(state); + } +} + +public class ShadeBaseStateMessage : DeviceStateMessageBase +{ + [JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)] + public string MiddleButtonLabel { get; set; } + + [JsonProperty("isOpen", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsOpen { get; set; } + + [JsonProperty("isClosed", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsClosed { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs index 2cb2ced0..4d6f040c 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs @@ -6,104 +6,103 @@ using PepperDash.Essentials.Core.Monitoring; using System; using System.Threading.Tasks; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class SystemMonitorMessenger : MessengerBase { - public class SystemMonitorMessenger : MessengerBase + private readonly SystemMonitorController systemMonitor; + + public SystemMonitorMessenger(string key, SystemMonitorController sysMon, string messagePath) + : base(key, messagePath, sysMon) { - private readonly SystemMonitorController systemMonitor; + systemMonitor = sysMon ?? throw new ArgumentNullException("sysMon"); - public SystemMonitorMessenger(string key, SystemMonitorController sysMon, string messagePath) - : base(key, messagePath, sysMon) + systemMonitor.SystemMonitorPropertiesChanged += SysMon_SystemMonitorPropertiesChanged; + + foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) { - systemMonitor = sysMon ?? throw new ArgumentNullException("sysMon"); - - systemMonitor.SystemMonitorPropertiesChanged += SysMon_SystemMonitorPropertiesChanged; - - foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) - { - p.Value.ProgramInfoChanged += ProgramInfoChanged; - } - - CrestronConsole.AddNewConsoleCommand(s => SendFullStatusMessage(), "SendFullSysMonStatus", - "Sends the full System Monitor Status", ConsoleAccessLevelEnum.AccessOperator); + p.Value.ProgramInfoChanged += ProgramInfoChanged; } - /// - /// Posts the program information message - /// - /// - /// - private void ProgramInfoChanged(object sender, ProgramInfoEventArgs e) + CrestronConsole.AddNewConsoleCommand(s => SendFullStatusMessage(), "SendFullSysMonStatus", + "Sends the full System Monitor Status", ConsoleAccessLevelEnum.AccessOperator); + } + + /// + /// Posts the program information message + /// + /// + /// + private void ProgramInfoChanged(object sender, ProgramInfoEventArgs e) + { + if (e.ProgramInfo != null) { - if (e.ProgramInfo != null) - { - //Debug.Console(1, "Posting Status Message: {0}", e.ProgramInfo.ToString()); - PostStatusMessage(JToken.FromObject(e.ProgramInfo) - ); - } - } - - /// - /// Posts the system monitor properties - /// - /// - /// - private void SysMon_SystemMonitorPropertiesChanged(object sender, EventArgs e) - { - SendSystemMonitorStatusMessage(); - } - - private void SendFullStatusMessage() - { - SendSystemMonitorStatusMessage(); - - foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) - { - PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo)); - } - } - - private void SendSystemMonitorStatusMessage() - { - // This takes a while, launch a new thread - - Task.Run(() => PostStatusMessage(JToken.FromObject(new SystemMonitorStateMessage - { - - TimeZone = systemMonitor.TimeZoneFeedback.IntValue, - TimeZoneName = systemMonitor.TimeZoneTextFeedback.StringValue, - IoControllerVersion = systemMonitor.IoControllerVersionFeedback.StringValue, - SnmpVersion = systemMonitor.SnmpVersionFeedback.StringValue, - BacnetVersion = systemMonitor.BaCnetAppVersionFeedback.StringValue, - ControllerVersion = systemMonitor.ControllerVersionFeedback.StringValue - }) - )); - } - - protected override void RegisterActions() - { - AddAction("/fullStatus", (id, content) => SendFullStatusMessage()); + //Debug.Console(1, "Posting Status Message: {0}", e.ProgramInfo.ToString()); + PostStatusMessage(JToken.FromObject(e.ProgramInfo) + ); } } - public class SystemMonitorStateMessage + /// + /// Posts the system monitor properties + /// + /// + /// + private void SysMon_SystemMonitorPropertiesChanged(object sender, EventArgs e) { - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] - public int TimeZone { get; set; } - - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] - public string TimeZoneName { get; set; } - - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] - public string IoControllerVersion { get; set; } - - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] - public string SnmpVersion { get; set; } - - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] - public string BacnetVersion { get; set; } - - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] - public string ControllerVersion { get; set; } + SendSystemMonitorStatusMessage(); } + + private void SendFullStatusMessage() + { + SendSystemMonitorStatusMessage(); + + foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) + { + PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo)); + } + } + + private void SendSystemMonitorStatusMessage() + { + // This takes a while, launch a new thread + + Task.Run(() => PostStatusMessage(JToken.FromObject(new SystemMonitorStateMessage + { + + TimeZone = systemMonitor.TimeZoneFeedback.IntValue, + TimeZoneName = systemMonitor.TimeZoneTextFeedback.StringValue, + IoControllerVersion = systemMonitor.IoControllerVersionFeedback.StringValue, + SnmpVersion = systemMonitor.SnmpVersionFeedback.StringValue, + BacnetVersion = systemMonitor.BaCnetAppVersionFeedback.StringValue, + ControllerVersion = systemMonitor.ControllerVersionFeedback.StringValue + }) + )); + } + + protected override void RegisterActions() + { + AddAction("/fullStatus", (id, content) => SendFullStatusMessage()); + } +} + +public class SystemMonitorStateMessage +{ + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public int TimeZone { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string TimeZoneName { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string IoControllerVersion { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string SnmpVersion { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string BacnetVersion { get; set; } + + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + public string ControllerVersion { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs index f0600dd5..d721a794 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs @@ -3,91 +3,90 @@ using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Displays; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class TwoWayDisplayBaseMessenger : MessengerBase { - public class TwoWayDisplayBaseMessenger : MessengerBase + private readonly TwoWayDisplayBase _display; + + public TwoWayDisplayBaseMessenger(string key, string messagePath, TwoWayDisplayBase display) + : base(key, messagePath, display) { - private readonly TwoWayDisplayBase _display; - - public TwoWayDisplayBaseMessenger(string key, string messagePath, TwoWayDisplayBase display) - : base(key, messagePath, display) - { - _display = display; - } - - #region Overrides of MessengerBase - - public void SendFullStatus() - { - var messageObj = new TwoWayDisplayBaseStateMessage - { - //PowerState = _display.PowerIsOnFeedback.BoolValue, - CurrentInput = _display.CurrentInputFeedback.StringValue - }; - - PostStatusMessage(messageObj); - } - - protected override void RegisterActions() - { - base.RegisterActions(); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - //_display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; - _display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange; - _display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange; - _display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange; - } - - private void CurrentInputFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) - { - PostStatusMessage(JToken.FromObject(new - { - currentInput = feedbackEventArgs.StringValue - }) - ); - } - - - //private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) - //{ - // PostStatusMessage(JToken.FromObject(new - // { - // powerState = feedbackEventArgs.BoolValue - // }) - // ); - //} - - private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) - { - PostStatusMessage(JToken.FromObject(new - { - isWarming = feedbackEventArgs.BoolValue - }) - ); - } - - private void IsCoolingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) - { - PostStatusMessage(JToken.FromObject(new - { - isCooling = feedbackEventArgs.BoolValue - }) - ); - - - } - - #endregion + _display = display; } - public class TwoWayDisplayBaseStateMessage : DeviceStateMessageBase - { - //[JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] - //public bool? PowerState { get; set; } + #region Overrides of MessengerBase - [JsonProperty("currentInput", NullValueHandling = NullValueHandling.Ignore)] - public string CurrentInput { get; set; } + public void SendFullStatus() + { + var messageObj = new TwoWayDisplayBaseStateMessage + { + //PowerState = _display.PowerIsOnFeedback.BoolValue, + CurrentInput = _display.CurrentInputFeedback.StringValue + }; + + PostStatusMessage(messageObj); } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + //_display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; + _display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange; + _display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange; + _display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange; + } + + private void CurrentInputFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + currentInput = feedbackEventArgs.StringValue + }) + ); + } + + + //private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + //{ + // PostStatusMessage(JToken.FromObject(new + // { + // powerState = feedbackEventArgs.BoolValue + // }) + // ); + //} + + private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + isWarming = feedbackEventArgs.BoolValue + }) + ); + } + + private void IsCoolingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + PostStatusMessage(JToken.FromObject(new + { + isCooling = feedbackEventArgs.BoolValue + }) + ); + + + } + + #endregion +} + +public class TwoWayDisplayBaseStateMessage : DeviceStateMessageBase +{ + //[JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] + //public bool? PowerState { get; set; } + + [JsonProperty("currentInput", NullValueHandling = NullValueHandling.Ignore)] + public string CurrentInput { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs index 16cf642e..69ecbf06 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs @@ -13,1080 +13,1079 @@ using System; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +/// +/// Provides a messaging bridge for a VideoCodecBase device +/// +public class VideoCodecBaseMessenger : MessengerBase { /// - /// Provides a messaging bridge for a VideoCodecBase device + /// /// - public class VideoCodecBaseMessenger : MessengerBase + protected VideoCodecBase Codec { get; private set; } + + + + /// + /// + /// + /// + /// + /// + public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messagePath) + : base(key, messagePath, codec) { - /// - /// - /// - protected VideoCodecBase Codec { get; private set; } + Codec = codec ?? throw new ArgumentNullException("codec"); + codec.CallStatusChange += Codec_CallStatusChange; + codec.IsReadyChange += Codec_IsReadyChange; - - - /// - /// - /// - /// - /// - /// - public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messagePath) - : base(key, messagePath, codec) + if (codec is IHasDirectory dirCodec) { - Codec = codec ?? throw new ArgumentNullException("codec"); - codec.CallStatusChange += Codec_CallStatusChange; - codec.IsReadyChange += Codec_IsReadyChange; - - if (codec is IHasDirectory dirCodec) - { - dirCodec.DirectoryResultReturned += DirCodec_DirectoryResultReturned; - } - - if (codec is IHasCallHistory recCodec) - { - recCodec.CallHistory.RecentCallsListHasChanged += CallHistory_RecentCallsListHasChanged; - } - - if (codec is IPasswordPrompt pwPromptCodec) - { - pwPromptCodec.PasswordRequired += OnPasswordRequired; - } + dirCodec.DirectoryResultReturned += DirCodec_DirectoryResultReturned; } - private void OnPasswordRequired(object sender, PasswordPromptEventArgs args) + if (codec is IHasCallHistory recCodec) { - var eventMsg = new PasswordPromptEventMessage + recCodec.CallHistory.RecentCallsListHasChanged += CallHistory_RecentCallsListHasChanged; + } + + if (codec is IPasswordPrompt pwPromptCodec) + { + pwPromptCodec.PasswordRequired += OnPasswordRequired; + } + } + + private void OnPasswordRequired(object sender, PasswordPromptEventArgs args) + { + var eventMsg = new PasswordPromptEventMessage + { + Message = args.Message, + LastAttemptWasIncorrect = args.LastAttemptWasIncorrect, + LoginAttemptFailed = args.LoginAttemptFailed, + LoginAttemptCancelled = args.LoginAttemptCancelled, + EventType = "passwordPrompt" + }; + + PostEventMessage(eventMsg); + } + + /// + /// + /// + /// + /// + private void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e) + { + try + { + var state = new VideoCodecBaseStateMessage(); + + if (!(sender is CodecCallHistory codecCallHistory)) return; + var recents = codecCallHistory.RecentCalls; + + if (recents != null) { - Message = args.Message, - LastAttemptWasIncorrect = args.LastAttemptWasIncorrect, - LoginAttemptFailed = args.LoginAttemptFailed, - LoginAttemptCancelled = args.LoginAttemptCancelled, - EventType = "passwordPrompt" + state.RecentCalls = recents; + + PostStatusMessage(state); + } + } + catch (Exception ex) + { + this.LogError(ex, "Error posting call history"); + } + } + + /// + /// + /// + /// + /// + protected virtual void DirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e) + { + if (Codec is IHasDirectory) + SendDirectory(e.Directory); + } + + /// + /// Posts the current directory + /// + protected void SendDirectory(CodecDirectory directory) + { + try + { + var state = new VideoCodecBaseStateMessage(); + + + if (Codec is IHasDirectory dirCodec) + { + this.LogVerbose("Sending Directory. Directory Item Count: {directoryItemCount}", directory.CurrentDirectoryResults.Count); + + //state.CurrentDirectory = PrefixDirectoryFolderItems(directory); + state.CurrentDirectory = directory; + + CrestronInvoke.BeginInvoke((o) => PostStatusMessage(state)); + } + } + catch (Exception ex) + { + this.LogError(ex, "Error sending directory"); + } + } + + /// + /// + /// + /// + /// + private void Codec_IsReadyChange(object sender, EventArgs e) + { + try + { + var state = new VideoCodecBaseStateMessage + { + IsReady = true }; - PostEventMessage(eventMsg); + PostStatusMessage(state); + + SendFullStatus(); + } catch (Exception ex) + { + this.LogError(ex, "Error sending codec ready status"); + } + } + + /// + /// Called from base's RegisterWithAppServer method + /// + /// + protected override void RegisterActions() + { + try + { + base.RegisterActions(); + + AddAction("/isReady", (id, content) => SendIsReady()); + + AddAction("/fullStatus", (id, content) => SendFullStatus()); + + AddAction("/dial", (id, content) => + { + var value = content.ToObject>(); + + Codec.Dial(value.Value); + }); + + AddAction("/dialMeeting", (id, content) => Codec.Dial(content.ToObject())); + + AddAction("/endCallById", (id, content) => + { + var s = content.ToObject>(); + var call = GetCallWithId(s.Value); + if (call != null) + Codec.EndCall(call); + }); + + AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); + + AddAction("/dtmf", (id, content) => + { + var s = content.ToObject>(); + Codec.SendDtmf(s.Value); + }); + + AddAction("/rejectById", (id, content) => + { + var s = content.ToObject>(); + + var call = GetCallWithId(s.Value); + if (call != null) + Codec.RejectCall(call); + }); + + AddAction("/acceptById", (id, content) => + { + var s = content.ToObject>(); + + var call = GetCallWithId(s.Value); + if (call != null) + Codec.AcceptCall(call); + }); + + Codec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange; + Codec.SharingSourceFeedback.OutputChange += SharingSourceFeedback_OutputChange; + + // Directory actions + if (Codec is IHasDirectory dirCodec) + { + AddAction("/getDirectory", (id, content) => GetDirectoryRoot()); + + AddAction("/directoryById", (id, content) => + { + var msg = content.ToObject>(); + GetDirectory(msg.Value); + }); + + AddAction("/directorySearch", (id, content) => + { + var msg = content.ToObject>(); + + GetDirectory(msg.Value); + }); + + AddAction("/directoryBack", (id, content) => GetPreviousDirectory()); + + dirCodec.PhonebookSyncState.InitialSyncCompleted += PhonebookSyncState_InitialSyncCompleted; + } + + // History actions + if (Codec is IHasCallHistory recCodec) + { + AddAction("/getCallHistory", (id, content) => PostCallHistory()); + } + if (Codec is IHasCodecCameras cameraCodec) + { + this.LogVerbose("Adding IHasCodecCameras Actions"); + + cameraCodec.CameraSelected += CameraCodec_CameraSelected; + + AddAction("/cameraSelect", (id, content) => + { + var msg = content.ToObject>(); + + cameraCodec.SelectCamera(msg.Value); + }); + + + MapCameraActions(); + + if (Codec is IHasCodecRoomPresets presetsCodec) + { + this.LogVerbose("Adding IHasCodecRoomPresets Actions"); + + presetsCodec.CodecRoomPresetsListHasChanged += PresetsCodec_CameraPresetsListHasChanged; + + AddAction("/cameraPreset", (id, content) => + { + var msg = content.ToObject>(); + + presetsCodec.CodecRoomPresetSelect(msg.Value); + }); + + AddAction("/cameraPresetStore", (id, content) => + { + var msg = content.ToObject(); + + presetsCodec.CodecRoomPresetStore(msg.ID, msg.Description); + }); + } + + if (Codec is IHasCameraAutoMode speakerTrackCodec) + { + this.LogVerbose("Adding IHasCameraAutoMode Actions"); + + speakerTrackCodec.CameraAutoModeIsOnFeedback.OutputChange += CameraAutoModeIsOnFeedback_OutputChange; + + AddAction("/cameraModeAuto", (id, content) => speakerTrackCodec.CameraAutoModeOn()); + + AddAction("/cameraModeManual", (id, content) => speakerTrackCodec.CameraAutoModeOff()); + } + + if (Codec is IHasCameraOff cameraOffCodec) + { + this.LogVerbose("Adding IHasCameraOff Actions"); + + cameraOffCodec.CameraIsOffFeedback.OutputChange += (CameraIsOffFeedback_OutputChange); + + AddAction("/cameraModeOff", (id, content) => cameraOffCodec.CameraOff()); + } + } + + + + if (Codec is IHasCodecSelfView selfViewCodec) + { + this.LogVerbose("Adding IHasCodecSelfView Actions"); + + AddAction("/cameraSelfView", (id, content) => selfViewCodec.SelfViewModeToggle()); + + selfViewCodec.SelfviewIsOnFeedback.OutputChange += new EventHandler(SelfviewIsOnFeedback_OutputChange); + } + + + if (Codec is IHasCodecLayouts layoutsCodec) + { + this.LogVerbose("Adding IHasCodecLayouts Actions"); + + AddAction("/cameraRemoteView", (id, content) => layoutsCodec.LocalLayoutToggle()); + + AddAction("/cameraLayout", (id, content) => layoutsCodec.LocalLayoutToggle()); + } + + if (Codec is IPasswordPrompt pwCodec) + { + this.LogVerbose("Adding IPasswordPrompt Actions"); + + AddAction("/password", (id, content) => + { + var msg = content.ToObject>(); + + pwCodec.SubmitPassword(msg.Value); + }); + } + + + if (Codec is IHasFarEndContentStatus farEndContentStatus) + { + farEndContentStatus.ReceivingContent.OutputChange += + (sender, args) => PostReceivingContent(args.BoolValue); + } + + this.LogVerbose("Adding Privacy & Standby Actions"); + + AddAction("/privacyModeOn", (id, content) => Codec.PrivacyModeOn()); + AddAction("/privacyModeOff", (id, content) => Codec.PrivacyModeOff()); + AddAction("/privacyModeToggle", (id, content) => Codec.PrivacyModeToggle()); + AddAction("/sharingStart", (id, content) => Codec.StartSharing()); + AddAction("/sharingStop", (id, content) => Codec.StopSharing()); + AddAction("/standbyOn", (id, content) => Codec.StandbyActivate()); + AddAction("/standbyOff", (id, content) => Codec.StandbyDeactivate()); + } + catch (Exception e) + { + this.LogException(e, "Exception adding paths"); + } + } + + private void SharingSourceFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + try + { + var state = new VideoCodecBaseStateMessage + { + SharingSource = e.StringValue + }; + + PostStatusMessage(state); + } catch (Exception ex) + { + this.LogError(ex, "Error posting sharing source"); + } + } + + private void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + try + { + var state = new VideoCodecBaseStateMessage + { + SharingContentIsOn = e.BoolValue + }; + + PostStatusMessage(state); + } catch (Exception ex) + { + this.LogError(ex, "Error posting sharing content"); + } + } + + private void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) + { + try + { + var state = new VideoCodecBaseStateMessage + { + InitialPhonebookSyncComplete = true + }; + + PostStatusMessage(state); + } + catch (Exception ex) + { + this.LogError(ex, "Error posting phonebook sync state"); + } + } + + private void CameraIsOffFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + PostCameraMode(); + } + + private void SelfviewIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + PostCameraSelfView(); + } + + private void PresetsCodec_CameraPresetsListHasChanged(object sender, EventArgs e) + { + PostCameraPresets(); + } + + private void CameraAutoModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + PostCameraMode(); + } + + + private void CameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e) + { + try + { + MapCameraActions(); + PostSelectedCamera(); + } catch(Exception ex) + { + this.LogError(ex, "Exception handling camera selected event"); + } + } + + /// + /// Maps the camera control actions to the current selected camera on the codec + /// + private void MapCameraActions() + { + if (Codec is IHasCameras cameraCodec && cameraCodec.SelectedCamera != null) + { + RemoveAction("/cameraUp"); + RemoveAction("/cameraDown"); + RemoveAction("/cameraLeft"); + RemoveAction("/cameraRight"); + RemoveAction("/cameraZoomIn"); + RemoveAction("/cameraZoomOut"); + RemoveAction("/cameraHome"); + + if (cameraCodec.SelectedCamera is IHasCameraPtzControl camera) + { + AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + camera.TiltUp(); + return; + } + + camera.TiltStop(); + })); + + AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + camera.TiltDown(); + return; + } + + camera.TiltStop(); + })); + + AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + camera.PanLeft(); + return; + } + + camera.PanStop(); + })); + + AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + camera.PanRight(); + return; + } + + camera.PanStop(); + })); + + AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + camera.ZoomIn(); + return; + } + + camera.ZoomStop(); + })); + + AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + camera.ZoomOut(); + return; + } + + camera.ZoomStop(); + })); + AddAction("/cameraHome", (id, content) => camera.PositionHome()); + + + RemoveAction("/cameraAutoFocus"); + RemoveAction("/cameraFocusNear"); + RemoveAction("/cameraFocusFar"); + + if (cameraCodec is IHasCameraFocusControl focusCamera) + { + AddAction("/cameraAutoFocus", (id, content) => focusCamera.TriggerAutoFocus()); + + AddAction("/cameraFocusNear", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + focusCamera.FocusNear(); + return; + } + + focusCamera.FocusStop(); + })); + + AddAction("/cameraFocusFar", (id, content) => HandleCameraPressAndHold(content, (b) => + { + if (b) + { + focusCamera.FocusFar(); + return; + } + + focusCamera.FocusStop(); + })); + } + } + } + } + + private void HandleCameraPressAndHold(JToken content, Action cameraAction) + { + var state = content.ToObject>(); + + var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); + if (timerHandler == null) + { + return; } - /// - /// - /// - /// - /// - private void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e) - { - try - { - var state = new VideoCodecBaseStateMessage(); + timerHandler(state.Value, cameraAction); - if (!(sender is CodecCallHistory codecCallHistory)) return; - var recents = codecCallHistory.RecentCalls; + cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); + } + + private string GetCameraMode() + { + string m = ""; + + if (Codec is IHasCameraAutoMode speakerTrackCodec) + { + m = speakerTrackCodec.CameraAutoModeIsOnFeedback.BoolValue + ? eCameraControlMode.Auto.ToString().ToLower() + : eCameraControlMode.Manual.ToString().ToLower(); + } + + if (Codec is IHasCameraOff cameraOffCodec) + { + if (cameraOffCodec.CameraIsOffFeedback.BoolValue) + m = eCameraControlMode.Off.ToString().ToLower(); + } + + return m; + } + + private void PostCallHistory() + { + try + { + var codec = (Codec as IHasCallHistory); + + if (codec != null) + { + var status = new VideoCodecBaseStateMessage(); + + var recents = codec.CallHistory.RecentCalls; if (recents != null) { - state.RecentCalls = recents; + status.RecentCalls = codec.CallHistory.RecentCalls; - PostStatusMessage(state); - } - } - catch (Exception ex) - { - this.LogError(ex, "Error posting call history"); - } - } - - /// - /// - /// - /// - /// - protected virtual void DirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e) - { - if (Codec is IHasDirectory) - SendDirectory(e.Directory); - } - - /// - /// Posts the current directory - /// - protected void SendDirectory(CodecDirectory directory) - { - try - { - var state = new VideoCodecBaseStateMessage(); - - - if (Codec is IHasDirectory dirCodec) - { - this.LogVerbose("Sending Directory. Directory Item Count: {directoryItemCount}", directory.CurrentDirectoryResults.Count); - - //state.CurrentDirectory = PrefixDirectoryFolderItems(directory); - state.CurrentDirectory = directory; - - CrestronInvoke.BeginInvoke((o) => PostStatusMessage(state)); - } - } - catch (Exception ex) - { - this.LogError(ex, "Error sending directory"); - } - } - - /// - /// - /// - /// - /// - private void Codec_IsReadyChange(object sender, EventArgs e) - { - try - { - var state = new VideoCodecBaseStateMessage - { - IsReady = true - }; - - PostStatusMessage(state); - - SendFullStatus(); - } catch (Exception ex) - { - this.LogError(ex, "Error sending codec ready status"); - } - } - - /// - /// Called from base's RegisterWithAppServer method - /// - /// - protected override void RegisterActions() - { - try - { - base.RegisterActions(); - - AddAction("/isReady", (id, content) => SendIsReady()); - - AddAction("/fullStatus", (id, content) => SendFullStatus()); - - AddAction("/dial", (id, content) => - { - var value = content.ToObject>(); - - Codec.Dial(value.Value); - }); - - AddAction("/dialMeeting", (id, content) => Codec.Dial(content.ToObject())); - - AddAction("/endCallById", (id, content) => - { - var s = content.ToObject>(); - var call = GetCallWithId(s.Value); - if (call != null) - Codec.EndCall(call); - }); - - AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); - - AddAction("/dtmf", (id, content) => - { - var s = content.ToObject>(); - Codec.SendDtmf(s.Value); - }); - - AddAction("/rejectById", (id, content) => - { - var s = content.ToObject>(); - - var call = GetCallWithId(s.Value); - if (call != null) - Codec.RejectCall(call); - }); - - AddAction("/acceptById", (id, content) => - { - var s = content.ToObject>(); - - var call = GetCallWithId(s.Value); - if (call != null) - Codec.AcceptCall(call); - }); - - Codec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange; - Codec.SharingSourceFeedback.OutputChange += SharingSourceFeedback_OutputChange; - - // Directory actions - if (Codec is IHasDirectory dirCodec) - { - AddAction("/getDirectory", (id, content) => GetDirectoryRoot()); - - AddAction("/directoryById", (id, content) => - { - var msg = content.ToObject>(); - GetDirectory(msg.Value); - }); - - AddAction("/directorySearch", (id, content) => - { - var msg = content.ToObject>(); - - GetDirectory(msg.Value); - }); - - AddAction("/directoryBack", (id, content) => GetPreviousDirectory()); - - dirCodec.PhonebookSyncState.InitialSyncCompleted += PhonebookSyncState_InitialSyncCompleted; - } - - // History actions - if (Codec is IHasCallHistory recCodec) - { - AddAction("/getCallHistory", (id, content) => PostCallHistory()); - } - if (Codec is IHasCodecCameras cameraCodec) - { - this.LogVerbose("Adding IHasCodecCameras Actions"); - - cameraCodec.CameraSelected += CameraCodec_CameraSelected; - - AddAction("/cameraSelect", (id, content) => - { - var msg = content.ToObject>(); - - cameraCodec.SelectCamera(msg.Value); - }); - - - MapCameraActions(); - - if (Codec is IHasCodecRoomPresets presetsCodec) - { - this.LogVerbose("Adding IHasCodecRoomPresets Actions"); - - presetsCodec.CodecRoomPresetsListHasChanged += PresetsCodec_CameraPresetsListHasChanged; - - AddAction("/cameraPreset", (id, content) => - { - var msg = content.ToObject>(); - - presetsCodec.CodecRoomPresetSelect(msg.Value); - }); - - AddAction("/cameraPresetStore", (id, content) => - { - var msg = content.ToObject(); - - presetsCodec.CodecRoomPresetStore(msg.ID, msg.Description); - }); - } - - if (Codec is IHasCameraAutoMode speakerTrackCodec) - { - this.LogVerbose("Adding IHasCameraAutoMode Actions"); - - speakerTrackCodec.CameraAutoModeIsOnFeedback.OutputChange += CameraAutoModeIsOnFeedback_OutputChange; - - AddAction("/cameraModeAuto", (id, content) => speakerTrackCodec.CameraAutoModeOn()); - - AddAction("/cameraModeManual", (id, content) => speakerTrackCodec.CameraAutoModeOff()); - } - - if (Codec is IHasCameraOff cameraOffCodec) - { - this.LogVerbose("Adding IHasCameraOff Actions"); - - cameraOffCodec.CameraIsOffFeedback.OutputChange += (CameraIsOffFeedback_OutputChange); - - AddAction("/cameraModeOff", (id, content) => cameraOffCodec.CameraOff()); - } - } - - - - if (Codec is IHasCodecSelfView selfViewCodec) - { - this.LogVerbose("Adding IHasCodecSelfView Actions"); - - AddAction("/cameraSelfView", (id, content) => selfViewCodec.SelfViewModeToggle()); - - selfViewCodec.SelfviewIsOnFeedback.OutputChange += new EventHandler(SelfviewIsOnFeedback_OutputChange); - } - - - if (Codec is IHasCodecLayouts layoutsCodec) - { - this.LogVerbose("Adding IHasCodecLayouts Actions"); - - AddAction("/cameraRemoteView", (id, content) => layoutsCodec.LocalLayoutToggle()); - - AddAction("/cameraLayout", (id, content) => layoutsCodec.LocalLayoutToggle()); - } - - if (Codec is IPasswordPrompt pwCodec) - { - this.LogVerbose("Adding IPasswordPrompt Actions"); - - AddAction("/password", (id, content) => - { - var msg = content.ToObject>(); - - pwCodec.SubmitPassword(msg.Value); - }); - } - - - if (Codec is IHasFarEndContentStatus farEndContentStatus) - { - farEndContentStatus.ReceivingContent.OutputChange += - (sender, args) => PostReceivingContent(args.BoolValue); - } - - this.LogVerbose("Adding Privacy & Standby Actions"); - - AddAction("/privacyModeOn", (id, content) => Codec.PrivacyModeOn()); - AddAction("/privacyModeOff", (id, content) => Codec.PrivacyModeOff()); - AddAction("/privacyModeToggle", (id, content) => Codec.PrivacyModeToggle()); - AddAction("/sharingStart", (id, content) => Codec.StartSharing()); - AddAction("/sharingStop", (id, content) => Codec.StopSharing()); - AddAction("/standbyOn", (id, content) => Codec.StandbyActivate()); - AddAction("/standbyOff", (id, content) => Codec.StandbyDeactivate()); - } - catch (Exception e) - { - this.LogException(e, "Exception adding paths"); - } - } - - private void SharingSourceFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - try - { - var state = new VideoCodecBaseStateMessage - { - SharingSource = e.StringValue - }; - - PostStatusMessage(state); - } catch (Exception ex) - { - this.LogError(ex, "Error posting sharing source"); - } - } - - private void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - try - { - var state = new VideoCodecBaseStateMessage - { - SharingContentIsOn = e.BoolValue - }; - - PostStatusMessage(state); - } catch (Exception ex) - { - this.LogError(ex, "Error posting sharing content"); - } - } - - private void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) - { - try - { - var state = new VideoCodecBaseStateMessage - { - InitialPhonebookSyncComplete = true - }; - - PostStatusMessage(state); - } - catch (Exception ex) - { - this.LogError(ex, "Error posting phonebook sync state"); - } - } - - private void CameraIsOffFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - PostCameraMode(); - } - - private void SelfviewIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - PostCameraSelfView(); - } - - private void PresetsCodec_CameraPresetsListHasChanged(object sender, EventArgs e) - { - PostCameraPresets(); - } - - private void CameraAutoModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - PostCameraMode(); - } - - - private void CameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e) - { - try - { - MapCameraActions(); - PostSelectedCamera(); - } catch(Exception ex) - { - this.LogError(ex, "Exception handling camera selected event"); - } - } - - /// - /// Maps the camera control actions to the current selected camera on the codec - /// - private void MapCameraActions() - { - if (Codec is IHasCameras cameraCodec && cameraCodec.SelectedCamera != null) - { - RemoveAction("/cameraUp"); - RemoveAction("/cameraDown"); - RemoveAction("/cameraLeft"); - RemoveAction("/cameraRight"); - RemoveAction("/cameraZoomIn"); - RemoveAction("/cameraZoomOut"); - RemoveAction("/cameraHome"); - - if (cameraCodec.SelectedCamera is IHasCameraPtzControl camera) - { - AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - camera.TiltUp(); - return; - } - - camera.TiltStop(); - })); - - AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - camera.TiltDown(); - return; - } - - camera.TiltStop(); - })); - - AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - camera.PanLeft(); - return; - } - - camera.PanStop(); - })); - - AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - camera.PanRight(); - return; - } - - camera.PanStop(); - })); - - AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - camera.ZoomIn(); - return; - } - - camera.ZoomStop(); - })); - - AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - camera.ZoomOut(); - return; - } - - camera.ZoomStop(); - })); - AddAction("/cameraHome", (id, content) => camera.PositionHome()); - - - RemoveAction("/cameraAutoFocus"); - RemoveAction("/cameraFocusNear"); - RemoveAction("/cameraFocusFar"); - - if (cameraCodec is IHasCameraFocusControl focusCamera) - { - AddAction("/cameraAutoFocus", (id, content) => focusCamera.TriggerAutoFocus()); - - AddAction("/cameraFocusNear", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - focusCamera.FocusNear(); - return; - } - - focusCamera.FocusStop(); - })); - - AddAction("/cameraFocusFar", (id, content) => HandleCameraPressAndHold(content, (b) => - { - if (b) - { - focusCamera.FocusFar(); - return; - } - - focusCamera.FocusStop(); - })); - } + PostStatusMessage(status); } } } - - private void HandleCameraPressAndHold(JToken content, Action cameraAction) + catch (Exception ex) { - var state = content.ToObject>(); - - var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); - if (timerHandler == null) - { - return; - } - - timerHandler(state.Value, cameraAction); - - cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); - } - - private string GetCameraMode() - { - string m = ""; - - if (Codec is IHasCameraAutoMode speakerTrackCodec) - { - m = speakerTrackCodec.CameraAutoModeIsOnFeedback.BoolValue - ? eCameraControlMode.Auto.ToString().ToLower() - : eCameraControlMode.Manual.ToString().ToLower(); - } - - if (Codec is IHasCameraOff cameraOffCodec) - { - if (cameraOffCodec.CameraIsOffFeedback.BoolValue) - m = eCameraControlMode.Off.ToString().ToLower(); - } - - return m; - } - - private void PostCallHistory() - { - try - { - var codec = (Codec as IHasCallHistory); - - if (codec != null) - { - var status = new VideoCodecBaseStateMessage(); - - var recents = codec.CallHistory.RecentCalls; - - if (recents != null) - { - status.RecentCalls = codec.CallHistory.RecentCalls; - - PostStatusMessage(status); - } - } - } - catch (Exception ex) - { - this.LogError(ex, "Error posting call history"); - } - } - - /// - /// Helper to grab a call with string ID - /// - /// - /// - private CodecActiveCallItem GetCallWithId(string id) - { - return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); - } - - /// - /// - /// - /// - private void GetDirectory(string id) - { - if (!(Codec is IHasDirectory dirCodec)) - { - return; - } - dirCodec.GetDirectoryFolderContents(id); - } - - /// - /// - /// - private void GetDirectoryRoot() - { - try - { - if (!(Codec is IHasDirectory dirCodec)) - { - // do something else? - return; - } - if (!dirCodec.PhonebookSyncState.InitialSyncComplete) - { - var state = new VideoCodecBaseStateMessage - { - InitialPhonebookSyncComplete = false - }; - - PostStatusMessage(state); - return; - } - - dirCodec.SetCurrentDirectoryToRoot(); - } - catch (Exception ex) - { - this.LogError(ex, "Error getting directory root"); - } - } - - /// - /// Requests the parent folder contents - /// - private void GetPreviousDirectory() - { - if (!(Codec is IHasDirectory dirCodec)) - { - return; - } - - dirCodec.GetDirectoryParentFolderContents(); - } - - /// - /// Handler for codec changes - /// - private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) - { - SendFullStatus(); - } - - /// - /// - /// - private void SendIsReady() - { - try - { - var status = new VideoCodecBaseStateMessage(); - - var codecType = Codec.GetType(); - - status.IsReady = Codec.IsReady; - status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; - - PostStatusMessage(status); - } - catch (Exception ex) - { - this.LogError(ex, "Error sending codec ready status"); - } - } - - /// - /// Helper method to build call status for vtc - /// - /// - protected VideoCodecBaseStateMessage GetStatus() - { - try - { - var status = new VideoCodecBaseStateMessage(); - - if (Codec is IHasCodecCameras camerasCodec) - { - status.Cameras = new CameraStatus - { - CameraManualIsSupported = true, - CameraAutoIsSupported = Codec.SupportsCameraAutoMode, - CameraOffIsSupported = Codec.SupportsCameraOff, - CameraMode = GetCameraMode(), - Cameras = camerasCodec.Cameras, - SelectedCamera = GetSelectedCamera(camerasCodec) - }; - } - - if (Codec is IHasDirectory directoryCodec) - { - status.HasDirectory = true; - status.HasDirectorySearch = true; - status.CurrentDirectory = directoryCodec.CurrentDirectoryResult; - } - - var codecType = Codec.GetType(); - - status.CameraSelfViewIsOn = Codec is IHasCodecSelfView && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue; - status.IsInCall = Codec.IsInCall; - status.PrivacyModeIsOn = Codec.PrivacyModeIsOnFeedback.BoolValue; - status.SharingContentIsOn = Codec.SharingContentIsOnFeedback.BoolValue; - status.SharingSource = Codec.SharingSourceFeedback.StringValue; - status.StandbyIsOn = Codec.StandbyIsOnFeedback.BoolValue; - status.Calls = Codec.ActiveCalls; - status.Info = Codec.CodecInfo; - status.ShowSelfViewByDefault = Codec.ShowSelfViewByDefault; - status.SupportsAdHocMeeting = Codec is IHasStartMeeting; - status.HasRecents = Codec is IHasCallHistory; - status.HasCameras = Codec is IHasCameras; - status.Presets = GetCurrentPresets(); - status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; - status.ReceivingContent = Codec is IHasFarEndContentStatus && (Codec as IHasFarEndContentStatus).ReceivingContent.BoolValue; - - if (Codec is IHasMeetingInfo meetingInfoCodec) - { - status.MeetingInfo = meetingInfoCodec.MeetingInfo; - } - - return status; - } - catch (Exception ex) - { - this.LogError(ex, "Error getting codec status"); - return null; - } - } - - protected virtual void SendFullStatus() - { - if (!Codec.IsReady) - { - return; - } - - CrestronInvoke.BeginInvoke((o) => PostStatusMessage(GetStatus())); - } - - private void PostReceivingContent(bool receivingContent) - { - try - { - var state = new VideoCodecBaseStateMessage - { - ReceivingContent = receivingContent - }; - - PostStatusMessage(state); - } catch(Exception ex) - { - this.LogError(ex, "Error posting receiving content"); - } - } - - private void PostCameraSelfView() - { - try - { - var status = new VideoCodecBaseStateMessage - { - CameraSelfViewIsOn = Codec is IHasCodecSelfView - && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue - }; - - PostStatusMessage(status); - } - catch (Exception ex) - { - this.LogError(ex, "Error posting camera self view"); - } - } - - /// - /// - /// - private void PostCameraMode() - { - try - { - var status = new VideoCodecBaseStateMessage - { - CameraMode = GetCameraMode() - }; - - PostStatusMessage(status); - } - catch (Exception ex) - { - this.LogError(ex, "Error posting camera mode"); - } - } - - private void PostSelectedCamera() - { - try - { - var camerasCodec = Codec as IHasCodecCameras; - - var status = new VideoCodecBaseStateMessage - { - Cameras = new CameraStatus() { SelectedCamera = GetSelectedCamera(camerasCodec) }, - Presets = GetCurrentPresets() - }; - - PostStatusMessage(status); - } - catch (Exception e) - { - this.LogError(e, "Error posting selected camera"); - } - } - - private void PostCameraPresets() - { - try - { - var status = new VideoCodecBaseStateMessage - { - Presets = GetCurrentPresets() - }; - - PostStatusMessage(status); - } - catch (Exception e) - { - this.LogError(e, "Error posting camera presets"); - } - } - - private Camera GetSelectedCamera(IHasCodecCameras camerasCodec) - { - var camera = new Camera(); - - if (camerasCodec.SelectedCameraFeedback != null) - camera.Key = camerasCodec.SelectedCameraFeedback.StringValue; - if (camerasCodec.SelectedCamera != null) - { - camera.Name = camerasCodec.SelectedCamera.Name; - - camera.Capabilities = new CameraCapabilities() - { - CanPan = camerasCodec.SelectedCamera.CanPan, - CanTilt = camerasCodec.SelectedCamera.CanTilt, - CanZoom = camerasCodec.SelectedCamera.CanZoom, - CanFocus = camerasCodec.SelectedCamera.CanFocus, - }; - } - - if (camerasCodec.ControllingFarEndCameraFeedback != null) - camera.IsFarEnd = camerasCodec.ControllingFarEndCameraFeedback.BoolValue; - - - return camera; - } - - private List GetCurrentPresets() - { - var presetsCodec = Codec as IHasCodecRoomPresets; - - List currentPresets = null; - - if (presetsCodec != null && Codec is IHasFarEndCameraControl && - (Codec as IHasFarEndCameraControl).ControllingFarEndCameraFeedback.BoolValue) - currentPresets = presetsCodec.FarEndRoomPresets; - else if (presetsCodec != null) currentPresets = presetsCodec.NearEndPresets; - - return currentPresets; + this.LogError(ex, "Error posting call history"); } } /// - /// A class that represents the state data to be sent to the user app + /// Helper to grab a call with string ID /// - public class VideoCodecBaseStateMessage : DeviceStateMessageBase + /// + /// + private CodecActiveCallItem GetCallWithId(string id) { - - [JsonProperty("calls", NullValueHandling = NullValueHandling.Ignore)] - public List Calls { get; set; } - - [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] - public string CameraMode { get; set; } - - [JsonProperty("cameraSelfView", NullValueHandling = NullValueHandling.Ignore)] - public bool? CameraSelfViewIsOn { get; set; } - - [JsonProperty("cameras", NullValueHandling = NullValueHandling.Ignore)] - public CameraStatus Cameras { get; set; } - - [JsonProperty("cameraSupportsAutoMode", NullValueHandling = NullValueHandling.Ignore)] - public bool? CameraSupportsAutoMode { get; set; } - - [JsonProperty("cameraSupportsOffMode", NullValueHandling = NullValueHandling.Ignore)] - public bool? CameraSupportsOffMode { get; set; } - - [JsonProperty("currentDialString", NullValueHandling = NullValueHandling.Ignore)] - public string CurrentDialString { get; set; } - - [JsonProperty("currentDirectory", NullValueHandling = NullValueHandling.Ignore)] - public CodecDirectory CurrentDirectory { get; set; } - - [JsonProperty("directorySelectedFolderName", NullValueHandling = NullValueHandling.Ignore)] - public string DirectorySelectedFolderName { get; set; } - - [JsonProperty("hasCameras", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasCameras { get; set; } - - [JsonProperty("hasDirectory", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasDirectory { get; set; } - - [JsonProperty("hasDirectorySearch", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasDirectorySearch { get; set; } - - [JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasPresets { get; set; } - - [JsonProperty("hasRecents", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasRecents { get; set; } - - [JsonProperty("initialPhonebookSyncComplete", NullValueHandling = NullValueHandling.Ignore)] - public bool? InitialPhonebookSyncComplete { get; set; } - - [JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)] - public VideoCodecInfo Info { get; set; } - - [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsInCall { get; set; } - - [JsonProperty("isReady", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsReady { get; set; } - - [JsonProperty("isZoomRoom", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsZoomRoom { get; set; } - - [JsonProperty("meetingInfo", NullValueHandling = NullValueHandling.Ignore)] - public MeetingInfo MeetingInfo { get; set; } - - [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] - public List Presets { get; set; } - - [JsonProperty("privacyModeIsOn", NullValueHandling = NullValueHandling.Ignore)] - public bool? PrivacyModeIsOn { get; set; } - - [JsonProperty("receivingContent", NullValueHandling = NullValueHandling.Ignore)] - public bool? ReceivingContent { get; set; } - - [JsonProperty("recentCalls", NullValueHandling = NullValueHandling.Ignore)] - public List RecentCalls { get; set; } - - [JsonProperty("sharingContentIsOn", NullValueHandling = NullValueHandling.Ignore)] - public bool? SharingContentIsOn { get; set; } - - [JsonProperty("sharingSource", NullValueHandling = NullValueHandling.Ignore)] - public string SharingSource { get; set; } - - [JsonProperty("showCamerasWhenNotInCall", NullValueHandling = NullValueHandling.Ignore)] - public bool? ShowCamerasWhenNotInCall { get; set; } - - [JsonProperty("showSelfViewByDefault", NullValueHandling = NullValueHandling.Ignore)] - public bool? ShowSelfViewByDefault { get; set; } - - [JsonProperty("standbyIsOn", NullValueHandling = NullValueHandling.Ignore)] - public bool? StandbyIsOn { get; set; } - - [JsonProperty("supportsAdHocMeeting", NullValueHandling = NullValueHandling.Ignore)] - public bool? SupportsAdHocMeeting { get; set; } + return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); } - public class CameraStatus + /// + /// + /// + /// + private void GetDirectory(string id) { - [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] - public bool? CameraManualIsSupported { get; set; } - - [JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)] - public bool? CameraAutoIsSupported { get; set; } - - [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] - public bool? CameraOffIsSupported { get; set; } - - [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] - public string CameraMode { get; set; } - - [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] - public List Cameras { get; set; } - - [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] - public Camera SelectedCamera { get; set; } + if (!(Codec is IHasDirectory dirCodec)) + { + return; + } + dirCodec.GetDirectoryFolderContents(id); } - public class Camera + /// + /// + /// + private void GetDirectoryRoot() { - [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] - public string Key { get; set; } + try + { + if (!(Codec is IHasDirectory dirCodec)) + { + // do something else? + return; + } + if (!dirCodec.PhonebookSyncState.InitialSyncComplete) + { + var state = new VideoCodecBaseStateMessage + { + InitialPhonebookSyncComplete = false + }; - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string Name { get; set; } + PostStatusMessage(state); + return; + } - [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsFarEnd { get; set; } - - [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] - public CameraCapabilities Capabilities { get; set; } + dirCodec.SetCurrentDirectoryToRoot(); + } + catch (Exception ex) + { + this.LogError(ex, "Error getting directory root"); + } } - public class CameraCapabilities + /// + /// Requests the parent folder contents + /// + private void GetPreviousDirectory() { - [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] - public bool? CanPan { get; set; } - - [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] - public bool? CanTilt { get; set; } - - [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] - public bool? CanZoom { get; set; } - - [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] - public bool? CanFocus { get; set; } + if (!(Codec is IHasDirectory dirCodec)) + { + return; + } + dirCodec.GetDirectoryParentFolderContents(); } - public class VideoCodecBaseEventMessage : DeviceEventMessageBase + /// + /// Handler for codec changes + /// + private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) { - + SendFullStatus(); } - public class PasswordPromptEventMessage : VideoCodecBaseEventMessage + /// + /// + /// + private void SendIsReady() { - [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] - public string Message { get; set; } - [JsonProperty("lastAttemptWasIncorrect", NullValueHandling = NullValueHandling.Ignore)] - public bool LastAttemptWasIncorrect { get; set; } + try + { + var status = new VideoCodecBaseStateMessage(); - [JsonProperty("loginAttemptFailed", NullValueHandling = NullValueHandling.Ignore)] - public bool LoginAttemptFailed { get; set; } + var codecType = Codec.GetType(); - [JsonProperty("loginAttemptCancelled", NullValueHandling = NullValueHandling.Ignore)] - public bool LoginAttemptCancelled { get; set; } + status.IsReady = Codec.IsReady; + status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; + + PostStatusMessage(status); + } + catch (Exception ex) + { + this.LogError(ex, "Error sending codec ready status"); + } } + + /// + /// Helper method to build call status for vtc + /// + /// + protected VideoCodecBaseStateMessage GetStatus() + { + try + { + var status = new VideoCodecBaseStateMessage(); + + if (Codec is IHasCodecCameras camerasCodec) + { + status.Cameras = new CameraStatus + { + CameraManualIsSupported = true, + CameraAutoIsSupported = Codec.SupportsCameraAutoMode, + CameraOffIsSupported = Codec.SupportsCameraOff, + CameraMode = GetCameraMode(), + Cameras = camerasCodec.Cameras, + SelectedCamera = GetSelectedCamera(camerasCodec) + }; + } + + if (Codec is IHasDirectory directoryCodec) + { + status.HasDirectory = true; + status.HasDirectorySearch = true; + status.CurrentDirectory = directoryCodec.CurrentDirectoryResult; + } + + var codecType = Codec.GetType(); + + status.CameraSelfViewIsOn = Codec is IHasCodecSelfView && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue; + status.IsInCall = Codec.IsInCall; + status.PrivacyModeIsOn = Codec.PrivacyModeIsOnFeedback.BoolValue; + status.SharingContentIsOn = Codec.SharingContentIsOnFeedback.BoolValue; + status.SharingSource = Codec.SharingSourceFeedback.StringValue; + status.StandbyIsOn = Codec.StandbyIsOnFeedback.BoolValue; + status.Calls = Codec.ActiveCalls; + status.Info = Codec.CodecInfo; + status.ShowSelfViewByDefault = Codec.ShowSelfViewByDefault; + status.SupportsAdHocMeeting = Codec is IHasStartMeeting; + status.HasRecents = Codec is IHasCallHistory; + status.HasCameras = Codec is IHasCameras; + status.Presets = GetCurrentPresets(); + status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; + status.ReceivingContent = Codec is IHasFarEndContentStatus && (Codec as IHasFarEndContentStatus).ReceivingContent.BoolValue; + + if (Codec is IHasMeetingInfo meetingInfoCodec) + { + status.MeetingInfo = meetingInfoCodec.MeetingInfo; + } + + return status; + } + catch (Exception ex) + { + this.LogError(ex, "Error getting codec status"); + return null; + } + } + + protected virtual void SendFullStatus() + { + if (!Codec.IsReady) + { + return; + } + + CrestronInvoke.BeginInvoke((o) => PostStatusMessage(GetStatus())); + } + + private void PostReceivingContent(bool receivingContent) + { + try + { + var state = new VideoCodecBaseStateMessage + { + ReceivingContent = receivingContent + }; + + PostStatusMessage(state); + } catch(Exception ex) + { + this.LogError(ex, "Error posting receiving content"); + } + } + + private void PostCameraSelfView() + { + try + { + var status = new VideoCodecBaseStateMessage + { + CameraSelfViewIsOn = Codec is IHasCodecSelfView + && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue + }; + + PostStatusMessage(status); + } + catch (Exception ex) + { + this.LogError(ex, "Error posting camera self view"); + } + } + + /// + /// + /// + private void PostCameraMode() + { + try + { + var status = new VideoCodecBaseStateMessage + { + CameraMode = GetCameraMode() + }; + + PostStatusMessage(status); + } + catch (Exception ex) + { + this.LogError(ex, "Error posting camera mode"); + } + } + + private void PostSelectedCamera() + { + try + { + var camerasCodec = Codec as IHasCodecCameras; + + var status = new VideoCodecBaseStateMessage + { + Cameras = new CameraStatus() { SelectedCamera = GetSelectedCamera(camerasCodec) }, + Presets = GetCurrentPresets() + }; + + PostStatusMessage(status); + } + catch (Exception e) + { + this.LogError(e, "Error posting selected camera"); + } + } + + private void PostCameraPresets() + { + try + { + var status = new VideoCodecBaseStateMessage + { + Presets = GetCurrentPresets() + }; + + PostStatusMessage(status); + } + catch (Exception e) + { + this.LogError(e, "Error posting camera presets"); + } + } + + private Camera GetSelectedCamera(IHasCodecCameras camerasCodec) + { + var camera = new Camera(); + + if (camerasCodec.SelectedCameraFeedback != null) + camera.Key = camerasCodec.SelectedCameraFeedback.StringValue; + if (camerasCodec.SelectedCamera != null) + { + camera.Name = camerasCodec.SelectedCamera.Name; + + camera.Capabilities = new CameraCapabilities() + { + CanPan = camerasCodec.SelectedCamera.CanPan, + CanTilt = camerasCodec.SelectedCamera.CanTilt, + CanZoom = camerasCodec.SelectedCamera.CanZoom, + CanFocus = camerasCodec.SelectedCamera.CanFocus, + }; + } + + if (camerasCodec.ControllingFarEndCameraFeedback != null) + camera.IsFarEnd = camerasCodec.ControllingFarEndCameraFeedback.BoolValue; + + + return camera; + } + + private List GetCurrentPresets() + { + var presetsCodec = Codec as IHasCodecRoomPresets; + + List currentPresets = null; + + if (presetsCodec != null && Codec is IHasFarEndCameraControl && + (Codec as IHasFarEndCameraControl).ControllingFarEndCameraFeedback.BoolValue) + currentPresets = presetsCodec.FarEndRoomPresets; + else if (presetsCodec != null) currentPresets = presetsCodec.NearEndPresets; + + return currentPresets; + } +} + +/// +/// A class that represents the state data to be sent to the user app +/// +public class VideoCodecBaseStateMessage : DeviceStateMessageBase +{ + + [JsonProperty("calls", NullValueHandling = NullValueHandling.Ignore)] + public List Calls { get; set; } + + [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] + public string CameraMode { get; set; } + + [JsonProperty("cameraSelfView", NullValueHandling = NullValueHandling.Ignore)] + public bool? CameraSelfViewIsOn { get; set; } + + [JsonProperty("cameras", NullValueHandling = NullValueHandling.Ignore)] + public CameraStatus Cameras { get; set; } + + [JsonProperty("cameraSupportsAutoMode", NullValueHandling = NullValueHandling.Ignore)] + public bool? CameraSupportsAutoMode { get; set; } + + [JsonProperty("cameraSupportsOffMode", NullValueHandling = NullValueHandling.Ignore)] + public bool? CameraSupportsOffMode { get; set; } + + [JsonProperty("currentDialString", NullValueHandling = NullValueHandling.Ignore)] + public string CurrentDialString { get; set; } + + [JsonProperty("currentDirectory", NullValueHandling = NullValueHandling.Ignore)] + public CodecDirectory CurrentDirectory { get; set; } + + [JsonProperty("directorySelectedFolderName", NullValueHandling = NullValueHandling.Ignore)] + public string DirectorySelectedFolderName { get; set; } + + [JsonProperty("hasCameras", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasCameras { get; set; } + + [JsonProperty("hasDirectory", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasDirectory { get; set; } + + [JsonProperty("hasDirectorySearch", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasDirectorySearch { get; set; } + + [JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasPresets { get; set; } + + [JsonProperty("hasRecents", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasRecents { get; set; } + + [JsonProperty("initialPhonebookSyncComplete", NullValueHandling = NullValueHandling.Ignore)] + public bool? InitialPhonebookSyncComplete { get; set; } + + [JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)] + public VideoCodecInfo Info { get; set; } + + [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsInCall { get; set; } + + [JsonProperty("isReady", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsReady { get; set; } + + [JsonProperty("isZoomRoom", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsZoomRoom { get; set; } + + [JsonProperty("meetingInfo", NullValueHandling = NullValueHandling.Ignore)] + public MeetingInfo MeetingInfo { get; set; } + + [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] + public List Presets { get; set; } + + [JsonProperty("privacyModeIsOn", NullValueHandling = NullValueHandling.Ignore)] + public bool? PrivacyModeIsOn { get; set; } + + [JsonProperty("receivingContent", NullValueHandling = NullValueHandling.Ignore)] + public bool? ReceivingContent { get; set; } + + [JsonProperty("recentCalls", NullValueHandling = NullValueHandling.Ignore)] + public List RecentCalls { get; set; } + + [JsonProperty("sharingContentIsOn", NullValueHandling = NullValueHandling.Ignore)] + public bool? SharingContentIsOn { get; set; } + + [JsonProperty("sharingSource", NullValueHandling = NullValueHandling.Ignore)] + public string SharingSource { get; set; } + + [JsonProperty("showCamerasWhenNotInCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? ShowCamerasWhenNotInCall { get; set; } + + [JsonProperty("showSelfViewByDefault", NullValueHandling = NullValueHandling.Ignore)] + public bool? ShowSelfViewByDefault { get; set; } + + [JsonProperty("standbyIsOn", NullValueHandling = NullValueHandling.Ignore)] + public bool? StandbyIsOn { get; set; } + + [JsonProperty("supportsAdHocMeeting", NullValueHandling = NullValueHandling.Ignore)] + public bool? SupportsAdHocMeeting { get; set; } +} + +public class CameraStatus +{ + [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool? CameraManualIsSupported { get; set; } + + [JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool? CameraAutoIsSupported { get; set; } + + [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool? CameraOffIsSupported { get; set; } + + [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] + public string CameraMode { get; set; } + + [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] + public List Cameras { get; set; } + + [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] + public Camera SelectedCamera { get; set; } +} + +public class Camera +{ + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key { get; set; } + + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + + [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsFarEnd { get; set; } + + [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] + public CameraCapabilities Capabilities { get; set; } +} + +public class CameraCapabilities +{ + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + public bool? CanPan { get; set; } + + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + public bool? CanTilt { get; set; } + + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + public bool? CanZoom { get; set; } + + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + public bool? CanFocus { get; set; } + +} + +public class VideoCodecBaseEventMessage : DeviceEventMessageBase +{ + +} + +public class PasswordPromptEventMessage : VideoCodecBaseEventMessage +{ + [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] + public string Message { get; set; } + [JsonProperty("lastAttemptWasIncorrect", NullValueHandling = NullValueHandling.Ignore)] + public bool LastAttemptWasIncorrect { get; set; } + + [JsonProperty("loginAttemptFailed", NullValueHandling = NullValueHandling.Ignore)] + public bool LoginAttemptFailed { get; set; } + + [JsonProperty("loginAttemptCancelled", NullValueHandling = NullValueHandling.Ignore)] + public bool LoginAttemptCancelled { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs index 6e92d9da..8f109bec 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs @@ -2,17 +2,16 @@ using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -namespace PepperDash.Essentials.AppServer.Messengers +namespace PepperDash.Essentials.AppServer.Messengers; + +public class MobileControlMessage : IMobileControlMessage { - public class MobileControlMessage : IMobileControlMessage - { - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("clientId")] - public string ClientId { get; set; } + [JsonProperty("clientId")] + public string ClientId { get; set; } - [JsonProperty("content")] - public JToken Content { get; set; } - } + [JsonProperty("content")] + public JToken Content { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs index 1d804758..19571494 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs @@ -1,10 +1,9 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + +public class MobileControlSimpleContent { - public class MobileControlSimpleContent - { - [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] - public T Value { get; set; } - } + [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] + public T Value { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs index fd6e8713..2770e67d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs @@ -1,570 +1,569 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + +// ReSharper disable once InconsistentNaming +public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced { - // ReSharper disable once InconsistentNaming - public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced - { - [JoinName("QrCodeUrl")] - public JoinDataComplete QrCodeUrl = - new JoinDataComplete(new JoinData { JoinNumber = 403, JoinSpan = 1 }, - new JoinMetadata - { - Description = "QR Code URL", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("PortalSystemUrl")] - public JoinDataComplete PortalSystemUrl = - new JoinDataComplete(new JoinData { JoinNumber = 404, JoinSpan = 1 }, + [JoinName("QrCodeUrl")] + public JoinDataComplete QrCodeUrl = + new JoinDataComplete(new JoinData { JoinNumber = 403, JoinSpan = 1 }, new JoinMetadata { - Description = "Portal System URL", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("MasterVolume")] - public JoinDataComplete MasterVolume = - new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Master Volume Mute Toggle/FB/Level/Label", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.DigitalAnalogSerial - }); - - [JoinName("VolumeJoinStart")] - public JoinDataComplete VolumeJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, - new JoinMetadata - { - Description = "Volume Mute Toggle/FB/Level/Label", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.DigitalAnalogSerial - }); - - [JoinName("PrivacyMute")] - public JoinDataComplete PrivacyMute = - new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Privacy Mute Toggle/FB", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("PromptForCode")] - public JoinDataComplete PromptForCode = - new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Prompt User for Code", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ClientJoined")] - public JoinDataComplete ClientJoined = - new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Client Joined", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ActivityPhoneCallEnable")] - public JoinDataComplete ActivityPhoneCallEnable = - new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Enable Activity Phone Call", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ActivityVideoCallEnable")] - public JoinDataComplete ActivityVideoCallEnable = - new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Enable Activity Video Call", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ActivityShare")] - public JoinDataComplete ActivityShare = - new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Activity Share", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ActivityPhoneCall")] - public JoinDataComplete ActivityPhoneCall = - new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Activity Phone Call", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ActivityVideoCall")] - public JoinDataComplete ActivityVideoCall = - new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Activity Video Call", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ShutdownPromptDuration")] - public JoinDataComplete ShutdownPromptDuration = - new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Shutdown Cancel", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); - - [JoinName("ShutdownCancel")] - public JoinDataComplete ShutdownCancel = - new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Shutdown Cancel", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ShutdownEnd")] - public JoinDataComplete ShutdownEnd = - new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Shutdown End", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ShutdownStart")] - public JoinDataComplete ShutdownStart = - new JoinDataComplete(new JoinData { JoinNumber = 63, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Shutdown Start", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SourceHasChanged")] - public JoinDataComplete SourceHasChanged = - new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Source Changed", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CurrentSourceKey")] - public JoinDataComplete CurrentSourceKey = - new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Key of selected source", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - - - [JoinName("ConfigIsLocal")] - public JoinDataComplete ConfigIsLocal = - new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Config is local to Essentials", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("NumberOfAuxFaders")] - public JoinDataComplete NumberOfAuxFaders = - new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Number of Auxilliary Faders", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); - - [JoinName("SpeedDialNameStartJoin")] - public JoinDataComplete SpeedDialNameStartJoin = - new JoinDataComplete(new JoinData { JoinNumber = 241, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Speed Dial names", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("SpeedDialNumberStartJoin")] - public JoinDataComplete SpeedDialNumberStartJoin = - new JoinDataComplete(new JoinData { JoinNumber = 251, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Speed Dial numbers", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("SpeedDialVisibleStartJoin")] - public JoinDataComplete SpeedDialVisibleStartJoin = - new JoinDataComplete(new JoinData { JoinNumber = 261, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Speed Dial Visible", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("RoomIsOn")] - public JoinDataComplete RoomIsOn = - new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Room Is On", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("UserCodeToSystem")] - public JoinDataComplete UserCodeToSystem = - new JoinDataComplete(new JoinData { JoinNumber = 401, JoinSpan = 1 }, - new JoinMetadata - { - Description = "User Code", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ServerUrl")] - public JoinDataComplete ServerUrl = - new JoinDataComplete(new JoinData { JoinNumber = 402, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Server URL", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ConfigRoomName")] - public JoinDataComplete ConfigRoomName = - new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Room Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ConfigHelpMessage")] - public JoinDataComplete ConfigHelpMessage = - new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Room help message", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ConfigHelpNumber")] - public JoinDataComplete ConfigHelpNumber = - new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Room help number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ConfigRoomPhoneNumber")] - public JoinDataComplete ConfigRoomPhoneNumber = - new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Room phone number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ConfigRoomURI")] - public JoinDataComplete ConfigRoomUri = - new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Room URI", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("ApiOnlineAndAuthorized")] - public JoinDataComplete ApiOnlineAndAuthorized = - new JoinDataComplete(new JoinData { JoinNumber = 500, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Config info from SIMPL is ready", + Description = "QR Code URL", JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ConfigIsReady")] - public JoinDataComplete ConfigIsReady = - new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Config info from SIMPL is ready", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ReadyForConfig")] - public JoinDataComplete ReadyForConfig = - new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Config info from SIMPL is ready", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("HideVideoConfRecents")] - public JoinDataComplete HideVideoConfRecents = - new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Hide Video Conference Recents", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("ShowCameraWhenNotInCall")] - public JoinDataComplete ShowCameraWhenNotInCall = - new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Show camera when not in call", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("UseSourceEnabled")] - public JoinDataComplete UseSourceEnabled = - new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Use Source Enabled Joins", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - - [JoinName("SourceShareDisableJoinStart")] - public JoinDataComplete SourceShareDisableJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source is not sharable", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SourceIsEnabledJoinStart")] - public JoinDataComplete SourceIsEnabledJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source is enabled/visible", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SourceIsControllableJoinStart")] - public JoinDataComplete SourceIsControllableJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source is controllable", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SourceIsAudioSourceJoinStart")] - public JoinDataComplete SourceIsAudioSourceJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source is Audio Source", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - - [JoinName("SourceNameJoinStart")] - public JoinDataComplete SourceNameJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source Names", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("SourceIconJoinStart")] - public JoinDataComplete SourceIconJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source Icons", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("SourceKeyJoinStart")] - public JoinDataComplete SourceKeyJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source Keys", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("SourceControlDeviceKeyJoinStart")] - public JoinDataComplete SourceControlDeviceKeyJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source Control Device Keys", - JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); - [JoinName("SourceTypeJoinStart")] - public JoinDataComplete SourceTypeJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, - new JoinMetadata - { - Description = "Source Types", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CameraNearNameStart")] - public JoinDataComplete CameraNearNameStart = - new JoinDataComplete(new JoinData { JoinNumber = 761, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Near End Camera Names", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CameraFarName")] - public JoinDataComplete CameraFarName = - new JoinDataComplete(new JoinData { JoinNumber = 771, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Far End Camera Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - #region Advanced Sharing - [JoinName("SupportsAdvancedSharing")] - public JoinDataComplete SupportsAdvancedSharing = - new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Supports Advanced Sharing", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("UseDestinationEnable")] - public JoinDataComplete UseDestinationEnable = - new JoinDataComplete(new JoinData { JoinNumber = 506, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Use Destination Enable", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - - [JoinName("UserCanChangeShareMode")] - public JoinDataComplete UserCanChangeShareMode = - new JoinDataComplete(new JoinData { JoinNumber = 507, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Share Mode Toggle Visible to User", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DestinationNameJoinStart")] - public JoinDataComplete DestinationNameJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 801, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Destination Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DestinationDeviceKeyJoinStart")] - public JoinDataComplete DestinationDeviceKeyJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 811, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Destination Device Key", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DestinationTypeJoinStart")] - public JoinDataComplete DestinationTypeJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 821, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Destination type. Should be Audio, Video, AudioVideo", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DestinationIsEnabledJoinStart")] - public JoinDataComplete DestinationIsEnabledJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 801, JoinSpan = 10 }, - new JoinMetadata - { - Description = "Show Destination on UI", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - #endregion - - public MobileControlSIMPLRoomJoinMap(uint joinStart) - : base(joinStart, typeof(MobileControlSIMPLRoomJoinMap)) + [JoinName("PortalSystemUrl")] + public JoinDataComplete PortalSystemUrl = + new JoinDataComplete(new JoinData { JoinNumber = 404, JoinSpan = 1 }, + new JoinMetadata { - } + Description = "Portal System URL", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("MasterVolume")] + public JoinDataComplete MasterVolume = + new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Master Volume Mute Toggle/FB/Level/Label", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.DigitalAnalogSerial + }); + + [JoinName("VolumeJoinStart")] + public JoinDataComplete VolumeJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, + new JoinMetadata + { + Description = "Volume Mute Toggle/FB/Level/Label", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.DigitalAnalogSerial + }); + + [JoinName("PrivacyMute")] + public JoinDataComplete PrivacyMute = + new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Privacy Mute Toggle/FB", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PromptForCode")] + public JoinDataComplete PromptForCode = + new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Prompt User for Code", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ClientJoined")] + public JoinDataComplete ClientJoined = + new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Client Joined", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ActivityPhoneCallEnable")] + public JoinDataComplete ActivityPhoneCallEnable = + new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Enable Activity Phone Call", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ActivityVideoCallEnable")] + public JoinDataComplete ActivityVideoCallEnable = + new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Enable Activity Video Call", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ActivityShare")] + public JoinDataComplete ActivityShare = + new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Activity Share", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ActivityPhoneCall")] + public JoinDataComplete ActivityPhoneCall = + new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Activity Phone Call", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ActivityVideoCall")] + public JoinDataComplete ActivityVideoCall = + new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Activity Video Call", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ShutdownPromptDuration")] + public JoinDataComplete ShutdownPromptDuration = + new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Shutdown Cancel", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("ShutdownCancel")] + public JoinDataComplete ShutdownCancel = + new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Shutdown Cancel", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ShutdownEnd")] + public JoinDataComplete ShutdownEnd = + new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Shutdown End", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ShutdownStart")] + public JoinDataComplete ShutdownStart = + new JoinDataComplete(new JoinData { JoinNumber = 63, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Shutdown Start", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SourceHasChanged")] + public JoinDataComplete SourceHasChanged = + new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Source Changed", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CurrentSourceKey")] + public JoinDataComplete CurrentSourceKey = + new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Key of selected source", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + + + [JoinName("ConfigIsLocal")] + public JoinDataComplete ConfigIsLocal = + new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Config is local to Essentials", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("NumberOfAuxFaders")] + public JoinDataComplete NumberOfAuxFaders = + new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Number of Auxilliary Faders", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("SpeedDialNameStartJoin")] + public JoinDataComplete SpeedDialNameStartJoin = + new JoinDataComplete(new JoinData { JoinNumber = 241, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Speed Dial names", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SpeedDialNumberStartJoin")] + public JoinDataComplete SpeedDialNumberStartJoin = + new JoinDataComplete(new JoinData { JoinNumber = 251, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Speed Dial numbers", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SpeedDialVisibleStartJoin")] + public JoinDataComplete SpeedDialVisibleStartJoin = + new JoinDataComplete(new JoinData { JoinNumber = 261, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Speed Dial Visible", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("RoomIsOn")] + public JoinDataComplete RoomIsOn = + new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Room Is On", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("UserCodeToSystem")] + public JoinDataComplete UserCodeToSystem = + new JoinDataComplete(new JoinData { JoinNumber = 401, JoinSpan = 1 }, + new JoinMetadata + { + Description = "User Code", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ServerUrl")] + public JoinDataComplete ServerUrl = + new JoinDataComplete(new JoinData { JoinNumber = 402, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Server URL", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ConfigRoomName")] + public JoinDataComplete ConfigRoomName = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Room Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ConfigHelpMessage")] + public JoinDataComplete ConfigHelpMessage = + new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Room help message", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ConfigHelpNumber")] + public JoinDataComplete ConfigHelpNumber = + new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Room help number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ConfigRoomPhoneNumber")] + public JoinDataComplete ConfigRoomPhoneNumber = + new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Room phone number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ConfigRoomURI")] + public JoinDataComplete ConfigRoomUri = + new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Room URI", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("ApiOnlineAndAuthorized")] + public JoinDataComplete ApiOnlineAndAuthorized = + new JoinDataComplete(new JoinData { JoinNumber = 500, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Config info from SIMPL is ready", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ConfigIsReady")] + public JoinDataComplete ConfigIsReady = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Config info from SIMPL is ready", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ReadyForConfig")] + public JoinDataComplete ReadyForConfig = + new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Config info from SIMPL is ready", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("HideVideoConfRecents")] + public JoinDataComplete HideVideoConfRecents = + new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Hide Video Conference Recents", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("ShowCameraWhenNotInCall")] + public JoinDataComplete ShowCameraWhenNotInCall = + new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Show camera when not in call", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("UseSourceEnabled")] + public JoinDataComplete UseSourceEnabled = + new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Use Source Enabled Joins", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("SourceShareDisableJoinStart")] + public JoinDataComplete SourceShareDisableJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source is not sharable", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SourceIsEnabledJoinStart")] + public JoinDataComplete SourceIsEnabledJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source is enabled/visible", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SourceIsControllableJoinStart")] + public JoinDataComplete SourceIsControllableJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source is controllable", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SourceIsAudioSourceJoinStart")] + public JoinDataComplete SourceIsAudioSourceJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source is Audio Source", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("SourceNameJoinStart")] + public JoinDataComplete SourceNameJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source Names", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SourceIconJoinStart")] + public JoinDataComplete SourceIconJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source Icons", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SourceKeyJoinStart")] + public JoinDataComplete SourceKeyJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source Keys", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SourceControlDeviceKeyJoinStart")] + public JoinDataComplete SourceControlDeviceKeyJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source Control Device Keys", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SourceTypeJoinStart")] + public JoinDataComplete SourceTypeJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, + new JoinMetadata + { + Description = "Source Types", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CameraNearNameStart")] + public JoinDataComplete CameraNearNameStart = + new JoinDataComplete(new JoinData { JoinNumber = 761, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Near End Camera Names", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CameraFarName")] + public JoinDataComplete CameraFarName = + new JoinDataComplete(new JoinData { JoinNumber = 771, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Far End Camera Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + #region Advanced Sharing + [JoinName("SupportsAdvancedSharing")] + public JoinDataComplete SupportsAdvancedSharing = + new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Supports Advanced Sharing", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("UseDestinationEnable")] + public JoinDataComplete UseDestinationEnable = + new JoinDataComplete(new JoinData { JoinNumber = 506, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Use Destination Enable", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("UserCanChangeShareMode")] + public JoinDataComplete UserCanChangeShareMode = + new JoinDataComplete(new JoinData { JoinNumber = 507, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Share Mode Toggle Visible to User", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DestinationNameJoinStart")] + public JoinDataComplete DestinationNameJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 801, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Destination Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DestinationDeviceKeyJoinStart")] + public JoinDataComplete DestinationDeviceKeyJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 811, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Destination Device Key", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DestinationTypeJoinStart")] + public JoinDataComplete DestinationTypeJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 821, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Destination type. Should be Audio, Video, AudioVideo", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DestinationIsEnabledJoinStart")] + public JoinDataComplete DestinationIsEnabledJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 801, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Show Destination on UI", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + #endregion + + public MobileControlSIMPLRoomJoinMap(uint joinStart) + : base(joinStart, typeof(MobileControlSIMPLRoomJoinMap)) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs index 10c516ee..d61a68ec 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs @@ -1,52 +1,62 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + +public class MobileControlSIMPLRunDirectRouteActionJoinMap : JoinMapBaseAdvanced { - public class MobileControlSIMPLRunDirectRouteActionJoinMap : JoinMapBaseAdvanced - { - [JoinName("AdvancedSharingModeFb")] - public JoinDataComplete AdvancedSharingModeFb = - new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Use Advanced Sharing Mode", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("AdvancedSharingModeFb")] + public JoinDataComplete AdvancedSharingModeFb = + new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Use Advanced Sharing Mode", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("AdvancedSharingModeOn")] - public JoinDataComplete AdvancedSharingModeOn = - new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Use Advanced Sharing Mode", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("AdvancedSharingModeOn")] + public JoinDataComplete AdvancedSharingModeOn = + new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Use Advanced Sharing Mode", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("AdvancedSharingModeOff")] - public JoinDataComplete AdvancedSharingModeOff = - new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Use Advanced Sharing Mode", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("AdvancedSharingModeOff")] + public JoinDataComplete AdvancedSharingModeOff = + new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Use Advanced Sharing Mode", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("AdvancedSharingModeToggle")] - public JoinDataComplete AdvancedSharingModeToggle = - new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Use Advanced Sharing Mode", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); + [JoinName("AdvancedSharingModeToggle")] + public JoinDataComplete AdvancedSharingModeToggle = + new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Use Advanced Sharing Mode", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); - [JoinName("SourceForDestinationJoinStart")] - public JoinDataComplete SourceForDestinationJoinStart = - new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 10 }, + [JoinName("SourceForDestinationJoinStart")] + public JoinDataComplete SourceForDestinationJoinStart = + new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 10 }, + new JoinMetadata + { + Description = "Source to Route to Destination & FB", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("SourceForDestinationAudio")] + public JoinDataComplete SourceForDestinationAudio = + new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Source to Route to Destination & FB", @@ -54,19 +64,8 @@ namespace PepperDash.Essentials.AppServer JoinType = eJoinType.Serial }); - [JoinName("SourceForDestinationAudio")] - public JoinDataComplete SourceForDestinationAudio = - new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, - new JoinMetadata - { - Description = "Source to Route to Destination & FB", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - - public MobileControlSIMPLRunDirectRouteActionJoinMap(uint joinStart) - : base(joinStart, typeof(MobileControlSIMPLRunDirectRouteActionJoinMap)) - { - } + public MobileControlSIMPLRunDirectRouteActionJoinMap(uint joinStart) + : base(joinStart, typeof(MobileControlSIMPLRunDirectRouteActionJoinMap)) + { } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLAtcJoinMap.cs b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLAtcJoinMap.cs index 0ec4de5a..8d7c78b5 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLAtcJoinMap.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLAtcJoinMap.cs @@ -1,247 +1,246 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + +public class SIMPLAtcJoinMap : JoinMapBaseAdvanced { - public class SIMPLAtcJoinMap : JoinMapBaseAdvanced + [JoinName("EndCall")] + public JoinDataComplete EndCall = + new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Hang Up", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingAnswer")] + public JoinDataComplete IncomingAnswer = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Answer Incoming Call", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingReject")] + public JoinDataComplete IncomingReject = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Reject Incoming Call", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SpeedDialStart")] + public JoinDataComplete SpeedDialStart = + new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, + new JoinMetadata() + { + Description = "Speed Dial", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CurrentDialString")] + public JoinDataComplete CurrentDialString = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Dial String", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CurrentCallNumber")] + public JoinDataComplete CurrentCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Call Number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CurrentCallName")] + public JoinDataComplete CurrentCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Call Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("HookState")] + public JoinDataComplete HookState = + new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Hook State", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CallDirection")] + public JoinDataComplete CallDirection = + new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Call Direction", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("IncomingCallName")] + public JoinDataComplete IncomingCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Incoming Call Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("IncomingCallNumber")] + public JoinDataComplete IncomingCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Incoming Call Number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("0")] + public JoinDataComplete Dtmf0 = + new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 0", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("1")] + public JoinDataComplete Dtmf1 = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 1", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("2")] + public JoinDataComplete Dtmf2 = + new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 2", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("3")] + public JoinDataComplete Dtmf3 = + new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 3", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("4")] + public JoinDataComplete Dtmf4 = + new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 4", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("5")] + public JoinDataComplete Dtmf5 = + new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 5", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("6")] + public JoinDataComplete Dtmf6 = + new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 6", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("7")] + public JoinDataComplete Dtmf7 = + new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 7", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("8")] + public JoinDataComplete Dtmf8 = + new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 8", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("9")] + public JoinDataComplete Dtmf9 = + new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 9", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("*")] + public JoinDataComplete DtmfStar = + new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF *", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("#")] + public JoinDataComplete DtmfPound = + new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF #", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + /// + /// Constructor that passes the joinStart to the base class + /// + /// + public SIMPLAtcJoinMap(uint joinStart) + : base(joinStart, typeof(SIMPLAtcJoinMap)) { - [JoinName("EndCall")] - public JoinDataComplete EndCall = - new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Hang Up", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("IncomingAnswer")] - public JoinDataComplete IncomingAnswer = - new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Answer Incoming Call", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("IncomingReject")] - public JoinDataComplete IncomingReject = - new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Reject Incoming Call", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SpeedDialStart")] - public JoinDataComplete SpeedDialStart = - new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, - new JoinMetadata() - { - Description = "Speed Dial", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CurrentDialString")] - public JoinDataComplete CurrentDialString = - new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Dial String", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CurrentCallNumber")] - public JoinDataComplete CurrentCallNumber = - new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Call Number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CurrentCallName")] - public JoinDataComplete CurrentCallName = - new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Call Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("HookState")] - public JoinDataComplete HookState = - new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Hook State", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CallDirection")] - public JoinDataComplete CallDirection = - new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Call Direction", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("IncomingCallName")] - public JoinDataComplete IncomingCallName = - new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Incoming Call Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("IncomingCallNumber")] - public JoinDataComplete IncomingCallNumber = - new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Incoming Call Number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("0")] - public JoinDataComplete Dtmf0 = - new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 0", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("1")] - public JoinDataComplete Dtmf1 = - new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 1", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("2")] - public JoinDataComplete Dtmf2 = - new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 2", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("3")] - public JoinDataComplete Dtmf3 = - new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 3", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("4")] - public JoinDataComplete Dtmf4 = - new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 4", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("5")] - public JoinDataComplete Dtmf5 = - new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 5", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("6")] - public JoinDataComplete Dtmf6 = - new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 6", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("7")] - public JoinDataComplete Dtmf7 = - new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 7", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("8")] - public JoinDataComplete Dtmf8 = - new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 8", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("9")] - public JoinDataComplete Dtmf9 = - new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 9", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("*")] - public JoinDataComplete DtmfStar = - new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF *", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("#")] - public JoinDataComplete DtmfPound = - new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF #", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - /// - /// Constructor that passes the joinStart to the base class - /// - /// - public SIMPLAtcJoinMap(uint joinStart) - : base(joinStart, typeof(SIMPLAtcJoinMap)) - { - } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs index 69b32495..59b9fbf2 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs @@ -1,553 +1,552 @@ using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.AppServer +namespace PepperDash.Essentials.AppServer; + +public class SIMPLVtcJoinMap : JoinMapBaseAdvanced { - public class SIMPLVtcJoinMap : JoinMapBaseAdvanced + [JoinName("EndCall")] + public JoinDataComplete EndCall = + new JoinDataComplete(new JoinData() { JoinNumber = 24, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Hang Up", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingCall")] + public JoinDataComplete IncomingCall = + new JoinDataComplete(new JoinData() { JoinNumber = 50, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Incoming Call", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingAnswer")] + public JoinDataComplete IncomingAnswer = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Answer Incoming Call", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingReject")] + public JoinDataComplete IncomingReject = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Reject Incoming Call", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SpeedDialStart")] + public JoinDataComplete SpeedDialStart = + new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, + new JoinMetadata() + { + Description = "Speed Dial", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectorySearchBusy")] + public JoinDataComplete DirectorySearchBusy = + new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory Search Busy FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryLineSelected")] + public JoinDataComplete DirectoryLineSelected = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory Line Selected FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryEntryIsContact")] + public JoinDataComplete DirectoryEntryIsContact = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory Selected Entry Is Contact FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryIsRoot")] + public JoinDataComplete DirectoryIsRoot = + new JoinDataComplete(new JoinData() { JoinNumber = 102, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory is on Root FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DDirectoryHasChanged")] + public JoinDataComplete DDirectoryHasChanged = + new JoinDataComplete(new JoinData() { JoinNumber = 103, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory has changed FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryRoot")] + public JoinDataComplete DirectoryRoot = + new JoinDataComplete(new JoinData() { JoinNumber = 104, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Go to Directory Root", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryFolderBack")] + public JoinDataComplete DirectoryFolderBack = + new JoinDataComplete(new JoinData() { JoinNumber = 105, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Go back one directory level", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryDialSelectedLine")] + public JoinDataComplete DirectoryDialSelectedLine = + new JoinDataComplete(new JoinData() { JoinNumber = 106, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Dial selected directory line", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraTiltUp")] + public JoinDataComplete CameraTiltUp = + new JoinDataComplete(new JoinData() { JoinNumber = 111, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Tilt Up", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraTiltDown")] + public JoinDataComplete CameraTiltDown = + new JoinDataComplete(new JoinData() { JoinNumber = 112, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Tilt Down", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraPanLeft")] + public JoinDataComplete CameraPanLeft = + new JoinDataComplete(new JoinData() { JoinNumber = 113, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Pan Left", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraPanRight")] + public JoinDataComplete CameraPanRight = + new JoinDataComplete(new JoinData() { JoinNumber = 114, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Pan Right", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraZoomIn")] + public JoinDataComplete CameraZoomIn = + new JoinDataComplete(new JoinData() { JoinNumber = 115, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Zoom In", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraZoomOut")] + public JoinDataComplete CameraZoomOut = + new JoinDataComplete(new JoinData() { JoinNumber = 116, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Zoom Out", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraPresetStart")] + public JoinDataComplete CameraPresetStart = + new JoinDataComplete(new JoinData() { JoinNumber = 121, JoinSpan = 5 }, + new JoinMetadata() + { + Description = "Camera Presets", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraModeAuto")] + public JoinDataComplete CameraModeAuto = + new JoinDataComplete(new JoinData() { JoinNumber = 131, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Mode Auto", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraModeManual")] + public JoinDataComplete CameraModeManual = + new JoinDataComplete(new JoinData() { JoinNumber = 132, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Mode Manual", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraModeOff")] + public JoinDataComplete CameraModeOff = + new JoinDataComplete(new JoinData() { JoinNumber = 133, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Mode Off", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraSelfView")] + public JoinDataComplete CameraSelfView = + new JoinDataComplete(new JoinData() { JoinNumber = 141, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Self View Toggle/FB", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraLayout")] + public JoinDataComplete CameraLayout = + new JoinDataComplete(new JoinData() { JoinNumber = 142, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Layout Toggle", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraSupportsAutoMode")] + public JoinDataComplete CameraSupportsAutoMode = + new JoinDataComplete(new JoinData() { JoinNumber = 143, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Supports Auto Mode FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraSupportsOffMode")] + public JoinDataComplete CameraSupportsOffMode = + new JoinDataComplete(new JoinData() { JoinNumber = 144, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Supports Off Mode FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraNumberSelect")] + public JoinDataComplete CameraNumberSelect = + new JoinDataComplete(new JoinData() { JoinNumber = 60, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Camera Number Select/FB", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectorySelectRow")] + public JoinDataComplete DirectorySelectRow = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory Select Row", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("DirectoryRowCount")] + public JoinDataComplete DirectoryRowCount = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory Row Count FB", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("CurrentDialString")] + public JoinDataComplete CurrentDialString = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Dial String", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CurrentCallName")] + public JoinDataComplete CurrentCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Call Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CurrentCallNumber")] + public JoinDataComplete CurrentCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Call Number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("HookState")] + public JoinDataComplete HookState = + new JoinDataComplete(new JoinData() { JoinNumber = 31, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Hook State", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CallDirection")] + public JoinDataComplete CallDirection = + new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Current Call Direction", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("IncomingCallName")] + public JoinDataComplete IncomingCallName = + new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Incoming Call Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("IncomingCallNumber")] + public JoinDataComplete IncomingCallNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Incoming Call Number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectorySearchString")] + public JoinDataComplete DirectorySearchString = + new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Directory Search String", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectoryEntriesStart")] + public JoinDataComplete DirectoryEntriesStart = + new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 255 }, + new JoinMetadata() + { + Description = "Directory Entries", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectoryEntrySelectedName")] + public JoinDataComplete DirectoryEntrySelectedName = + new JoinDataComplete(new JoinData() { JoinNumber = 356, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Selected Directory Entry Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectoryEntrySelectedNumber")] + public JoinDataComplete DirectoryEntrySelectedNumber = + new JoinDataComplete(new JoinData() { JoinNumber = 357, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Selected Directory Entry Number", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectorySelectedFolderName")] + public JoinDataComplete DirectorySelectedFolderName = + new JoinDataComplete(new JoinData() { JoinNumber = 358, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "Selected Directory Folder Name", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("1")] + public JoinDataComplete Dtmf1 = + new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 1", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("2")] + public JoinDataComplete Dtmf2 = + new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 2", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("3")] + public JoinDataComplete Dtmf3 = + new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 3", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("4")] + public JoinDataComplete Dtmf4 = + new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 4", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("5")] + public JoinDataComplete Dtmf5 = + new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 5", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("6")] + public JoinDataComplete Dtmf6 = + new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 6", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("7")] + public JoinDataComplete Dtmf7 = + new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 7", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("8")] + public JoinDataComplete Dtmf8 = + new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 8", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("9")] + public JoinDataComplete Dtmf9 = + new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 9", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("0")] + public JoinDataComplete Dtmf0 = + new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF 0", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("*")] + public JoinDataComplete DtmfStar = + new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF *", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("#")] + public JoinDataComplete DtmfPound = + new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, + new JoinMetadata() + { + Description = "DTMF #", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + public SIMPLVtcJoinMap(uint joinStart) + : base(joinStart, typeof(SIMPLVtcJoinMap)) { - [JoinName("EndCall")] - public JoinDataComplete EndCall = - new JoinDataComplete(new JoinData() { JoinNumber = 24, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Hang Up", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("IncomingCall")] - public JoinDataComplete IncomingCall = - new JoinDataComplete(new JoinData() { JoinNumber = 50, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Incoming Call", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("IncomingAnswer")] - public JoinDataComplete IncomingAnswer = - new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Answer Incoming Call", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("IncomingReject")] - public JoinDataComplete IncomingReject = - new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Reject Incoming Call", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SpeedDialStart")] - public JoinDataComplete SpeedDialStart = - new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, - new JoinMetadata() - { - Description = "Speed Dial", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectorySearchBusy")] - public JoinDataComplete DirectorySearchBusy = - new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory Search Busy FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectoryLineSelected")] - public JoinDataComplete DirectoryLineSelected = - new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory Line Selected FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectoryEntryIsContact")] - public JoinDataComplete DirectoryEntryIsContact = - new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory Selected Entry Is Contact FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectoryIsRoot")] - public JoinDataComplete DirectoryIsRoot = - new JoinDataComplete(new JoinData() { JoinNumber = 102, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory is on Root FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DDirectoryHasChanged")] - public JoinDataComplete DDirectoryHasChanged = - new JoinDataComplete(new JoinData() { JoinNumber = 103, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory has changed FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectoryRoot")] - public JoinDataComplete DirectoryRoot = - new JoinDataComplete(new JoinData() { JoinNumber = 104, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Go to Directory Root", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectoryFolderBack")] - public JoinDataComplete DirectoryFolderBack = - new JoinDataComplete(new JoinData() { JoinNumber = 105, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Go back one directory level", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectoryDialSelectedLine")] - public JoinDataComplete DirectoryDialSelectedLine = - new JoinDataComplete(new JoinData() { JoinNumber = 106, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Dial selected directory line", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraTiltUp")] - public JoinDataComplete CameraTiltUp = - new JoinDataComplete(new JoinData() { JoinNumber = 111, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Tilt Up", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraTiltDown")] - public JoinDataComplete CameraTiltDown = - new JoinDataComplete(new JoinData() { JoinNumber = 112, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Tilt Down", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraPanLeft")] - public JoinDataComplete CameraPanLeft = - new JoinDataComplete(new JoinData() { JoinNumber = 113, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Pan Left", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraPanRight")] - public JoinDataComplete CameraPanRight = - new JoinDataComplete(new JoinData() { JoinNumber = 114, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Pan Right", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraZoomIn")] - public JoinDataComplete CameraZoomIn = - new JoinDataComplete(new JoinData() { JoinNumber = 115, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Zoom In", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraZoomOut")] - public JoinDataComplete CameraZoomOut = - new JoinDataComplete(new JoinData() { JoinNumber = 116, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Zoom Out", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraPresetStart")] - public JoinDataComplete CameraPresetStart = - new JoinDataComplete(new JoinData() { JoinNumber = 121, JoinSpan = 5 }, - new JoinMetadata() - { - Description = "Camera Presets", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraModeAuto")] - public JoinDataComplete CameraModeAuto = - new JoinDataComplete(new JoinData() { JoinNumber = 131, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Mode Auto", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraModeManual")] - public JoinDataComplete CameraModeManual = - new JoinDataComplete(new JoinData() { JoinNumber = 132, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Mode Manual", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraModeOff")] - public JoinDataComplete CameraModeOff = - new JoinDataComplete(new JoinData() { JoinNumber = 133, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Mode Off", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraSelfView")] - public JoinDataComplete CameraSelfView = - new JoinDataComplete(new JoinData() { JoinNumber = 141, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Self View Toggle/FB", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraLayout")] - public JoinDataComplete CameraLayout = - new JoinDataComplete(new JoinData() { JoinNumber = 142, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Layout Toggle", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraSupportsAutoMode")] - public JoinDataComplete CameraSupportsAutoMode = - new JoinDataComplete(new JoinData() { JoinNumber = 143, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Supports Auto Mode FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraSupportsOffMode")] - public JoinDataComplete CameraSupportsOffMode = - new JoinDataComplete(new JoinData() { JoinNumber = 144, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Supports Off Mode FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("CameraNumberSelect")] - public JoinDataComplete CameraNumberSelect = - new JoinDataComplete(new JoinData() { JoinNumber = 60, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Camera Number Select/FB", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("DirectorySelectRow")] - public JoinDataComplete DirectorySelectRow = - new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory Select Row", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Analog - }); - - [JoinName("DirectoryRowCount")] - public JoinDataComplete DirectoryRowCount = - new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory Row Count FB", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Analog - }); - - [JoinName("CurrentDialString")] - public JoinDataComplete CurrentDialString = - new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Dial String", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CurrentCallName")] - public JoinDataComplete CurrentCallName = - new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Call Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CurrentCallNumber")] - public JoinDataComplete CurrentCallNumber = - new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Call Number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("HookState")] - public JoinDataComplete HookState = - new JoinDataComplete(new JoinData() { JoinNumber = 31, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Hook State", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("CallDirection")] - public JoinDataComplete CallDirection = - new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Current Call Direction", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("IncomingCallName")] - public JoinDataComplete IncomingCallName = - new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Incoming Call Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("IncomingCallNumber")] - public JoinDataComplete IncomingCallNumber = - new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Incoming Call Number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DirectorySearchString")] - public JoinDataComplete DirectorySearchString = - new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Directory Search String", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DirectoryEntriesStart")] - public JoinDataComplete DirectoryEntriesStart = - new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 255 }, - new JoinMetadata() - { - Description = "Directory Entries", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DirectoryEntrySelectedName")] - public JoinDataComplete DirectoryEntrySelectedName = - new JoinDataComplete(new JoinData() { JoinNumber = 356, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Selected Directory Entry Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DirectoryEntrySelectedNumber")] - public JoinDataComplete DirectoryEntrySelectedNumber = - new JoinDataComplete(new JoinData() { JoinNumber = 357, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Selected Directory Entry Number", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("DirectorySelectedFolderName")] - public JoinDataComplete DirectorySelectedFolderName = - new JoinDataComplete(new JoinData() { JoinNumber = 358, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "Selected Directory Folder Name", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Serial - }); - - [JoinName("1")] - public JoinDataComplete Dtmf1 = - new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 1", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("2")] - public JoinDataComplete Dtmf2 = - new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 2", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("3")] - public JoinDataComplete Dtmf3 = - new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 3", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("4")] - public JoinDataComplete Dtmf4 = - new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 4", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("5")] - public JoinDataComplete Dtmf5 = - new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 5", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("6")] - public JoinDataComplete Dtmf6 = - new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 6", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("7")] - public JoinDataComplete Dtmf7 = - new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 7", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("8")] - public JoinDataComplete Dtmf8 = - new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 8", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("9")] - public JoinDataComplete Dtmf9 = - new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 9", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("0")] - public JoinDataComplete Dtmf0 = - new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF 0", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("*")] - public JoinDataComplete DtmfStar = - new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF *", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("#")] - public JoinDataComplete DtmfPound = - new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, - new JoinMetadata() - { - Description = "DTMF #", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - public SIMPLVtcJoinMap(uint joinStart) - : base(joinStart, typeof(SIMPLVtcJoinMap)) - { - } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs b/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs index 4e4a4439..59faab0e 100644 --- a/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs +++ b/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs @@ -1,19 +1,18 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class AuthorizationResponse { - public class AuthorizationResponse - { - [JsonProperty("authorized")] - public bool Authorized { get; set; } + [JsonProperty("authorized")] + public bool Authorized { get; set; } - [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] - public string Reason { get; set; } = null; - } - - public class AuthorizationRequest - { - [JsonProperty("grantCode")] - public string GrantCode { get; set; } - } + [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] + public string Reason { get; set; } = null; +} + +public class AuthorizationRequest +{ + [JsonProperty("grantCode")] + public string GrantCode { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl/Interfaces.cs b/src/PepperDash.Essentials.MobileControl/Interfaces.cs index dc5552c6..418e7cc1 100644 --- a/src/PepperDash.Essentials.MobileControl/Interfaces.cs +++ b/src/PepperDash.Essentials.MobileControl/Interfaces.cs @@ -1,16 +1,15 @@ using System; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +/// +/// Represents a room whose configuration is derived from runtime data, +/// perhaps from another program, and that the data may not be fully +/// available at startup. +/// +public interface IDelayedConfiguration { - /// - /// Represents a room whose configuration is derived from runtime data, - /// perhaps from another program, and that the data may not be fully - /// available at startup. - /// - public interface IDelayedConfiguration - { - event EventHandler ConfigurationIsReady; - } + event EventHandler ConfigurationIsReady; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs b/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs index 2f12f5bd..905bff7b 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlAction.cs @@ -2,18 +2,17 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class MobileControlAction : IMobileControlAction { - public class MobileControlAction : IMobileControlAction + public IMobileControlMessenger Messenger { get; private set; } + + public Action Action { get; private set; } + + public MobileControlAction(IMobileControlMessenger messenger, Action handler) { - public IMobileControlMessenger Messenger { get; private set; } - - public Action Action { get; private set; } - - public MobileControlAction(IMobileControlMessenger messenger, Action handler) - { - Messenger = messenger; - Action = handler; - } + Messenger = messenger; + Action = handler; } } diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs b/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs index af25f27a..8bc7de9e 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs @@ -2,143 +2,142 @@ using Newtonsoft.Json.Converters; using System.Collections.Generic; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +/// +/// +/// +public class MobileControlConfig { + [JsonProperty("serverUrl")] + public string ServerUrl { get; set; } + + [JsonProperty("clientAppUrl")] + public string ClientAppUrl { get; set; } + + [JsonProperty("directServer")] + public MobileControlDirectServerPropertiesConfig DirectServer { get; set; } + + [JsonProperty("applicationConfig")] + public MobileControlApplicationConfig ApplicationConfig { get; set; } = null; + + [JsonProperty("enableApiServer")] + public bool EnableApiServer { get; set; } = true; +} + +public class MobileControlDirectServerPropertiesConfig +{ + [JsonProperty("enableDirectServer")] + public bool EnableDirectServer { get; set; } + + [JsonProperty("port")] + public int Port { get; set; } + + [JsonProperty("logging")] + public MobileControlLoggingConfig Logging { get; set; } + + [JsonProperty("automaticallyForwardPortToCSLAN")] + public bool? AutomaticallyForwardPortToCSLAN { get; set; } + + public MobileControlDirectServerPropertiesConfig() + { + Logging = new MobileControlLoggingConfig(); + } +} + +public class MobileControlLoggingConfig +{ + [JsonProperty("enableRemoteLogging")] + public bool EnableRemoteLogging { get; set; } + + [JsonProperty("host")] + public string Host { get; set; } + + [JsonProperty("port")] + public int Port { get; set; } + + + +} + +public class MobileControlRoomBridgePropertiesConfig +{ + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("roomKey")] + public string RoomKey { get; set; } +} + +/// +/// +/// +public class MobileControlSimplRoomBridgePropertiesConfig +{ + [JsonProperty("eiscId")] + public string EiscId { get; set; } +} + +public class MobileControlApplicationConfig +{ + [JsonProperty("apiPath")] + public string ApiPath { get; set; } + + [JsonProperty("gatewayAppPath")] + public string GatewayAppPath { get; set; } + + [JsonProperty("enableDev")] + public bool? EnableDev { get; set; } + + [JsonProperty("logoPath")] /// - /// + /// Client logo to be used in header and/or splash screen /// - public class MobileControlConfig - { - [JsonProperty("serverUrl")] - public string ServerUrl { get; set; } + public string LogoPath { get; set; } - [JsonProperty("clientAppUrl")] - public string ClientAppUrl { get; set; } + [JsonProperty("iconSet")] + [JsonConverter(typeof(StringEnumConverter))] + public MCIconSet? IconSet { get; set; } - [JsonProperty("directServer")] - public MobileControlDirectServerPropertiesConfig DirectServer { get; set; } + [JsonProperty("loginMode")] + public string LoginMode { get; set; } - [JsonProperty("applicationConfig")] - public MobileControlApplicationConfig ApplicationConfig { get; set; } = null; + [JsonProperty("modes")] + public Dictionary Modes { get; set; } - [JsonProperty("enableApiServer")] - public bool EnableApiServer { get; set; } = true; - } + [JsonProperty("enableRemoteLogging")] + public bool Logging { get; set; } - public class MobileControlDirectServerPropertiesConfig - { - [JsonProperty("enableDirectServer")] - public bool EnableDirectServer { get; set; } + [JsonProperty("partnerMetadata", NullValueHandling = NullValueHandling.Ignore)] + public List PartnerMetadata { get; set; } +} - [JsonProperty("port")] - public int Port { get; set; } +public class MobileControlPartnerMetadata +{ + [JsonProperty("role")] + public string Role { get; set; } - [JsonProperty("logging")] - public MobileControlLoggingConfig Logging { get; set; } + [JsonProperty("description")] + public string Description { get; set; } - [JsonProperty("automaticallyForwardPortToCSLAN")] - public bool? AutomaticallyForwardPortToCSLAN { get; set; } + [JsonProperty("logoPath")] + public string LogoPath { get; set; } +} - public MobileControlDirectServerPropertiesConfig() - { - Logging = new MobileControlLoggingConfig(); - } - } +public class McMode +{ + [JsonProperty("listPageText")] + public string ListPageText { get; set; } + [JsonProperty("loginHelpText")] + public string LoginHelpText { get; set; } - public class MobileControlLoggingConfig - { - [JsonProperty("enableRemoteLogging")] - public bool EnableRemoteLogging { get; set; } + [JsonProperty("passcodePageText")] + public string PasscodePageText { get; set; } +} - [JsonProperty("host")] - public string Host { get; set; } - - [JsonProperty("port")] - public int Port { get; set; } - - - - } - - public class MobileControlRoomBridgePropertiesConfig - { - [JsonProperty("key")] - public string Key { get; set; } - - [JsonProperty("roomKey")] - public string RoomKey { get; set; } - } - - /// - /// - /// - public class MobileControlSimplRoomBridgePropertiesConfig - { - [JsonProperty("eiscId")] - public string EiscId { get; set; } - } - - public class MobileControlApplicationConfig - { - [JsonProperty("apiPath")] - public string ApiPath { get; set; } - - [JsonProperty("gatewayAppPath")] - public string GatewayAppPath { get; set; } - - [JsonProperty("enableDev")] - public bool? EnableDev { get; set; } - - [JsonProperty("logoPath")] - /// - /// Client logo to be used in header and/or splash screen - /// - public string LogoPath { get; set; } - - [JsonProperty("iconSet")] - [JsonConverter(typeof(StringEnumConverter))] - public MCIconSet? IconSet { get; set; } - - [JsonProperty("loginMode")] - public string LoginMode { get; set; } - - [JsonProperty("modes")] - public Dictionary Modes { get; set; } - - [JsonProperty("enableRemoteLogging")] - public bool Logging { get; set; } - - [JsonProperty("partnerMetadata", NullValueHandling = NullValueHandling.Ignore)] - public List PartnerMetadata { get; set; } - } - - public class MobileControlPartnerMetadata - { - [JsonProperty("role")] - public string Role { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("logoPath")] - public string LogoPath { get; set; } - } - - public class McMode - { - [JsonProperty("listPageText")] - public string ListPageText { get; set; } - [JsonProperty("loginHelpText")] - public string LoginHelpText { get; set; } - - [JsonProperty("passcodePageText")] - public string PasscodePageText { get; set; } - } - - public enum MCIconSet - { - GOOGLE, - HABANERO, - NEO - } +public enum MCIconSet +{ + GOOGLE, + HABANERO, + NEO } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs b/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs index 9fc8cc41..1e04e484 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs @@ -8,27 +8,26 @@ using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials -{ - public class MobileControlDeviceFactory : EssentialsDeviceFactory - { - public MobileControlDeviceFactory() - { - TypeNames = new List { "appserver", "mobilecontrol", "webserver" }; - } +namespace PepperDash.Essentials; - public override EssentialsDevice BuildDevice(DeviceConfig dc) +public class MobileControlDeviceFactory : EssentialsDeviceFactory +{ + public MobileControlDeviceFactory() + { + TypeNames = new List { "appserver", "mobilecontrol", "webserver" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + try { - try - { - var props = dc.Properties.ToObject(); - return new MobileControlSystemController(dc.Key, dc.Name, props); - } - catch (Exception e) - { - Debug.LogMessage(e, "Error building Mobile Control System Controller"); - return null; - } + var props = dc.Properties.ToObject(); + return new MobileControlSystemController(dc.Key, dc.Name, props); + } + catch (Exception e) + { + Debug.LogMessage(e, "Error building Mobile Control System Controller"); + return null; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs b/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs index 0ba33b6e..4621586c 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs @@ -3,52 +3,51 @@ using PepperDash.Essentials.Core.Config; using System.Collections.Generic; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +/// +/// Used to overlay additional config data from mobile control on +/// +public class MobileControlEssentialsConfig : EssentialsConfig { - /// - /// Used to overlay additional config data from mobile control on - /// - public class MobileControlEssentialsConfig : EssentialsConfig + [JsonProperty("runtimeInfo")] + public MobileControlRuntimeInfo RuntimeInfo { get; set; } + + public MobileControlEssentialsConfig(EssentialsConfig config) + : base() { - [JsonProperty("runtimeInfo")] - public MobileControlRuntimeInfo RuntimeInfo { get; set; } + // TODO: Consider using Reflection to iterate properties + this.Devices = config.Devices; + this.Info = config.Info; + this.JoinMaps = config.JoinMaps; + this.Rooms = config.Rooms; + this.SourceLists = config.SourceLists; + this.DestinationLists = config.DestinationLists; + this.SystemUrl = config.SystemUrl; + this.TemplateUrl = config.TemplateUrl; + this.TieLines = config.TieLines; - public MobileControlEssentialsConfig(EssentialsConfig config) - : base() - { - // TODO: Consider using Reflection to iterate properties - this.Devices = config.Devices; - this.Info = config.Info; - this.JoinMaps = config.JoinMaps; - this.Rooms = config.Rooms; - this.SourceLists = config.SourceLists; - this.DestinationLists = config.DestinationLists; - this.SystemUrl = config.SystemUrl; - this.TemplateUrl = config.TemplateUrl; - this.TieLines = config.TieLines; + if (this.Info == null) + this.Info = new InfoConfig(); - if (this.Info == null) - this.Info = new InfoConfig(); - - RuntimeInfo = new MobileControlRuntimeInfo(); - } + RuntimeInfo = new MobileControlRuntimeInfo(); } +} - /// - /// Used to add any additional runtime information from mobile control to be send to the API - /// - public class MobileControlRuntimeInfo - { - [JsonProperty("pluginVersion")] - public string PluginVersion { get; set; } +/// +/// Used to add any additional runtime information from mobile control to be send to the API +/// +public class MobileControlRuntimeInfo +{ + [JsonProperty("pluginVersion")] + public string PluginVersion { get; set; } - [JsonProperty("essentialsVersion")] - public string EssentialsVersion { get; set; } + [JsonProperty("essentialsVersion")] + public string EssentialsVersion { get; set; } - [JsonProperty("pepperDashCoreVersion")] - public string PepperDashCoreVersion { get; set; } + [JsonProperty("pepperDashCoreVersion")] + public string PepperDashCoreVersion { get; set; } - [JsonProperty("essentialsPlugins")] - public List EssentialsPlugins { get; set; } - } + [JsonProperty("essentialsPlugins")] + public List EssentialsPlugins { get; set; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index b17e0490..d7d956e3 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -38,1538 +38,1538 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using WebSocketSharp; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class MobileControlSystemController : EssentialsDevice, IMobileControl { - public class MobileControlSystemController : EssentialsDevice, IMobileControl + private bool _initialized = false; + private const long ServerReconnectInterval = 5000; + private const long PingInterval = 25000; + + private readonly Dictionary> _actionDictionary = + new Dictionary>( + StringComparer.InvariantCultureIgnoreCase + ); + + public Dictionary> ActionDictionary => _actionDictionary; + + private readonly GenericQueue _receiveQueue; + private readonly List _roomBridges = + new List(); + + private readonly Dictionary _messengers = + new Dictionary(); + + private readonly Dictionary _defaultMessengers = + new Dictionary(); + + private readonly GenericQueue _transmitToServerQueue; + + private readonly GenericQueue _transmitToClientsQueue; + + private bool _disableReconnect; + private WebSocket _wsClient2; + + public MobileControlApiService ApiService { get; private set; } + + public List RoomBridges => _roomBridges; + + private readonly MobileControlWebsocketServer _directServer; + + public MobileControlWebsocketServer DirectServer => _directServer; + + private readonly CCriticalSection _wsCriticalSection = new CCriticalSection(); + + public string SystemUrl; //set only from SIMPL Bridge! + + public bool Connected => _wsClient2 != null && _wsClient2.IsAlive; + + private IEssentialsRoomCombiner _roomCombiner; + + public string SystemUuid { - private bool _initialized = false; - private const long ServerReconnectInterval = 5000; - private const long PingInterval = 25000; + get + { + // Check to see if the SystemUuid value is populated. If not populated from configuration, check for value from SIMPL bridge. + if ( + !string.IsNullOrEmpty(ConfigReader.ConfigObject.SystemUuid) + && ConfigReader.ConfigObject.SystemUuid != "missing url" + ) + { + return ConfigReader.ConfigObject.SystemUuid; + } - private readonly Dictionary> _actionDictionary = - new Dictionary>( - StringComparer.InvariantCultureIgnoreCase + this.LogWarning( + "No system_url value defined in config. Checking for value from SIMPL Bridge." ); - public Dictionary> ActionDictionary => _actionDictionary; - - private readonly GenericQueue _receiveQueue; - private readonly List _roomBridges = - new List(); - - private readonly Dictionary _messengers = - new Dictionary(); - - private readonly Dictionary _defaultMessengers = - new Dictionary(); - - private readonly GenericQueue _transmitToServerQueue; - - private readonly GenericQueue _transmitToClientsQueue; - - private bool _disableReconnect; - private WebSocket _wsClient2; - - public MobileControlApiService ApiService { get; private set; } - - public List RoomBridges => _roomBridges; - - private readonly MobileControlWebsocketServer _directServer; - - public MobileControlWebsocketServer DirectServer => _directServer; - - private readonly CCriticalSection _wsCriticalSection = new CCriticalSection(); - - public string SystemUrl; //set only from SIMPL Bridge! - - public bool Connected => _wsClient2 != null && _wsClient2.IsAlive; - - private IEssentialsRoomCombiner _roomCombiner; - - public string SystemUuid - { - get + if (!string.IsNullOrEmpty(SystemUrl)) { - // Check to see if the SystemUuid value is populated. If not populated from configuration, check for value from SIMPL bridge. - if ( - !string.IsNullOrEmpty(ConfigReader.ConfigObject.SystemUuid) - && ConfigReader.ConfigObject.SystemUuid != "missing url" - ) - { - return ConfigReader.ConfigObject.SystemUuid; - } - - this.LogWarning( - "No system_url value defined in config. Checking for value from SIMPL Bridge." + this.LogError( + "No system_url value defined in config or SIMPL Bridge. Unable to connect to Mobile Control." ); - - if (!string.IsNullOrEmpty(SystemUrl)) - { - this.LogError( - "No system_url value defined in config or SIMPL Bridge. Unable to connect to Mobile Control." - ); - return string.Empty; - } - - var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*"); - string uuid = result.Groups[1].Value; - return uuid; + return string.Empty; } + + var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*"); + string uuid = result.Groups[1].Value; + return uuid; } + } - public BoolFeedback ApiOnlineAndAuthorized { get; private set; } + public BoolFeedback ApiOnlineAndAuthorized { get; private set; } - /// - /// Used for tracking HTTP debugging - /// - private bool _httpDebugEnabled; + /// + /// Used for tracking HTTP debugging + /// + private bool _httpDebugEnabled; - private bool _isAuthorized; + private bool _isAuthorized; - /// - /// Tracks if the system is authorized to the API server - /// - public bool IsAuthorized + /// + /// Tracks if the system is authorized to the API server + /// + public bool IsAuthorized + { + get { return _isAuthorized; } + private set { - get { return _isAuthorized; } - private set - { - if (value == _isAuthorized) - return; + if (value == _isAuthorized) + return; - _isAuthorized = value; - ApiOnlineAndAuthorized.FireUpdate(); - } + _isAuthorized = value; + ApiOnlineAndAuthorized.FireUpdate(); } + } - private DateTime _lastAckMessage; + private DateTime _lastAckMessage; - public DateTime LastAckMessage => _lastAckMessage; + public DateTime LastAckMessage => _lastAckMessage; - private CTimer _pingTimer; + private CTimer _pingTimer; - private CTimer _serverReconnectTimer; - private LogLevel _wsLogLevel = LogLevel.Error; + private CTimer _serverReconnectTimer; + private LogLevel _wsLogLevel = LogLevel.Error; - /// - /// - /// - /// - /// - /// - public MobileControlSystemController(string key, string name, MobileControlConfig config) - : base(key, name) + /// + /// + /// + /// + /// + /// + public MobileControlSystemController(string key, string name, MobileControlConfig config) + : base(key, name) + { + Config = config; + + // The queue that will collect the incoming messages in the order they are received + //_receiveQueue = new ReceiveQueue(key, ParseStreamRx); + _receiveQueue = new GenericQueue( + key + "-rxqueue", + Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, + 25 + ); + + // The queue that will collect the outgoing messages in the order they are received + _transmitToServerQueue = new GenericQueue( + key + "-txqueue", + Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, + 25 + ); + + if (Config.DirectServer != null && Config.DirectServer.EnableDirectServer) { - Config = config; + _directServer = new MobileControlWebsocketServer( + Key + "-directServer", + Config.DirectServer.Port, + this + ); + DeviceManager.AddDevice(_directServer); - // The queue that will collect the incoming messages in the order they are received - //_receiveQueue = new ReceiveQueue(key, ParseStreamRx); - _receiveQueue = new GenericQueue( - key + "-rxqueue", + _transmitToClientsQueue = new GenericQueue( + key + "-clienttxqueue", Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, 25 ); - - // The queue that will collect the outgoing messages in the order they are received - _transmitToServerQueue = new GenericQueue( - key + "-txqueue", - Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, - 25 - ); - - if (Config.DirectServer != null && Config.DirectServer.EnableDirectServer) - { - _directServer = new MobileControlWebsocketServer( - Key + "-directServer", - Config.DirectServer.Port, - this - ); - DeviceManager.AddDevice(_directServer); - - _transmitToClientsQueue = new GenericQueue( - key + "-clienttxqueue", - Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, - 25 - ); - } - - Host = config.ServerUrl; - if (!Host.StartsWith("http")) - { - Host = "https://" + Host; - } - - ApiService = new MobileControlApiService(Host); - - this.LogInformation( - "Mobile UI controller initializing for server:{0}", - config.ServerUrl - ); - - if (Global.Platform == eDevicePlatform.Appliance) - { - AddConsoleCommands(); - } - - AddPreActivationAction(() => LinkSystemMonitorToAppServer()); - - AddPreActivationAction(() => SetupDefaultDeviceMessengers()); - - AddPreActivationAction(() => SetupDefaultRoomMessengers()); - - AddPreActivationAction(() => AddWebApiPaths()); - - AddPreActivationAction(() => - { - _roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); - - if (_roomCombiner == null) - return; - - _roomCombiner.RoomCombinationScenarioChanged += OnRoomCombinationScenarioChanged; - }); - - CrestronEnvironment.ProgramStatusEventHandler += - CrestronEnvironment_ProgramStatusEventHandler; - - ApiOnlineAndAuthorized = new BoolFeedback(() => - { - if (_wsClient2 == null) - return false; - - return _wsClient2.IsAlive && IsAuthorized; - }); } - private void SetupDefaultRoomMessengers() + Host = config.ServerUrl; + if (!Host.StartsWith("http")) { - this.LogVerbose("Setting up room messengers"); - - foreach (var room in DeviceManager.AllDevices.OfType()) - { - this.LogVerbose( - "Setting up room messengers for room: {key}", - room.Key - ); - - var messenger = new MobileControlEssentialsRoomBridge(room); - - messenger.AddParent(this); - - _roomBridges.Add(messenger); - - AddDefaultDeviceMessenger(messenger); - - this.LogVerbose( - "Attempting to set up default room messengers for room: {0}", - room.Key - ); - - if (room is IRoomEventSchedule) - { - this.LogInformation("Setting up event schedule messenger for room: {key}", room.Key); - - var scheduleMessenger = new RoomEventScheduleMessenger( - $"{room.Key}-schedule-{Key}", - string.Format("/room/{0}", room.Key), - room as IRoomEventSchedule - ); - - AddDefaultDeviceMessenger(scheduleMessenger); - } - - if (room is ITechPassword) - { - this.LogInformation("Setting up tech password messenger for room: {key}", room.Key); - - var techPasswordMessenger = new ITechPasswordMessenger( - $"{room.Key}-techPassword-{Key}", - string.Format("/room/{0}", room.Key), - room as ITechPassword - ); - - AddDefaultDeviceMessenger(techPasswordMessenger); - } - - if (room is IShutdownPromptTimer) - { - this.LogInformation("Setting up shutdown prompt timer messenger for room: {key}", this, room.Key); - - var shutdownPromptTimerMessenger = new IShutdownPromptTimerMessenger( - $"{room.Key}-shutdownPromptTimer-{Key}", - string.Format("/room/{0}", room.Key), - room as IShutdownPromptTimer - ); - - AddDefaultDeviceMessenger(shutdownPromptTimerMessenger); - } - - if (room is ILevelControls levelControls) - { - this.LogInformation("Setting up level controls messenger for room: {key}", this, room.Key); - - var levelControlsMessenger = new ILevelControlsMessenger( - $"{room.Key}-levelControls-{Key}", - $"/room/{room.Key}", - levelControls - ); - - AddDefaultDeviceMessenger(levelControlsMessenger); - } - } + Host = "https://" + Host; } - /// - /// Set up the messengers for each device type - /// - private void SetupDefaultDeviceMessengers() + ApiService = new MobileControlApiService(Host); + + this.LogInformation( + "Mobile UI controller initializing for server:{0}", + config.ServerUrl + ); + + if (Global.Platform == eDevicePlatform.Appliance) { - bool messengerAdded = false; + AddConsoleCommands(); + } - var allDevices = DeviceManager.AllDevices.Where((d) => !(d is IEssentialsRoom)); + AddPreActivationAction(() => LinkSystemMonitorToAppServer()); - this.LogInformation( - "All Devices that aren't rooms count: {0}", - allDevices?.Count() + AddPreActivationAction(() => SetupDefaultDeviceMessengers()); + + AddPreActivationAction(() => SetupDefaultRoomMessengers()); + + AddPreActivationAction(() => AddWebApiPaths()); + + AddPreActivationAction(() => + { + _roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); + + if (_roomCombiner == null) + return; + + _roomCombiner.RoomCombinationScenarioChanged += OnRoomCombinationScenarioChanged; + }); + + CrestronEnvironment.ProgramStatusEventHandler += + CrestronEnvironment_ProgramStatusEventHandler; + + ApiOnlineAndAuthorized = new BoolFeedback(() => + { + if (_wsClient2 == null) + return false; + + return _wsClient2.IsAlive && IsAuthorized; + }); + } + + private void SetupDefaultRoomMessengers() + { + this.LogVerbose("Setting up room messengers"); + + foreach (var room in DeviceManager.AllDevices.OfType()) + { + this.LogVerbose( + "Setting up room messengers for room: {key}", + room.Key ); - var count = allDevices.Count(); + var messenger = new MobileControlEssentialsRoomBridge(room); - foreach (var device in allDevices) + messenger.AddParent(this); + + _roomBridges.Add(messenger); + + AddDefaultDeviceMessenger(messenger); + + this.LogVerbose( + "Attempting to set up default room messengers for room: {0}", + room.Key + ); + + if (room is IRoomEventSchedule) { - try + this.LogInformation("Setting up event schedule messenger for room: {key}", room.Key); + + var scheduleMessenger = new RoomEventScheduleMessenger( + $"{room.Key}-schedule-{Key}", + string.Format("/room/{0}", room.Key), + room as IRoomEventSchedule + ); + + AddDefaultDeviceMessenger(scheduleMessenger); + } + + if (room is ITechPassword) + { + this.LogInformation("Setting up tech password messenger for room: {key}", room.Key); + + var techPasswordMessenger = new ITechPasswordMessenger( + $"{room.Key}-techPassword-{Key}", + string.Format("/room/{0}", room.Key), + room as ITechPassword + ); + + AddDefaultDeviceMessenger(techPasswordMessenger); + } + + if (room is IShutdownPromptTimer) + { + this.LogInformation("Setting up shutdown prompt timer messenger for room: {key}", this, room.Key); + + var shutdownPromptTimerMessenger = new IShutdownPromptTimerMessenger( + $"{room.Key}-shutdownPromptTimer-{Key}", + string.Format("/room/{0}", room.Key), + room as IShutdownPromptTimer + ); + + AddDefaultDeviceMessenger(shutdownPromptTimerMessenger); + } + + if (room is ILevelControls levelControls) + { + this.LogInformation("Setting up level controls messenger for room: {key}", this, room.Key); + + var levelControlsMessenger = new ILevelControlsMessenger( + $"{room.Key}-levelControls-{Key}", + $"/room/{room.Key}", + levelControls + ); + + AddDefaultDeviceMessenger(levelControlsMessenger); + } + } + } + + /// + /// Set up the messengers for each device type + /// + private void SetupDefaultDeviceMessengers() + { + bool messengerAdded = false; + + var allDevices = DeviceManager.AllDevices.Where((d) => !(d is IEssentialsRoom)); + + this.LogInformation( + "All Devices that aren't rooms count: {0}", + allDevices?.Count() + ); + + var count = allDevices.Count(); + + foreach (var device in allDevices) + { + try + { + this.LogVerbose( + "Attempting to set up device messengers for {deviceKey}", + device.Key + ); + + // StatusMonitorBase which is prop of ICommunicationMonitor is not a PepperDash.Core.Device, but is in the device array + if (device is ICommunicationMonitor) { this.LogVerbose( - "Attempting to set up device messengers for {deviceKey}", + "Checking if {deviceKey} implements ICommunicationMonitor", device.Key ); - // StatusMonitorBase which is prop of ICommunicationMonitor is not a PepperDash.Core.Device, but is in the device array - if (device is ICommunicationMonitor) + if (!(device is ICommunicationMonitor commMonitor)) { - this.LogVerbose( - "Checking if {deviceKey} implements ICommunicationMonitor", - device.Key - ); - - if (!(device is ICommunicationMonitor commMonitor)) - { - this.LogDebug( - "{deviceKey} does not implement ICommunicationMonitor. Skipping CommunicationMonitorMessenger", - device.Key - ); - - this.LogDebug("Created all messengers for {deviceKey}. Devices Left: {deviceCount}", device.Key, --count); - - continue; - } - this.LogDebug( - "Adding CommunicationMonitorMessenger for {deviceKey}", + "{deviceKey} does not implement ICommunicationMonitor. Skipping CommunicationMonitorMessenger", device.Key ); - var commMessenger = new ICommunicationMonitorMessenger( - $"{device.Key}-commMonitor-{Key}", - string.Format("/device/{0}", device.Key), - commMonitor - ); + this.LogDebug("Created all messengers for {deviceKey}. Devices Left: {deviceCount}", device.Key, --count); - AddDefaultDeviceMessenger(commMessenger); - - messengerAdded = true; + continue; } - if (device is CameraBase cameraDevice) - { - this.LogVerbose( - "Adding CameraBaseMessenger for {deviceKey}", - device.Key - ); - - var cameraMessenger = new CameraBaseMessenger( - $"{device.Key}-cameraBase-{Key}", - cameraDevice, - $"/device/{device.Key}" - ); - - AddDefaultDeviceMessenger(cameraMessenger); - - messengerAdded = true; - } - - if (device is BlueJeansPc) - { - this.LogVerbose( - "Adding IRunRouteActionMessnger for {deviceKey}", - device.Key - ); - - var routeMessenger = new RunRouteActionMessenger( - $"{device.Key}-runRouteAction-{Key}", - device as BlueJeansPc, - $"/device/{device.Key}" - ); - - AddDefaultDeviceMessenger(routeMessenger); - - messengerAdded = true; - } - - if (device is ITvPresetsProvider) - { - this.LogVerbose( - "Trying to cast to ITvPresetsProvider for {deviceKey}", - device.Key - ); - - var presetsDevice = device as ITvPresetsProvider; - - - this.LogVerbose( - "Adding ITvPresetsProvider for {deviceKey}", - device.Key - ); - - var presetsMessenger = new DevicePresetsModelMessenger( - $"{device.Key}-presets-{Key}", - $"/device/{device.Key}", - presetsDevice - ); - - AddDefaultDeviceMessenger(presetsMessenger); - - messengerAdded = true; - } - - - if (device is DisplayBase) - { - this.LogVerbose("Adding actions for device: {0}", device.Key); - - var dbMessenger = new DisplayBaseMessenger( - $"{device.Key}-displayBase-{Key}", - $"/device/{device.Key}", - device as DisplayBase - ); - - AddDefaultDeviceMessenger(dbMessenger); - - messengerAdded = true; - } - - if (device is TwoWayDisplayBase twoWayDisplay) - { - this.LogVerbose( - "Adding TwoWayDisplayBase for {deviceKey}", - device.Key - ); - var twoWayDisplayMessenger = new TwoWayDisplayBaseMessenger( - $"{device.Key}-twoWayDisplay-{Key}", - string.Format("/device/{0}", device.Key), - twoWayDisplay - ); - AddDefaultDeviceMessenger(twoWayDisplayMessenger); - - messengerAdded = true; - } - - if (device is IBasicVolumeWithFeedback) - { - var deviceKey = device.Key; - this.LogVerbose( - "Adding IBasicVolumeControlWithFeedback for {deviceKey}", - deviceKey - ); - - var volControlDevice = device as IBasicVolumeWithFeedback; - var messenger = new DeviceVolumeMessenger( - $"{device.Key}-volume-{Key}", - string.Format("/device/{0}", deviceKey), - volControlDevice - ); - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is ILightingScenes || device is LightingBase) - { - var deviceKey = device.Key; - - this.LogVerbose( - "Adding LightingBaseMessenger for {deviceKey}", - deviceKey - ); - - var lightingDevice = device as ILightingScenes; - var messenger = new ILightingScenesMessenger( - $"{device.Key}-lighting-{Key}", - lightingDevice, - string.Format("/device/{0}", deviceKey) - ); - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IShadesOpenCloseStop) - { - var deviceKey = device.Key; - var shadeDevice = device as IShadesOpenCloseStop; - - this.LogVerbose( - "Adding ShadeBaseMessenger for {deviceKey}", - deviceKey - ); - - var messenger = new IShadesOpenCloseStopMessenger( - $"{device.Key}-shades-{Key}", - shadeDevice, - string.Format("/device/{0}", deviceKey) - ); - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is VideoCodecBase codec) - { - this.LogVerbose( - "Adding VideoCodecBaseMessenger for {deviceKey}", codec.Key); - - var messenger = new VideoCodecBaseMessenger( - $"{codec.Key}-videoCodec-{Key}", - codec, - $"/device/{codec.Key}" - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is AudioCodecBase audioCodec) - { - this.LogVerbose( - "Adding AudioCodecBaseMessenger for {deviceKey}", audioCodec.Key - ); - - var messenger = new AudioCodecBaseMessenger( - $"{audioCodec.Key}-audioCodec-{Key}", - audioCodec, - $"/device/{audioCodec.Key}" - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is ISetTopBoxControls stbDevice) - { - this.LogVerbose( - "Adding ISetTopBoxControlMessenger for {deviceKey}" - ); - - var messenger = new ISetTopBoxControlsMessenger( - $"{device.Key}-stb-{Key}", - $"/device/{device.Key}", - stbDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IChannel channelDevice) - { - this.LogVerbose( - "Adding IChannelMessenger for {deviceKey}", device.Key - ); - - var messenger = new IChannelMessenger( - $"{device.Key}-channel-{Key}", - $"/device/{device.Key}", - channelDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IColor colorDevice) - { - this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key); - - var messenger = new IColorMessenger( - $"{device.Key}-color-{Key}", - $"/device/{device.Key}", - colorDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IDPad dPadDevice) - { - this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key); - - var messenger = new IDPadMessenger( - $"{device.Key}-dPad-{Key}", - $"/device/{device.Key}", - dPadDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is INumericKeypad nkDevice) - { - this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key); - - var messenger = new INumericKeypadMessenger( - $"{device.Key}-numericKeypad-{Key}", - $"/device/{device.Key}", - nkDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHasPowerControl pcDevice) - { - this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key); - - var messenger = new IHasPowerMessenger( - $"{device.Key}-powerControl-{Key}", - $"/device/{device.Key}", - pcDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHasPowerControlWithFeedback powerControl) - { - var deviceKey = device.Key; - this.LogVerbose( - "Adding IHasPowerControlWithFeedbackMessenger for {deviceKey}", - deviceKey - ); - - var messenger = new IHasPowerControlWithFeedbackMessenger( - $"{device.Key}-powerFeedback-{Key}", - string.Format("/device/{0}", deviceKey), - powerControl - ); - AddDefaultDeviceMessenger(messenger); - messengerAdded = true; - } - - if (device is ITransport transportDevice) - { - this.LogVerbose( - "Adding ITransportMessenger for {deviceKey}", device.Key - ); - - var messenger = new ITransportMessenger( - $"{device.Key}-transport-{Key}", - $"/device/{device.Key}", - transportDevice - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHasCurrentSourceInfoChange csiChange) - { - this.LogVerbose("Adding IHasCurrentSourceInfoMessenger for {deviceKey}", device.Key); - - var messenger = new IHasCurrentSourceInfoMessenger( - $"{device.Key}-currentSource-{Key}", - $"/device/{device.Key}", - csiChange - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is ISwitchedOutput switchedDevice) - { - this.LogVerbose( - "Adding ISwitchedOutputMessenger for {deviceKey}", device.Key - ); - - var messenger = new ISwitchedOutputMessenger( - $"{device.Key}-switchedOutput-{Key}", - switchedDevice, - $"/device/{device.Key}" - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IDeviceInfoProvider provider) - { - this.LogVerbose("Adding IHasDeviceInfoMessenger for {deviceKey}", device.Key - ); - - var messenger = new DeviceInfoMessenger( - $"{device.Key}-deviceInfo-{Key}", - $"/device/{device.Key}", - provider - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is ILevelControls levelControls) - { - this.LogVerbose( - "Adding LevelControlsMessenger for {deviceKey}", device.Key - ); - - var messenger = new ILevelControlsMessenger( - $"{device.Key}-levelControls-{Key}", - $"/device/{device.Key}", - levelControls - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHasInputs stringInputs) - { - this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); - - var messenger = new IHasInputsMessenger( - $"{device.Key}-inputs-{Key}", - $"/device/{device.Key}", - stringInputs - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHasInputs byteInputs) - { - this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); - - var messenger = new IHasInputsMessenger( - $"{device.Key}-inputs-{Key}", - $"/device/{device.Key}", - byteInputs - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHasInputs intInputs) - { - this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); - - var messenger = new IHasInputsMessenger( - $"{device.Key}-inputs-{Key}", - $"/device/{device.Key}", - intInputs - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IMatrixRouting matrix) - { - this.LogVerbose( - "Adding IMatrixRoutingMessenger for {deviceKey}", - device.Key - ); - - var messenger = new IMatrixRoutingMessenger( - $"{device.Key}-matrixRouting", - $"/device/{device.Key}", - matrix - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is ITemperatureSensor tempSensor) - { - this.LogVerbose( - "Adding ITemperatureSensor for {deviceKey}", - device.Key - ); - - var messenger = new ITemperatureSensorMessenger( - $"{device.Key}-tempSensor", - tempSensor, - $"/device/{device.Key}" - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IHumiditySensor humSensor) - { - this.LogVerbose( - "Adding IHumiditySensor for {deviceKey}", - device.Key - ); - - var messenger = new IHumiditySensorMessenger( - $"{device.Key}-humiditySensor", - humSensor, - $"/device/{device.Key}" - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IEssentialsRoomCombiner roomCombiner) - { - this.LogVerbose( - "Adding IEssentialsRoomCombinerMessenger for {deviceKey}", device.Key - ); - - var messenger = new IEssentialsRoomCombinerMessenger( - $"{device.Key}-roomCombiner-{Key}", - $"/device/{device.Key}", - roomCombiner - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IProjectorScreenLiftControl screenLiftControl) - { - this.LogVerbose("Adding IProjectorScreenLiftControlMessenger for {deviceKey}", device.Key - ); - - var messenger = new IProjectorScreenLiftControlMessenger( - $"{device.Key}-screenLiftControl-{Key}", - $"/device/{device.Key}", - screenLiftControl - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - if (device is IDspPresets dspPresets) - { - this.LogVerbose("Adding IDspPresetsMessenger for {deviceKey}", device.Key - ); - - var messenger = new IDspPresetsMessenger( - $"{device.Key}-dspPresets-{Key}", - $"/device/{device.Key}", - dspPresets - ); - - AddDefaultDeviceMessenger(messenger); - - messengerAdded = true; - } - - this.LogVerbose("Trying to cast to generic device for device: {key}", device.Key); - - if (device is EssentialsDevice) - { - if (!(device is EssentialsDevice genericDevice) || messengerAdded) - { - this.LogVerbose( - "Skipping GenericMessenger for {deviceKey}. Messenger(s) Added: {messengersAdded}.", - device.Key, - messengerAdded - ); - this.LogDebug( - "AllDevices Completed a device. Devices Left: {count}", - --count - ); - continue; - } - - this.LogDebug( - "Adding GenericMessenger for {deviceKey}", - this, - genericDevice?.Key - ); - - AddDefaultDeviceMessenger( - new GenericMessenger( - genericDevice.Key + "-" + Key + "-generic", - genericDevice, - string.Format("/device/{0}", genericDevice.Key) - ) - ); - } - else - { - this.LogVerbose( - "Not Essentials Device. Skipping GenericMessenger for {deviceKey}", - device.Key - ); - } this.LogDebug( - "AllDevices Completed a device. Devices Left: {count}", - --count + "Adding CommunicationMonitorMessenger for {deviceKey}", + device.Key ); + + var commMessenger = new ICommunicationMonitorMessenger( + $"{device.Key}-commMonitor-{Key}", + string.Format("/device/{0}", device.Key), + commMonitor + ); + + AddDefaultDeviceMessenger(commMessenger); + + messengerAdded = true; } - catch (Exception ex) + if (device is CameraBase cameraDevice) { - this.LogException(ex, "Exception setting up default device messengers"); + this.LogVerbose( + "Adding CameraBaseMessenger for {deviceKey}", + device.Key + ); + + var cameraMessenger = new CameraBaseMessenger( + $"{device.Key}-cameraBase-{Key}", + cameraDevice, + $"/device/{device.Key}" + ); + + AddDefaultDeviceMessenger(cameraMessenger); + + messengerAdded = true; } - } - } - private void AddWebApiPaths() - { - var apiServer = DeviceManager - .AllDevices.OfType() - .FirstOrDefault(d => d.Key == "essentialsWebApi"); + if (device is BlueJeansPc) + { + this.LogVerbose( + "Adding IRunRouteActionMessnger for {deviceKey}", + device.Key + ); - if (apiServer == null) - { - this.LogWarning("No API Server available"); - return; - } + var routeMessenger = new RunRouteActionMessenger( + $"{device.Key}-runRouteAction-{Key}", + device as BlueJeansPc, + $"/device/{device.Key}" + ); - // TODO: Add routes for the rest of the MC console commands - var routes = new List - { - new HttpCwsRoute($"device/{Key}/authorize") - { - Name = "MobileControlAuthorize", - RouteHandler = new MobileAuthRequestHandler(this) - }, - new HttpCwsRoute($"device/{Key}/info") - { - Name = "MobileControlInformation", - RouteHandler = new MobileInfoHandler(this) - }, - new HttpCwsRoute($"device/{Key}/actionPaths") - { - Name = "MobileControlActionPaths", - RouteHandler = new ActionPathsHandler(this) + AddDefaultDeviceMessenger(routeMessenger); + + messengerAdded = true; } - }; - apiServer.AddRoute(routes); - } - - private void AddConsoleCommands() - { - CrestronConsole.AddNewConsoleCommand( - AuthorizeSystem, - "mobileauth", - "Authorizes system to talk to Mobile Control server", - ConsoleAccessLevelEnum.AccessOperator - ); - CrestronConsole.AddNewConsoleCommand( - s => ShowInfo(), - "mobileinfo", - "Shows information for current mobile control session", - ConsoleAccessLevelEnum.AccessOperator - ); - CrestronConsole.AddNewConsoleCommand( - s => + if (device is ITvPresetsProvider) { - s = s.Trim(); - if (!string.IsNullOrEmpty(s)) + this.LogVerbose( + "Trying to cast to ITvPresetsProvider for {deviceKey}", + device.Key + ); + + var presetsDevice = device as ITvPresetsProvider; + + + this.LogVerbose( + "Adding ITvPresetsProvider for {deviceKey}", + device.Key + ); + + var presetsMessenger = new DevicePresetsModelMessenger( + $"{device.Key}-presets-{Key}", + $"/device/{device.Key}", + presetsDevice + ); + + AddDefaultDeviceMessenger(presetsMessenger); + + messengerAdded = true; + } + + + if (device is DisplayBase) + { + this.LogVerbose("Adding actions for device: {0}", device.Key); + + var dbMessenger = new DisplayBaseMessenger( + $"{device.Key}-displayBase-{Key}", + $"/device/{device.Key}", + device as DisplayBase + ); + + AddDefaultDeviceMessenger(dbMessenger); + + messengerAdded = true; + } + + if (device is TwoWayDisplayBase twoWayDisplay) + { + this.LogVerbose( + "Adding TwoWayDisplayBase for {deviceKey}", + device.Key + ); + var twoWayDisplayMessenger = new TwoWayDisplayBaseMessenger( + $"{device.Key}-twoWayDisplay-{Key}", + string.Format("/device/{0}", device.Key), + twoWayDisplay + ); + AddDefaultDeviceMessenger(twoWayDisplayMessenger); + + messengerAdded = true; + } + + if (device is IBasicVolumeWithFeedback) + { + var deviceKey = device.Key; + this.LogVerbose( + "Adding IBasicVolumeControlWithFeedback for {deviceKey}", + deviceKey + ); + + var volControlDevice = device as IBasicVolumeWithFeedback; + var messenger = new DeviceVolumeMessenger( + $"{device.Key}-volume-{Key}", + string.Format("/device/{0}", deviceKey), + volControlDevice + ); + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ILightingScenes || device is LightingBase) + { + var deviceKey = device.Key; + + this.LogVerbose( + "Adding LightingBaseMessenger for {deviceKey}", + deviceKey + ); + + var lightingDevice = device as ILightingScenes; + var messenger = new ILightingScenesMessenger( + $"{device.Key}-lighting-{Key}", + lightingDevice, + string.Format("/device/{0}", deviceKey) + ); + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IShadesOpenCloseStop) + { + var deviceKey = device.Key; + var shadeDevice = device as IShadesOpenCloseStop; + + this.LogVerbose( + "Adding ShadeBaseMessenger for {deviceKey}", + deviceKey + ); + + var messenger = new IShadesOpenCloseStopMessenger( + $"{device.Key}-shades-{Key}", + shadeDevice, + string.Format("/device/{0}", deviceKey) + ); + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is VideoCodecBase codec) + { + this.LogVerbose( + "Adding VideoCodecBaseMessenger for {deviceKey}", codec.Key); + + var messenger = new VideoCodecBaseMessenger( + $"{codec.Key}-videoCodec-{Key}", + codec, + $"/device/{codec.Key}" + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is AudioCodecBase audioCodec) + { + this.LogVerbose( + "Adding AudioCodecBaseMessenger for {deviceKey}", audioCodec.Key + ); + + var messenger = new AudioCodecBaseMessenger( + $"{audioCodec.Key}-audioCodec-{Key}", + audioCodec, + $"/device/{audioCodec.Key}" + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ISetTopBoxControls stbDevice) + { + this.LogVerbose( + "Adding ISetTopBoxControlMessenger for {deviceKey}" + ); + + var messenger = new ISetTopBoxControlsMessenger( + $"{device.Key}-stb-{Key}", + $"/device/{device.Key}", + stbDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IChannel channelDevice) + { + this.LogVerbose( + "Adding IChannelMessenger for {deviceKey}", device.Key + ); + + var messenger = new IChannelMessenger( + $"{device.Key}-channel-{Key}", + $"/device/{device.Key}", + channelDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IColor colorDevice) + { + this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key); + + var messenger = new IColorMessenger( + $"{device.Key}-color-{Key}", + $"/device/{device.Key}", + colorDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IDPad dPadDevice) + { + this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key); + + var messenger = new IDPadMessenger( + $"{device.Key}-dPad-{Key}", + $"/device/{device.Key}", + dPadDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is INumericKeypad nkDevice) + { + this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key); + + var messenger = new INumericKeypadMessenger( + $"{device.Key}-numericKeypad-{Key}", + $"/device/{device.Key}", + nkDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasPowerControl pcDevice) + { + this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key); + + var messenger = new IHasPowerMessenger( + $"{device.Key}-powerControl-{Key}", + $"/device/{device.Key}", + pcDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasPowerControlWithFeedback powerControl) + { + var deviceKey = device.Key; + this.LogVerbose( + "Adding IHasPowerControlWithFeedbackMessenger for {deviceKey}", + deviceKey + ); + + var messenger = new IHasPowerControlWithFeedbackMessenger( + $"{device.Key}-powerFeedback-{Key}", + string.Format("/device/{0}", deviceKey), + powerControl + ); + AddDefaultDeviceMessenger(messenger); + messengerAdded = true; + } + + if (device is ITransport transportDevice) + { + this.LogVerbose( + "Adding ITransportMessenger for {deviceKey}", device.Key + ); + + var messenger = new ITransportMessenger( + $"{device.Key}-transport-{Key}", + $"/device/{device.Key}", + transportDevice + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasCurrentSourceInfoChange csiChange) + { + this.LogVerbose("Adding IHasCurrentSourceInfoMessenger for {deviceKey}", device.Key); + + var messenger = new IHasCurrentSourceInfoMessenger( + $"{device.Key}-currentSource-{Key}", + $"/device/{device.Key}", + csiChange + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ISwitchedOutput switchedDevice) + { + this.LogVerbose( + "Adding ISwitchedOutputMessenger for {deviceKey}", device.Key + ); + + var messenger = new ISwitchedOutputMessenger( + $"{device.Key}-switchedOutput-{Key}", + switchedDevice, + $"/device/{device.Key}" + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IDeviceInfoProvider provider) + { + this.LogVerbose("Adding IHasDeviceInfoMessenger for {deviceKey}", device.Key + ); + + var messenger = new DeviceInfoMessenger( + $"{device.Key}-deviceInfo-{Key}", + $"/device/{device.Key}", + provider + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ILevelControls levelControls) + { + this.LogVerbose( + "Adding LevelControlsMessenger for {deviceKey}", device.Key + ); + + var messenger = new ILevelControlsMessenger( + $"{device.Key}-levelControls-{Key}", + $"/device/{device.Key}", + levelControls + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasInputs stringInputs) + { + this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); + + var messenger = new IHasInputsMessenger( + $"{device.Key}-inputs-{Key}", + $"/device/{device.Key}", + stringInputs + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasInputs byteInputs) + { + this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); + + var messenger = new IHasInputsMessenger( + $"{device.Key}-inputs-{Key}", + $"/device/{device.Key}", + byteInputs + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHasInputs intInputs) + { + this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); + + var messenger = new IHasInputsMessenger( + $"{device.Key}-inputs-{Key}", + $"/device/{device.Key}", + intInputs + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IMatrixRouting matrix) + { + this.LogVerbose( + "Adding IMatrixRoutingMessenger for {deviceKey}", + device.Key + ); + + var messenger = new IMatrixRoutingMessenger( + $"{device.Key}-matrixRouting", + $"/device/{device.Key}", + matrix + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is ITemperatureSensor tempSensor) + { + this.LogVerbose( + "Adding ITemperatureSensor for {deviceKey}", + device.Key + ); + + var messenger = new ITemperatureSensorMessenger( + $"{device.Key}-tempSensor", + tempSensor, + $"/device/{device.Key}" + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IHumiditySensor humSensor) + { + this.LogVerbose( + "Adding IHumiditySensor for {deviceKey}", + device.Key + ); + + var messenger = new IHumiditySensorMessenger( + $"{device.Key}-humiditySensor", + humSensor, + $"/device/{device.Key}" + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IEssentialsRoomCombiner roomCombiner) + { + this.LogVerbose( + "Adding IEssentialsRoomCombinerMessenger for {deviceKey}", device.Key + ); + + var messenger = new IEssentialsRoomCombinerMessenger( + $"{device.Key}-roomCombiner-{Key}", + $"/device/{device.Key}", + roomCombiner + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IProjectorScreenLiftControl screenLiftControl) + { + this.LogVerbose("Adding IProjectorScreenLiftControlMessenger for {deviceKey}", device.Key + ); + + var messenger = new IProjectorScreenLiftControlMessenger( + $"{device.Key}-screenLiftControl-{Key}", + $"/device/{device.Key}", + screenLiftControl + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + if (device is IDspPresets dspPresets) + { + this.LogVerbose("Adding IDspPresetsMessenger for {deviceKey}", device.Key + ); + + var messenger = new IDspPresetsMessenger( + $"{device.Key}-dspPresets-{Key}", + $"/device/{device.Key}", + dspPresets + ); + + AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; + } + + this.LogVerbose("Trying to cast to generic device for device: {key}", device.Key); + + if (device is EssentialsDevice) + { + if (!(device is EssentialsDevice genericDevice) || messengerAdded) { - _httpDebugEnabled = (s.Trim() != "0"); + this.LogVerbose( + "Skipping GenericMessenger for {deviceKey}. Messenger(s) Added: {messengersAdded}.", + device.Key, + messengerAdded + ); + this.LogDebug( + "AllDevices Completed a device. Devices Left: {count}", + --count + ); + continue; } - CrestronConsole.ConsoleCommandResponse( - "HTTP Debug {0}", - _httpDebugEnabled ? "Enabled" : "Disabled" - ); - }, - "mobilehttpdebug", - "1 enables more verbose HTTP response debugging", - ConsoleAccessLevelEnum.AccessOperator - ); - CrestronConsole.AddNewConsoleCommand( - TestHttpRequest, - "mobilehttprequest", - "Tests an HTTP get to URL given", - ConsoleAccessLevelEnum.AccessOperator - ); - CrestronConsole.AddNewConsoleCommand( - PrintActionDictionaryPaths, - "mobileshowactionpaths", - "Prints the paths in the Action Dictionary", - ConsoleAccessLevelEnum.AccessOperator - ); - CrestronConsole.AddNewConsoleCommand( - s => + this.LogDebug( + "Adding GenericMessenger for {deviceKey}", + this, + genericDevice?.Key + ); + + AddDefaultDeviceMessenger( + new GenericMessenger( + genericDevice.Key + "-" + Key + "-generic", + genericDevice, + string.Format("/device/{0}", genericDevice.Key) + ) + ); + } + else { - _disableReconnect = false; - - CrestronConsole.ConsoleCommandResponse( - $"Connecting to MC API server" + this.LogVerbose( + "Not Essentials Device. Skipping GenericMessenger for {deviceKey}", + device.Key ); - - ConnectWebsocketClient(); - }, - "mobileconnect", - "Forces connect of websocket", - ConsoleAccessLevelEnum.AccessOperator - ); - - CrestronConsole.AddNewConsoleCommand( - s => - { - _disableReconnect = true; - - CleanUpWebsocketClient(); - - CrestronConsole.ConsoleCommandResponse( - $"Disonnected from MC API server" - ); - }, - "mobiledisco", - "Disconnects websocket", - ConsoleAccessLevelEnum.AccessOperator - ); - - CrestronConsole.AddNewConsoleCommand( - ParseStreamRx, - "mobilesimulateaction", - "Simulates a message from the server", - ConsoleAccessLevelEnum.AccessOperator - ); - - CrestronConsole.AddNewConsoleCommand( - SetWebsocketDebugLevel, - "mobilewsdebug", - "Set Websocket debug level", - ConsoleAccessLevelEnum.AccessProgrammer - ); - } - - public MobileControlConfig Config { get; private set; } - - public string Host { get; private set; } - - public string ClientAppUrl => Config.ClientAppUrl; - - private void OnRoomCombinationScenarioChanged( - object sender, - EventArgs eventArgs - ) - { - SendMessageObject(new MobileControlMessage { Type = "/system/roomCombinationChanged" }); - } - - public bool CheckForDeviceMessenger(string key) - { - return _messengers.ContainsKey(key); - } - - public void AddDeviceMessenger(IMobileControlMessenger messenger) - { - if (_messengers.ContainsKey(messenger.Key)) - { - this.LogWarning("Messenger with key {messengerKey) already added", messenger.Key); - return; - } - - if (messenger is IDelayedConfiguration simplMessenger) - { - simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; - } - - if (messenger is MobileControlBridgeBase roomBridge) - { - _roomBridges.Add(roomBridge); - } - - this.LogVerbose( - "Adding messenger with key {messengerKey} for path {messengerPath}", - messenger.Key, - messenger.MessagePath - ); - - _messengers.Add(messenger.Key, messenger); - - if (_initialized) - { - this.LogDebug("Registering messenger {messengerKey} AFTER initialization", messenger.Key); - messenger.RegisterWithAppServer(this); - } - } - - private void AddDefaultDeviceMessenger(IMobileControlMessenger messenger) - { - if (_defaultMessengers.ContainsKey(messenger.Key)) - { - this.LogWarning( - "Default messenger with key {messengerKey} already added", - messenger.Key + } + this.LogDebug( + "AllDevices Completed a device. Devices Left: {count}", + --count ); - return; } - if (messenger is IDelayedConfiguration simplMessenger) + catch (Exception ex) { - simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; - } - this.LogVerbose( - "Adding default messenger with key {messengerKey} for path {messengerPath}", - messenger.Key, - messenger.MessagePath - ); - - _defaultMessengers.Add(messenger.Key, messenger); - - if (_initialized) - { - RegisterMessengerWithServer(messenger); + this.LogException(ex, "Exception setting up default device messengers"); } } + } - private void RegisterMessengerWithServer(IMobileControlMessenger messenger) + private void AddWebApiPaths() + { + var apiServer = DeviceManager + .AllDevices.OfType() + .FirstOrDefault(d => d.Key == "essentialsWebApi"); + + if (apiServer == null) { - this.LogVerbose( - "Registering messenger with key {messengerKey} for path {messengerPath}", - messenger.Key, - messenger.MessagePath - ); + this.LogWarning("No API Server available"); + return; + } + // TODO: Add routes for the rest of the MC console commands + var routes = new List + { + new HttpCwsRoute($"device/{Key}/authorize") + { + Name = "MobileControlAuthorize", + RouteHandler = new MobileAuthRequestHandler(this) + }, + new HttpCwsRoute($"device/{Key}/info") + { + Name = "MobileControlInformation", + RouteHandler = new MobileInfoHandler(this) + }, + new HttpCwsRoute($"device/{Key}/actionPaths") + { + Name = "MobileControlActionPaths", + RouteHandler = new ActionPathsHandler(this) + } + }; + + apiServer.AddRoute(routes); + } + + private void AddConsoleCommands() + { + CrestronConsole.AddNewConsoleCommand( + AuthorizeSystem, + "mobileauth", + "Authorizes system to talk to Mobile Control server", + ConsoleAccessLevelEnum.AccessOperator + ); + CrestronConsole.AddNewConsoleCommand( + s => ShowInfo(), + "mobileinfo", + "Shows information for current mobile control session", + ConsoleAccessLevelEnum.AccessOperator + ); + CrestronConsole.AddNewConsoleCommand( + s => + { + s = s.Trim(); + if (!string.IsNullOrEmpty(s)) + { + _httpDebugEnabled = (s.Trim() != "0"); + } + CrestronConsole.ConsoleCommandResponse( + "HTTP Debug {0}", + _httpDebugEnabled ? "Enabled" : "Disabled" + ); + }, + "mobilehttpdebug", + "1 enables more verbose HTTP response debugging", + ConsoleAccessLevelEnum.AccessOperator + ); + CrestronConsole.AddNewConsoleCommand( + TestHttpRequest, + "mobilehttprequest", + "Tests an HTTP get to URL given", + ConsoleAccessLevelEnum.AccessOperator + ); + + CrestronConsole.AddNewConsoleCommand( + PrintActionDictionaryPaths, + "mobileshowactionpaths", + "Prints the paths in the Action Dictionary", + ConsoleAccessLevelEnum.AccessOperator + ); + CrestronConsole.AddNewConsoleCommand( + s => + { + _disableReconnect = false; + + CrestronConsole.ConsoleCommandResponse( + $"Connecting to MC API server" + ); + + ConnectWebsocketClient(); + }, + "mobileconnect", + "Forces connect of websocket", + ConsoleAccessLevelEnum.AccessOperator + ); + + CrestronConsole.AddNewConsoleCommand( + s => + { + _disableReconnect = true; + + CleanUpWebsocketClient(); + + CrestronConsole.ConsoleCommandResponse( + $"Disonnected from MC API server" + ); + }, + "mobiledisco", + "Disconnects websocket", + ConsoleAccessLevelEnum.AccessOperator + ); + + CrestronConsole.AddNewConsoleCommand( + ParseStreamRx, + "mobilesimulateaction", + "Simulates a message from the server", + ConsoleAccessLevelEnum.AccessOperator + ); + + CrestronConsole.AddNewConsoleCommand( + SetWebsocketDebugLevel, + "mobilewsdebug", + "Set Websocket debug level", + ConsoleAccessLevelEnum.AccessProgrammer + ); + } + + public MobileControlConfig Config { get; private set; } + + public string Host { get; private set; } + + public string ClientAppUrl => Config.ClientAppUrl; + + private void OnRoomCombinationScenarioChanged( + object sender, + EventArgs eventArgs + ) + { + SendMessageObject(new MobileControlMessage { Type = "/system/roomCombinationChanged" }); + } + + public bool CheckForDeviceMessenger(string key) + { + return _messengers.ContainsKey(key); + } + + public void AddDeviceMessenger(IMobileControlMessenger messenger) + { + if (_messengers.ContainsKey(messenger.Key)) + { + this.LogWarning("Messenger with key {messengerKey) already added", messenger.Key); + return; + } + + if (messenger is IDelayedConfiguration simplMessenger) + { + simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; + } + + if (messenger is MobileControlBridgeBase roomBridge) + { + _roomBridges.Add(roomBridge); + } + + this.LogVerbose( + "Adding messenger with key {messengerKey} for path {messengerPath}", + messenger.Key, + messenger.MessagePath + ); + + _messengers.Add(messenger.Key, messenger); + + if (_initialized) + { + this.LogDebug("Registering messenger {messengerKey} AFTER initialization", messenger.Key); messenger.RegisterWithAppServer(this); } + } - public override void Initialize() + private void AddDefaultDeviceMessenger(IMobileControlMessenger messenger) + { + if (_defaultMessengers.ContainsKey(messenger.Key)) { - foreach (var messenger in _messengers) - { - try - { - RegisterMessengerWithServer(messenger.Value); - } - catch (Exception ex) - { - this.LogException(ex, "Exception registering custom messenger {messengerKey}", messenger.Key); - continue; - } - } - - foreach (var messenger in _defaultMessengers) - { - try - { - RegisterMessengerWithServer(messenger.Value); - } - catch (Exception ex) - { - this.LogException(ex, "Exception registering default messenger {messengerKey}", messenger.Key); - continue; - } - } - - var simplMessengers = _messengers.OfType().ToList(); - - if (simplMessengers.Count > 0) - { - return; - } - - _initialized = true; - - RegisterSystemToServer(); + this.LogWarning( + "Default messenger with key {messengerKey} already added", + messenger.Key + ); + return; } - #region IMobileControl Members + if (messenger is IDelayedConfiguration simplMessenger) + { + simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; + } + this.LogVerbose( + "Adding default messenger with key {messengerKey} for path {messengerPath}", + messenger.Key, + messenger.MessagePath + ); - public static IMobileControl GetAppServer() + _defaultMessengers.Add(messenger.Key, messenger); + + if (_initialized) + { + RegisterMessengerWithServer(messenger); + } + } + + private void RegisterMessengerWithServer(IMobileControlMessenger messenger) + { + this.LogVerbose( + "Registering messenger with key {messengerKey} for path {messengerPath}", + messenger.Key, + messenger.MessagePath + ); + + messenger.RegisterWithAppServer(this); + } + + public override void Initialize() + { + foreach (var messenger in _messengers) { try { - var appServer = - DeviceManager.GetDevices().SingleOrDefault(s => s is IMobileControl) - as MobileControlSystemController; - return appServer; + RegisterMessengerWithServer(messenger.Value); } - catch (Exception e) + catch (Exception ex) { - Debug.LogMessage(e, "Unable to find MobileControlSystemController in Devices"); - return null; + this.LogException(ex, "Exception registering custom messenger {messengerKey}", messenger.Key); + continue; } } - /// - /// Generates the url and creates the websocket client - /// - private bool CreateWebsocket() + foreach (var messenger in _defaultMessengers) { + try + { + RegisterMessengerWithServer(messenger.Value); + } + catch (Exception ex) + { + this.LogException(ex, "Exception registering default messenger {messengerKey}", messenger.Key); + continue; + } + } + + var simplMessengers = _messengers.OfType().ToList(); + + if (simplMessengers.Count > 0) + { + return; + } + + _initialized = true; + + RegisterSystemToServer(); + } + + #region IMobileControl Members + + public static IMobileControl GetAppServer() + { + try + { + var appServer = + DeviceManager.GetDevices().SingleOrDefault(s => s is IMobileControl) + as MobileControlSystemController; + return appServer; + } + catch (Exception e) + { + Debug.LogMessage(e, "Unable to find MobileControlSystemController in Devices"); + return null; + } + } + + /// + /// Generates the url and creates the websocket client + /// + private bool CreateWebsocket() + { + if (_wsClient2 != null) + { + _wsClient2.Close(); + _wsClient2 = null; + } + + if (string.IsNullOrEmpty(SystemUuid)) + { + this.LogError( + "System UUID not defined. Unable to connect to Mobile Control" + ); + return false; + } + + var wsHost = Host.Replace("http", "ws"); + var url = string.Format("{0}/system/join/{1}", wsHost, SystemUuid); + + _wsClient2 = new WebSocket(url) + { + Log = + { + Output = (data, s) => + this.LogDebug( + "Message from websocket: {message}", + data + ) + } + }; + + _wsClient2.SslConfiguration.EnabledSslProtocols = + System.Security.Authentication.SslProtocols.Tls11 + | System.Security.Authentication.SslProtocols.Tls12; + + _wsClient2.OnMessage += HandleMessage; + _wsClient2.OnOpen += HandleOpen; + _wsClient2.OnError += HandleError; + _wsClient2.OnClose += HandleClose; + + return true; + } + + public void LinkSystemMonitorToAppServer() + { + if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Appliance) + { + this.LogWarning( + "System Monitor does not exist for this platform. Skipping..." + ); + return; + } + + if (!(DeviceManager.GetDeviceForKey("systemMonitor") is SystemMonitorController sysMon)) + { + return; + } + + var key = sysMon.Key + "-" + Key; + var messenger = new SystemMonitorMessenger(key, sysMon, "/device/systemMonitor"); + + AddDeviceMessenger(messenger); + } + + #endregion + + private void SetWebsocketDebugLevel(string cmdparameters) + { + if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4) + { + this.LogInformation( + "Setting websocket log level not currently allowed on 4 series." + ); + return; // Web socket log level not currently allowed in series4 + } + + if (string.IsNullOrEmpty(cmdparameters)) + { + this.LogInformation("Current Websocket debug level: {webSocketDebugLevel}", _wsLogLevel); + return; + } + + if (cmdparameters.ToLower().Contains("help") || cmdparameters.ToLower().Contains("?")) + { + CrestronConsole.ConsoleCommandResponse( + $"valid options are:\r\n{LogLevel.Trace}\r\n{LogLevel.Debug}\r\n{LogLevel.Info}\r\n{LogLevel.Warn}\r\n{LogLevel.Error}\r\n{LogLevel.Fatal}\r\n" + ); + } + + try + { + var debugLevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdparameters, true); + + _wsLogLevel = debugLevel; + if (_wsClient2 != null) { - _wsClient2.Close(); - _wsClient2 = null; + _wsClient2.Log.Level = _wsLogLevel; } - if (string.IsNullOrEmpty(SystemUuid)) - { - this.LogError( - "System UUID not defined. Unable to connect to Mobile Control" - ); - return false; - } - - var wsHost = Host.Replace("http", "ws"); - var url = string.Format("{0}/system/join/{1}", wsHost, SystemUuid); - - _wsClient2 = new WebSocket(url) - { - Log = - { - Output = (data, s) => - this.LogDebug( - "Message from websocket: {message}", - data - ) - } - }; - - _wsClient2.SslConfiguration.EnabledSslProtocols = - System.Security.Authentication.SslProtocols.Tls11 - | System.Security.Authentication.SslProtocols.Tls12; - - _wsClient2.OnMessage += HandleMessage; - _wsClient2.OnOpen += HandleOpen; - _wsClient2.OnError += HandleError; - _wsClient2.OnClose += HandleClose; - - return true; + CrestronConsole.ConsoleCommandResponse($"Websocket log level set to {debugLevel}"); } - - public void LinkSystemMonitorToAppServer() + catch { - if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Appliance) - { - this.LogWarning( - "System Monitor does not exist for this platform. Skipping..." - ); - return; - } + CrestronConsole.ConsoleCommandResponse( + $"{cmdparameters} is not a valid debug level. Valid options are:\r\n{LogLevel.Trace}\r\n{LogLevel.Debug}\r\n{LogLevel.Info}\r\n{LogLevel.Warn}\r\n{LogLevel.Error}\r\n{LogLevel.Fatal}\r\n" + ); - if (!(DeviceManager.GetDeviceForKey("systemMonitor") is SystemMonitorController sysMon)) - { - return; - } - - var key = sysMon.Key + "-" + Key; - var messenger = new SystemMonitorMessenger(key, sysMon, "/device/systemMonitor"); - - AddDeviceMessenger(messenger); } + } - #endregion - - private void SetWebsocketDebugLevel(string cmdparameters) + /// + /// Sends message to server to indicate the system is shutting down + /// + /// + private void CrestronEnvironment_ProgramStatusEventHandler( + eProgramStatusEventType programEventType + ) + { + if ( + programEventType != eProgramStatusEventType.Stopping + || _wsClient2 == null + || !_wsClient2.IsAlive + ) { - if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4) + return; + } + + _disableReconnect = true; + + StopServerReconnectTimer(); + CleanUpWebsocketClient(); + } + + public void PrintActionDictionaryPaths(object o) + { + CrestronConsole.ConsoleCommandResponse("ActionDictionary Contents:\r\n"); + + foreach (var (messengerKey, actionPath) in GetActionDictionaryPaths()) + { + CrestronConsole.ConsoleCommandResponse($"<{messengerKey}> {actionPath}\r\n"); + } + } + + public List<(string, string)> GetActionDictionaryPaths() + { + var paths = new List<(string, string)>(); + + foreach (var item in _actionDictionary) + { + var messengers = item.Value.Select(a => a.Messenger).Cast(); + foreach (var messenger in messengers) { - this.LogInformation( - "Setting websocket log level not currently allowed on 4 series." - ); - return; // Web socket log level not currently allowed in series4 - } - - if (string.IsNullOrEmpty(cmdparameters)) - { - this.LogInformation("Current Websocket debug level: {webSocketDebugLevel}", _wsLogLevel); - return; - } - - if (cmdparameters.ToLower().Contains("help") || cmdparameters.ToLower().Contains("?")) - { - CrestronConsole.ConsoleCommandResponse( - $"valid options are:\r\n{LogLevel.Trace}\r\n{LogLevel.Debug}\r\n{LogLevel.Info}\r\n{LogLevel.Warn}\r\n{LogLevel.Error}\r\n{LogLevel.Fatal}\r\n" - ); - } - - try - { - var debugLevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdparameters, true); - - _wsLogLevel = debugLevel; - - if (_wsClient2 != null) + foreach (var actionPath in messenger.GetActionPaths()) { - _wsClient2.Log.Level = _wsLogLevel; + paths.Add((messenger.Key, $"{item.Key}{actionPath}")); } - - CrestronConsole.ConsoleCommandResponse($"Websocket log level set to {debugLevel}"); - } - catch - { - CrestronConsole.ConsoleCommandResponse( - $"{cmdparameters} is not a valid debug level. Valid options are:\r\n{LogLevel.Trace}\r\n{LogLevel.Debug}\r\n{LogLevel.Info}\r\n{LogLevel.Warn}\r\n{LogLevel.Error}\r\n{LogLevel.Fatal}\r\n" - ); - } } - /// - /// Sends message to server to indicate the system is shutting down - /// - /// - private void CrestronEnvironment_ProgramStatusEventHandler( - eProgramStatusEventType programEventType + return paths; + } + + /// + /// Adds an action to the dictionary + /// + /// The path of the API command + /// The action to be triggered by the commmand + public void AddAction(T messenger, Action action) + where T : IMobileControlMessenger + { + if ( + _actionDictionary.TryGetValue( + messenger.MessagePath, + out List actionList + ) ) { if ( - programEventType != eProgramStatusEventType.Stopping - || _wsClient2 == null - || !_wsClient2.IsAlive - ) - { - return; - } - - _disableReconnect = true; - - StopServerReconnectTimer(); - CleanUpWebsocketClient(); - } - - public void PrintActionDictionaryPaths(object o) - { - CrestronConsole.ConsoleCommandResponse("ActionDictionary Contents:\r\n"); - - foreach (var (messengerKey, actionPath) in GetActionDictionaryPaths()) - { - CrestronConsole.ConsoleCommandResponse($"<{messengerKey}> {actionPath}\r\n"); - } - } - - public List<(string, string)> GetActionDictionaryPaths() - { - var paths = new List<(string, string)>(); - - foreach (var item in _actionDictionary) - { - var messengers = item.Value.Select(a => a.Messenger).Cast(); - foreach (var messenger in messengers) - { - foreach (var actionPath in messenger.GetActionPaths()) - { - paths.Add((messenger.Key, $"{item.Key}{actionPath}")); - } - } - } - - return paths; - } - - /// - /// Adds an action to the dictionary - /// - /// The path of the API command - /// The action to be triggered by the commmand - public void AddAction(T messenger, Action action) - where T : IMobileControlMessenger - { - if ( - _actionDictionary.TryGetValue( - messenger.MessagePath, - out List actionList + actionList.Any(a => + a.Messenger.GetType() == messenger.GetType() + && a.Messenger.DeviceKey == messenger.DeviceKey ) ) { - if ( - actionList.Any(a => - a.Messenger.GetType() == messenger.GetType() - && a.Messenger.DeviceKey == messenger.DeviceKey - ) - ) - { - this.LogWarning("Messenger of type {messengerType} already exists. Skipping actions for {messengerKey}", messenger.GetType().Name, messenger.Key); - return; - } - - actionList.Add(new MobileControlAction(messenger, action)); + this.LogWarning("Messenger of type {messengerType} already exists. Skipping actions for {messengerKey}", messenger.GetType().Name, messenger.Key); return; } - actionList = new List - { - new MobileControlAction(messenger, action) - }; - - _actionDictionary.Add(messenger.MessagePath, actionList); + actionList.Add(new MobileControlAction(messenger, action)); + return; } - /// - /// Removes an action from the dictionary - /// - /// - public void RemoveAction(string key) + actionList = new List { - if (_actionDictionary.ContainsKey(key)) - { - _actionDictionary.Remove(key); - } + new MobileControlAction(messenger, action) + }; + + _actionDictionary.Add(messenger.MessagePath, actionList); + } + + /// + /// Removes an action from the dictionary + /// + /// + public void RemoveAction(string key) + { + if (_actionDictionary.ContainsKey(key)) + { + _actionDictionary.Remove(key); } + } - public MobileControlBridgeBase GetRoomBridge(string key) + public MobileControlBridgeBase GetRoomBridge(string key) + { + return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); + } + + public IMobileControlRoomMessenger GetRoomMessenger(string key) + { + return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); + } + + /// + /// + /// + /// + /// + private void Bridge_ConfigurationIsReady(object sender, EventArgs e) + { + this.LogDebug("Bridge ready. Registering"); + + // send the configuration object to the server + + if (_wsClient2 == null) { - return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); + RegisterSystemToServer(); } - - public IMobileControlRoomMessenger GetRoomMessenger(string key) + else if (!_wsClient2.IsAlive) { - return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); - } - - /// - /// - /// - /// - /// - private void Bridge_ConfigurationIsReady(object sender, EventArgs e) - { - this.LogDebug("Bridge ready. Registering"); - - // send the configuration object to the server - - if (_wsClient2 == null) - { - RegisterSystemToServer(); - } - else if (!_wsClient2.IsAlive) - { - ConnectWebsocketClient(); - } - else - { - SendInitialMessage(); - } - } - - /// - /// - /// - /// - private void ReconnectToServerTimerCallback(object o) - { - this.LogDebug("Attempting to reconnect to server..."); - ConnectWebsocketClient(); } - - /// - /// Verifies system connection with servers - /// - private void AuthorizeSystem(string code) + else { - if ( - string.IsNullOrEmpty(SystemUuid) - || SystemUuid.Equals("missing url", StringComparison.OrdinalIgnoreCase) - ) - { - CrestronConsole.ConsoleCommandResponse( - "System does not have a UUID. Please ensure proper configuration is loaded and restart." - ); - return; - } - if (string.IsNullOrEmpty(code)) - { - CrestronConsole.ConsoleCommandResponse( - "Please enter a grant code to authorize a system" - ); - return; - } - if (string.IsNullOrEmpty(Config.ServerUrl)) - { - CrestronConsole.ConsoleCommandResponse( - "Mobile control API address is not set. Check portal configuration" - ); - return; - } + SendInitialMessage(); + } + } - var authTask = ApiService.SendAuthorizationRequest(Host, code, SystemUuid); + /// + /// + /// + /// + private void ReconnectToServerTimerCallback(object o) + { + this.LogDebug("Attempting to reconnect to server..."); - authTask.ContinueWith(t => - { - var response = t.Result; + ConnectWebsocketClient(); + } - if (response.Authorized) - { - this.LogDebug("System authorized, sending config."); - RegisterSystemToServer(); - return; - } - - this.LogInformation(response.Reason); - }); + /// + /// Verifies system connection with servers + /// + private void AuthorizeSystem(string code) + { + if ( + string.IsNullOrEmpty(SystemUuid) + || SystemUuid.Equals("missing url", StringComparison.OrdinalIgnoreCase) + ) + { + CrestronConsole.ConsoleCommandResponse( + "System does not have a UUID. Please ensure proper configuration is loaded and restart." + ); + return; + } + if (string.IsNullOrEmpty(code)) + { + CrestronConsole.ConsoleCommandResponse( + "Please enter a grant code to authorize a system" + ); + return; + } + if (string.IsNullOrEmpty(Config.ServerUrl)) + { + CrestronConsole.ConsoleCommandResponse( + "Mobile control API address is not set. Check portal configuration" + ); + return; } - /// - /// Dumps info in response to console command. - /// - private void ShowInfo() + var authTask = ApiService.SendAuthorizationRequest(Host, code, SystemUuid); + + authTask.ContinueWith(t => { - var url = Config != null ? Host : "No config"; - string name; - string code; - if (_roomBridges != null && _roomBridges.Count > 0) - { - name = _roomBridges[0].RoomName; - code = _roomBridges[0].UserCode; - } - else - { - name = "No config"; - code = "Not available"; - } - var conn = _wsClient2 == null ? "No client" : (_wsClient2.IsAlive ? "Yes" : "No"); + var response = t.Result; - var secSinceLastAck = DateTime.Now - _lastAckMessage; - - if (Config.EnableApiServer) + if (response.Authorized) { - CrestronConsole.ConsoleCommandResponse( - @"Mobile Control Edge Server API Information: + this.LogDebug("System authorized, sending config."); + RegisterSystemToServer(); + return; + } + + this.LogInformation(response.Reason); + }); + } + + /// + /// Dumps info in response to console command. + /// + private void ShowInfo() + { + var url = Config != null ? Host : "No config"; + string name; + string code; + if (_roomBridges != null && _roomBridges.Count > 0) + { + name = _roomBridges[0].RoomName; + code = _roomBridges[0].UserCode; + } + else + { + name = "No config"; + code = "Not available"; + } + var conn = _wsClient2 == null ? "No client" : (_wsClient2.IsAlive ? "Yes" : "No"); + + var secSinceLastAck = DateTime.Now - _lastAckMessage; + + if (Config.EnableApiServer) + { + CrestronConsole.ConsoleCommandResponse( + @"Mobile Control Edge Server API Information: Server address: {0} System Name: {1} @@ -1578,65 +1578,65 @@ namespace PepperDash.Essentials System User code: {4} Connected?: {5} Seconds Since Last Ack: {6}", - url, - name, - ConfigReader.ConfigObject.SystemUrl, - SystemUuid, - code, - conn, - secSinceLastAck.Seconds - ); - } - else - { - CrestronConsole.ConsoleCommandResponse( - @" + url, + name, + ConfigReader.ConfigObject.SystemUrl, + SystemUuid, + code, + conn, + secSinceLastAck.Seconds + ); + } + else + { + CrestronConsole.ConsoleCommandResponse( + @" Mobile Control Edge Server API Information: Not Enabled in Config. " - ); - } + ); + } - if ( - Config.DirectServer != null - && Config.DirectServer.EnableDirectServer - && _directServer != null - ) - { - CrestronConsole.ConsoleCommandResponse( - @" + if ( + Config.DirectServer != null + && Config.DirectServer.EnableDirectServer + && _directServer != null + ) + { + CrestronConsole.ConsoleCommandResponse( + @" Mobile Control Direct Server Information: User App URL: {0} Server port: {1} ", - string.Format("{0}[insert_client_token]", _directServer.UserAppUrlPrefix), - _directServer.Port - ); + string.Format("{0}[insert_client_token]", _directServer.UserAppUrlPrefix), + _directServer.Port + ); - CrestronConsole.ConsoleCommandResponse( - @" + CrestronConsole.ConsoleCommandResponse( + @" UI Client Info: Tokens Defined: {0} Clients Connected: {1} ", - _directServer.UiClients.Count, - _directServer.ConnectedUiClientsCount - ); + _directServer.UiClients.Count, + _directServer.ConnectedUiClientsCount + ); - var clientNo = 1; - foreach (var clientContext in _directServer.UiClients) + var clientNo = 1; + foreach (var clientContext in _directServer.UiClients) + { + var isAlive = false; + var duration = "Not Connected"; + + if (clientContext.Value.Client != null) { - var isAlive = false; - var duration = "Not Connected"; + isAlive = clientContext.Value.Client.Context.WebSocket.IsAlive; + duration = clientContext.Value.Client.ConnectedDuration.ToString(); + } - if (clientContext.Value.Client != null) - { - isAlive = clientContext.Value.Client.Context.WebSocket.IsAlive; - duration = clientContext.Value.Client.ConnectedDuration.ToString(); - } - - CrestronConsole.ConsoleCommandResponse( - @" + CrestronConsole.ConsoleCommandResponse( + @" Client {0}: Room Key: {1} Touchpanel Key: {6} @@ -1645,708 +1645,707 @@ Client URL: {3} Connected: {4} Duration: {5} ", - clientNo, - clientContext.Value.Token.RoomKey, - clientContext.Key, - string.Format("{0}{1}", _directServer.UserAppUrlPrefix, clientContext.Key), - isAlive, - duration, - clientContext.Value.Token.TouchpanelKey - ); - clientNo++; - } + clientNo, + clientContext.Value.Token.RoomKey, + clientContext.Key, + string.Format("{0}{1}", _directServer.UserAppUrlPrefix, clientContext.Key), + isAlive, + duration, + clientContext.Value.Token.TouchpanelKey + ); + clientNo++; } - else - { - CrestronConsole.ConsoleCommandResponse( - @" + } + else + { + CrestronConsole.ConsoleCommandResponse( + @" Mobile Control Direct Server Infromation: Not Enabled in Config." - ); - } - } - - /// - /// Registers the room with the server - /// - public void RegisterSystemToServer() - { - - if (!Config.EnableApiServer) - { - this.LogInformation( - "ApiServer disabled via config. Cancelling attempt to register to server." - ); - return; - } - - var result = CreateWebsocket(); - - if (!result) - { - this.LogFatal("Unable to create websocket."); - return; - } - - ConnectWebsocketClient(); - } - - /// - /// Connects the Websocket Client - /// - private void ConnectWebsocketClient() - { - try - { - _wsCriticalSection.Enter(); - - // set to 99999 to let things work on 4-Series - if ( - (CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series4) - == eCrestronSeries.Series4 - ) - { - _wsClient2.Log.Level = (LogLevel)99999; - } - else if ( - (CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series3) - == eCrestronSeries.Series3 - ) - { - _wsClient2.Log.Level = _wsLogLevel; - } - - //This version of the websocket client is TLS1.2 ONLY - - //Fires OnMessage event when PING is received. - _wsClient2.EmitOnPing = true; - - this.LogDebug( - "Connecting mobile control client to {mobileControlUrl}", - _wsClient2.Url - ); - - TryConnect(); - } - finally - { - _wsCriticalSection.Leave(); - } - } - - /// - /// Attempts to connect the websocket - /// - private void TryConnect() - { - try - { - IsAuthorized = false; - _wsClient2.Connect(); - } - catch (InvalidOperationException) - { - this.LogError( - "Maximum retries exceeded. Restarting websocket" - ); - HandleConnectFailure(); - } - catch (IOException ex) - { - this.LogException(ex, "IO Exception on connect"); - HandleConnectFailure(); - } - catch (Exception ex) - { - this.LogException( - ex, - "Error on Websocket Connect" - ); - HandleConnectFailure(); - } - } - - /// - /// Gracefully handles conect failures by reconstructing the ws client and starting the reconnect timer - /// - private void HandleConnectFailure() - { - _wsClient2 = null; - - var wsHost = Host.Replace("http", "ws"); - var url = string.Format("{0}/system/join/{1}", wsHost, SystemUuid); - _wsClient2 = new WebSocket(url) - { - Log = - { - Output = (data, s) => - this.LogDebug( - "Message from websocket: {message}", - data - ) - } - }; - - _wsClient2.OnMessage -= HandleMessage; - _wsClient2.OnOpen -= HandleOpen; - _wsClient2.OnError -= HandleError; - _wsClient2.OnClose -= HandleClose; - - _wsClient2.OnMessage += HandleMessage; - _wsClient2.OnOpen += HandleOpen; - _wsClient2.OnError += HandleError; - _wsClient2.OnClose += HandleClose; - - StartServerReconnectTimer(); - } - - /// - /// - /// - /// - /// - private void HandleOpen(object sender, EventArgs e) - { - StopServerReconnectTimer(); - StartPingTimer(); - this.LogInformation("Mobile Control API connected"); - SendMessageObject(new MobileControlMessage { Type = "hello" }); - } - - /// - /// - /// - /// - /// - private void HandleMessage(object sender, MessageEventArgs e) - { - if (e.IsPing) - { - _lastAckMessage = DateTime.Now; - IsAuthorized = true; - ResetPingTimer(); - return; - } - - if (e.IsText && e.Data.Length > 0) - { - _receiveQueue.Enqueue(new ProcessStringMessage(e.Data, ParseStreamRx)); - } - } - - /// - /// - /// - /// - /// - private void HandleError(object sender, ErrorEventArgs e) - { - this.LogError("Websocket error {0}", e.Message); - - IsAuthorized = false; - StartServerReconnectTimer(); - } - - /// - /// - /// - /// - /// - private void HandleClose(object sender, CloseEventArgs e) - { - this.LogDebug( - "Websocket close {code} {reason}, clean={wasClean}", - e.Code, - e.Reason, - e.WasClean ); + } + } + + /// + /// Registers the room with the server + /// + public void RegisterSystemToServer() + { + + if (!Config.EnableApiServer) + { + this.LogInformation( + "ApiServer disabled via config. Cancelling attempt to register to server." + ); + return; + } + + var result = CreateWebsocket(); + + if (!result) + { + this.LogFatal("Unable to create websocket."); + return; + } + + ConnectWebsocketClient(); + } + + /// + /// Connects the Websocket Client + /// + private void ConnectWebsocketClient() + { + try + { + _wsCriticalSection.Enter(); + + // set to 99999 to let things work on 4-Series + if ( + (CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series4) + == eCrestronSeries.Series4 + ) + { + _wsClient2.Log.Level = (LogLevel)99999; + } + else if ( + (CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series3) + == eCrestronSeries.Series3 + ) + { + _wsClient2.Log.Level = _wsLogLevel; + } + + //This version of the websocket client is TLS1.2 ONLY + + //Fires OnMessage event when PING is received. + _wsClient2.EmitOnPing = true; + + this.LogDebug( + "Connecting mobile control client to {mobileControlUrl}", + _wsClient2.Url + ); + + TryConnect(); + } + finally + { + _wsCriticalSection.Leave(); + } + } + + /// + /// Attempts to connect the websocket + /// + private void TryConnect() + { + try + { IsAuthorized = false; - StopPingTimer(); - - // Start the reconnect timer only if disableReconnect is false and the code isn't 4200. 4200 indicates system is not authorized; - if (_disableReconnect || e.Code == 4200) - { - return; - } - - StartServerReconnectTimer(); + _wsClient2.Connect(); } - - /// - /// After a "hello" from the server, sends config and stuff - /// - private void SendInitialMessage() + catch (InvalidOperationException) { - this.LogInformation("Sending initial join message"); - - var touchPanels = DeviceManager - .AllDevices.OfType() - .Where(tp => !tp.UseDirectServer) - .Select( - (tp) => - { - return new { touchPanelKey = tp.Key, roomKey = tp.DefaultRoomKey }; - } - ); - - var msg = new MobileControlMessage - { - Type = "join", - Content = JToken.FromObject( - new { config = GetConfigWithPluginVersion(), touchPanels } - ) - }; - - SendMessageObject(msg); + this.LogError( + "Maximum retries exceeded. Restarting websocket" + ); + HandleConnectFailure(); } - - public MobileControlEssentialsConfig GetConfigWithPluginVersion() + catch (IOException ex) { - // Populate the application name and version number - var confObject = new MobileControlEssentialsConfig(ConfigReader.ConfigObject); + this.LogException(ex, "IO Exception on connect"); + HandleConnectFailure(); + } + catch (Exception ex) + { + this.LogException( + ex, + "Error on Websocket Connect" + ); + HandleConnectFailure(); + } + } - confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; + /// + /// Gracefully handles conect failures by reconstructing the ws client and starting the reconnect timer + /// + private void HandleConnectFailure() + { + _wsClient2 = null; - var essentialsVersion = Global.AssemblyVersion; - confObject.Info.RuntimeInfo.AssemblyVersion = essentialsVersion; - - - // // Set for local testing - // confObject.RuntimeInfo.PluginVersion = "4.0.0-localBuild"; - - // Populate the plugin version - var pluginVersion = Assembly - .GetExecutingAssembly() - .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); - - - if (pluginVersion[0] is AssemblyInformationalVersionAttribute fullVersionAtt) + var wsHost = Host.Replace("http", "ws"); + var url = string.Format("{0}/system/join/{1}", wsHost, SystemUuid); + _wsClient2 = new WebSocket(url) + { + Log = { - var pluginInformationalVersion = fullVersionAtt.InformationalVersion; - - confObject.RuntimeInfo.PluginVersion = pluginInformationalVersion; - confObject.RuntimeInfo.EssentialsVersion = Global.AssemblyVersion; - confObject.RuntimeInfo.PepperDashCoreVersion = PluginLoader.PepperDashCoreAssembly.Version; - confObject.RuntimeInfo.EssentialsPlugins = PluginLoader.EssentialsPluginAssemblies; + Output = (data, s) => + this.LogDebug( + "Message from websocket: {message}", + data + ) } - return confObject; + }; + + _wsClient2.OnMessage -= HandleMessage; + _wsClient2.OnOpen -= HandleOpen; + _wsClient2.OnError -= HandleError; + _wsClient2.OnClose -= HandleClose; + + _wsClient2.OnMessage += HandleMessage; + _wsClient2.OnOpen += HandleOpen; + _wsClient2.OnError += HandleError; + _wsClient2.OnClose += HandleClose; + + StartServerReconnectTimer(); + } + + /// + /// + /// + /// + /// + private void HandleOpen(object sender, EventArgs e) + { + StopServerReconnectTimer(); + StartPingTimer(); + this.LogInformation("Mobile Control API connected"); + SendMessageObject(new MobileControlMessage { Type = "hello" }); + } + + /// + /// + /// + /// + /// + private void HandleMessage(object sender, MessageEventArgs e) + { + if (e.IsPing) + { + _lastAckMessage = DateTime.Now; + IsAuthorized = true; + ResetPingTimer(); + return; } - public void SetClientUrl(string path, string roomKey = null) + if (e.IsText && e.Data.Length > 0) + { + _receiveQueue.Enqueue(new ProcessStringMessage(e.Data, ParseStreamRx)); + } + } + + /// + /// + /// + /// + /// + private void HandleError(object sender, ErrorEventArgs e) + { + this.LogError("Websocket error {0}", e.Message); + + IsAuthorized = false; + StartServerReconnectTimer(); + } + + /// + /// + /// + /// + /// + private void HandleClose(object sender, CloseEventArgs e) + { + this.LogDebug( + "Websocket close {code} {reason}, clean={wasClean}", + e.Code, + e.Reason, + e.WasClean + ); + IsAuthorized = false; + StopPingTimer(); + + // Start the reconnect timer only if disableReconnect is false and the code isn't 4200. 4200 indicates system is not authorized; + if (_disableReconnect || e.Code == 4200) + { + return; + } + + StartServerReconnectTimer(); + } + + /// + /// After a "hello" from the server, sends config and stuff + /// + private void SendInitialMessage() + { + this.LogInformation("Sending initial join message"); + + var touchPanels = DeviceManager + .AllDevices.OfType() + .Where(tp => !tp.UseDirectServer) + .Select( + (tp) => + { + return new { touchPanelKey = tp.Key, roomKey = tp.DefaultRoomKey }; + } + ); + + var msg = new MobileControlMessage + { + Type = "join", + Content = JToken.FromObject( + new { config = GetConfigWithPluginVersion(), touchPanels } + ) + }; + + SendMessageObject(msg); + } + + public MobileControlEssentialsConfig GetConfigWithPluginVersion() + { + // Populate the application name and version number + var confObject = new MobileControlEssentialsConfig(ConfigReader.ConfigObject); + + confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; + + var essentialsVersion = Global.AssemblyVersion; + confObject.Info.RuntimeInfo.AssemblyVersion = essentialsVersion; + + + // // Set for local testing + // confObject.RuntimeInfo.PluginVersion = "4.0.0-localBuild"; + + // Populate the plugin version + var pluginVersion = Assembly + .GetExecutingAssembly() + .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); + + + if (pluginVersion[0] is AssemblyInformationalVersionAttribute fullVersionAtt) + { + var pluginInformationalVersion = fullVersionAtt.InformationalVersion; + + confObject.RuntimeInfo.PluginVersion = pluginInformationalVersion; + confObject.RuntimeInfo.EssentialsVersion = Global.AssemblyVersion; + confObject.RuntimeInfo.PepperDashCoreVersion = PluginLoader.PepperDashCoreAssembly.Version; + confObject.RuntimeInfo.EssentialsPlugins = PluginLoader.EssentialsPluginAssemblies; + } + return confObject; + } + + public void SetClientUrl(string path, string roomKey = null) + { + var message = new MobileControlMessage + { + Type = string.IsNullOrEmpty(roomKey) ? $"/event/system/setUrl" : $"/event/room/{roomKey}/setUrl", + Content = JToken.FromObject(new MobileControlSimpleContent { Value = path }) + }; + + SendMessageObject(message); + } + + /// + /// Sends any object type to server + /// + /// + public void SendMessageObject(IMobileControlMessage o) + { + + if (Config.EnableApiServer) + { + + _transmitToServerQueue.Enqueue(new TransmitMessage(o, _wsClient2)); + + } + + if ( + Config.DirectServer != null + && Config.DirectServer.EnableDirectServer + && _directServer != null + ) + { + _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); + } + + } + + + public void SendMessageObjectToDirectClient(object o) + { + if ( + Config.DirectServer != null + && Config.DirectServer.EnableDirectServer + && _directServer != null + ) + { + _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); + } + } + + + /// + /// Disconnects the Websocket Client and stops the heartbeat timer + /// + private void CleanUpWebsocketClient() + { + if (_wsClient2 == null) + { + return; + } + + this.LogDebug("Disconnecting websocket"); + + _wsClient2.Close(); + } + + private void ResetPingTimer() + { + // This tells us we're online with the API and getting pings + _pingTimer.Reset(PingInterval); + } + + private void StartPingTimer() + { + StopPingTimer(); + _pingTimer = new CTimer(PingTimerCallback, null, PingInterval); + } + + private void StopPingTimer() + { + if (_pingTimer == null) + { + return; + } + + _pingTimer.Stop(); + _pingTimer.Dispose(); + _pingTimer = null; + } + + private void PingTimerCallback(object o) + { + this.LogDebug( + + "Ping timer expired. Closing websocket" + ); + + try + { + _wsClient2.Close(); + } + catch (Exception ex) + { + this.LogException(ex, + "Exception closing websocket" + ); + + HandleConnectFailure(); + } + } + + /// + /// + /// + private void StartServerReconnectTimer() + { + StopServerReconnectTimer(); + _serverReconnectTimer = new CTimer( + ReconnectToServerTimerCallback, + ServerReconnectInterval + ); + this.LogDebug("Reconnect Timer Started."); + } + + /// + /// Does what it says + /// + private void StopServerReconnectTimer() + { + if (_serverReconnectTimer == null) + { + return; + } + _serverReconnectTimer.Stop(); + _serverReconnectTimer = null; + } + + /// + /// Resets reconnect timer and updates usercode + /// + /// + private void HandleHeartBeat(JToken content) + { + SendMessageObject(new MobileControlMessage { Type = "/system/heartbeatAck" }); + + var code = content["userCode"]; + if (code == null) + { + return; + } + + foreach (var b in _roomBridges) + { + b.SetUserCode(code.Value()); + } + } + + private void HandleClientJoined(JToken content) + { + var clientId = content["clientId"].Value(); + var roomKey = content["roomKey"].Value(); + + if (_roomCombiner == null) { var message = new MobileControlMessage { - Type = string.IsNullOrEmpty(roomKey) ? $"/event/system/setUrl" : $"/event/room/{roomKey}/setUrl", - Content = JToken.FromObject(new MobileControlSimpleContent { Value = path }) + Type = "/system/roomKey", + ClientId = clientId, + Content = roomKey }; SendMessageObject(message); + return; } - /// - /// Sends any object type to server - /// - /// - public void SendMessageObject(IMobileControlMessage o) + if (!_roomCombiner.CurrentScenario.UiMap.ContainsKey(roomKey)) { + this.LogWarning( + "Unable to find correct roomKey for {roomKey} in current scenario. Returning {roomKey} as roomKey", roomKey); - if (Config.EnableApiServer) - { - - _transmitToServerQueue.Enqueue(new TransmitMessage(o, _wsClient2)); - - } - - if ( - Config.DirectServer != null - && Config.DirectServer.EnableDirectServer - && _directServer != null - ) - { - _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); - } - - } - - - public void SendMessageObjectToDirectClient(object o) - { - if ( - Config.DirectServer != null - && Config.DirectServer.EnableDirectServer - && _directServer != null - ) - { - _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); - } - } - - - /// - /// Disconnects the Websocket Client and stops the heartbeat timer - /// - private void CleanUpWebsocketClient() - { - if (_wsClient2 == null) - { - return; - } - - this.LogDebug("Disconnecting websocket"); - - _wsClient2.Close(); - } - - private void ResetPingTimer() - { - // This tells us we're online with the API and getting pings - _pingTimer.Reset(PingInterval); - } - - private void StartPingTimer() - { - StopPingTimer(); - _pingTimer = new CTimer(PingTimerCallback, null, PingInterval); - } - - private void StopPingTimer() - { - if (_pingTimer == null) - { - return; - } - - _pingTimer.Stop(); - _pingTimer.Dispose(); - _pingTimer = null; - } - - private void PingTimerCallback(object o) - { - this.LogDebug( - - "Ping timer expired. Closing websocket" - ); - - try - { - _wsClient2.Close(); - } - catch (Exception ex) - { - this.LogException(ex, - "Exception closing websocket" - ); - - HandleConnectFailure(); - } - } - - /// - /// - /// - private void StartServerReconnectTimer() - { - StopServerReconnectTimer(); - _serverReconnectTimer = new CTimer( - ReconnectToServerTimerCallback, - ServerReconnectInterval - ); - this.LogDebug("Reconnect Timer Started."); - } - - /// - /// Does what it says - /// - private void StopServerReconnectTimer() - { - if (_serverReconnectTimer == null) - { - return; - } - _serverReconnectTimer.Stop(); - _serverReconnectTimer = null; - } - - /// - /// Resets reconnect timer and updates usercode - /// - /// - private void HandleHeartBeat(JToken content) - { - SendMessageObject(new MobileControlMessage { Type = "/system/heartbeatAck" }); - - var code = content["userCode"]; - if (code == null) - { - return; - } - - foreach (var b in _roomBridges) - { - b.SetUserCode(code.Value()); - } - } - - private void HandleClientJoined(JToken content) - { - var clientId = content["clientId"].Value(); - var roomKey = content["roomKey"].Value(); - - if (_roomCombiner == null) - { - var message = new MobileControlMessage - { - Type = "/system/roomKey", - ClientId = clientId, - Content = roomKey - }; - - SendMessageObject(message); - return; - } - - if (!_roomCombiner.CurrentScenario.UiMap.ContainsKey(roomKey)) - { - this.LogWarning( - "Unable to find correct roomKey for {roomKey} in current scenario. Returning {roomKey} as roomKey", roomKey); - - var message = new MobileControlMessage - { - Type = "/system/roomKey", - ClientId = clientId, - Content = roomKey - }; - - SendMessageObject(message); - return; - } - - var newRoomKey = _roomCombiner.CurrentScenario.UiMap[roomKey]; - - var newMessage = new MobileControlMessage + var message = new MobileControlMessage { Type = "/system/roomKey", ClientId = clientId, - Content = newRoomKey + Content = roomKey }; - SendMessageObject(newMessage); + SendMessageObject(message); + return; } - private void HandleUserCode(JToken content, Action action = null) + var newRoomKey = _roomCombiner.CurrentScenario.UiMap[roomKey]; + + var newMessage = new MobileControlMessage { - var code = content["userCode"]; + Type = "/system/roomKey", + ClientId = clientId, + Content = newRoomKey + }; - JToken qrChecksum; + SendMessageObject(newMessage); + } - try - { - qrChecksum = content.SelectToken("qrChecksum", false); - } - catch - { - qrChecksum = new JValue(string.Empty); - } + private void HandleUserCode(JToken content, Action action = null) + { + var code = content["userCode"]; - if (code == null) - { - return; - } + JToken qrChecksum; - if (action == null) - { - foreach (var bridge in _roomBridges) - { - bridge.SetUserCode(code.Value(), qrChecksum.Value()); - } - - return; - } - - action(code.Value(), qrChecksum.Value()); + try + { + qrChecksum = content.SelectToken("qrChecksum", false); + } + catch + { + qrChecksum = new JValue(string.Empty); } - public void HandleClientMessage(string message) + if (code == null) { - _receiveQueue.Enqueue(new ProcessStringMessage(message, ParseStreamRx)); + return; } - /// - /// - /// - private void ParseStreamRx(string messageText) + if (action == null) { - if (string.IsNullOrEmpty(messageText)) + foreach (var bridge in _roomBridges) { - return; + bridge.SetUserCode(code.Value(), qrChecksum.Value()); } - if (!messageText.Contains("/system/heartbeat")) + return; + } + + action(code.Value(), qrChecksum.Value()); + } + + public void HandleClientMessage(string message) + { + _receiveQueue.Enqueue(new ProcessStringMessage(message, ParseStreamRx)); + } + + /// + /// + /// + private void ParseStreamRx(string messageText) + { + if (string.IsNullOrEmpty(messageText)) + { + return; + } + + if (!messageText.Contains("/system/heartbeat")) + { + this.LogDebug( + "Message RX: {messageText}", + messageText + ); + } + + try + { + var message = JsonConvert.DeserializeObject(messageText); + + switch (message.Type) { - this.LogDebug( - "Message RX: {messageText}", - messageText - ); + case "hello": + SendInitialMessage(); + break; + case "/system/heartbeat": + HandleHeartBeat(message.Content); + break; + case "/system/userCode": + HandleUserCode(message.Content); + break; + case "/system/clientJoined": + HandleClientJoined(message.Content); + break; + case "/system/reboot": + SystemMonitorController.ProcessorReboot(); + break; + case "/system/programReset": + SystemMonitorController.ProgramReset(InitialParametersClass.ApplicationNumber); + break; + case "raw": + var wrapper = message.Content.ToObject(); + DeviceJsonApi.DoDeviceAction(wrapper); + break; + case "close": + this.LogDebug("Received close message from server"); + break; + default: + // Incoming message example + // /room/roomA/status + // /room/roomAB/status + + // ActionDictionary Keys example + // /room/roomA + // /room/roomAB + + // Can't do direct comparison because it will match /room/roomA with /room/roomA/xxx instead of /room/roomAB/xxx + var handlers = _actionDictionary.Where(kv => message.Type.StartsWith(kv.Key + "/")).SelectMany(kv => kv.Value).ToList(); // adds trailing slash to ensure above case is handled + + + if (handlers.Count == 0) + { + this.LogInformation("-- Warning: Incoming message has no registered handler {type}", message.Type); + break; + } + + foreach (var handler in handlers) + { + Task.Run( + () => + handler.Action(message.Type, message.ClientId, message.Content) + ); + } + + break; + } + } + catch (Exception err) + { + this.LogException( + err, + "Unable to parse {message}", + messageText + ); + } + } + + /// + /// + /// + /// + private void TestHttpRequest(string s) + { + { + s = s.Trim(); + if (string.IsNullOrEmpty(s)) + { + PrintTestHttpRequestUsage(); + return; + } + var tokens = s.Split(' '); + if (tokens.Length < 2) + { + CrestronConsole.ConsoleCommandResponse("Too few paramaters\r"); + PrintTestHttpRequestUsage(); + return; } try { - var message = JsonConvert.DeserializeObject(messageText); - - switch (message.Type) + var url = tokens[1]; + switch (tokens[0].ToLower()) { - case "hello": - SendInitialMessage(); + case "get": + { + var resp = new HttpClient().Get(url); + CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); + } break; - case "/system/heartbeat": - HandleHeartBeat(message.Content); - break; - case "/system/userCode": - HandleUserCode(message.Content); - break; - case "/system/clientJoined": - HandleClientJoined(message.Content); - break; - case "/system/reboot": - SystemMonitorController.ProcessorReboot(); - break; - case "/system/programReset": - SystemMonitorController.ProgramReset(InitialParametersClass.ApplicationNumber); - break; - case "raw": - var wrapper = message.Content.ToObject(); - DeviceJsonApi.DoDeviceAction(wrapper); - break; - case "close": - this.LogDebug("Received close message from server"); + case "post": + { + var resp = new HttpClient().Post(url, new byte[] { }); + CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); + } break; default: - // Incoming message example - // /room/roomA/status - // /room/roomAB/status - - // ActionDictionary Keys example - // /room/roomA - // /room/roomAB - - // Can't do direct comparison because it will match /room/roomA with /room/roomA/xxx instead of /room/roomAB/xxx - var handlers = _actionDictionary.Where(kv => message.Type.StartsWith(kv.Key + "/")).SelectMany(kv => kv.Value).ToList(); // adds trailing slash to ensure above case is handled - - - if (handlers.Count == 0) - { - this.LogInformation("-- Warning: Incoming message has no registered handler {type}", message.Type); - break; - } - - foreach (var handler in handlers) - { - Task.Run( - () => - handler.Action(message.Type, message.ClientId, message.Content) - ); - } - + CrestronConsole.ConsoleCommandResponse("Only get or post supported\r"); + PrintTestHttpRequestUsage(); break; } } - catch (Exception err) + catch (HttpException e) { - this.LogException( - err, - "Unable to parse {message}", - messageText + CrestronConsole.ConsoleCommandResponse("Exception in request:\r"); + CrestronConsole.ConsoleCommandResponse( + "Response URL: {0}\r", + e.Response.ResponseUrl + ); + CrestronConsole.ConsoleCommandResponse( + "Response Error Code: {0}\r", + e.Response.Code + ); + CrestronConsole.ConsoleCommandResponse( + "Response body: {0}\r", + e.Response.ContentString ); } } - - /// - /// - /// - /// - private void TestHttpRequest(string s) - { - { - s = s.Trim(); - if (string.IsNullOrEmpty(s)) - { - PrintTestHttpRequestUsage(); - return; - } - var tokens = s.Split(' '); - if (tokens.Length < 2) - { - CrestronConsole.ConsoleCommandResponse("Too few paramaters\r"); - PrintTestHttpRequestUsage(); - return; - } - - try - { - var url = tokens[1]; - switch (tokens[0].ToLower()) - { - case "get": - { - var resp = new HttpClient().Get(url); - CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); - } - break; - case "post": - { - var resp = new HttpClient().Post(url, new byte[] { }); - CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); - } - break; - default: - CrestronConsole.ConsoleCommandResponse("Only get or post supported\r"); - PrintTestHttpRequestUsage(); - break; - } - } - catch (HttpException e) - { - CrestronConsole.ConsoleCommandResponse("Exception in request:\r"); - CrestronConsole.ConsoleCommandResponse( - "Response URL: {0}\r", - e.Response.ResponseUrl - ); - CrestronConsole.ConsoleCommandResponse( - "Response Error Code: {0}\r", - e.Response.Code - ); - CrestronConsole.ConsoleCommandResponse( - "Response body: {0}\r", - e.Response.ContentString - ); - } - } - } - - private void PrintTestHttpRequestUsage() - { - CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); - } } - public class ClientSpecificUpdateRequest + private void PrintTestHttpRequestUsage() { - public ClientSpecificUpdateRequest(Action action) - { - ResponseMethod = action; - } - - public Action ResponseMethod { get; private set; } - } - - public class UserCodeChanged - { - public Action UpdateUserCode { get; private set; } - - public UserCodeChanged(Action updateMethod) - { - UpdateUserCode = updateMethod; - } + CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); + } +} + +public class ClientSpecificUpdateRequest +{ + public ClientSpecificUpdateRequest(Action action) + { + ResponseMethod = action; + } + + public Action ResponseMethod { get; private set; } +} + +public class UserCodeChanged +{ + public Action UpdateUserCode { get; private set; } + + public UserCodeChanged(Action updateMethod) + { + UpdateUserCode = updateMethod; } } diff --git a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs index c005ca17..f3cb8d68 100644 --- a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs +++ b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs @@ -5,127 +5,126 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; using System; -namespace PepperDash.Essentials.RoomBridges +namespace PepperDash.Essentials.RoomBridges; + +/// +/// +/// +public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger { - /// - /// - /// - public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger + public event EventHandler UserCodeChanged; + + public event EventHandler UserPromptedForCode; + + public event EventHandler ClientJoined; + + public event EventHandler AppUrlChanged; + + public IMobileControl Parent { get; private set; } + + public string AppUrl { get; private set; } + public string UserCode { get; private set; } + + public string QrCodeUrl { get; protected set; } + + public string QrCodeChecksum { get; protected set; } + + public string McServerUrl { get; private set; } + + public abstract string RoomName { get; } + + public abstract string RoomKey { get; } + + protected MobileControlBridgeBase(string key, string messagePath) + : base(key, messagePath) { - public event EventHandler UserCodeChanged; + } - public event EventHandler UserPromptedForCode; + protected MobileControlBridgeBase(string key, string messagePath, IKeyName device) + : base(key, messagePath, device) + { + } - public event EventHandler ClientJoined; + /// + /// Set the parent. Does nothing else. Override to add functionality such + /// as adding actions to parent + /// + /// + public virtual void AddParent(IMobileControl parent) + { + Parent = parent; - public event EventHandler AppUrlChanged; + McServerUrl = Parent.ClientAppUrl; + } - public IMobileControl Parent { get; private set; } - - public string AppUrl { get; private set; } - public string UserCode { get; private set; } - - public string QrCodeUrl { get; protected set; } - - public string QrCodeChecksum { get; protected set; } - - public string McServerUrl { get; private set; } - - public abstract string RoomName { get; } - - public abstract string RoomKey { get; } - - protected MobileControlBridgeBase(string key, string messagePath) - : base(key, messagePath) + /// + /// Sets the UserCode on the bridge object. Called from controller. A changed code will + /// fire method UserCodeChange. Override that to handle changes + /// + /// + public void SetUserCode(string code) + { + var changed = UserCode != code; + UserCode = code; + if (changed) { - } - - protected MobileControlBridgeBase(string key, string messagePath, IKeyName device) - : base(key, messagePath, device) - { - } - - /// - /// Set the parent. Does nothing else. Override to add functionality such - /// as adding actions to parent - /// - /// - public virtual void AddParent(IMobileControl parent) - { - Parent = parent; - - McServerUrl = Parent.ClientAppUrl; - } - - /// - /// Sets the UserCode on the bridge object. Called from controller. A changed code will - /// fire method UserCodeChange. Override that to handle changes - /// - /// - public void SetUserCode(string code) - { - var changed = UserCode != code; - UserCode = code; - if (changed) - { - UserCodeChange(); - } - } - - - /// - /// Sets the UserCode on the bridge object. Called from controller. A changed code will - /// fire method UserCodeChange. Override that to handle changes - /// - /// - /// Checksum of the QR code. Used for Cisco codec branding command - public void SetUserCode(string code, string qrChecksum) - { - QrCodeChecksum = qrChecksum; - - SetUserCode(code); - } - - public virtual void UpdateAppUrl(string url) - { - AppUrl = url; - - var handler = AppUrlChanged; - - if (handler == null) return; - - handler(this, new EventArgs()); - } - - /// - /// Empty method in base class. Override this to add functionality - /// when code changes - /// - protected virtual void UserCodeChange() - { - this.LogDebug("Server user code changed: {userCode}", UserCode); - - var qrUrl = string.Format($"{Parent.Host}/api/rooms/{Parent.SystemUuid}/{RoomKey}/qr?x={new Random().Next()}"); - QrCodeUrl = qrUrl; - - this.LogDebug("Server user code changed: {userCode} - {qrCodeUrl}", UserCode, qrUrl); - - OnUserCodeChanged(); - } - - protected void OnUserCodeChanged() - { - UserCodeChanged?.Invoke(this, new EventArgs()); - } - - protected void OnUserPromptedForCode() - { - UserPromptedForCode?.Invoke(this, new EventArgs()); - } - - protected void OnClientJoined() - { - ClientJoined?.Invoke(this, new EventArgs()); + UserCodeChange(); } } + + + /// + /// Sets the UserCode on the bridge object. Called from controller. A changed code will + /// fire method UserCodeChange. Override that to handle changes + /// + /// + /// Checksum of the QR code. Used for Cisco codec branding command + public void SetUserCode(string code, string qrChecksum) + { + QrCodeChecksum = qrChecksum; + + SetUserCode(code); + } + + public virtual void UpdateAppUrl(string url) + { + AppUrl = url; + + var handler = AppUrlChanged; + + if (handler == null) return; + + handler(this, new EventArgs()); + } + + /// + /// Empty method in base class. Override this to add functionality + /// when code changes + /// + protected virtual void UserCodeChange() + { + this.LogDebug("Server user code changed: {userCode}", UserCode); + + var qrUrl = string.Format($"{Parent.Host}/api/rooms/{Parent.SystemUuid}/{RoomKey}/qr?x={new Random().Next()}"); + QrCodeUrl = qrUrl; + + this.LogDebug("Server user code changed: {userCode} - {qrCodeUrl}", UserCode, qrUrl); + + OnUserCodeChanged(); + } + + protected void OnUserCodeChanged() + { + UserCodeChanged?.Invoke(this, new EventArgs()); + } + + protected void OnUserPromptedForCode() + { + UserPromptedForCode?.Invoke(this, new EventArgs()); + } + + protected void OnClientJoined() + { + ClientJoined?.Invoke(this, new EventArgs()); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs index 9009c4cc..cb5d51ae 100644 --- a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs +++ b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs @@ -23,944 +23,943 @@ using System.Linq; using IShades = PepperDash.Essentials.Core.Shades.IShades; using ShadeBase = PepperDash.Essentials.Devices.Common.Shades.ShadeBase; -namespace PepperDash.Essentials.RoomBridges +namespace PepperDash.Essentials.RoomBridges; + +public class MobileControlEssentialsRoomBridge : MobileControlBridgeBase { - public class MobileControlEssentialsRoomBridge : MobileControlBridgeBase - { - private List _touchPanelTokens = new List(); - public IEssentialsRoom Room { get; private set; } - - public string DefaultRoomKey { get; private set; } - /// - /// - /// - public override string RoomName - { - get { return Room.Name; } - } - - public override string RoomKey - { - get { return Room.Key; } - } - - public MobileControlEssentialsRoomBridge(IEssentialsRoom room) : - this($"mobileControlBridge-{room.Key}", room.Key, room) - { - Room = room; - } - - public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device) - { - DefaultRoomKey = roomKey; - - AddPreActivationAction(GetRoom); - } - - - protected override void RegisterActions() - { - // we add actions to the messaging system with a path, and a related action. Custom action - // content objects can be handled in the controller's LineReceived method - and perhaps other - // sub-controller parsing could be attached to these classes, so that the systemController - // doesn't need to know about everything. - - this.LogInformation("Registering Actions with AppServer"); - - AddAction("/promptForCode", (id, content) => OnUserPromptedForCode()); - AddAction("/clientJoined", (id, content) => OnClientJoined()); - - AddAction("/touchPanels", (id, content) => OnTouchPanelsUpdated(content)); - - AddAction($"/userApp", (id, content) => OnUserAppUpdated(content)); - - AddAction("/userCode", (id, content) => - { - var msg = content.ToObject(); - - SetUserCode(msg.UserCode, msg.QrChecksum ?? string.Empty); - }); - - - // Source Changes and room off - AddAction("/status", (id, content) => - { - SendFullStatusForClientId(id, Room); - }); - - if (Room is IRunRouteAction routeRoom) - AddAction("/source", (id, content) => - { - - var msg = content.ToObject(); - - this.LogVerbose("Received request to route to source: {sourceListKey} on list: {sourceList}", msg.SourceListItemKey, msg.SourceListKey); - - routeRoom.RunRouteAction(msg.SourceListItemKey, msg.SourceListKey); - }); - - if (Room is IRunDirectRouteAction directRouteRoom) - { - AddAction("/directRoute", (id, content) => - { - var msg = content.ToObject(); - - - this.LogVerbose("Running direct route from {sourceKey} to {destinationKey} with signal type {signalType}", msg.SourceKey, msg.DestinationKey, msg.SignalType); - - directRouteRoom.RunDirectRoute(msg.SourceKey, msg.DestinationKey, msg.SignalType); - }); - } - - - if (Room is IRunDefaultPresentRoute defaultRoom) - AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute()); - - if (Room is IHasCurrentSourceInfoChange sscRoom) - sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange; - - if (Room is IEssentialsHuddleVtc1Room vtcRoom) - { - if (vtcRoom.ScheduleSource != null) - { - var key = vtcRoom.Key + "-" + Key; - - if (!AppServerController.CheckForDeviceMessenger(key)) - { - var scheduleMessenger = new IHasScheduleAwarenessMessenger(key, vtcRoom.ScheduleSource, - $"/room/{vtcRoom.Key}"); - AppServerController.AddDeviceMessenger(scheduleMessenger); - } - } - - vtcRoom.InCallFeedback.OutputChange += InCallFeedback_OutputChange; - } - - if (Room is IPrivacy privacyRoom) - { - AddAction("/volumes/master/privacyMuteToggle", (id, content) => privacyRoom.PrivacyModeToggle()); - - privacyRoom.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; - } - - - if (Room is IRunDefaultCallRoute defCallRm) - { - AddAction("/activityVideo", (id, content) => defCallRm.RunDefaultCallRoute()); - } - - Room.OnFeedback.OutputChange += OnFeedback_OutputChange; - Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; - Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; - - AddTechRoomActions(); - - if (Room is IHasCurrentVolumeControls volumeRoom) - { - volumeRoom.CurrentVolumeDeviceChange += Room_CurrentVolumeDeviceChange; - - if (volumeRoom.CurrentVolumeControls == null) return; - - AddAction("/volumes/master/level", (id, content) => - { - var msg = content.ToObject>(); - - - if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) - basicVolumeWithFeedback.SetVolume(msg.Value); - }); - - AddAction("/volumes/master/muteToggle", (id, content) => volumeRoom.CurrentVolumeControls.MuteToggle()); - - AddAction("/volumes/master/muteOn", (id, content) => - { - if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) - basicVolumeWithFeedback.MuteOn(); - }); - - AddAction("/volumes/master/muteOff", (id, content) => - { - if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) - basicVolumeWithFeedback.MuteOff(); - }); - - AddAction("/volumes/master/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => - { - if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) - { - basicVolumeWithFeedback.VolumeUp(b); - } - } - )); - - AddAction("/volumes/master/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => - { - if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) - { - basicVolumeWithFeedback.VolumeDown(b); - } - } - )); - - // Registers for initial volume events, if possible - if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback currentVolumeDevice) - { - this.LogVerbose("Registering for volume feedback events"); - - currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; - currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; - } - } - } - - private void OnTouchPanelsUpdated(JToken content) - { - var message = content.ToObject(); - - _touchPanelTokens = message.TouchPanels; - - UpdateTouchPanelAppUrls(message.UserAppUrl); - } - - private void UpdateTouchPanelAppUrls(string userAppUrl) - { - foreach (var tp in _touchPanelTokens) - { - var dev = DeviceManager.AllDevices.OfType().FirstOrDefault((tpc) => tpc.Key.Equals(tp.TouchpanelKey, StringComparison.InvariantCultureIgnoreCase)); - - if (dev == null) - { - continue; - } - - //UpdateAppUrl($"{userAppUrl}?token={tp.Token}"); - - dev.SetAppUrl($"{userAppUrl}?token={tp.Token}"); - } - } - - private void OnUserAppUpdated(JToken content) - { - var message = content.ToObject(); - - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Updating User App URL to {userAppUrl}. Full Message: {@message}", this, message.UserAppUrl, content); - - UpdateTouchPanelAppUrls(message.UserAppUrl); - } - - private void InCallFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - var state = new RoomStateMessage - { - IsInCall = e.BoolValue - }; - PostStatusMessage(state); - } - - private void GetRoom() - { - if (Room != null) - { - this.LogInformation("Room with key {key} already linked.", DefaultRoomKey); - return; - } - - - if (!(DeviceManager.GetDeviceForKey(DefaultRoomKey) is IEssentialsRoom tempRoom)) - { - this.LogInformation("Room with key {key} not found or is not an Essentials Room", DefaultRoomKey); - return; - } - - Room = tempRoom; - } - - protected override void UserCodeChange() - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Server user code changed: {userCode}", this, UserCode); - - var qrUrl = string.Format("{0}/rooms/{1}/{3}/qr?x={2}", Parent?.Host, Parent?.SystemUuid, new Random().Next(), DefaultRoomKey); - - QrCodeUrl = qrUrl; - - this.LogDebug("Server user code changed: {userCode} - {qrUrl}", UserCode, qrUrl); - - OnUserCodeChanged(); - } - - /* /// - /// Override of base: calls base to add parent and then registers actions and events. - /// - /// - public override void AddParent(MobileControlSystemController parent) - { - base.AddParent(parent); - - }*/ - - private void AddTechRoomActions() - { - if (!(Room is IEssentialsTechRoom techRoom)) - { - return; - } - - AddAction("/roomPowerOn", (id, content) => techRoom.RoomPowerOn()); - AddAction("/roomPowerOff", (id, content) => techRoom.RoomPowerOff()); - } - - private void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - var state = new RoomStateMessage(); - - var volumes = new Dictionary - { - { "master", new Volume("master") - { - PrivacyMuted = e.BoolValue - } - } - }; - - state.Volumes = volumes; - - PostStatusMessage(state); - } - - /// - /// - /// - /// - /// - private void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - // sharing source - string shareText; - bool isSharing; - - if (Room is IHasCurrentSourceInfoChange srcInfoRoom && Room is IHasVideoCodec vcRoom && vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null) - { - shareText = srcInfoRoom.CurrentSourceInfo.PreferredName; - isSharing = true; - } - else - { - shareText = "None"; - isSharing = false; - } - - var state = new RoomStateMessage - { - Share = new ShareState - { - CurrentShareText = shareText, - IsSharing = isSharing - } - }; - - PostStatusMessage(state); - } - - /// - /// - /// - /// - /// - private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - var state = new - { - isWarmingUp = e.BoolValue - }; - - PostStatusMessage(JToken.FromObject(state)); - } - - /// - /// - /// - /// - /// - private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - var state = new - { - isCoolingDown = e.BoolValue - }; - PostStatusMessage(JToken.FromObject(state)); - } - - /// - /// - /// - /// - /// - private void OnFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - var state = new - { - isOn = e.BoolValue - }; - PostStatusMessage(JToken.FromObject(state)); - } - - private void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) - { - if (e.OldDev is IBasicVolumeWithFeedback) - { - var oldDev = e.OldDev as IBasicVolumeWithFeedback; - oldDev.MuteFeedback.OutputChange -= MuteFeedback_OutputChange; - oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange; - } - - if (e.NewDev is IBasicVolumeWithFeedback) - { - var newDev = e.NewDev as IBasicVolumeWithFeedback; - newDev.MuteFeedback.OutputChange += MuteFeedback_OutputChange; - newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; - } - } - - /// - /// Event handler for mute changes - /// - private void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - var state = new RoomStateMessage(); - - var volumes = new Dictionary - { - { "master", new Volume("master", e.BoolValue) } - }; - - state.Volumes = volumes; - - PostStatusMessage(state); - } - - /// - /// Handles Volume changes on room - /// - private void VolumeLevelFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - - var state = new - { - volumes = new Dictionary - { - { "master", new Volume("master", e.IntValue) } - } - }; - PostStatusMessage(JToken.FromObject(state)); - } - - - private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type) - { - /* Example message - * { -   "type":"/room/status", -   "content": { -     "selectedSourceKey": "off", -   } - } - */ - - } - - /// - /// Sends the full status of the room to the server - /// - /// - private void SendFullStatusForClientId(string id, IEssentialsRoom room) - { - //Parent.SendMessageObject(GetFullStatus(room)); - var message = GetFullStatusForClientId(room); - - if (message == null) - { - return; - } - PostStatusMessage(message, id); - } - - - /// - /// Gets full room status - /// - /// The room to get status of - /// The status response message - private RoomStateMessage GetFullStatusForClientId(IEssentialsRoom room) - { - try - { - this.LogVerbose("GetFullStatus"); - - var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null; - - var volumes = new Dictionary(); - if (room is IHasCurrentVolumeControls rmVc) - { - if (rmVc.CurrentVolumeControls is IBasicVolumeWithFeedback vc) - { - var volume = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, ""); - if (room is IPrivacy privacyRoom) - { - volume.HasPrivacyMute = true; - volume.PrivacyMuted = privacyRoom.PrivacyModeIsOnFeedback.BoolValue; - } - - volumes.Add("master", volume); - } - } - - var state = new RoomStateMessage - { - Configuration = GetRoomConfiguration(room), - ActivityMode = 1, - IsOn = room.OnFeedback.BoolValue, - SelectedSourceKey = sourceKey, - Volumes = volumes, - IsWarmingUp = room.IsWarmingUpFeedback.BoolValue, - IsCoolingDown = room.IsCoolingDownFeedback.BoolValue - }; - - if (room is IEssentialsHuddleVtc1Room vtcRoom) - { - state.IsInCall = vtcRoom.InCallFeedback.BoolValue; - } - - return state; - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Error getting full status", this); - return null; - } - } - - /// - /// Determines the configuration of the room and the details about the devices associated with the room - /// - /// - private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) - { - try - { - var configuration = new RoomConfiguration - { - //ShutdownPromptSeconds = room.ShutdownPromptSeconds, - TouchpanelKeys = DeviceManager.AllDevices. - OfType() - .Where((tp) => tp.DefaultRoomKey.Equals(room.Key, StringComparison.InvariantCultureIgnoreCase)) - .Select(tp => tp.Key).ToList() - }; - - try - { - var zrcTp = DeviceManager.AllDevices.OfType().SingleOrDefault((tp) => tp.ZoomRoomController); - - configuration.ZoomRoomControllerKey = zrcTp?.Key; - } - catch - { - configuration.ZoomRoomControllerKey = room.Key; - } - - if (room is IHasCiscoNavigatorTouchpanel ciscoNavRoom) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting CiscoNavigatorKey to: {ciscoNavRoom.CiscoNavigatorTouchpanelKey}", this); - configuration.CiscoNavigatorKey = ciscoNavRoom.CiscoNavigatorTouchpanelKey; - } - - - - // find the room combiner for this room by checking if the room is in the list of rooms for the room combiner - var roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); - - configuration.RoomCombinerKey = roomCombiner?.Key; - - - if (room is IEssentialsRoomPropertiesConfig propertiesConfig) - { - configuration.HelpMessage = propertiesConfig.PropertiesConfig.HelpMessageForDisplay; - } - - if (room is IEssentialsHuddleSpaceRoom huddleRoom && !string.IsNullOrEmpty(huddleRoom.PropertiesConfig.HelpMessageForDisplay)) - { - this.LogVerbose("Getting huddle room config"); - configuration.HelpMessage = huddleRoom.PropertiesConfig.HelpMessageForDisplay; - configuration.UiBehavior = huddleRoom.PropertiesConfig.UiBehavior; - configuration.DefaultPresentationSourceKey = huddleRoom.PropertiesConfig.DefaultSourceItem; - - } - - if (room is IEssentialsHuddleVtc1Room vtc1Room && !string.IsNullOrEmpty(vtc1Room.PropertiesConfig.HelpMessageForDisplay)) - { - this.LogVerbose("Getting vtc room config"); - configuration.HelpMessage = vtc1Room.PropertiesConfig.HelpMessageForDisplay; - configuration.UiBehavior = vtc1Room.PropertiesConfig.UiBehavior; - configuration.DefaultPresentationSourceKey = vtc1Room.PropertiesConfig.DefaultSourceItem; - } - - if (room is IEssentialsTechRoom techRoom && !string.IsNullOrEmpty(techRoom.PropertiesConfig.HelpMessage)) - { - this.LogVerbose("Getting tech room config"); - configuration.HelpMessage = techRoom.PropertiesConfig.HelpMessage; - } - - if (room is IHasVideoCodec vcRoom) - { - if (vcRoom.VideoCodec != null) - { - this.LogVerbose("Getting codec config"); - var type = vcRoom.VideoCodec.GetType(); - - configuration.HasVideoConferencing = true; - configuration.VideoCodecKey = vcRoom.VideoCodec.Key; - configuration.VideoCodecIsZoomRoom = type.Name.Equals("ZoomRoom", StringComparison.InvariantCultureIgnoreCase); - } - } - ; - - if (room is IHasAudioCodec acRoom) - { - if (acRoom.AudioCodec != null) - { - this.LogVerbose("Getting audio codec config"); - configuration.HasAudioConferencing = true; - configuration.AudioCodecKey = acRoom.AudioCodec.Key; - } - } - - - if (room is IHasMatrixRouting matrixRoutingRoom) - { - this.LogVerbose("Getting matrix routing config"); - configuration.MatrixRoutingKey = matrixRoutingRoom.MatrixRoutingDeviceKey; - configuration.EndpointKeys = matrixRoutingRoom.EndpointKeys; - } - - if (room is IEnvironmentalControls envRoom) - { - this.LogVerbose("Getting environmental controls config. RoomHasEnvironmentalControls: {hasEnvironmentalControls}", envRoom.HasEnvironmentalControlDevices); - configuration.HasEnvironmentalControls = envRoom.HasEnvironmentalControlDevices; - - if (envRoom.HasEnvironmentalControlDevices) - { - this.LogVerbose("Room Has {count} Environmental Control Devices.", envRoom.EnvironmentalControlDevices.Count); - - foreach (var dev in envRoom.EnvironmentalControlDevices) - { - this.LogVerbose("Adding environmental device: {key}", dev.Key); - - eEnvironmentalDeviceTypes type = eEnvironmentalDeviceTypes.None; - - if (dev is ILightingScenes) - { - type = eEnvironmentalDeviceTypes.Lighting; - } - else if (dev is ShadeBase || dev is IShadesOpenCloseStop || dev is IShadesOpenClosePreset) - { - type = eEnvironmentalDeviceTypes.Shade; - } - else if (dev is IShades) - { - type = eEnvironmentalDeviceTypes.ShadeController; - } - else if (dev is ISwitchedOutput) - { - type = eEnvironmentalDeviceTypes.Relay; - } - - this.LogVerbose("Environmental Device Type: {type}", type); - - var envDevice = new EnvironmentalDeviceConfiguration(dev.Key, type); - - configuration.EnvironmentalDevices.Add(envDevice); - } - } - else - { - this.LogVerbose("Room Has No Environmental Control Devices"); - } - } - - if (room is IHasDefaultDisplay defDisplayRoom) - { - this.LogVerbose("Getting default display config"); - configuration.DefaultDisplayKey = defDisplayRoom.DefaultDisplay.Key; - configuration.Destinations.Add(eSourceListItemDestinationTypes.defaultDisplay, defDisplayRoom.DefaultDisplay.Key); - } - - if (room is IHasMultipleDisplays multiDisplayRoom) - { - this.LogVerbose("Getting multiple display config"); - - if (multiDisplayRoom.Displays == null) - { - this.LogVerbose("Displays collection is null"); - } - else - { - this.LogVerbose("Displays collection exists"); - - configuration.Destinations = multiDisplayRoom.Displays.ToDictionary(kv => kv.Key, kv => kv.Value.Key); - } - } - - if (room is IHasAccessoryDevices accRoom) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Getting accessory devices config", this); - - if (accRoom.AccessoryDeviceKeys == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection is null", this); - } - else - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection exists", this); - - configuration.AccessoryDeviceKeys = accRoom.AccessoryDeviceKeys; - } - } - - var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); - if (sourceList != null) - { - this.LogVerbose("Getting source list config"); - configuration.SourceList = sourceList; - configuration.HasRoutingControls = true; - - foreach (var source in sourceList) - { - if (source.Value.SourceDevice is Devices.Common.IRSetTopBoxBase) - { - configuration.HasSetTopBoxControls = true; - continue; - } - else if (source.Value.SourceDevice is CameraBase) - { - configuration.HasCameraControls = true; - continue; - } - } - } - - var destinationList = ConfigReader.ConfigObject.GetDestinationListForKey(room.DestinationListKey); - - if (destinationList != null) - { - configuration.DestinationList = destinationList; - } - - var audioControlPointList = ConfigReader.ConfigObject.GetAudioControlPointListForKey(room.AudioControlPointListKey); - - if (audioControlPointList != null) - { - configuration.AudioControlPointList = audioControlPointList; - } - - var cameraList = ConfigReader.ConfigObject.GetCameraListForKey(room.CameraListKey); - - if (cameraList != null) - { - configuration.CameraList = cameraList; - } - - return configuration; - - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception getting room configuration"); - return new RoomConfiguration(); - } - } - - } - - public class RoomStateMessage : DeviceStateMessageBase - { - [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] - public RoomConfiguration Configuration { get; set; } - - [JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)] - public int? ActivityMode { get; set; } - [JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)] - public bool? AdvancedSharingActive { get; set; } - [JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsOn { get; set; } - [JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsWarmingUp { get; set; } - [JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsCoolingDown { get; set; } - [JsonProperty("selectedSourceKey", NullValueHandling = NullValueHandling.Ignore)] - public string SelectedSourceKey { get; set; } - [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] - public ShareState Share { get; set; } - - [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary Volumes { get; set; } - - [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsInCall { get; set; } - } - - public class ShareState - { - [JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)] - public string CurrentShareText { get; set; } - [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] - public bool? Enabled { get; set; } - [JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)] - public bool? IsSharing { get; set; } - } + private List _touchPanelTokens = new List(); + public IEssentialsRoom Room { get; private set; } + public string DefaultRoomKey { get; private set; } /// - /// Represents the capabilities of the room and the associated device info + /// /// - public class RoomConfiguration + public override string RoomName { - //[JsonProperty("shutdownPromptSeconds", NullValueHandling = NullValueHandling.Ignore)] - //public int? ShutdownPromptSeconds { get; set; } + get { return Room.Name; } + } - [JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasVideoConferencing { get; set; } - [JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)] - public bool? VideoCodecIsZoomRoom { get; set; } - [JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasAudioConferencing { get; set; } - [JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasEnvironmentalControls { get; set; } - [JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasCameraControls { get; set; } - [JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasSetTopBoxControls { get; set; } - [JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasRoutingControls { get; set; } + public override string RoomKey + { + get { return Room.Key; } + } - [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] - public List TouchpanelKeys { get; set; } + public MobileControlEssentialsRoomBridge(IEssentialsRoom room) : + this($"mobileControlBridge-{room.Key}", room.Key, room) + { + Room = room; + } - [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] - public string ZoomRoomControllerKey { get; set; } + public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device) + { + DefaultRoomKey = roomKey; - [JsonProperty("ciscoNavigatorKey", NullValueHandling = NullValueHandling.Ignore)] - public string CiscoNavigatorKey { get; set; } + AddPreActivationAction(GetRoom); + } - [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] - public string VideoCodecKey { get; set; } - [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] - public string AudioCodecKey { get; set; } - [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] - public string MatrixRoutingKey { get; set; } - [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] - public List EndpointKeys { get; set; } + protected override void RegisterActions() + { + // we add actions to the messaging system with a path, and a related action. Custom action + // content objects can be handled in the controller's LineReceived method - and perhaps other + // sub-controller parsing could be attached to these classes, so that the systemController + // doesn't need to know about everything. - [JsonProperty("accessoryDeviceKeys", NullValueHandling = NullValueHandling.Ignore)] - public List AccessoryDeviceKeys { get; set; } + this.LogInformation("Registering Actions with AppServer"); - [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] - public string DefaultDisplayKey { get; set; } - [JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary Destinations { get; set; } - [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] - public List EnvironmentalDevices { get; set; } - [JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary SourceList { get; set; } + AddAction("/promptForCode", (id, content) => OnUserPromptedForCode()); + AddAction("/clientJoined", (id, content) => OnClientJoined()); - [JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary DestinationList { get; set; } + AddAction("/touchPanels", (id, content) => OnTouchPanelsUpdated(content)); - [JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)] - public AudioControlPointListItem AudioControlPointList { get; set; } + AddAction($"/userApp", (id, content) => OnUserAppUpdated(content)); - [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary CameraList { get; set; } - - [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] - public string DefaultPresentationSourceKey { get; set; } - - - [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] - public string HelpMessage { get; set; } - - [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] - public string TechPassword { get; set; } - - [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] - public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } - - [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] - public bool? SupportsAdvancedSharing { get; set; } - [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] - public bool? UserCanChangeShareMode { get; set; } - - [JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)] - public string RoomCombinerKey { get; set; } - - public RoomConfiguration() + AddAction("/userCode", (id, content) => { - Destinations = new Dictionary(); - EnvironmentalDevices = new List(); - SourceList = new Dictionary(); - TouchpanelKeys = new List(); + var msg = content.ToObject(); + + SetUserCode(msg.UserCode, msg.QrChecksum ?? string.Empty); + }); + + + // Source Changes and room off + AddAction("/status", (id, content) => + { + SendFullStatusForClientId(id, Room); + }); + + if (Room is IRunRouteAction routeRoom) + AddAction("/source", (id, content) => + { + + var msg = content.ToObject(); + + this.LogVerbose("Received request to route to source: {sourceListKey} on list: {sourceList}", msg.SourceListItemKey, msg.SourceListKey); + + routeRoom.RunRouteAction(msg.SourceListItemKey, msg.SourceListKey); + }); + + if (Room is IRunDirectRouteAction directRouteRoom) + { + AddAction("/directRoute", (id, content) => + { + var msg = content.ToObject(); + + + this.LogVerbose("Running direct route from {sourceKey} to {destinationKey} with signal type {signalType}", msg.SourceKey, msg.DestinationKey, msg.SignalType); + + directRouteRoom.RunDirectRoute(msg.SourceKey, msg.DestinationKey, msg.SignalType); + }); + } + + + if (Room is IRunDefaultPresentRoute defaultRoom) + AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute()); + + if (Room is IHasCurrentSourceInfoChange sscRoom) + sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange; + + if (Room is IEssentialsHuddleVtc1Room vtcRoom) + { + if (vtcRoom.ScheduleSource != null) + { + var key = vtcRoom.Key + "-" + Key; + + if (!AppServerController.CheckForDeviceMessenger(key)) + { + var scheduleMessenger = new IHasScheduleAwarenessMessenger(key, vtcRoom.ScheduleSource, + $"/room/{vtcRoom.Key}"); + AppServerController.AddDeviceMessenger(scheduleMessenger); + } + } + + vtcRoom.InCallFeedback.OutputChange += InCallFeedback_OutputChange; + } + + if (Room is IPrivacy privacyRoom) + { + AddAction("/volumes/master/privacyMuteToggle", (id, content) => privacyRoom.PrivacyModeToggle()); + + privacyRoom.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; + } + + + if (Room is IRunDefaultCallRoute defCallRm) + { + AddAction("/activityVideo", (id, content) => defCallRm.RunDefaultCallRoute()); + } + + Room.OnFeedback.OutputChange += OnFeedback_OutputChange; + Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; + Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; + + AddTechRoomActions(); + + if (Room is IHasCurrentVolumeControls volumeRoom) + { + volumeRoom.CurrentVolumeDeviceChange += Room_CurrentVolumeDeviceChange; + + if (volumeRoom.CurrentVolumeControls == null) return; + + AddAction("/volumes/master/level", (id, content) => + { + var msg = content.ToObject>(); + + + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + basicVolumeWithFeedback.SetVolume(msg.Value); + }); + + AddAction("/volumes/master/muteToggle", (id, content) => volumeRoom.CurrentVolumeControls.MuteToggle()); + + AddAction("/volumes/master/muteOn", (id, content) => + { + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + basicVolumeWithFeedback.MuteOn(); + }); + + AddAction("/volumes/master/muteOff", (id, content) => + { + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + basicVolumeWithFeedback.MuteOff(); + }); + + AddAction("/volumes/master/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => + { + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + { + basicVolumeWithFeedback.VolumeUp(b); + } + } + )); + + AddAction("/volumes/master/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => + { + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) + { + basicVolumeWithFeedback.VolumeDown(b); + } + } + )); + + // Registers for initial volume events, if possible + if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback currentVolumeDevice) + { + this.LogVerbose("Registering for volume feedback events"); + + currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; + currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; + } } } - public class EnvironmentalDeviceConfiguration + private void OnTouchPanelsUpdated(JToken content) { - [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Ignore)] - public string DeviceKey { get; private set; } + var message = content.ToObject(); - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)] - public eEnvironmentalDeviceTypes DeviceType { get; private set; } + _touchPanelTokens = message.TouchPanels; - public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type) + UpdateTouchPanelAppUrls(message.UserAppUrl); + } + + private void UpdateTouchPanelAppUrls(string userAppUrl) + { + foreach (var tp in _touchPanelTokens) { - DeviceKey = key; - DeviceType = type; + var dev = DeviceManager.AllDevices.OfType().FirstOrDefault((tpc) => tpc.Key.Equals(tp.TouchpanelKey, StringComparison.InvariantCultureIgnoreCase)); + + if (dev == null) + { + continue; + } + + //UpdateAppUrl($"{userAppUrl}?token={tp.Token}"); + + dev.SetAppUrl($"{userAppUrl}?token={tp.Token}"); } } - public enum eEnvironmentalDeviceTypes + private void OnUserAppUpdated(JToken content) { - None, - Lighting, - Shade, - ShadeController, - Relay, + var message = content.ToObject(); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Updating User App URL to {userAppUrl}. Full Message: {@message}", this, message.UserAppUrl, content); + + UpdateTouchPanelAppUrls(message.UserAppUrl); } - public class ApiTouchPanelToken + private void InCallFeedback_OutputChange(object sender, FeedbackEventArgs e) { - [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] - public List TouchPanels { get; set; } = new List(); - - [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] - public string UserAppUrl { get; set; } = ""; + var state = new RoomStateMessage + { + IsInCall = e.BoolValue + }; + PostStatusMessage(state); } -#if SERIES3 - public class SourceSelectMessageContent + private void GetRoom() { - public string SourceListItem { get; set; } - public string SourceListKey { get; set; } + if (Room != null) + { + this.LogInformation("Room with key {key} already linked.", DefaultRoomKey); + return; + } + + + if (!(DeviceManager.GetDeviceForKey(DefaultRoomKey) is IEssentialsRoom tempRoom)) + { + this.LogInformation("Room with key {key} not found or is not an Essentials Room", DefaultRoomKey); + return; + } + + Room = tempRoom; } - public class DirectRoute + protected override void UserCodeChange() { - public string SourceKey { get; set; } - public string DestinationKey { get; set; } + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Server user code changed: {userCode}", this, UserCode); + + var qrUrl = string.Format("{0}/rooms/{1}/{3}/qr?x={2}", Parent?.Host, Parent?.SystemUuid, new Random().Next(), DefaultRoomKey); + + QrCodeUrl = qrUrl; + + this.LogDebug("Server user code changed: {userCode} - {qrUrl}", UserCode, qrUrl); + + OnUserCodeChanged(); + } + + /* /// + /// Override of base: calls base to add parent and then registers actions and events. + /// + /// + public override void AddParent(MobileControlSystemController parent) + { + base.AddParent(parent); + + }*/ + + private void AddTechRoomActions() + { + if (!(Room is IEssentialsTechRoom techRoom)) + { + return; + } + + AddAction("/roomPowerOn", (id, content) => techRoom.RoomPowerOn()); + AddAction("/roomPowerOff", (id, content) => techRoom.RoomPowerOff()); + } + + private void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + var state = new RoomStateMessage(); + + var volumes = new Dictionary + { + { "master", new Volume("master") + { + PrivacyMuted = e.BoolValue + } + } + }; + + state.Volumes = volumes; + + PostStatusMessage(state); } /// /// /// - /// - public delegate void PressAndHoldAction(bool b); + /// + /// + private void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + // sharing source + string shareText; + bool isSharing; + + if (Room is IHasCurrentSourceInfoChange srcInfoRoom && Room is IHasVideoCodec vcRoom && vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null) + { + shareText = srcInfoRoom.CurrentSourceInfo.PreferredName; + isSharing = true; + } + else + { + shareText = "None"; + isSharing = false; + } + + var state = new RoomStateMessage + { + Share = new ShareState + { + CurrentShareText = shareText, + IsSharing = isSharing + } + }; + + PostStatusMessage(state); + } + + /// + /// + /// + /// + /// + private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + var state = new + { + isWarmingUp = e.BoolValue + }; + + PostStatusMessage(JToken.FromObject(state)); + } + + /// + /// + /// + /// + /// + private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + var state = new + { + isCoolingDown = e.BoolValue + }; + PostStatusMessage(JToken.FromObject(state)); + } + + /// + /// + /// + /// + /// + private void OnFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + var state = new + { + isOn = e.BoolValue + }; + PostStatusMessage(JToken.FromObject(state)); + } + + private void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) + { + if (e.OldDev is IBasicVolumeWithFeedback) + { + var oldDev = e.OldDev as IBasicVolumeWithFeedback; + oldDev.MuteFeedback.OutputChange -= MuteFeedback_OutputChange; + oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange; + } + + if (e.NewDev is IBasicVolumeWithFeedback) + { + var newDev = e.NewDev as IBasicVolumeWithFeedback; + newDev.MuteFeedback.OutputChange += MuteFeedback_OutputChange; + newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; + } + } + + /// + /// Event handler for mute changes + /// + private void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + var state = new RoomStateMessage(); + + var volumes = new Dictionary + { + { "master", new Volume("master", e.BoolValue) } + }; + + state.Volumes = volumes; + + PostStatusMessage(state); + } + + /// + /// Handles Volume changes on room + /// + private void VolumeLevelFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + + var state = new + { + volumes = new Dictionary + { + { "master", new Volume("master", e.IntValue) } + } + }; + PostStatusMessage(JToken.FromObject(state)); + } + + + private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type) + { + /* Example message + * { +   "type":"/room/status", +   "content": { +     "selectedSourceKey": "off", +   } + } + */ + + } + + /// + /// Sends the full status of the room to the server + /// + /// + private void SendFullStatusForClientId(string id, IEssentialsRoom room) + { + //Parent.SendMessageObject(GetFullStatus(room)); + var message = GetFullStatusForClientId(room); + + if (message == null) + { + return; + } + PostStatusMessage(message, id); + } + + + /// + /// Gets full room status + /// + /// The room to get status of + /// The status response message + private RoomStateMessage GetFullStatusForClientId(IEssentialsRoom room) + { + try + { + this.LogVerbose("GetFullStatus"); + + var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null; + + var volumes = new Dictionary(); + if (room is IHasCurrentVolumeControls rmVc) + { + if (rmVc.CurrentVolumeControls is IBasicVolumeWithFeedback vc) + { + var volume = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, ""); + if (room is IPrivacy privacyRoom) + { + volume.HasPrivacyMute = true; + volume.PrivacyMuted = privacyRoom.PrivacyModeIsOnFeedback.BoolValue; + } + + volumes.Add("master", volume); + } + } + + var state = new RoomStateMessage + { + Configuration = GetRoomConfiguration(room), + ActivityMode = 1, + IsOn = room.OnFeedback.BoolValue, + SelectedSourceKey = sourceKey, + Volumes = volumes, + IsWarmingUp = room.IsWarmingUpFeedback.BoolValue, + IsCoolingDown = room.IsCoolingDownFeedback.BoolValue + }; + + if (room is IEssentialsHuddleVtc1Room vtcRoom) + { + state.IsInCall = vtcRoom.InCallFeedback.BoolValue; + } + + return state; + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Error getting full status", this); + return null; + } + } + + /// + /// Determines the configuration of the room and the details about the devices associated with the room + /// + /// + private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) + { + try + { + var configuration = new RoomConfiguration + { + //ShutdownPromptSeconds = room.ShutdownPromptSeconds, + TouchpanelKeys = DeviceManager.AllDevices. + OfType() + .Where((tp) => tp.DefaultRoomKey.Equals(room.Key, StringComparison.InvariantCultureIgnoreCase)) + .Select(tp => tp.Key).ToList() + }; + + try + { + var zrcTp = DeviceManager.AllDevices.OfType().SingleOrDefault((tp) => tp.ZoomRoomController); + + configuration.ZoomRoomControllerKey = zrcTp?.Key; + } + catch + { + configuration.ZoomRoomControllerKey = room.Key; + } + + if (room is IHasCiscoNavigatorTouchpanel ciscoNavRoom) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting CiscoNavigatorKey to: {ciscoNavRoom.CiscoNavigatorTouchpanelKey}", this); + configuration.CiscoNavigatorKey = ciscoNavRoom.CiscoNavigatorTouchpanelKey; + } + + + + // find the room combiner for this room by checking if the room is in the list of rooms for the room combiner + var roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); + + configuration.RoomCombinerKey = roomCombiner?.Key; + + + if (room is IEssentialsRoomPropertiesConfig propertiesConfig) + { + configuration.HelpMessage = propertiesConfig.PropertiesConfig.HelpMessageForDisplay; + } + + if (room is IEssentialsHuddleSpaceRoom huddleRoom && !string.IsNullOrEmpty(huddleRoom.PropertiesConfig.HelpMessageForDisplay)) + { + this.LogVerbose("Getting huddle room config"); + configuration.HelpMessage = huddleRoom.PropertiesConfig.HelpMessageForDisplay; + configuration.UiBehavior = huddleRoom.PropertiesConfig.UiBehavior; + configuration.DefaultPresentationSourceKey = huddleRoom.PropertiesConfig.DefaultSourceItem; + + } + + if (room is IEssentialsHuddleVtc1Room vtc1Room && !string.IsNullOrEmpty(vtc1Room.PropertiesConfig.HelpMessageForDisplay)) + { + this.LogVerbose("Getting vtc room config"); + configuration.HelpMessage = vtc1Room.PropertiesConfig.HelpMessageForDisplay; + configuration.UiBehavior = vtc1Room.PropertiesConfig.UiBehavior; + configuration.DefaultPresentationSourceKey = vtc1Room.PropertiesConfig.DefaultSourceItem; + } + + if (room is IEssentialsTechRoom techRoom && !string.IsNullOrEmpty(techRoom.PropertiesConfig.HelpMessage)) + { + this.LogVerbose("Getting tech room config"); + configuration.HelpMessage = techRoom.PropertiesConfig.HelpMessage; + } + + if (room is IHasVideoCodec vcRoom) + { + if (vcRoom.VideoCodec != null) + { + this.LogVerbose("Getting codec config"); + var type = vcRoom.VideoCodec.GetType(); + + configuration.HasVideoConferencing = true; + configuration.VideoCodecKey = vcRoom.VideoCodec.Key; + configuration.VideoCodecIsZoomRoom = type.Name.Equals("ZoomRoom", StringComparison.InvariantCultureIgnoreCase); + } + } + ; + + if (room is IHasAudioCodec acRoom) + { + if (acRoom.AudioCodec != null) + { + this.LogVerbose("Getting audio codec config"); + configuration.HasAudioConferencing = true; + configuration.AudioCodecKey = acRoom.AudioCodec.Key; + } + } + + + if (room is IHasMatrixRouting matrixRoutingRoom) + { + this.LogVerbose("Getting matrix routing config"); + configuration.MatrixRoutingKey = matrixRoutingRoom.MatrixRoutingDeviceKey; + configuration.EndpointKeys = matrixRoutingRoom.EndpointKeys; + } + + if (room is IEnvironmentalControls envRoom) + { + this.LogVerbose("Getting environmental controls config. RoomHasEnvironmentalControls: {hasEnvironmentalControls}", envRoom.HasEnvironmentalControlDevices); + configuration.HasEnvironmentalControls = envRoom.HasEnvironmentalControlDevices; + + if (envRoom.HasEnvironmentalControlDevices) + { + this.LogVerbose("Room Has {count} Environmental Control Devices.", envRoom.EnvironmentalControlDevices.Count); + + foreach (var dev in envRoom.EnvironmentalControlDevices) + { + this.LogVerbose("Adding environmental device: {key}", dev.Key); + + eEnvironmentalDeviceTypes type = eEnvironmentalDeviceTypes.None; + + if (dev is ILightingScenes) + { + type = eEnvironmentalDeviceTypes.Lighting; + } + else if (dev is ShadeBase || dev is IShadesOpenCloseStop || dev is IShadesOpenClosePreset) + { + type = eEnvironmentalDeviceTypes.Shade; + } + else if (dev is IShades) + { + type = eEnvironmentalDeviceTypes.ShadeController; + } + else if (dev is ISwitchedOutput) + { + type = eEnvironmentalDeviceTypes.Relay; + } + + this.LogVerbose("Environmental Device Type: {type}", type); + + var envDevice = new EnvironmentalDeviceConfiguration(dev.Key, type); + + configuration.EnvironmentalDevices.Add(envDevice); + } + } + else + { + this.LogVerbose("Room Has No Environmental Control Devices"); + } + } + + if (room is IHasDefaultDisplay defDisplayRoom) + { + this.LogVerbose("Getting default display config"); + configuration.DefaultDisplayKey = defDisplayRoom.DefaultDisplay.Key; + configuration.Destinations.Add(eSourceListItemDestinationTypes.defaultDisplay, defDisplayRoom.DefaultDisplay.Key); + } + + if (room is IHasMultipleDisplays multiDisplayRoom) + { + this.LogVerbose("Getting multiple display config"); + + if (multiDisplayRoom.Displays == null) + { + this.LogVerbose("Displays collection is null"); + } + else + { + this.LogVerbose("Displays collection exists"); + + configuration.Destinations = multiDisplayRoom.Displays.ToDictionary(kv => kv.Key, kv => kv.Value.Key); + } + } + + if (room is IHasAccessoryDevices accRoom) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Getting accessory devices config", this); + + if (accRoom.AccessoryDeviceKeys == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection is null", this); + } + else + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection exists", this); + + configuration.AccessoryDeviceKeys = accRoom.AccessoryDeviceKeys; + } + } + + var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); + if (sourceList != null) + { + this.LogVerbose("Getting source list config"); + configuration.SourceList = sourceList; + configuration.HasRoutingControls = true; + + foreach (var source in sourceList) + { + if (source.Value.SourceDevice is Devices.Common.IRSetTopBoxBase) + { + configuration.HasSetTopBoxControls = true; + continue; + } + else if (source.Value.SourceDevice is CameraBase) + { + configuration.HasCameraControls = true; + continue; + } + } + } + + var destinationList = ConfigReader.ConfigObject.GetDestinationListForKey(room.DestinationListKey); + + if (destinationList != null) + { + configuration.DestinationList = destinationList; + } + + var audioControlPointList = ConfigReader.ConfigObject.GetAudioControlPointListForKey(room.AudioControlPointListKey); + + if (audioControlPointList != null) + { + configuration.AudioControlPointList = audioControlPointList; + } + + var cameraList = ConfigReader.ConfigObject.GetCameraListForKey(room.CameraListKey); + + if (cameraList != null) + { + configuration.CameraList = cameraList; + } + + return configuration; + + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception getting room configuration"); + return new RoomConfiguration(); + } + } + +} + +public class RoomStateMessage : DeviceStateMessageBase +{ + [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] + public RoomConfiguration Configuration { get; set; } + + [JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)] + public int? ActivityMode { get; set; } + [JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)] + public bool? AdvancedSharingActive { get; set; } + [JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsOn { get; set; } + [JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsWarmingUp { get; set; } + [JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsCoolingDown { get; set; } + [JsonProperty("selectedSourceKey", NullValueHandling = NullValueHandling.Ignore)] + public string SelectedSourceKey { get; set; } + [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] + public ShareState Share { get; set; } + + [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary Volumes { get; set; } + + [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsInCall { get; set; } +} + +public class ShareState +{ + [JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)] + public string CurrentShareText { get; set; } + [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] + public bool? Enabled { get; set; } + [JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsSharing { get; set; } +} + +/// +/// Represents the capabilities of the room and the associated device info +/// +public class RoomConfiguration +{ + //[JsonProperty("shutdownPromptSeconds", NullValueHandling = NullValueHandling.Ignore)] + //public int? ShutdownPromptSeconds { get; set; } + + [JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasVideoConferencing { get; set; } + [JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)] + public bool? VideoCodecIsZoomRoom { get; set; } + [JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasAudioConferencing { get; set; } + [JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasEnvironmentalControls { get; set; } + [JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasCameraControls { get; set; } + [JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasSetTopBoxControls { get; set; } + [JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasRoutingControls { get; set; } + + [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] + public List TouchpanelKeys { get; set; } + + [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] + public string ZoomRoomControllerKey { get; set; } + + [JsonProperty("ciscoNavigatorKey", NullValueHandling = NullValueHandling.Ignore)] + public string CiscoNavigatorKey { get; set; } + + + [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] + public string VideoCodecKey { get; set; } + [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] + public string AudioCodecKey { get; set; } + [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] + public string MatrixRoutingKey { get; set; } + [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] + public List EndpointKeys { get; set; } + + [JsonProperty("accessoryDeviceKeys", NullValueHandling = NullValueHandling.Ignore)] + public List AccessoryDeviceKeys { get; set; } + + [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] + public string DefaultDisplayKey { get; set; } + [JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary Destinations { get; set; } + [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] + public List EnvironmentalDevices { get; set; } + [JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary SourceList { get; set; } + + [JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary DestinationList { get; set; } + + [JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)] + public AudioControlPointListItem AudioControlPointList { get; set; } + + [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary CameraList { get; set; } + + [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] + public string DefaultPresentationSourceKey { get; set; } + + + [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] + public string HelpMessage { get; set; } + + [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] + public string TechPassword { get; set; } + + [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] + public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } + + [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] + public bool? SupportsAdvancedSharing { get; set; } + [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] + public bool? UserCanChangeShareMode { get; set; } + + [JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)] + public string RoomCombinerKey { get; set; } + + public RoomConfiguration() + { + Destinations = new Dictionary(); + EnvironmentalDevices = new List(); + SourceList = new Dictionary(); + TouchpanelKeys = new List(); + } +} + +public class EnvironmentalDeviceConfiguration +{ + [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Ignore)] + public string DeviceKey { get; private set; } + + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)] + public eEnvironmentalDeviceTypes DeviceType { get; private set; } + + public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type) + { + DeviceKey = key; + DeviceType = type; + } +} + +public enum eEnvironmentalDeviceTypes +{ + None, + Lighting, + Shade, + ShadeController, + Relay, +} + +public class ApiTouchPanelToken +{ + [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] + public List TouchPanels { get; set; } = new List(); + + [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] + public string UserAppUrl { get; set; } = ""; +} + +#if SERIES3 +public class SourceSelectMessageContent +{ + public string SourceListItem { get; set; } + public string SourceListKey { get; set; } +} + +public class DirectRoute +{ + public string SourceKey { get; set; } + public string DestinationKey { get; set; } +} + +/// +/// +/// +/// +public delegate void PressAndHoldAction(bool b); #endif -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs b/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs index 262c7e07..2872dd66 100644 --- a/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs +++ b/src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs @@ -3,75 +3,74 @@ using System; using System.Net.Http; using System.Threading.Tasks; -namespace PepperDash.Essentials.Services +namespace PepperDash.Essentials.Services; + + +public class MobileControlApiService { + private readonly HttpClient _client; - public class MobileControlApiService + public MobileControlApiService(string apiUrl) { - private readonly HttpClient _client; - - public MobileControlApiService(string apiUrl) + var handler = new HttpClientHandler { - var handler = new HttpClientHandler + AllowAutoRedirect = false, + ServerCertificateCustomValidationCallback = (req, cert, certChain, errors) => true + }; + + _client = new HttpClient(handler); + } + + public async Task SendAuthorizationRequest(string apiUrl, string grantCode, string systemUuid) + { + try + { + var request = new HttpRequestMessage(HttpMethod.Get, $"{apiUrl}/system/{systemUuid}/authorize?grantCode={grantCode}"); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Sending authorization request to {host}", null, request.RequestUri); + + var response = await _client.SendAsync(request); + + var authResponse = new AuthorizationResponse { - AllowAutoRedirect = false, - ServerCertificateCustomValidationCallback = (req, cert, certChain, errors) => true + Authorized = response.StatusCode == System.Net.HttpStatusCode.OK }; - _client = new HttpClient(handler); - } - - public async Task SendAuthorizationRequest(string apiUrl, string grantCode, string systemUuid) - { - try + if (authResponse.Authorized) { - var request = new HttpRequestMessage(HttpMethod.Get, $"{apiUrl}/system/{systemUuid}/authorize?grantCode={grantCode}"); + return authResponse; + } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Sending authorization request to {host}", null, request.RequestUri); + if (response.StatusCode == System.Net.HttpStatusCode.Moved) + { + var location = response.Headers.Location; - var response = await _client.SendAsync(request); - - var authResponse = new AuthorizationResponse - { - Authorized = response.StatusCode == System.Net.HttpStatusCode.OK - }; - - if (authResponse.Authorized) - { - return authResponse; - } - - if (response.StatusCode == System.Net.HttpStatusCode.Moved) - { - var location = response.Headers.Location; - - authResponse.Reason = $"ERROR: Mobile Control API has moved. Please adjust configuration to \"{location}\""; - - return authResponse; - } - - var responseString = await response.Content.ReadAsStringAsync(); - - switch (responseString) - { - case "codeNotFound": - authResponse.Reason = $"Authorization failed. Code not found for system UUID {systemUuid}"; - break; - case "uuidNotFound": - authResponse.Reason = $"Authorization failed. System UUID {systemUuid} not found. Check Essentials configuration."; - break; - default: - authResponse.Reason = $"Authorization failed. Response {response.StatusCode}: {responseString}"; - break; - } + authResponse.Reason = $"ERROR: Mobile Control API has moved. Please adjust configuration to \"{location}\""; return authResponse; } - catch (Exception ex) + + var responseString = await response.Content.ReadAsStringAsync(); + + switch (responseString) { - Debug.LogMessage(ex, "Error authorizing with Mobile Control"); - return new AuthorizationResponse { Authorized = false, Reason = ex.Message }; + case "codeNotFound": + authResponse.Reason = $"Authorization failed. Code not found for system UUID {systemUuid}"; + break; + case "uuidNotFound": + authResponse.Reason = $"Authorization failed. System UUID {systemUuid} not found. Check Essentials configuration."; + break; + default: + authResponse.Reason = $"Authorization failed. Response {response.StatusCode}: {responseString}"; + break; } + + return authResponse; + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Error authorizing with Mobile Control"); + return new AuthorizationResponse { Authorized = false, Reason = ex.Message }; } } } diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs index 7dc4ae16..918ae2f2 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs @@ -1,11 +1,10 @@ using PepperDash.Core; -namespace PepperDash.Essentials.Touchpanel -{ - public interface ITheme : IKeyed - { - string Theme { get; } +namespace PepperDash.Essentials.Touchpanel; - void UpdateTheme(string theme); - } +public interface ITheme : IKeyed +{ + string Theme { get; } + + void UpdateTheme(string theme); } diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs index 814b51c6..886ac6bb 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs @@ -1,25 +1,24 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +public interface ITswAppControl : IKeyed { - public interface ITswAppControl : IKeyed - { - BoolFeedback AppOpenFeedback { get; } + BoolFeedback AppOpenFeedback { get; } - void HideOpenApp(); + void HideOpenApp(); - void CloseOpenApp(); + void CloseOpenApp(); - void OpenApp(); - } - - public interface ITswZoomControl : IKeyed - { - BoolFeedback ZoomIncomingCallFeedback { get; } - - BoolFeedback ZoomInCallFeedback { get; } - - void EndZoomCall(); - } + void OpenApp(); +} + +public interface ITswZoomControl : IKeyed +{ + BoolFeedback ZoomIncomingCallFeedback { get; } + + BoolFeedback ZoomInCallFeedback { get; } + + void EndZoomCall(); } diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs index 19e04775..c2f39767 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs @@ -4,56 +4,55 @@ using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +public class ITswAppControlMessenger : MessengerBase { - public class ITswAppControlMessenger : MessengerBase + private readonly ITswAppControl _appControl; + + public ITswAppControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) { - private readonly ITswAppControl _appControl; - - public ITswAppControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) - { - _appControl = device as ITswAppControl; - } - - protected override void RegisterActions() - { - if (_appControl == null) - { - this.LogInformation("{deviceKey} does not implement ITswAppControl", _device.Key); - return; - } - - AddAction($"/fullStatus", (id, context) => SendFullStatus()); - - AddAction($"/openApp", (id, context) => _appControl.OpenApp()); - - AddAction($"/closeApp", (id, context) => _appControl.CloseOpenApp()); - - AddAction($"/hideApp", (id, context) => _appControl.HideOpenApp()); - - _appControl.AppOpenFeedback.OutputChange += (s, a) => - { - PostStatusMessage(JToken.FromObject(new - { - appOpen = a.BoolValue - })); - }; - } - - private void SendFullStatus() - { - var message = new TswAppStateMessage - { - AppOpen = _appControl.AppOpenFeedback.BoolValue, - }; - - PostStatusMessage(message); - } + _appControl = device as ITswAppControl; } - public class TswAppStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)] - public bool? AppOpen { get; set; } + if (_appControl == null) + { + this.LogInformation("{deviceKey} does not implement ITswAppControl", _device.Key); + return; + } + + AddAction($"/fullStatus", (id, context) => SendFullStatus()); + + AddAction($"/openApp", (id, context) => _appControl.OpenApp()); + + AddAction($"/closeApp", (id, context) => _appControl.CloseOpenApp()); + + AddAction($"/hideApp", (id, context) => _appControl.HideOpenApp()); + + _appControl.AppOpenFeedback.OutputChange += (s, a) => + { + PostStatusMessage(JToken.FromObject(new + { + appOpen = a.BoolValue + })); + }; + } + + private void SendFullStatus() + { + var message = new TswAppStateMessage + { + AppOpen = _appControl.AppOpenFeedback.BoolValue, + }; + + PostStatusMessage(message); } } + +public class TswAppStateMessage : DeviceStateMessageBase +{ + [JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)] + public bool? AppOpen { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs index cbd4f6a2..da62a198 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs @@ -5,69 +5,68 @@ using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +public class ITswZoomControlMessenger : MessengerBase { - public class ITswZoomControlMessenger : MessengerBase + private readonly ITswZoomControl _zoomControl; + + public ITswZoomControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) { - private readonly ITswZoomControl _zoomControl; - - public ITswZoomControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) - { - _zoomControl = device as ITswZoomControl; - } - - protected override void RegisterActions() - { - if (_zoomControl == null) - { - this.LogInformation("{deviceKey} does not implement ITswZoomControl", _device.Key); - return; - } - - AddAction($"/fullStatus", (id, context) => SendFullStatus()); - - - AddAction($"/endCall", (id, context) => _zoomControl.EndZoomCall()); - - _zoomControl.ZoomIncomingCallFeedback.OutputChange += (s, a) => - { - PostStatusMessage(JToken.FromObject(new - { - incomingCall = a.BoolValue, - inCall = _zoomControl.ZoomInCallFeedback.BoolValue - })); - }; - - - _zoomControl.ZoomInCallFeedback.OutputChange += (s, a) => - { - PostStatusMessage(JToken.FromObject( - new - { - inCall = a.BoolValue, - incomingCall = _zoomControl.ZoomIncomingCallFeedback.BoolValue - })); - }; - } - - private void SendFullStatus() - { - var message = new TswZoomStateMessage - { - InCall = _zoomControl?.ZoomInCallFeedback.BoolValue, - IncomingCall = _zoomControl?.ZoomIncomingCallFeedback.BoolValue - }; - - PostStatusMessage(message); - } + _zoomControl = device as ITswZoomControl; } - public class TswZoomStateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("inCall", NullValueHandling = NullValueHandling.Ignore)] - public bool? InCall { get; set; } + if (_zoomControl == null) + { + this.LogInformation("{deviceKey} does not implement ITswZoomControl", _device.Key); + return; + } - [JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)] - public bool? IncomingCall { get; set; } + AddAction($"/fullStatus", (id, context) => SendFullStatus()); + + + AddAction($"/endCall", (id, context) => _zoomControl.EndZoomCall()); + + _zoomControl.ZoomIncomingCallFeedback.OutputChange += (s, a) => + { + PostStatusMessage(JToken.FromObject(new + { + incomingCall = a.BoolValue, + inCall = _zoomControl.ZoomInCallFeedback.BoolValue + })); + }; + + + _zoomControl.ZoomInCallFeedback.OutputChange += (s, a) => + { + PostStatusMessage(JToken.FromObject( + new + { + inCall = a.BoolValue, + incomingCall = _zoomControl.ZoomIncomingCallFeedback.BoolValue + })); + }; + } + + private void SendFullStatus() + { + var message = new TswZoomStateMessage + { + InCall = _zoomControl?.ZoomInCallFeedback.BoolValue, + IncomingCall = _zoomControl?.ZoomIncomingCallFeedback.BoolValue + }; + + PostStatusMessage(message); } } + +public class TswZoomStateMessage : DeviceStateMessageBase +{ + [JsonProperty("inCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? InCall { get; set; } + + [JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)] + public bool? IncomingCall { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 9acd04f4..1f36b1ed 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -15,560 +15,559 @@ using System.Collections.Generic; using System.Linq; using Feedback = PepperDash.Essentials.Core.Feedback; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +//public interface IMobileControlTouchpanelController +//{ +// StringFeedback AppUrlFeedback { get; } +// string DefaultRoomKey { get; } +// string DeviceKey { get; } +//} + + +public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlTouchpanelController, ITheme { - //public interface IMobileControlTouchpanelController - //{ - // StringFeedback AppUrlFeedback { get; } - // string DefaultRoomKey { get; } - // string DeviceKey { get; } - //} + private readonly MobileControlTouchpanelProperties localConfig; + private IMobileControlRoomMessenger _bridge; + + private string _appUrl; + + public StringFeedback AppUrlFeedback { get; private set; } + private readonly StringFeedback QrCodeUrlFeedback; + private readonly StringFeedback McServerUrlFeedback; + private readonly StringFeedback UserCodeFeedback; + + private readonly BoolFeedback _appOpenFeedback; + + public BoolFeedback AppOpenFeedback => _appOpenFeedback; + + private readonly BoolFeedback _zoomIncomingCallFeedback; + + public BoolFeedback ZoomIncomingCallFeedback => _zoomIncomingCallFeedback; + + private readonly BoolFeedback _zoomInCallFeedback; + + public event DeviceInfoChangeHandler DeviceInfoChanged; + + public BoolFeedback ZoomInCallFeedback => _zoomInCallFeedback; - public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlTouchpanelController, ITheme + public FeedbackCollection Feedbacks { get; private set; } + + public FeedbackCollection ZoomFeedbacks { get; private set; } + + public string DefaultRoomKey => _config.DefaultRoomKey; + + public bool UseDirectServer => localConfig.UseDirectServer; + + public bool ZoomRoomController => localConfig.ZoomRoomController; + + public string Theme => localConfig.Theme; + + public StringFeedback ThemeFeedback { get; private set; } + + public DeviceInfo DeviceInfo => new DeviceInfo(); + + public MobileControlTouchpanelController(string key, string name, BasicTriListWithSmartObject panel, MobileControlTouchpanelProperties config) : base(key, name, panel, config) { - private readonly MobileControlTouchpanelProperties localConfig; - private IMobileControlRoomMessenger _bridge; + localConfig = config; - private string _appUrl; + AddPostActivationAction(SubscribeForMobileControlUpdates); - public StringFeedback AppUrlFeedback { get; private set; } - private readonly StringFeedback QrCodeUrlFeedback; - private readonly StringFeedback McServerUrlFeedback; - private readonly StringFeedback UserCodeFeedback; + ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme); + AppUrlFeedback = new StringFeedback($"{Key}-appUrl", () => _appUrl); + QrCodeUrlFeedback = new StringFeedback($"{Key}-qrCodeUrl", () => _bridge?.QrCodeUrl); + McServerUrlFeedback = new StringFeedback($"{Key}-mcServerUrl", () => _bridge?.McServerUrl); + UserCodeFeedback = new StringFeedback($"{Key}-userCode", () => _bridge?.UserCode); - private readonly BoolFeedback _appOpenFeedback; - - public BoolFeedback AppOpenFeedback => _appOpenFeedback; - - private readonly BoolFeedback _zoomIncomingCallFeedback; - - public BoolFeedback ZoomIncomingCallFeedback => _zoomIncomingCallFeedback; - - private readonly BoolFeedback _zoomInCallFeedback; - - public event DeviceInfoChangeHandler DeviceInfoChanged; - - public BoolFeedback ZoomInCallFeedback => _zoomInCallFeedback; - - - public FeedbackCollection Feedbacks { get; private set; } - - public FeedbackCollection ZoomFeedbacks { get; private set; } - - public string DefaultRoomKey => _config.DefaultRoomKey; - - public bool UseDirectServer => localConfig.UseDirectServer; - - public bool ZoomRoomController => localConfig.ZoomRoomController; - - public string Theme => localConfig.Theme; - - public StringFeedback ThemeFeedback { get; private set; } - - public DeviceInfo DeviceInfo => new DeviceInfo(); - - public MobileControlTouchpanelController(string key, string name, BasicTriListWithSmartObject panel, MobileControlTouchpanelProperties config) : base(key, name, panel, config) + _appOpenFeedback = new BoolFeedback($"{Key}-appOpen", () => { - localConfig = config; - - AddPostActivationAction(SubscribeForMobileControlUpdates); - - ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme); - AppUrlFeedback = new StringFeedback($"{Key}-appUrl", () => _appUrl); - QrCodeUrlFeedback = new StringFeedback($"{Key}-qrCodeUrl", () => _bridge?.QrCodeUrl); - McServerUrlFeedback = new StringFeedback($"{Key}-mcServerUrl", () => _bridge?.McServerUrl); - UserCodeFeedback = new StringFeedback($"{Key}-userCode", () => _bridge?.UserCode); - - _appOpenFeedback = new BoolFeedback($"{Key}-appOpen", () => + if (Panel is TswX60BaseClass tsX60) { - if (Panel is TswX60BaseClass tsX60) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"x60 sending {tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue}"); - return !tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue; - } + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"x60 sending {tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue}"); + return !tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue; + } - if (Panel is TswX70Base tsX70) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"x70 sending {tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue}"); - return !tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue; - } - - return false; - }); - - _zoomIncomingCallFeedback = new BoolFeedback($"{Key}-zoomIncomingCall", () => + if (Panel is TswX70Base tsX70) { - if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) - { - return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; - } + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"x70 sending {tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue}"); + return !tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue; + } - if (Panel is TswX70Base tsX70) - { - return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; - } + return false; + }); - return false; - }); - - _zoomInCallFeedback = new BoolFeedback($"{Key}-zoomInCall", () => + _zoomIncomingCallFeedback = new BoolFeedback($"{Key}-zoomIncomingCall", () => + { + if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) { - if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) - { - return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; - } + return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; + } - if (Panel is TswX70Base tsX70) - { - return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; - } - - return false; - }); - - Feedbacks = new FeedbackCollection + if (Panel is TswX70Base tsX70) { - AppUrlFeedback, QrCodeUrlFeedback, McServerUrlFeedback, UserCodeFeedback + return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; + } + + return false; + }); + + _zoomInCallFeedback = new BoolFeedback($"{Key}-zoomInCall", () => + { + if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) + { + return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; + } + + if (Panel is TswX70Base tsX70) + { + return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; + } + + return false; + }); + + Feedbacks = new FeedbackCollection + { + AppUrlFeedback, QrCodeUrlFeedback, McServerUrlFeedback, UserCodeFeedback + }; + + ZoomFeedbacks = new FeedbackCollection { + AppOpenFeedback, _zoomInCallFeedback, _zoomIncomingCallFeedback + }; + + RegisterForExtenders(); + } + + public void UpdateTheme(string theme) + { + localConfig.Theme = theme; + + var props = JToken.FromObject(localConfig); + + var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault((d) => d.Key == Key); + + if (deviceConfig == null) { return; } + + deviceConfig.Properties = props; + + ConfigWriter.UpdateDeviceConfig(deviceConfig); + } + + private void RegisterForExtenders() + { + if (Panel is TswXX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + + UpdateZoomFeedbacks(); + + if (!x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue) + { + x70Panel.ExtenderButtonToolbarReservedSigs.ShowButtonToolbar(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button2On(); + } + else + { + x70Panel.ExtenderButtonToolbarReservedSigs.HideButtonToolbar(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button2Off(); + } }; - ZoomFeedbacks = new FeedbackCollection { - AppOpenFeedback, _zoomInCallFeedback, _zoomIncomingCallFeedback + + x70Panel.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 Zoom Room Ap Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + + if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) + { + ZoomIncomingCallFeedback.FireUpdate(); + } + else if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.Number) + { + ZoomInCallFeedback.FireUpdate(); + } }; - RegisterForExtenders(); + + x70Panel.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => + { + DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + + var handler = DeviceInfoChanged; + + if (handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + }; + + x70Panel.ExtenderApplicationControlReservedSigs.Use(); + x70Panel.ExtenderZoomRoomAppReservedSigs.Use(); + x70Panel.ExtenderEthernetReservedSigs.Use(); + x70Panel.ExtenderButtonToolbarReservedSigs.Use(); + + x70Panel.ExtenderButtonToolbarReservedSigs.Button1Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button3Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button4Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button5Off(); + x70Panel.ExtenderButtonToolbarReservedSigs.Button6Off(); + + return; } - public void UpdateTheme(string theme) + if (Panel is TswX60WithZoomRoomAppReservedSigs x60withZoomApp) { - localConfig.Theme = theme; + x60withZoomApp.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); - var props = JToken.FromObject(localConfig); + if (a.Sig.Number == x60withZoomApp.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.Number) + { + AppOpenFeedback.FireUpdate(); + } + }; + x60withZoomApp.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 Zoom Room App Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault((d) => d.Key == Key); + if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) + { + ZoomIncomingCallFeedback.FireUpdate(); + } + else if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.Number) + { + ZoomInCallFeedback.FireUpdate(); + } + }; - if (deviceConfig == null) { return; } + x60withZoomApp.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => + { + DeviceInfo.MacAddress = x60withZoomApp.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x60withZoomApp.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - deviceConfig.Properties = props; + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); - ConfigWriter.UpdateDeviceConfig(deviceConfig); + var handler = DeviceInfoChanged; + + if (handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + }; + + x60withZoomApp.ExtenderZoomRoomAppReservedSigs.Use(); + x60withZoomApp.ExtenderApplicationControlReservedSigs.Use(); + x60withZoomApp.ExtenderEthernetReservedSigs.Use(); + } + } + + public override bool CustomActivate() + { + var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); + + var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this); + + var themeMessenger = new ThemeMessenger($"themeMessenger-{Key}", $"/device/{Key}", this); + + var mc = DeviceManager.AllDevices.OfType().FirstOrDefault(); + + if (mc == null) + { + return base.CustomActivate(); } - private void RegisterForExtenders() + if (!(Panel is TswXX70Base) && !(Panel is TswX60WithZoomRoomAppReservedSigs)) { - if (Panel is TswXX70Base x70Panel) - { - x70Panel.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); - - UpdateZoomFeedbacks(); - - if (!x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue) - { - x70Panel.ExtenderButtonToolbarReservedSigs.ShowButtonToolbar(); - x70Panel.ExtenderButtonToolbarReservedSigs.Button2On(); - } - else - { - x70Panel.ExtenderButtonToolbarReservedSigs.HideButtonToolbar(); - x70Panel.ExtenderButtonToolbarReservedSigs.Button2Off(); - } - }; - - - x70Panel.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 Zoom Room Ap Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); - - if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) - { - ZoomIncomingCallFeedback.FireUpdate(); - } - else if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.Number) - { - ZoomInCallFeedback.FireUpdate(); - } - }; - - - x70Panel.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => - { - DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; - DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); - - var handler = DeviceInfoChanged; - - if (handler == null) - { - return; - } - - handler(this, new DeviceInfoEventArgs(DeviceInfo)); - }; - - x70Panel.ExtenderApplicationControlReservedSigs.Use(); - x70Panel.ExtenderZoomRoomAppReservedSigs.Use(); - x70Panel.ExtenderEthernetReservedSigs.Use(); - x70Panel.ExtenderButtonToolbarReservedSigs.Use(); - - x70Panel.ExtenderButtonToolbarReservedSigs.Button1Off(); - x70Panel.ExtenderButtonToolbarReservedSigs.Button3Off(); - x70Panel.ExtenderButtonToolbarReservedSigs.Button4Off(); - x70Panel.ExtenderButtonToolbarReservedSigs.Button5Off(); - x70Panel.ExtenderButtonToolbarReservedSigs.Button6Off(); - - return; - } - - if (Panel is TswX60WithZoomRoomAppReservedSigs x60withZoomApp) - { - x60withZoomApp.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); - - if (a.Sig.Number == x60withZoomApp.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.Number) - { - AppOpenFeedback.FireUpdate(); - } - }; - x60withZoomApp.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 Zoom Room App Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); - - if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) - { - ZoomIncomingCallFeedback.FireUpdate(); - } - else if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.Number) - { - ZoomInCallFeedback.FireUpdate(); - } - }; - - x60withZoomApp.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => - { - DeviceInfo.MacAddress = x60withZoomApp.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; - DeviceInfo.IpAddress = x60withZoomApp.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); - - var handler = DeviceInfoChanged; - - if (handler == null) - { - return; - } - - handler(this, new DeviceInfoEventArgs(DeviceInfo)); - }; - - x60withZoomApp.ExtenderZoomRoomAppReservedSigs.Use(); - x60withZoomApp.ExtenderApplicationControlReservedSigs.Use(); - x60withZoomApp.ExtenderEthernetReservedSigs.Use(); - } - } - - public override bool CustomActivate() - { - var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); - - var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this); - - var themeMessenger = new ThemeMessenger($"themeMessenger-{Key}", $"/device/{Key}", this); - - var mc = DeviceManager.AllDevices.OfType().FirstOrDefault(); - - if (mc == null) - { - return base.CustomActivate(); - } - - if (!(Panel is TswXX70Base) && !(Panel is TswX60WithZoomRoomAppReservedSigs)) - { - mc.AddDeviceMessenger(themeMessenger); - - return base.CustomActivate(); - } - - mc.AddDeviceMessenger(appMessenger); - mc.AddDeviceMessenger(zoomMessenger); mc.AddDeviceMessenger(themeMessenger); return base.CustomActivate(); } + mc.AddDeviceMessenger(appMessenger); + mc.AddDeviceMessenger(zoomMessenger); + mc.AddDeviceMessenger(themeMessenger); - protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"System Device Extender args: ${args.Event}:${args.Sig}"); - } + return base.CustomActivate(); + } - protected override void SetupPanelDrivers(string roomKey) - { - AppUrlFeedback.LinkInputSig(Panel.StringInput[1]); - QrCodeUrlFeedback.LinkInputSig(Panel.StringInput[2]); - McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]); - UserCodeFeedback.LinkInputSig(Panel.StringInput[4]); - Panel.OnlineStatusChange += (sender, args) => - { - UpdateFeedbacks(); + protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"System Device Extender args: ${args.Event}:${args.Sig}"); + } - this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue); + protected override void SetupPanelDrivers(string roomKey) + { + AppUrlFeedback.LinkInputSig(Panel.StringInput[1]); + QrCodeUrlFeedback.LinkInputSig(Panel.StringInput[2]); + McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]); + UserCodeFeedback.LinkInputSig(Panel.StringInput[4]); - Panel.StringInput[1].StringValue = AppUrlFeedback.StringValue; - Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue; - Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue; - Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue; - }; - } - - private void SubscribeForMobileControlUpdates() - { - foreach (var dev in DeviceManager.AllDevices) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"{dev.Key}:{dev.GetType().Name}"); - } - - var mcList = DeviceManager.AllDevices.OfType().ToList(); - - if (mcList.Count == 0) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control controller found"); - - return; - } - - // use first in list, since there should only be one. - var mc = mcList[0]; - - var bridge = mc.GetRoomBridge(_config.DefaultRoomKey); - - if (bridge == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control bridge for {_config.DefaultRoomKey} found "); - return; - } - - _bridge = bridge; - - _bridge.UserCodeChanged += UpdateFeedbacks; - _bridge.AppUrlChanged += (s, a) => - { - this.LogInformation("AppURL changed"); - SetAppUrl(_bridge.AppUrl); - UpdateFeedbacks(s, a); - }; - - SetAppUrl(_bridge.AppUrl); - } - - public void SetAppUrl(string url) - { - _appUrl = url; - AppUrlFeedback.FireUpdate(); - } - - private void UpdateFeedbacks(object sender, EventArgs args) + Panel.OnlineStatusChange += (sender, args) => { UpdateFeedbacks(); + + this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue); + + Panel.StringInput[1].StringValue = AppUrlFeedback.StringValue; + Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue; + Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue; + Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue; + }; + } + + private void SubscribeForMobileControlUpdates() + { + foreach (var dev in DeviceManager.AllDevices) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"{dev.Key}:{dev.GetType().Name}"); } - private void UpdateFeedbacks() + var mcList = DeviceManager.AllDevices.OfType().ToList(); + + if (mcList.Count == 0) { - foreach (var feedback in Feedbacks) { this.LogDebug("Updating {feedbackKey}", feedback.Key); feedback.FireUpdate(); } + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control controller found"); + + return; } - private void UpdateZoomFeedbacks() + // use first in list, since there should only be one. + var mc = mcList[0]; + + var bridge = mc.GetRoomBridge(_config.DefaultRoomKey); + + if (bridge == null) { - foreach (var feedback in ZoomFeedbacks) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"Updating {feedback.Key}"); - feedback.FireUpdate(); - } + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control bridge for {_config.DefaultRoomKey} found "); + return; } - public void HideOpenApp() + _bridge = bridge; + + _bridge.UserCodeChanged += UpdateFeedbacks; + _bridge.AppUrlChanged += (s, a) => { - if (Panel is TswX70Base x70Panel) - { - x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplication(); - return; - } + this.LogInformation("AppURL changed"); + SetAppUrl(_bridge.AppUrl); + UpdateFeedbacks(s, a); + }; - if (Panel is TswX60BaseClass x60Panel) - { - x60Panel.ExtenderApplicationControlReservedSigs.HideOpenApplication(); - return; - } - } + SetAppUrl(_bridge.AppUrl); + } - public void OpenApp() + public void SetAppUrl(string url) + { + _appUrl = url; + AppUrlFeedback.FireUpdate(); + } + + private void UpdateFeedbacks(object sender, EventArgs args) + { + UpdateFeedbacks(); + } + + private void UpdateFeedbacks() + { + foreach (var feedback in Feedbacks) { this.LogDebug("Updating {feedbackKey}", feedback.Key); feedback.FireUpdate(); } + } + + private void UpdateZoomFeedbacks() + { + foreach (var feedback in ZoomFeedbacks) { - if (Panel is TswX70Base x70Panel) - { - x70Panel.ExtenderApplicationControlReservedSigs.OpenApplication(); - return; - } - - if (Panel is TswX60WithZoomRoomAppReservedSigs) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"X60 panel does not support zoom app"); - return; - } - } - - public void CloseOpenApp() - { - if (Panel is TswX70Base x70Panel) - { - x70Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); - return; - } - - if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) - { - x60Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); - return; - } - } - - public void EndZoomCall() - { - if (Panel is TswX70Base x70Panel) - { - x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); - return; - } - - if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) - { - x60Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); - return; - } - } - - public void UpdateDeviceInfo() - { - if (Panel is TswXX70Base x70Panel) - { - DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; - DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - - var handler = DeviceInfoChanged; - - if (handler == null) - { - return; - } - - handler(this, new DeviceInfoEventArgs(DeviceInfo)); - } - - if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) - { - DeviceInfo.MacAddress = x60Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; - DeviceInfo.IpAddress = x60Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - - var handler = DeviceInfoChanged; - - if (handler == null) - { - return; - } - - handler(this, new DeviceInfoEventArgs(DeviceInfo)); - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"Updating {feedback.Key}"); + feedback.FireUpdate(); } } - public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory + public void HideOpenApp() { - public MobileControlTouchpanelControllerFactory() + if (Panel is TswX70Base x70Panel) { - TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; - MinimumEssentialsFrameworkVersion = "2.0.0"; + x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplication(); + return; } - public override EssentialsDevice BuildDevice(DeviceConfig dc) + if (Panel is TswX60BaseClass x60Panel) { - var comm = CommFactory.GetControlPropertiesConfig(dc); - var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + x60Panel.ExtenderApplicationControlReservedSigs.HideOpenApplication(); + return; + } + } - var panel = GetPanelForType(dc.Type, comm.IpIdInt, props.ProjectName); - - if (panel == null) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Unable to create Touchpanel for type {0}. Touchpanel Controller WILL NOT function correctly", dc.Type); - } - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Factory Attempting to create new MobileControlTouchpanelController"); - - var panelController = new MobileControlTouchpanelController(dc.Key, dc.Name, panel, props); - - return panelController; + public void OpenApp() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.OpenApplication(); + return; } - private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName) + if (Panel is TswX60WithZoomRoomAppReservedSigs) { - type = type.ToLower().Replace("mc", ""); - try - { - if (type == "crestronapp") - { - var app = new CrestronApp(id, Global.ControlSystem); - app.ParameterProjectName.Value = projectName; - return app; - } - else if (type == "xpanel") - return new XpanelForHtml5(id, Global.ControlSystem); - else if (type == "tsw550") - return new Tsw550(id, Global.ControlSystem); - else if (type == "tsw552") - return new Tsw552(id, Global.ControlSystem); - else if (type == "tsw560") - return new Tsw560(id, Global.ControlSystem); - else if (type == "tsw750") - return new Tsw750(id, Global.ControlSystem); - else if (type == "tsw752") - return new Tsw752(id, Global.ControlSystem); - else if (type == "tsw760") - return new Tsw760(id, Global.ControlSystem); - else if (type == "tsw1050") - return new Tsw1050(id, Global.ControlSystem); - else if (type == "tsw1052") - return new Tsw1052(id, Global.ControlSystem); - else if (type == "tsw1060") - return new Tsw1060(id, Global.ControlSystem); - else if (type == "tsw570") - return new Tsw570(id, Global.ControlSystem); - else if (type == "tsw770") - return new Tsw770(id, Global.ControlSystem); - else if (type == "ts770") - return new Ts770(id, Global.ControlSystem); - else if (type == "tsw1070") - return new Tsw1070(id, Global.ControlSystem); - else if (type == "ts1070") - return new Ts1070(id, Global.ControlSystem); - else if (type == "dge1000") - return new Dge1000(id, Global.ControlSystem); - else + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"X60 panel does not support zoom app"); + return; + } + } - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW controller with type '{0}'", type); - return null; - } - } - catch (Exception e) + public void CloseOpenApp() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); + return; + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) + { + x60Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); + return; + } + } + + public void EndZoomCall() + { + if (Panel is TswX70Base x70Panel) + { + x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); + return; + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) + { + x60Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); + return; + } + } + + public void UpdateDeviceInfo() + { + if (Panel is TswXX70Base x70Panel) + { + DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + var handler = DeviceInfoChanged; + + if (handler == null) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message); + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + } + + if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) + { + DeviceInfo.MacAddress = x60Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; + DeviceInfo.IpAddress = x60Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; + + var handler = DeviceInfoChanged; + + if (handler == null) + { + return; + } + + handler(this, new DeviceInfoEventArgs(DeviceInfo)); + } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + } +} + +public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory +{ + public MobileControlTouchpanelControllerFactory() + { + TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; + MinimumEssentialsFrameworkVersion = "2.0.0"; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + var comm = CommFactory.GetControlPropertiesConfig(dc); + var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); + + var panel = GetPanelForType(dc.Type, comm.IpIdInt, props.ProjectName); + + if (panel == null) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Unable to create Touchpanel for type {0}. Touchpanel Controller WILL NOT function correctly", dc.Type); + } + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Factory Attempting to create new MobileControlTouchpanelController"); + + var panelController = new MobileControlTouchpanelController(dc.Key, dc.Name, panel, props); + + return panelController; + } + + private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName) + { + type = type.ToLower().Replace("mc", ""); + try + { + if (type == "crestronapp") + { + var app = new CrestronApp(id, Global.ControlSystem); + app.ParameterProjectName.Value = projectName; + return app; + } + else if (type == "xpanel") + return new XpanelForHtml5(id, Global.ControlSystem); + else if (type == "tsw550") + return new Tsw550(id, Global.ControlSystem); + else if (type == "tsw552") + return new Tsw552(id, Global.ControlSystem); + else if (type == "tsw560") + return new Tsw560(id, Global.ControlSystem); + else if (type == "tsw750") + return new Tsw750(id, Global.ControlSystem); + else if (type == "tsw752") + return new Tsw752(id, Global.ControlSystem); + else if (type == "tsw760") + return new Tsw760(id, Global.ControlSystem); + else if (type == "tsw1050") + return new Tsw1050(id, Global.ControlSystem); + else if (type == "tsw1052") + return new Tsw1052(id, Global.ControlSystem); + else if (type == "tsw1060") + return new Tsw1060(id, Global.ControlSystem); + else if (type == "tsw570") + return new Tsw570(id, Global.ControlSystem); + else if (type == "tsw770") + return new Tsw770(id, Global.ControlSystem); + else if (type == "ts770") + return new Ts770(id, Global.ControlSystem); + else if (type == "tsw1070") + return new Tsw1070(id, Global.ControlSystem); + else if (type == "ts1070") + return new Ts1070(id, Global.ControlSystem); + else if (type == "dge1000") + return new Dge1000(id, Global.ControlSystem); + else + + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW controller with type '{0}'", type); return null; } } + catch (Exception e) + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message); + return null; + } } } diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs index 87f6d9a9..4c12ebf2 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs @@ -1,20 +1,19 @@ using Newtonsoft.Json; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig { - public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig - { - [JsonProperty("useDirectServer")] - public bool UseDirectServer { get; set; } = false; + [JsonProperty("useDirectServer")] + public bool UseDirectServer { get; set; } = false; - [JsonProperty("zoomRoomController")] - public bool ZoomRoomController { get; set; } = false; + [JsonProperty("zoomRoomController")] + public bool ZoomRoomController { get; set; } = false; - [JsonProperty("buttonToolbarTimeoutInS")] - public ushort ButtonToolbarTimoutInS { get; set; } = 0; + [JsonProperty("buttonToolbarTimeoutInS")] + public ushort ButtonToolbarTimoutInS { get; set; } = 0; - [JsonProperty("theme")] - public string Theme { get; set; } = "light"; - } + [JsonProperty("theme")] + public string Theme { get; set; } = "light"; } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs index ab48b60a..57f23cb9 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs @@ -4,39 +4,38 @@ using PepperDash.Core; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; -namespace PepperDash.Essentials.Touchpanel +namespace PepperDash.Essentials.Touchpanel; + +public class ThemeMessenger : MessengerBase { - public class ThemeMessenger : MessengerBase + private readonly ITheme _tpDevice; + + public ThemeMessenger(string key, string path, ITheme device) : base(key, path, device as Device) { - private readonly ITheme _tpDevice; - - public ThemeMessenger(string key, string path, ITheme device) : base(key, path, device as Device) - { - _tpDevice = device; - } - - protected override void RegisterActions() - { - AddAction("/fullStatus", (id, content) => - { - PostStatusMessage(new ThemeUpdateMessage { Theme = _tpDevice.Theme }); - }); - - AddAction("/saveTheme", (id, content) => - { - var theme = content.ToObject>(); - - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Setting theme to {theme}", this, theme.Value); - _tpDevice.UpdateTheme(theme.Value); - - PostStatusMessage(JToken.FromObject(new { theme = theme.Value })); - }); - } + _tpDevice = device; } - public class ThemeUpdateMessage : DeviceStateMessageBase + protected override void RegisterActions() { - [JsonProperty("theme")] - public string Theme { get; set; } + AddAction("/fullStatus", (id, content) => + { + PostStatusMessage(new ThemeUpdateMessage { Theme = _tpDevice.Theme }); + }); + + AddAction("/saveTheme", (id, content) => + { + var theme = content.ToObject>(); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Setting theme to {theme}", this, theme.Value); + _tpDevice.UpdateTheme(theme.Value); + + PostStatusMessage(JToken.FromObject(new { theme = theme.Value })); + }); } } + +public class ThemeUpdateMessage : DeviceStateMessageBase +{ + [JsonProperty("theme")] + public string Theme { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs b/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs index b9ca686b..27d52c15 100644 --- a/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs +++ b/src/PepperDash.Essentials.MobileControl/TransmitMessage.cs @@ -10,121 +10,119 @@ using System; using System.Threading; using WebSocketSharp; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class TransmitMessage : IQueueMessage { - public class TransmitMessage : IQueueMessage + private readonly WebSocket _ws; + private readonly object msgToSend; + + public TransmitMessage(object msg, WebSocket ws) { - private readonly WebSocket _ws; - private readonly object msgToSend; - - public TransmitMessage(object msg, WebSocket ws) - { - _ws = ws; - msgToSend = msg; - } - - public TransmitMessage(DeviceStateMessageBase msg, WebSocket ws) - { - _ws = ws; - msgToSend = msg; - } - - #region Implementation of IQueueMessage - - public void Dispatch() - { - try - { - if (_ws == null) - { - Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is null"); - return; - } - - if (!_ws.IsAlive) - { - Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is not connected"); - return; - } - - - var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, - new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); - - Debug.LogMessage(LogEventLevel.Verbose, "Message TX: {0}", null, message); - - _ws.Send(message); - - - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Caught an exception in the Transmit Processor"); - } - } - #endregion + _ws = ws; + msgToSend = msg; } - - - public class MessageToClients : IQueueMessage + public TransmitMessage(DeviceStateMessageBase msg, WebSocket ws) { - private readonly MobileControlWebsocketServer _server; - private readonly object msgToSend; + _ws = ws; + msgToSend = msg; + } - public MessageToClients(object msg, MobileControlWebsocketServer server) + #region Implementation of IQueueMessage + + public void Dispatch() + { + try { - _server = server; - msgToSend = msg; - } - - public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server) - { - _server = server; - msgToSend = msg; - } - - #region Implementation of IQueueMessage - - public void Dispatch() - { - try + if (_ws == null) { - if (_server == null) - { - Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null"); - return; - } + Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is null"); + return; + } - var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, + if (!_ws.IsAlive) + { + Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is not connected"); + return; + } + + + var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); - var clientSpecificMessage = msgToSend as MobileControlMessage; - if (clientSpecificMessage.ClientId != null) - { - var clientId = clientSpecificMessage.ClientId; + Debug.LogMessage(LogEventLevel.Verbose, "Message TX: {0}", null, message); - _server.LogVerbose("Message TX To client {clientId} Message: {message}", clientId, message); + _ws.Send(message); - _server.SendMessageToClient(clientId, message); - return; - } - - _server.SendMessageToAllClients(message); - - _server.LogVerbose("Message TX To all clients: {message}", message); - } - catch (ThreadAbortException) - { - //Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Caught an exception in the Transmit Processor"); - } } - #endregion + catch (Exception ex) + { + Debug.LogMessage(ex, "Caught an exception in the Transmit Processor"); + } + } + #endregion +} + + + +public class MessageToClients : IQueueMessage +{ + private readonly MobileControlWebsocketServer _server; + private readonly object msgToSend; + + public MessageToClients(object msg, MobileControlWebsocketServer server) + { + _server = server; + msgToSend = msg; } + public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server) + { + _server = server; + msgToSend = msg; + } + + #region Implementation of IQueueMessage + + public void Dispatch() + { + try + { + if (_server == null) + { + Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null"); + return; + } + + var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, + new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); + + var clientSpecificMessage = msgToSend as MobileControlMessage; + if (clientSpecificMessage.ClientId != null) + { + var clientId = clientSpecificMessage.ClientId; + + _server.LogVerbose("Message TX To client {clientId} Message: {message}", clientId, message); + + _server.SendMessageToClient(clientId, message); + + return; + } + + _server.SendMessageToAllClients(message); + + _server.LogVerbose("Message TX To all clients: {message}", message); + } + catch (ThreadAbortException) + { + //Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Caught an exception in the Transmit Processor"); + } + } + #endregion } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs b/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs index 851f1b80..923137a0 100644 --- a/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs +++ b/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs @@ -1,13 +1,12 @@ using Newtonsoft.Json; -namespace PepperDash.Essentials -{ - public class UserCodeChangedContent - { - [JsonProperty("userCode")] - public string UserCode { get; set; } +namespace PepperDash.Essentials; - [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] - public string QrChecksum { get; set; } - } +public class UserCodeChangedContent +{ + [JsonProperty("userCode")] + public string UserCode { get; set; } + + [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] + public string QrChecksum { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl/Volumes.cs b/src/PepperDash.Essentials.MobileControl/Volumes.cs index 6cd83cf4..7abbba0a 100644 --- a/src/PepperDash.Essentials.MobileControl/Volumes.cs +++ b/src/PepperDash.Essentials.MobileControl/Volumes.cs @@ -1,76 +1,75 @@ using Newtonsoft.Json; using System.Collections.Generic; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class Volumes { - public class Volumes + [JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)] + public Volume Master { get; set; } + + [JsonProperty("auxFaders", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary AuxFaders { get; set; } + + [JsonProperty("numberOfAuxFaders", NullValueHandling = NullValueHandling.Ignore)] + public int? NumberOfAuxFaders { get; set; } + + public Volumes() { - [JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)] - public Volume Master { get; set; } + } +} - [JsonProperty("auxFaders", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary AuxFaders { get; set; } +public class Volume +{ + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key { get; set; } - [JsonProperty("numberOfAuxFaders", NullValueHandling = NullValueHandling.Ignore)] - public int? NumberOfAuxFaders { get; set; } + [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] + public int? Level { get; set; } - public Volumes() - { - } + [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] + public bool? Muted { get; set; } + + [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] + public string Label { get; set; } + + [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasMute { get; set; } + + [JsonProperty("hasPrivacyMute", NullValueHandling = NullValueHandling.Ignore)] + public bool? HasPrivacyMute { get; set; } + + [JsonProperty("privacyMuted", NullValueHandling = NullValueHandling.Ignore)] + public bool? PrivacyMuted { get; set; } + + + [JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)] + public string MuteIcon { get; set; } + + public Volume(string key, int level, bool muted, string label, bool hasMute, string muteIcon) + : this(key) + { + Level = level; + Muted = muted; + Label = label; + HasMute = hasMute; + MuteIcon = muteIcon; } - public class Volume + public Volume(string key, int level) + : this(key) { - [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] - public string Key { get; set; } + Level = level; + } - [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] - public int? Level { get; set; } + public Volume(string key, bool muted) + : this(key) + { + Muted = muted; + } - [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] - public bool? Muted { get; set; } - - [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] - public string Label { get; set; } - - [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasMute { get; set; } - - [JsonProperty("hasPrivacyMute", NullValueHandling = NullValueHandling.Ignore)] - public bool? HasPrivacyMute { get; set; } - - [JsonProperty("privacyMuted", NullValueHandling = NullValueHandling.Ignore)] - public bool? PrivacyMuted { get; set; } - - - [JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)] - public string MuteIcon { get; set; } - - public Volume(string key, int level, bool muted, string label, bool hasMute, string muteIcon) - : this(key) - { - Level = level; - Muted = muted; - Label = label; - HasMute = hasMute; - MuteIcon = muteIcon; - } - - public Volume(string key, int level) - : this(key) - { - Level = level; - } - - public Volume(string key, bool muted) - : this(key) - { - Muted = muted; - } - - public Volume(string key) - { - Key = key; - } + public Volume(string key) + { + Key = key; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs index 2988241b..f4324d62 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs @@ -4,48 +4,47 @@ using PepperDash.Core.Web.RequestHandlers; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.WebApiHandlers +namespace PepperDash.Essentials.WebApiHandlers; + +public class ActionPathsHandler : WebApiBaseRequestHandler { - public class ActionPathsHandler : WebApiBaseRequestHandler + private readonly MobileControlSystemController mcController; + public ActionPathsHandler(MobileControlSystemController controller) : base(true) { - private readonly MobileControlSystemController mcController; - public ActionPathsHandler(MobileControlSystemController controller) : base(true) - { - mcController = controller; - } - - protected override void HandleGet(HttpCwsContext context) - { - var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController)); - - context.Response.StatusCode = 200; - context.Response.ContentType = "application/json"; - context.Response.Headers.Add("Content-Type", "application/json"); - context.Response.Write(response, false); - context.Response.End(); - } + mcController = controller; } - public class ActionPathsResponse + protected override void HandleGet(HttpCwsContext context) { - [JsonIgnore] - private readonly MobileControlSystemController mcController; + var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController)); - [JsonProperty("actionPaths")] - public List ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2 }).ToList(); - - public ActionPathsResponse(MobileControlSystemController mcController) - { - this.mcController = mcController; - } - } - - public class ActionPath - { - [JsonProperty("messengerKey")] - public string MessengerKey { get; set; } - - [JsonProperty("path")] - public string Path { get; set; } + context.Response.StatusCode = 200; + context.Response.ContentType = "application/json"; + context.Response.Headers.Add("Content-Type", "application/json"); + context.Response.Write(response, false); + context.Response.End(); } } + +public class ActionPathsResponse +{ + [JsonIgnore] + private readonly MobileControlSystemController mcController; + + [JsonProperty("actionPaths")] + public List ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2 }).ToList(); + + public ActionPathsResponse(MobileControlSystemController mcController) + { + this.mcController = mcController; + } +} + +public class ActionPath +{ + [JsonProperty("messengerKey")] + public string MessengerKey { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs index 4f2774f4..34276764 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs @@ -6,54 +6,53 @@ using PepperDash.Essentials.Core.Web; using System; using System.Threading.Tasks; -namespace PepperDash.Essentials.WebApiHandlers +namespace PepperDash.Essentials.WebApiHandlers; + +public class MobileAuthRequestHandler : WebApiBaseRequestAsyncHandler { - public class MobileAuthRequestHandler : WebApiBaseRequestAsyncHandler + private readonly MobileControlSystemController mcController; + + public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true) { - private readonly MobileControlSystemController mcController; + mcController = controller; + } - public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true) + protected override async Task HandlePost(HttpCwsContext context) + { + try { - mcController = controller; - } + var requestBody = EssentialsWebApiHelpers.GetRequestBody(context.Request); - protected override async Task HandlePost(HttpCwsContext context) - { - try + var grantCode = JsonConvert.DeserializeObject(requestBody); + + if (string.IsNullOrEmpty(grantCode?.GrantCode)) { - var requestBody = EssentialsWebApiHelpers.GetRequestBody(context.Request); - - var grantCode = JsonConvert.DeserializeObject(requestBody); - - if (string.IsNullOrEmpty(grantCode?.GrantCode)) - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Missing grant code"); - context.Response.StatusCode = 400; - context.Response.StatusDescription = "Missing grant code"; - context.Response.End(); - return; - } - - var response = await mcController.ApiService.SendAuthorizationRequest(mcController.Host, grantCode.GrantCode, mcController.SystemUuid); - - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, $"response received"); - if (response.Authorized) - { - mcController.RegisterSystemToServer(); - } - - - context.Response.StatusCode = 200; - var responseBody = JsonConvert.SerializeObject(response, Formatting.None); - context.Response.ContentType = "application/json"; - context.Response.Headers.Add("Content-Type", "application/json"); - context.Response.Write(responseBody, false); + Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Missing grant code"); + context.Response.StatusCode = 400; + context.Response.StatusDescription = "Missing grant code"; context.Response.End(); + return; } - catch (Exception ex) + + var response = await mcController.ApiService.SendAuthorizationRequest(mcController.Host, grantCode.GrantCode, mcController.SystemUuid); + + Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, $"response received"); + if (response.Authorized) { - Debug.LogMessage(ex, "Exception recieved authorizing system"); + mcController.RegisterSystemToServer(); } + + + context.Response.StatusCode = 200; + var responseBody = JsonConvert.SerializeObject(response, Formatting.None); + context.Response.ContentType = "application/json"; + context.Response.Headers.Add("Content-Type", "application/json"); + context.Response.Write(responseBody, false); + context.Response.End(); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception recieved authorizing system"); } } } diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs index c8b97d0b..c9ca236c 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs @@ -8,152 +8,151 @@ using System; using System.Collections.Generic; using System.Linq; -namespace PepperDash.Essentials.WebApiHandlers +namespace PepperDash.Essentials.WebApiHandlers; + +public class MobileInfoHandler : WebApiBaseRequestHandler { - public class MobileInfoHandler : WebApiBaseRequestHandler + private readonly MobileControlSystemController mcController; + public MobileInfoHandler(MobileControlSystemController controller) : base(true) { - private readonly MobileControlSystemController mcController; - public MobileInfoHandler(MobileControlSystemController controller) : base(true) - { - mcController = controller; - } - - protected override void HandleGet(HttpCwsContext context) - { - try - { - var response = new InformationResponse(mcController); - - context.Response.StatusCode = 200; - context.Response.ContentType = "application/json"; - context.Response.Write(JsonConvert.SerializeObject(response), false); - context.Response.End(); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "exception showing mobile info"); - - context.Response.StatusCode = 500; - context.Response.End(); - } - } + mcController = controller; } - public class InformationResponse + protected override void HandleGet(HttpCwsContext context) { - [JsonIgnore] - private readonly MobileControlSystemController mcController; - - [JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)] - public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null; - - - [JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)] - public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null; - - - public InformationResponse(MobileControlSystemController controller) + try { - mcController = controller; + var response = new InformationResponse(mcController); + + context.Response.StatusCode = 200; + context.Response.ContentType = "application/json"; + context.Response.Write(JsonConvert.SerializeObject(response), false); + context.Response.End(); } - } - - public class MobileControlEdgeServer - { - [JsonIgnore] - private readonly MobileControlSystemController mcController; - - [JsonProperty("serverAddress")] - public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host; - - [JsonProperty("systemName")] - public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config"; - - [JsonProperty("systemUrl")] - public string SystemUrl => ConfigReader.ConfigObject.SystemUrl; - - [JsonProperty("userCode")] - public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available"; - - [JsonProperty("connected")] - public bool Connected => mcController.Connected; - - [JsonProperty("secondsSinceLastAck")] - public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds; - - public MobileControlEdgeServer(MobileControlSystemController controller) + catch (Exception ex) { - mcController = controller; - } - } + Debug.LogMessage(ex, "exception showing mobile info"); - public class MobileControlDirectServer - { - [JsonIgnore] - private readonly MobileControlWebsocketServer directServer; - - [JsonProperty("userAppUrl")] - public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]"; - - [JsonProperty("serverPort")] - public int ServerPort => directServer.Port; - - [JsonProperty("tokensDefined")] - public int TokensDefined => directServer.UiClients.Count; - - [JsonProperty("clientsConnected")] - public int ClientsConnected => directServer.ConnectedUiClientsCount; - - [JsonProperty("clients")] - public List Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList(); - - public MobileControlDirectServer(MobileControlWebsocketServer server) - { - directServer = server; - } - } - - public class MobileControlDirectClient - { - [JsonIgnore] - private readonly UiClientContext context; - - [JsonIgnore] - private readonly string Key; - - [JsonIgnore] - private readonly int clientNumber; - - [JsonIgnore] - private readonly string urlPrefix; - - [JsonProperty("clientNumber")] - public string ClientNumber => $"{clientNumber}"; - - [JsonProperty("roomKey")] - public string RoomKey => context.Token.RoomKey; - - [JsonProperty("touchpanelKey")] - public string TouchpanelKey => context.Token.TouchpanelKey; - - [JsonProperty("url")] - public string Url => $"{urlPrefix}{Key}"; - - [JsonProperty("token")] - public string Token => Key; - - [JsonProperty("connected")] - public bool Connected => context.Client != null && context.Client.Context.WebSocket.IsAlive; - - [JsonProperty("duration")] - public double Duration => context.Client == null ? 0 : context.Client.ConnectedDuration.TotalSeconds; - - public MobileControlDirectClient(KeyValuePair clientContext, int index, string urlPrefix) - { - context = clientContext.Value; - Key = clientContext.Key; - clientNumber = index; - this.urlPrefix = urlPrefix; + context.Response.StatusCode = 500; + context.Response.End(); } } } + +public class InformationResponse +{ + [JsonIgnore] + private readonly MobileControlSystemController mcController; + + [JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)] + public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null; + + + [JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)] + public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null; + + + public InformationResponse(MobileControlSystemController controller) + { + mcController = controller; + } +} + +public class MobileControlEdgeServer +{ + [JsonIgnore] + private readonly MobileControlSystemController mcController; + + [JsonProperty("serverAddress")] + public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host; + + [JsonProperty("systemName")] + public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config"; + + [JsonProperty("systemUrl")] + public string SystemUrl => ConfigReader.ConfigObject.SystemUrl; + + [JsonProperty("userCode")] + public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available"; + + [JsonProperty("connected")] + public bool Connected => mcController.Connected; + + [JsonProperty("secondsSinceLastAck")] + public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds; + + public MobileControlEdgeServer(MobileControlSystemController controller) + { + mcController = controller; + } +} + +public class MobileControlDirectServer +{ + [JsonIgnore] + private readonly MobileControlWebsocketServer directServer; + + [JsonProperty("userAppUrl")] + public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]"; + + [JsonProperty("serverPort")] + public int ServerPort => directServer.Port; + + [JsonProperty("tokensDefined")] + public int TokensDefined => directServer.UiClients.Count; + + [JsonProperty("clientsConnected")] + public int ClientsConnected => directServer.ConnectedUiClientsCount; + + [JsonProperty("clients")] + public List Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList(); + + public MobileControlDirectServer(MobileControlWebsocketServer server) + { + directServer = server; + } +} + +public class MobileControlDirectClient +{ + [JsonIgnore] + private readonly UiClientContext context; + + [JsonIgnore] + private readonly string Key; + + [JsonIgnore] + private readonly int clientNumber; + + [JsonIgnore] + private readonly string urlPrefix; + + [JsonProperty("clientNumber")] + public string ClientNumber => $"{clientNumber}"; + + [JsonProperty("roomKey")] + public string RoomKey => context.Token.RoomKey; + + [JsonProperty("touchpanelKey")] + public string TouchpanelKey => context.Token.TouchpanelKey; + + [JsonProperty("url")] + public string Url => $"{urlPrefix}{Key}"; + + [JsonProperty("token")] + public string Token => Key; + + [JsonProperty("connected")] + public bool Connected => context.Client != null && context.Client.Context.WebSocket.IsAlive; + + [JsonProperty("duration")] + public double Duration => context.Client == null ? 0 : context.Client.ConnectedDuration.TotalSeconds; + + public MobileControlDirectClient(KeyValuePair clientContext, int index, string urlPrefix) + { + context = clientContext.Value; + Key = clientContext.Key; + clientNumber = index; + this.urlPrefix = urlPrefix; + } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs index 73fdb104..4732fc4e 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs @@ -6,161 +6,160 @@ using PepperDash.Essentials.Core.Web; using PepperDash.Essentials.WebSocketServer; using Serilog.Events; -namespace PepperDash.Essentials.WebApiHandlers +namespace PepperDash.Essentials.WebApiHandlers; + +public class UiClientHandler : WebApiBaseRequestHandler { - public class UiClientHandler : WebApiBaseRequestHandler + private readonly MobileControlWebsocketServer server; + public UiClientHandler(MobileControlWebsocketServer directServer) : base(true) { - private readonly MobileControlWebsocketServer server; - public UiClientHandler(MobileControlWebsocketServer directServer) : base(true) + server = directServer; + } + + protected override void HandlePost(HttpCwsContext context) + { + var req = context.Request; + var res = context.Response; + var body = EssentialsWebApiHelpers.GetRequestBody(req); + + var request = JsonConvert.DeserializeObject(body); + + var response = new ClientResponse(); + + if (string.IsNullOrEmpty(request?.RoomKey)) { - server = directServer; + response.Error = "roomKey is required"; + + res.StatusCode = 400; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + return; } - protected override void HandlePost(HttpCwsContext context) + if (string.IsNullOrEmpty(request.GrantCode)) { - var req = context.Request; - var res = context.Response; - var body = EssentialsWebApiHelpers.GetRequestBody(req); + response.Error = "grantCode is required"; - var request = JsonConvert.DeserializeObject(body); + res.StatusCode = 400; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + return; + } - var response = new ClientResponse(); + var (token, path) = server.ValidateGrantCode(request.GrantCode, request.RoomKey); - if (string.IsNullOrEmpty(request?.RoomKey)) + response.Token = token; + response.Path = path; + + res.StatusCode = 200; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); + } + + protected override void HandleDelete(HttpCwsContext context) + { + var req = context.Request; + var res = context.Response; + var body = EssentialsWebApiHelpers.GetRequestBody(req); + + var request = JsonConvert.DeserializeObject(body); + + + + if (string.IsNullOrEmpty(request?.Token)) + { + var response = new ClientResponse { - response.Error = "roomKey is required"; + Error = "token is required" + }; - res.StatusCode = 400; - res.ContentType = "application/json"; - res.Headers.Add("Content-Type", "application/json"); - res.Write(JsonConvert.SerializeObject(response), false); - res.End(); - return; - } + res.StatusCode = 400; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); - if (string.IsNullOrEmpty(request.GrantCode)) + return; + } + + + + if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext)) + { + var response = new ClientResponse { - response.Error = "grantCode is required"; - - res.StatusCode = 400; - res.ContentType = "application/json"; - res.Headers.Add("Content-Type", "application/json"); - res.Write(JsonConvert.SerializeObject(response), false); - res.End(); - return; - } - - var (token, path) = server.ValidateGrantCode(request.GrantCode, request.RoomKey); - - response.Token = token; - response.Path = path; + Error = $"Unable to find client with token: {request.Token}" + }; res.StatusCode = 200; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); + + return; } - protected override void HandleDelete(HttpCwsContext context) + if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) { - var req = context.Request; - var res = context.Response; - var body = EssentialsWebApiHelpers.GetRequestBody(req); - - var request = JsonConvert.DeserializeObject(body); - - - - if (string.IsNullOrEmpty(request?.Token)) - { - var response = new ClientResponse - { - Error = "token is required" - }; - - res.StatusCode = 400; - res.ContentType = "application/json"; - res.Headers.Add("Content-Type", "application/json"); - res.Write(JsonConvert.SerializeObject(response), false); - res.End(); - - return; - } - - - - if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext)) - { - var response = new ClientResponse - { - Error = $"Unable to find client with token: {request.Token}" - }; - - res.StatusCode = 200; - res.ContentType = "application/json"; - res.Headers.Add("Content-Type", "application/json"); - res.Write(JsonConvert.SerializeObject(response), false); - res.End(); - - return; - } - - if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) - { - clientContext.Client.Context.WebSocket.Close(WebSocketSharp.CloseStatusCode.Normal, "Token removed from server"); - } - - var path = server.WsPath + request.Token; - - if (!server.Server.RemoveWebSocketService(path)) - { - Debug.LogMessage(LogEventLevel.Warning, "Unable to remove client with token {token}", request.Token); - - var response = new ClientResponse - { - Error = $"Unable to remove client with token {request.Token}" - }; - - res.StatusCode = 500; - res.ContentType = "application/json"; - res.Headers.Add("Content-Type", "application/json"); - res.Write(JsonConvert.SerializeObject(response), false); - res.End(); - - return; - } - - server.UiClients.Remove(request.Token); - - server.UpdateSecret(); - - res.StatusCode = 200; - res.End(); + clientContext.Client.Context.WebSocket.Close(WebSocketSharp.CloseStatusCode.Normal, "Token removed from server"); } - } - public class ClientRequest - { - [JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)] - public string RoomKey { get; set; } + var path = server.WsPath + request.Token; - [JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)] - public string GrantCode { get; set; } + if (!server.Server.RemoveWebSocketService(path)) + { + Debug.LogMessage(LogEventLevel.Warning, "Unable to remove client with token {token}", request.Token); - [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] - public string Token { get; set; } - } + var response = new ClientResponse + { + Error = $"Unable to remove client with token {request.Token}" + }; - public class ClientResponse - { - [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] - public string Error { get; set; } + res.StatusCode = 500; + res.ContentType = "application/json"; + res.Headers.Add("Content-Type", "application/json"); + res.Write(JsonConvert.SerializeObject(response), false); + res.End(); - [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] - public string Token { get; set; } + return; + } - [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] - public string Path { get; set; } + server.UiClients.Remove(request.Token); + + server.UpdateSecret(); + + res.StatusCode = 200; + res.End(); } } + +public class ClientRequest +{ + [JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)] + public string RoomKey { get; set; } + + [JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)] + public string GrantCode { get; set; } + + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + public string Token { get; set; } +} + +public class ClientResponse +{ + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + public string Token { get; set; } + + [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] + public string Path { get; set; } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index 859a7c7b..e74ba016 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -20,1262 +20,1261 @@ using WebSocketSharp.Net; using WebSocketSharp.Server; -namespace PepperDash.Essentials.WebSocketServer +namespace PepperDash.Essentials.WebSocketServer; + +public class MobileControlWebsocketServer : EssentialsDevice { - public class MobileControlWebsocketServer : EssentialsDevice + private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator; + + private readonly string localConfigFolderName = "_local-config"; + + private readonly string appConfigFileName = "_config.local.json"; + private readonly string appConfigCsFileName = "_config.cs.json"; + + /// + /// Where the key is the join token and the value is the room key + /// + //private Dictionary _joinTokens; + + private HttpServer _server; + + public HttpServer Server => _server; + + public Dictionary UiClients { get; private set; } + + private readonly MobileControlSystemController _parent; + + private WebSocketServerSecretProvider _secretProvider; + + private ServerTokenSecrets _secret; + + private static readonly HttpClient LogClient = new HttpClient(); + + private string SecretProviderKey { - private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator; - - private readonly string localConfigFolderName = "_local-config"; - - private readonly string appConfigFileName = "_config.local.json"; - private readonly string appConfigCsFileName = "_config.cs.json"; - - /// - /// Where the key is the join token and the value is the room key - /// - //private Dictionary _joinTokens; - - private HttpServer _server; - - public HttpServer Server => _server; - - public Dictionary UiClients { get; private set; } - - private readonly MobileControlSystemController _parent; - - private WebSocketServerSecretProvider _secretProvider; - - private ServerTokenSecrets _secret; - - private static readonly HttpClient LogClient = new HttpClient(); - - private string SecretProviderKey + get { - get - { - return string.Format("{0}:{1}-tokens", Global.ControlSystem.ProgramNumber, Key); - } + return string.Format("{0}:{1}-tokens", Global.ControlSystem.ProgramNumber, Key); } + } - private string lanIpAddress => CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter)); + private string lanIpAddress => CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter)); - private System.Net.IPAddress csIpAddress; + private System.Net.IPAddress csIpAddress; - private System.Net.IPAddress csSubnetMask; + private System.Net.IPAddress csSubnetMask; - /// - /// The path for the WebSocket messaging - /// - private readonly string _wsPath = "/mc/api/ui/join/"; + /// + /// The path for the WebSocket messaging + /// + private readonly string _wsPath = "/mc/api/ui/join/"; - public string WsPath => _wsPath; + public string WsPath => _wsPath; - /// - /// The path to the location of the files for the user app (single page Angular app) - /// - private readonly string _appPath = string.Format("{0}mcUserApp", Global.FilePathPrefix); + /// + /// The path to the location of the files for the user app (single page Angular app) + /// + private readonly string _appPath = string.Format("{0}mcUserApp", Global.FilePathPrefix); - /// - /// The base HREF that the user app uses - /// - private string _userAppBaseHref = "/mc/app"; + /// + /// The base HREF that the user app uses + /// + private string _userAppBaseHref = "/mc/app"; - /// - /// The port the server will run on - /// - public int Port { get; private set; } + /// + /// The port the server will run on + /// + public int Port { get; private set; } - public string UserAppUrlPrefix + public string UserAppUrlPrefix + { + get { - get - { - return string.Format("http://{0}:{1}{2}?token=", - CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), - Port, - _userAppBaseHref); + return string.Format("http://{0}:{1}{2}?token=", + CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), + Port, + _userAppBaseHref); - } } + } - public int ConnectedUiClientsCount + public int ConnectedUiClientsCount + { + get { - get - { - var count = 0; - - foreach (var client in UiClients) - { - if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive) - { - count++; - } - } - - return count; - } - } - - public MobileControlWebsocketServer(string key, int customPort, MobileControlSystemController parent) - : base(key) - { - _parent = parent; - - // Set the default port to be 50000 plus the slot number of the program - Port = 50000 + (int)Global.ControlSystem.ProgramNumber; - - if (customPort != 0) - { - Port = customPort; - } - - if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == true) - { - try - { - Debug.LogMessage(LogEventLevel.Information, "Automatically forwarding port {0} to CS LAN", Port); - - var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); - var csIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); - - var result = CrestronEthernetHelper.AddPortForwarding((ushort)Port, (ushort)Port, csIp, CrestronEthernetHelper.ePortMapTransport.TCP); - - if (result != CrestronEthernetHelper.PortForwardingUserPatRetCodes.NoErr) - { - Debug.LogMessage(LogEventLevel.Error, "Error adding port forwarding: {0}", result); - } - } - catch (ArgumentException) - { - Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Error automatically forwarding port to CS LAN"); - } - } - - try - { - var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); - var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); - var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); - - this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask); - this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress); - } - catch (ArgumentException) - { - if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == false) - { - Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this); - } - } - - - UiClients = new Dictionary(); - - //_joinTokens = new Dictionary(); - - if (Global.Platform == eDevicePlatform.Appliance) - { - AddConsoleCommands(); - } - - AddPreActivationAction(() => AddWebApiPaths()); - } - - private void AddWebApiPaths() - { - var apiServer = DeviceManager.AllDevices.OfType().FirstOrDefault(); - - if (apiServer == null) - { - this.LogInformation("No API Server available"); - return; - } - - var routes = new List - { - new HttpCwsRoute($"devices/{Key}/client") - { - Name = "ClientHandler", - RouteHandler = new UiClientHandler(this) - }, - }; - - apiServer.AddRoute(routes); - } - - private void AddConsoleCommands() - { - CrestronConsole.AddNewConsoleCommand(GenerateClientTokenFromConsole, "MobileAddUiClient", "Adds a client and generates a token. ? for more help", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(RemoveToken, "MobileRemoveUiClient", "Removes a client. ? for more help", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand((s) => PrintClientInfo(), "MobileGetClientInfo", "Displays the current client info", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(RemoveAllTokens, "MobileRemoveAllClients", "Removes all clients", ConsoleAccessLevelEnum.AccessOperator); - } - - - public override void Initialize() - { - try - { - base.Initialize(); - - _server = new HttpServer(Port, false); - - _server.OnGet += Server_OnGet; - - _server.OnOptions += Server_OnOptions; - - if (_parent.Config.DirectServer.Logging.EnableRemoteLogging) - { - _server.OnPost += Server_OnPost; - } - - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - - _server.Start(); - - if (_server.IsListening) - { - Debug.LogMessage(LogEventLevel.Information, "Mobile Control WebSocket Server listening on port {port}", this, _server.Port); - } - - CrestronEnvironment.ProgramStatusEventHandler += OnProgramStop; - - RetrieveSecret(); - - CreateFolderStructure(); - - AddClientsForTouchpanels(); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception intializing websocket server", this); - } - } - - private void AddClientsForTouchpanels() - { - var touchpanels = DeviceManager.AllDevices - .OfType().Where(tp => tp.UseDirectServer); - - - var touchpanelsToAdd = new List(); - - if (_secret != null) - { - var newTouchpanels = touchpanels.Where(tp => !_secret.Tokens.Any(t => t.Value.TouchpanelKey != null && t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase))); - - touchpanelsToAdd.AddRange(newTouchpanels); - } - else - { - touchpanelsToAdd.AddRange(touchpanels); - } - - foreach (var client in touchpanelsToAdd) - { - var bridge = _parent.GetRoomBridge(client.DefaultRoomKey); - - if (bridge == null) - { - this.LogWarning("Unable to find room with key: {defaultRoomKey}", client.DefaultRoomKey); - return; - } - - var (key, path) = GenerateClientToken(bridge, client.Key); - - if (key == null) - { - this.LogWarning("Unable to generate a client for {clientKey}", client.Key); - continue; - } - } - - var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); - - var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); - - this.LogVerbose("Processor IP: {processorIp}", processorIp); - - foreach (var touchpanel in touchpanels.Select(tp => - { - var token = _secret.Tokens.FirstOrDefault((t) => t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase)); - - var messenger = _parent.GetRoomBridge(tp.DefaultRoomKey); - - return new { token.Key, Touchpanel = tp, Messenger = messenger }; - })) - { - if (touchpanel.Key == null) - { - this.LogWarning("Token for touchpanel {touchpanelKey} not found", touchpanel.Touchpanel.Key); - continue; - } - - if (touchpanel.Messenger == null) - { - this.LogWarning("Unable to find room messenger for {defaultRoomKey}", touchpanel.Touchpanel.DefaultRoomKey); - continue; - } - - var appUrl = $"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; - - this.LogVerbose("Sending URL {appUrl}", appUrl); - - touchpanel.Messenger.UpdateAppUrl($"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); - } - } - - private void OnProgramStop(eProgramStatusEventType programEventType) - { - switch (programEventType) - { - case eProgramStatusEventType.Stopping: - _server.Stop(); - break; - } - } - - private void CreateFolderStructure() - { - if (!Directory.Exists(userAppPath)) - { - Directory.CreateDirectory(userAppPath); - } - - if (!Directory.Exists($"{userAppPath}{localConfigFolderName}")) - { - Directory.CreateDirectory($"{userAppPath}{localConfigFolderName}"); - } - - using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite))) - { - // Write the LAN application configuration file. Used when a request comes in for the application config from the LAN - var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); - - this.LogDebug("LAN Adapter ID: {lanAdapterId}", lanAdapterId); - - var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); - - var config = GetApplicationConfig(processorIp); - - var contents = JsonConvert.SerializeObject(config, Formatting.Indented); - - sw.Write(contents); - } - - short csAdapterId; - try - { - csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); - } - catch (ArgumentException) - { - this.LogDebug("This processor does not have a CS LAN"); - return; - } - - if(csAdapterId == -1) - { - this.LogDebug("CS LAN Adapter not found"); - return; - } - - this.LogDebug("CS LAN Adapter ID: {csAdapterId}. Adding CS Config", csAdapterId); - - using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigCsFileName}", FileMode.Create, FileAccess.ReadWrite))) - { - // Write the CS application configuration file. Used when a request comes in for the application config from the CS - var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); - - var config = GetApplicationConfig(processorIp); - - var contents = JsonConvert.SerializeObject(config, Formatting.Indented); - - sw.Write(contents); - } - } - - private MobileControlApplicationConfig GetApplicationConfig(string processorIp) - { - try - { - var config = new MobileControlApplicationConfig - { - ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port), - GatewayAppPath = "", - LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png", - EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false, - IconSet = _parent.Config.ApplicationConfig?.IconSet ?? MCIconSet.GOOGLE, - LoginMode = _parent.Config.ApplicationConfig?.LoginMode ?? "room-list", - Modes = _parent.Config.ApplicationConfig?.Modes ?? new Dictionary - { - { - "room-list", - new McMode { - ListPageText = "Please select your room", - LoginHelpText = "Please select your room from the list, then enter the code shown on the display.", - PasscodePageText = "Please enter the code shown on this room's display" - } - } - }, - Logging = _parent.Config.ApplicationConfig?.Logging ?? false, - PartnerMetadata = _parent.Config.ApplicationConfig?.PartnerMetadata ?? new List() - }; - - return config; - } - catch (Exception ex) - { - this.LogError(ex, "Error getting application configuration"); - - return null; - } - } - - /// - /// Attempts to retrieve secrets previously stored in memory - /// - private void RetrieveSecret() - { - try - { - // Add secret provider - _secretProvider = new WebSocketServerSecretProvider(SecretProviderKey); - - // Check for existing secrets - var secret = _secretProvider.GetSecret(SecretProviderKey); - - if (secret != null) - { - Debug.LogMessage(LogEventLevel.Information, "Secret successfully retrieved", this); - - Debug.LogMessage(LogEventLevel.Debug, "Secret: {0}", this, secret.Value.ToString()); - - - // populate the local secrets object - _secret = JsonConvert.DeserializeObject(secret.Value.ToString()); - - if (_secret != null && _secret.Tokens != null) - { - // populate the _uiClient collection - foreach (var token in _secret.Tokens) - { - if (token.Value == null) - { - Debug.LogMessage(LogEventLevel.Warning, "Token value is null", this); - continue; - } - - Debug.LogMessage(LogEventLevel.Information, "Adding token: {0} for room: {1}", this, token.Key, token.Value.RoomKey); - - if (UiClients == null) - { - Debug.LogMessage(LogEventLevel.Warning, "UiClients is null", this); - UiClients = new Dictionary(); - } - - UiClients.Add(token.Key, new UiClientContext(token.Value)); - } - } - - if (UiClients.Count > 0) - { - Debug.LogMessage(LogEventLevel.Information, "Restored {uiClientCount} UiClients from secrets data", this, UiClients.Count); - - foreach (var client in UiClients) - { - var key = client.Key; - var path = _wsPath + key; - var roomKey = client.Value.Token.RoomKey; - - _server.AddWebSocketService(path, () => - { - var c = new UiClient(); - Debug.LogMessage(LogEventLevel.Debug, "Constructing UiClient with id: {key}", this, key); - - c.Controller = _parent; - c.RoomKey = roomKey; - UiClients[key].SetClient(c); - return c; - }); - - - //_server.WebSocketServices.AddService(path, (c) => - //{ - // Debug.Console(2, this, "Constructing UiClient with id: {0}", key); - // c.Controller = _parent; - // c.RoomKey = roomKey; - // UiClients[key].SetClient(c); - //}); - } - } - } - else - { - Debug.LogMessage(LogEventLevel.Warning, "No secret found"); - } - - Debug.LogMessage(LogEventLevel.Debug, "{uiClientCount} UiClients restored from secrets data", this, UiClients.Count); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception retrieving secret", this); - } - } - - /// - /// Stores secrets to memory to persist through reboot - /// - public void UpdateSecret() - { - try - { - if (_secret == null) - { - Debug.LogMessage(LogEventLevel.Error, "Secret is null", this); - - _secret = new ServerTokenSecrets(string.Empty); - } - - _secret.Tokens.Clear(); - - foreach (var uiClientContext in UiClients) - { - _secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token); - } - - var serializedSecret = JsonConvert.SerializeObject(_secret); - - _secretProvider.SetSecret(SecretProviderKey, serializedSecret); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Exception updating secret", this); - } - } - - /// - /// Generates a new token based on validating a room key and grant code passed in. If valid, returns a token and adds a service to the server for that token's path - /// - /// - private void GenerateClientTokenFromConsole(string s) - { - if (s == "?" || string.IsNullOrEmpty(s)) - { - CrestronConsole.ConsoleCommandResponse(@"[RoomKey] [GrantCode] Validates the room key against the grant code and returns a token for use in a UI client"); - return; - } - - var values = s.Split(' '); - - if(values.Length < 2) - { - CrestronConsole.ConsoleCommandResponse("Invalid number of arguments. Please provide a room key and a grant code"); - return; - } - - - var roomKey = values[0]; - var grantCode = values[1]; - - var bridge = _parent.GetRoomBridge(roomKey); - - if (bridge == null) - { - CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find room with key: {0}", roomKey)); - return; - } - - var (token, path) = ValidateGrantCode(grantCode, bridge); - - if (token == null) - { - CrestronConsole.ConsoleCommandResponse("Grant Code is not valid"); - return; - } - - CrestronConsole.ConsoleCommandResponse($"Added new WebSocket UiClient service at path: {path}"); - CrestronConsole.ConsoleCommandResponse($"Token: {token}"); - } - - public (string, string) ValidateGrantCode(string grantCode, string roomKey) - { - var bridge = _parent.GetRoomBridge(roomKey); - - if (bridge == null) - { - this.LogWarning("Unable to find room with key: {roomKey}", roomKey); - return (null, null); - } - - return ValidateGrantCode(grantCode, bridge); - } - - public (string, string) ValidateGrantCode(string grantCode, MobileControlBridgeBase bridge) - { - // TODO: Authenticate grant code passed in - // For now, we just generate a random guid as the token and use it as the ClientId as well - var grantCodeIsValid = true; - - if (grantCodeIsValid) - { - if (_secret == null) - { - _secret = new ServerTokenSecrets(grantCode); - } - - return GenerateClientToken(bridge, ""); - } - else - { - return (null, null); - } - } - - public (string, string) GenerateClientToken(MobileControlBridgeBase bridge, string touchPanelKey = "") - { - var key = Guid.NewGuid().ToString(); - - var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey }; - - UiClients.Add(key, new UiClientContext(token)); - - var path = _wsPath + key; - - _server.AddWebSocketService(path, () => - { - var c = new UiClient(); - Debug.LogMessage(LogEventLevel.Verbose, "Constructing UiClient with id: {0}", this, key); - c.Controller = _parent; - c.RoomKey = bridge.RoomKey; - UiClients[key].SetClient(c); - return c; - }); - - Debug.LogMessage(LogEventLevel.Information, "Added new WebSocket UiClient service at path: {path}", this, path); - Debug.LogMessage(LogEventLevel.Information, "Token: {@token}", this, token); - - Debug.LogMessage(LogEventLevel.Verbose, "{serviceCount} websocket services present", this, _server.WebSocketServices.Count); - - UpdateSecret(); - - return (key, path); - } - - /// - /// Removes all clients from the server - /// - private void RemoveAllTokens(string s) - { - if (s == "?" || string.IsNullOrEmpty(s)) - { - CrestronConsole.ConsoleCommandResponse(@"Removes all clients from the server. To execute add 'confirm' to command"); - return; - } - - if (s != "confirm") - { - CrestronConsole.ConsoleCommandResponse(@"To remove all clients, add 'confirm' to the command"); - return; - } + var count = 0; foreach (var client in UiClients) { if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive) { - client.Value.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down"); - } - - var path = _wsPath + client.Key; - if (_server.RemoveWebSocketService(path)) - { - CrestronConsole.ConsoleCommandResponse(string.Format("Client removed with token: {0}", client.Key)); - } - else - { - CrestronConsole.ConsoleCommandResponse(string.Format("Unable to remove client with token : {0}", client.Key)); + count++; } } - UiClients.Clear(); + return count; + } + } - UpdateSecret(); + public MobileControlWebsocketServer(string key, int customPort, MobileControlSystemController parent) + : base(key) + { + _parent = parent; + + // Set the default port to be 50000 plus the slot number of the program + Port = 50000 + (int)Global.ControlSystem.ProgramNumber; + + if (customPort != 0) + { + Port = customPort; } - /// - /// Removes a client with the specified token value - /// - /// - private void RemoveToken(string s) + if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == true) { - if (s == "?" || string.IsNullOrEmpty(s)) + try { - CrestronConsole.ConsoleCommandResponse(@"[token] Removes the client with the specified token value"); + Debug.LogMessage(LogEventLevel.Information, "Automatically forwarding port {0} to CS LAN", Port); + + var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); + var csIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); + + var result = CrestronEthernetHelper.AddPortForwarding((ushort)Port, (ushort)Port, csIp, CrestronEthernetHelper.ePortMapTransport.TCP); + + if (result != CrestronEthernetHelper.PortForwardingUserPatRetCodes.NoErr) + { + Debug.LogMessage(LogEventLevel.Error, "Error adding port forwarding: {0}", result); + } + } + catch (ArgumentException) + { + Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Error automatically forwarding port to CS LAN"); + } + } + + try + { + var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); + var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); + var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); + + this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask); + this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress); + } + catch (ArgumentException) + { + if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == false) + { + Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this); + } + } + + + UiClients = new Dictionary(); + + //_joinTokens = new Dictionary(); + + if (Global.Platform == eDevicePlatform.Appliance) + { + AddConsoleCommands(); + } + + AddPreActivationAction(() => AddWebApiPaths()); + } + + private void AddWebApiPaths() + { + var apiServer = DeviceManager.AllDevices.OfType().FirstOrDefault(); + + if (apiServer == null) + { + this.LogInformation("No API Server available"); + return; + } + + var routes = new List + { + new HttpCwsRoute($"devices/{Key}/client") + { + Name = "ClientHandler", + RouteHandler = new UiClientHandler(this) + }, + }; + + apiServer.AddRoute(routes); + } + + private void AddConsoleCommands() + { + CrestronConsole.AddNewConsoleCommand(GenerateClientTokenFromConsole, "MobileAddUiClient", "Adds a client and generates a token. ? for more help", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(RemoveToken, "MobileRemoveUiClient", "Removes a client. ? for more help", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand((s) => PrintClientInfo(), "MobileGetClientInfo", "Displays the current client info", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(RemoveAllTokens, "MobileRemoveAllClients", "Removes all clients", ConsoleAccessLevelEnum.AccessOperator); + } + + + public override void Initialize() + { + try + { + base.Initialize(); + + _server = new HttpServer(Port, false); + + _server.OnGet += Server_OnGet; + + _server.OnOptions += Server_OnOptions; + + if (_parent.Config.DirectServer.Logging.EnableRemoteLogging) + { + _server.OnPost += Server_OnPost; + } + + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + + _server.Start(); + + if (_server.IsListening) + { + Debug.LogMessage(LogEventLevel.Information, "Mobile Control WebSocket Server listening on port {port}", this, _server.Port); + } + + CrestronEnvironment.ProgramStatusEventHandler += OnProgramStop; + + RetrieveSecret(); + + CreateFolderStructure(); + + AddClientsForTouchpanels(); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception intializing websocket server", this); + } + } + + private void AddClientsForTouchpanels() + { + var touchpanels = DeviceManager.AllDevices + .OfType().Where(tp => tp.UseDirectServer); + + + var touchpanelsToAdd = new List(); + + if (_secret != null) + { + var newTouchpanels = touchpanels.Where(tp => !_secret.Tokens.Any(t => t.Value.TouchpanelKey != null && t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase))); + + touchpanelsToAdd.AddRange(newTouchpanels); + } + else + { + touchpanelsToAdd.AddRange(touchpanels); + } + + foreach (var client in touchpanelsToAdd) + { + var bridge = _parent.GetRoomBridge(client.DefaultRoomKey); + + if (bridge == null) + { + this.LogWarning("Unable to find room with key: {defaultRoomKey}", client.DefaultRoomKey); return; } - var key = s; + var (key, path) = GenerateClientToken(bridge, client.Key); - if (UiClients.ContainsKey(key)) + if (key == null) { - var uiClientContext = UiClients[key]; - - if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive) - { - uiClientContext.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Token removed from server"); - } - - var path = _wsPath + key; - if (_server.RemoveWebSocketService(path)) - { - UiClients.Remove(key); - - UpdateSecret(); - - CrestronConsole.ConsoleCommandResponse(string.Format("Client removed with token: {0}", key)); - } - else - { - CrestronConsole.ConsoleCommandResponse(string.Format("Unable to remove client with token : {0}", key)); - } - } - else - { - CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find client with token: {0}", key)); + this.LogWarning("Unable to generate a client for {clientKey}", client.Key); + continue; } } - /// - /// Prints out info about current client IDs - /// - private void PrintClientInfo() + var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); + + var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); + + this.LogVerbose("Processor IP: {processorIp}", processorIp); + + foreach (var touchpanel in touchpanels.Select(tp => { - CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r"); + var token = _secret.Tokens.FirstOrDefault((t) => t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase)); - CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClients.Count)); + var messenger = _parent.GetRoomBridge(tp.DefaultRoomKey); - foreach (var client in UiClients) + return new { token.Key, Touchpanel = tp, Messenger = messenger }; + })) + { + if (touchpanel.Key == null) { - CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key)); + this.LogWarning("Token for touchpanel {touchpanelKey} not found", touchpanel.Touchpanel.Key); + continue; } + + if (touchpanel.Messenger == null) + { + this.LogWarning("Unable to find room messenger for {defaultRoomKey}", touchpanel.Touchpanel.DefaultRoomKey); + continue; + } + + var appUrl = $"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; + + this.LogVerbose("Sending URL {appUrl}", appUrl); + + touchpanel.Messenger.UpdateAppUrl($"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); + } + } + + private void OnProgramStop(eProgramStatusEventType programEventType) + { + switch (programEventType) + { + case eProgramStatusEventType.Stopping: + _server.Stop(); + break; + } + } + + private void CreateFolderStructure() + { + if (!Directory.Exists(userAppPath)) + { + Directory.CreateDirectory(userAppPath); } - private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + if (!Directory.Exists($"{userAppPath}{localConfigFolderName}")) { - if (programEventType == eProgramStatusEventType.Stopping) + Directory.CreateDirectory($"{userAppPath}{localConfigFolderName}"); + } + + using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite))) + { + // Write the LAN application configuration file. Used when a request comes in for the application config from the LAN + var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); + + this.LogDebug("LAN Adapter ID: {lanAdapterId}", lanAdapterId); + + var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); + + var config = GetApplicationConfig(processorIp); + + var contents = JsonConvert.SerializeObject(config, Formatting.Indented); + + sw.Write(contents); + } + + short csAdapterId; + try + { + csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); + } + catch (ArgumentException) + { + this.LogDebug("This processor does not have a CS LAN"); + return; + } + + if(csAdapterId == -1) + { + this.LogDebug("CS LAN Adapter not found"); + return; + } + + this.LogDebug("CS LAN Adapter ID: {csAdapterId}. Adding CS Config", csAdapterId); + + using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigCsFileName}", FileMode.Create, FileAccess.ReadWrite))) + { + // Write the CS application configuration file. Used when a request comes in for the application config from the CS + var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); + + var config = GetApplicationConfig(processorIp); + + var contents = JsonConvert.SerializeObject(config, Formatting.Indented); + + sw.Write(contents); + } + } + + private MobileControlApplicationConfig GetApplicationConfig(string processorIp) + { + try + { + var config = new MobileControlApplicationConfig { - foreach (var client in UiClients.Values) + ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port), + GatewayAppPath = "", + LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png", + EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false, + IconSet = _parent.Config.ApplicationConfig?.IconSet ?? MCIconSet.GOOGLE, + LoginMode = _parent.Config.ApplicationConfig?.LoginMode ?? "room-list", + Modes = _parent.Config.ApplicationConfig?.Modes ?? new Dictionary { - if (client.Client != null && client.Client.Context.WebSocket.IsAlive) { - client.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down"); + "room-list", + new McMode { + ListPageText = "Please select your room", + LoginHelpText = "Please select your room from the list, then enter the code shown on the display.", + PasscodePageText = "Please enter the code shown on this room's display" + } + } + }, + Logging = _parent.Config.ApplicationConfig?.Logging ?? false, + PartnerMetadata = _parent.Config.ApplicationConfig?.PartnerMetadata ?? new List() + }; + + return config; + } + catch (Exception ex) + { + this.LogError(ex, "Error getting application configuration"); + + return null; + } + } + + /// + /// Attempts to retrieve secrets previously stored in memory + /// + private void RetrieveSecret() + { + try + { + // Add secret provider + _secretProvider = new WebSocketServerSecretProvider(SecretProviderKey); + + // Check for existing secrets + var secret = _secretProvider.GetSecret(SecretProviderKey); + + if (secret != null) + { + Debug.LogMessage(LogEventLevel.Information, "Secret successfully retrieved", this); + + Debug.LogMessage(LogEventLevel.Debug, "Secret: {0}", this, secret.Value.ToString()); + + + // populate the local secrets object + _secret = JsonConvert.DeserializeObject(secret.Value.ToString()); + + if (_secret != null && _secret.Tokens != null) + { + // populate the _uiClient collection + foreach (var token in _secret.Tokens) + { + if (token.Value == null) + { + Debug.LogMessage(LogEventLevel.Warning, "Token value is null", this); + continue; + } + + Debug.LogMessage(LogEventLevel.Information, "Adding token: {0} for room: {1}", this, token.Key, token.Value.RoomKey); + + if (UiClients == null) + { + Debug.LogMessage(LogEventLevel.Warning, "UiClients is null", this); + UiClients = new Dictionary(); + } + + UiClients.Add(token.Key, new UiClientContext(token.Value)); } } - StopServer(); - } - } - - /// - /// Handler for GET requests to server - /// - /// - /// - private void Server_OnGet(object sender, HttpRequestEventArgs e) - { - try - { - var req = e.Request; - var res = e.Response; - res.ContentEncoding = Encoding.UTF8; - - res.AddHeader("Access-Control-Allow-Origin", "*"); - - var path = req.RawUrl; - - this.LogVerbose("GET Request received at path: {path}", path); - - // Call for user app to join the room with a token - if (path.StartsWith("/mc/api/ui/joinroom")) + if (UiClients.Count > 0) { - HandleJoinRequest(req, res); - } - // Call to get the server version - else if (path.StartsWith("/mc/api/version")) - { - HandleVersionRequest(res); - } - else if (path.StartsWith("/mc/app/logo")) - { - HandleImageRequest(req, res); - } - // Call to serve the user app - else if (path.StartsWith(_userAppBaseHref)) - { - HandleUserAppRequest(req, res, path); - } - else - { - // All other paths - res.StatusCode = 404; - res.Close(); - } - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Caught an exception in the OnGet handler", this); - } - } + Debug.LogMessage(LogEventLevel.Information, "Restored {uiClientCount} UiClients from secrets data", this, UiClients.Count); - private async void Server_OnPost(object sender, HttpRequestEventArgs e) - { - try - { - var req = e.Request; - var res = e.Response; - - res.AddHeader("Access-Control-Allow-Origin", "*"); - - var path = req.RawUrl; - var ip = req.RemoteEndPoint.Address.ToString(); - - this.LogVerbose("POST Request received at path: {path} from host {host}", path, ip); - - var body = new StreamReader(req.InputStream).ReadToEnd(); - - if (path.StartsWith("/mc/api/log")) - { - res.StatusCode = 200; - res.Close(); - - var logRequest = new HttpRequestMessage(HttpMethod.Post, $"http://{_parent.Config.DirectServer.Logging.Host}:{_parent.Config.DirectServer.Logging.Port}/logs") + foreach (var client in UiClients) { - Content = new StringContent(body, Encoding.UTF8, "application/json"), - }; + var key = client.Key; + var path = _wsPath + key; + var roomKey = client.Value.Token.RoomKey; - logRequest.Headers.Add("x-pepperdash-host", ip); + _server.AddWebSocketService(path, () => + { + var c = new UiClient(); + Debug.LogMessage(LogEventLevel.Debug, "Constructing UiClient with id: {key}", this, key); - await LogClient.SendAsync(logRequest); - - this.LogVerbose("Log data sent to {host}:{port}", _parent.Config.DirectServer.Logging.Host, _parent.Config.DirectServer.Logging.Port); - } - else - { - res.StatusCode = 404; - res.Close(); - } - } - catch (Exception ex) - { - this.LogException(ex, "Caught an exception in the OnPost handler"); - } - } - - private void Server_OnOptions(object sender, HttpRequestEventArgs e) - { - try - { - var res = e.Response; - - res.AddHeader("Access-Control-Allow-Origin", "*"); - res.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); - res.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); - - res.StatusCode = 200; - res.Close(); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Caught an exception in the OnPost handler", this); - } - } - - /// - /// Handle the request to join the room with a token - /// - /// - /// - private void HandleJoinRequest(HttpListenerRequest req, HttpListenerResponse res) - { - var qp = req.QueryString; - var token = qp["token"]; - - this.LogVerbose("Join Room Request with token: {token}", token); + c.Controller = _parent; + c.RoomKey = roomKey; + UiClients[key].SetClient(c); + return c; + }); - if (UiClients.TryGetValue(token, out UiClientContext clientContext)) - { - var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey); - - if (bridge != null) - { - res.StatusCode = 200; - res.ContentType = "application/json"; - - // Construct the response object - JoinResponse jRes = new JoinResponse - { - ClientId = token, - RoomKey = bridge.RoomKey, - SystemUuid = _parent.SystemUuid, - RoomUuid = _parent.SystemUuid, - Config = _parent.GetConfigWithPluginVersion(), - CodeExpires = new DateTime().AddYears(1), - UserCode = bridge.UserCode, - UserAppUrl = string.Format("http://{0}:{1}/mc/app", - CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), - Port), - EnableDebug = false - }; - - // Serialize to JSON and convert to Byte[] - var json = JsonConvert.SerializeObject(jRes); - var body = Encoding.UTF8.GetBytes(json); - res.ContentLength64 = body.LongLength; - - // Send the response - res.Close(body, true); - } - else - { - var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey); - res.StatusCode = 404; - res.ContentType = "application/json"; - this.LogVerbose("{message}", message); - var body = Encoding.UTF8.GetBytes(message); - res.ContentLength64 = body.LongLength; - res.Close(body, true); - + //_server.WebSocketServices.AddService(path, (c) => + //{ + // Debug.Console(2, this, "Constructing UiClient with id: {0}", key); + // c.Controller = _parent; + // c.RoomKey = roomKey; + // UiClients[key].SetClient(c); + //}); + } } } else { - var message = "Token invalid or has expired"; - res.StatusCode = 401; + Debug.LogMessage(LogEventLevel.Warning, "No secret found"); + } + + Debug.LogMessage(LogEventLevel.Debug, "{uiClientCount} UiClients restored from secrets data", this, UiClients.Count); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception retrieving secret", this); + } + } + + /// + /// Stores secrets to memory to persist through reboot + /// + public void UpdateSecret() + { + try + { + if (_secret == null) + { + Debug.LogMessage(LogEventLevel.Error, "Secret is null", this); + + _secret = new ServerTokenSecrets(string.Empty); + } + + _secret.Tokens.Clear(); + + foreach (var uiClientContext in UiClients) + { + _secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token); + } + + var serializedSecret = JsonConvert.SerializeObject(_secret); + + _secretProvider.SetSecret(SecretProviderKey, serializedSecret); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Exception updating secret", this); + } + } + + /// + /// Generates a new token based on validating a room key and grant code passed in. If valid, returns a token and adds a service to the server for that token's path + /// + /// + private void GenerateClientTokenFromConsole(string s) + { + if (s == "?" || string.IsNullOrEmpty(s)) + { + CrestronConsole.ConsoleCommandResponse(@"[RoomKey] [GrantCode] Validates the room key against the grant code and returns a token for use in a UI client"); + return; + } + + var values = s.Split(' '); + + if(values.Length < 2) + { + CrestronConsole.ConsoleCommandResponse("Invalid number of arguments. Please provide a room key and a grant code"); + return; + } + + + var roomKey = values[0]; + var grantCode = values[1]; + + var bridge = _parent.GetRoomBridge(roomKey); + + if (bridge == null) + { + CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find room with key: {0}", roomKey)); + return; + } + + var (token, path) = ValidateGrantCode(grantCode, bridge); + + if (token == null) + { + CrestronConsole.ConsoleCommandResponse("Grant Code is not valid"); + return; + } + + CrestronConsole.ConsoleCommandResponse($"Added new WebSocket UiClient service at path: {path}"); + CrestronConsole.ConsoleCommandResponse($"Token: {token}"); + } + + public (string, string) ValidateGrantCode(string grantCode, string roomKey) + { + var bridge = _parent.GetRoomBridge(roomKey); + + if (bridge == null) + { + this.LogWarning("Unable to find room with key: {roomKey}", roomKey); + return (null, null); + } + + return ValidateGrantCode(grantCode, bridge); + } + + public (string, string) ValidateGrantCode(string grantCode, MobileControlBridgeBase bridge) + { + // TODO: Authenticate grant code passed in + // For now, we just generate a random guid as the token and use it as the ClientId as well + var grantCodeIsValid = true; + + if (grantCodeIsValid) + { + if (_secret == null) + { + _secret = new ServerTokenSecrets(grantCode); + } + + return GenerateClientToken(bridge, ""); + } + else + { + return (null, null); + } + } + + public (string, string) GenerateClientToken(MobileControlBridgeBase bridge, string touchPanelKey = "") + { + var key = Guid.NewGuid().ToString(); + + var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey }; + + UiClients.Add(key, new UiClientContext(token)); + + var path = _wsPath + key; + + _server.AddWebSocketService(path, () => + { + var c = new UiClient(); + Debug.LogMessage(LogEventLevel.Verbose, "Constructing UiClient with id: {0}", this, key); + c.Controller = _parent; + c.RoomKey = bridge.RoomKey; + UiClients[key].SetClient(c); + return c; + }); + + Debug.LogMessage(LogEventLevel.Information, "Added new WebSocket UiClient service at path: {path}", this, path); + Debug.LogMessage(LogEventLevel.Information, "Token: {@token}", this, token); + + Debug.LogMessage(LogEventLevel.Verbose, "{serviceCount} websocket services present", this, _server.WebSocketServices.Count); + + UpdateSecret(); + + return (key, path); + } + + /// + /// Removes all clients from the server + /// + private void RemoveAllTokens(string s) + { + if (s == "?" || string.IsNullOrEmpty(s)) + { + CrestronConsole.ConsoleCommandResponse(@"Removes all clients from the server. To execute add 'confirm' to command"); + return; + } + + if (s != "confirm") + { + CrestronConsole.ConsoleCommandResponse(@"To remove all clients, add 'confirm' to the command"); + return; + } + + foreach (var client in UiClients) + { + if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive) + { + client.Value.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down"); + } + + var path = _wsPath + client.Key; + if (_server.RemoveWebSocketService(path)) + { + CrestronConsole.ConsoleCommandResponse(string.Format("Client removed with token: {0}", client.Key)); + } + else + { + CrestronConsole.ConsoleCommandResponse(string.Format("Unable to remove client with token : {0}", client.Key)); + } + } + + UiClients.Clear(); + + UpdateSecret(); + } + + /// + /// Removes a client with the specified token value + /// + /// + private void RemoveToken(string s) + { + if (s == "?" || string.IsNullOrEmpty(s)) + { + CrestronConsole.ConsoleCommandResponse(@"[token] Removes the client with the specified token value"); + return; + } + + var key = s; + + if (UiClients.ContainsKey(key)) + { + var uiClientContext = UiClients[key]; + + if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive) + { + uiClientContext.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Token removed from server"); + } + + var path = _wsPath + key; + if (_server.RemoveWebSocketService(path)) + { + UiClients.Remove(key); + + UpdateSecret(); + + CrestronConsole.ConsoleCommandResponse(string.Format("Client removed with token: {0}", key)); + } + else + { + CrestronConsole.ConsoleCommandResponse(string.Format("Unable to remove client with token : {0}", key)); + } + } + else + { + CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find client with token: {0}", key)); + } + } + + /// + /// Prints out info about current client IDs + /// + private void PrintClientInfo() + { + CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r"); + + CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClients.Count)); + + foreach (var client in UiClients) + { + CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key)); + } + } + + private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + { + foreach (var client in UiClients.Values) + { + if (client.Client != null && client.Client.Context.WebSocket.IsAlive) + { + client.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down"); + } + } + + StopServer(); + } + } + + /// + /// Handler for GET requests to server + /// + /// + /// + private void Server_OnGet(object sender, HttpRequestEventArgs e) + { + try + { + var req = e.Request; + var res = e.Response; + res.ContentEncoding = Encoding.UTF8; + + res.AddHeader("Access-Control-Allow-Origin", "*"); + + var path = req.RawUrl; + + this.LogVerbose("GET Request received at path: {path}", path); + + // Call for user app to join the room with a token + if (path.StartsWith("/mc/api/ui/joinroom")) + { + HandleJoinRequest(req, res); + } + // Call to get the server version + else if (path.StartsWith("/mc/api/version")) + { + HandleVersionRequest(res); + } + else if (path.StartsWith("/mc/app/logo")) + { + HandleImageRequest(req, res); + } + // Call to serve the user app + else if (path.StartsWith(_userAppBaseHref)) + { + HandleUserAppRequest(req, res, path); + } + else + { + // All other paths + res.StatusCode = 404; + res.Close(); + } + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Caught an exception in the OnGet handler", this); + } + } + + private async void Server_OnPost(object sender, HttpRequestEventArgs e) + { + try + { + var req = e.Request; + var res = e.Response; + + res.AddHeader("Access-Control-Allow-Origin", "*"); + + var path = req.RawUrl; + var ip = req.RemoteEndPoint.Address.ToString(); + + this.LogVerbose("POST Request received at path: {path} from host {host}", path, ip); + + var body = new StreamReader(req.InputStream).ReadToEnd(); + + if (path.StartsWith("/mc/api/log")) + { + res.StatusCode = 200; + res.Close(); + + var logRequest = new HttpRequestMessage(HttpMethod.Post, $"http://{_parent.Config.DirectServer.Logging.Host}:{_parent.Config.DirectServer.Logging.Port}/logs") + { + Content = new StringContent(body, Encoding.UTF8, "application/json"), + }; + + logRequest.Headers.Add("x-pepperdash-host", ip); + + await LogClient.SendAsync(logRequest); + + this.LogVerbose("Log data sent to {host}:{port}", _parent.Config.DirectServer.Logging.Host, _parent.Config.DirectServer.Logging.Port); + } + else + { + res.StatusCode = 404; + res.Close(); + } + } + catch (Exception ex) + { + this.LogException(ex, "Caught an exception in the OnPost handler"); + } + } + + private void Server_OnOptions(object sender, HttpRequestEventArgs e) + { + try + { + var res = e.Response; + + res.AddHeader("Access-Control-Allow-Origin", "*"); + res.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + res.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); + + res.StatusCode = 200; + res.Close(); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Caught an exception in the OnPost handler", this); + } + } + + /// + /// Handle the request to join the room with a token + /// + /// + /// + private void HandleJoinRequest(HttpListenerRequest req, HttpListenerResponse res) + { + var qp = req.QueryString; + var token = qp["token"]; + + this.LogVerbose("Join Room Request with token: {token}", token); + + + if (UiClients.TryGetValue(token, out UiClientContext clientContext)) + { + var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey); + + if (bridge != null) + { + res.StatusCode = 200; + res.ContentType = "application/json"; + + // Construct the response object + JoinResponse jRes = new JoinResponse + { + ClientId = token, + RoomKey = bridge.RoomKey, + SystemUuid = _parent.SystemUuid, + RoomUuid = _parent.SystemUuid, + Config = _parent.GetConfigWithPluginVersion(), + CodeExpires = new DateTime().AddYears(1), + UserCode = bridge.UserCode, + UserAppUrl = string.Format("http://{0}:{1}/mc/app", + CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), + Port), + EnableDebug = false + }; + + // Serialize to JSON and convert to Byte[] + var json = JsonConvert.SerializeObject(jRes); + var body = Encoding.UTF8.GetBytes(json); + res.ContentLength64 = body.LongLength; + + // Send the response + res.Close(body, true); + } + else + { + var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey); + res.StatusCode = 404; res.ContentType = "application/json"; this.LogVerbose("{message}", message); var body = Encoding.UTF8.GetBytes(message); res.ContentLength64 = body.LongLength; res.Close(body, true); + } } - - /// - /// Handles a server version request - /// - /// - private void HandleVersionRequest(HttpListenerResponse res) + else { - res.StatusCode = 200; + var message = "Token invalid or has expired"; + res.StatusCode = 401; res.ContentType = "application/json"; - var version = new Version() { ServerVersion = _parent.GetConfigWithPluginVersion().RuntimeInfo.PluginVersion }; - var message = JsonConvert.SerializeObject(version); this.LogVerbose("{message}", message); - var body = Encoding.UTF8.GetBytes(message); res.ContentLength64 = body.LongLength; res.Close(body, true); } + } - /// - /// Handler to return images requested by the user app - /// - /// - /// - private void HandleImageRequest(HttpListenerRequest req, HttpListenerResponse res) + /// + /// Handles a server version request + /// + /// + private void HandleVersionRequest(HttpListenerResponse res) + { + res.StatusCode = 200; + res.ContentType = "application/json"; + var version = new Version() { ServerVersion = _parent.GetConfigWithPluginVersion().RuntimeInfo.PluginVersion }; + var message = JsonConvert.SerializeObject(version); + this.LogVerbose("{message}", message); + + var body = Encoding.UTF8.GetBytes(message); + res.ContentLength64 = body.LongLength; + res.Close(body, true); + } + + /// + /// Handler to return images requested by the user app + /// + /// + /// + private void HandleImageRequest(HttpListenerRequest req, HttpListenerResponse res) + { + var path = req.RawUrl; + + Debug.LogMessage(LogEventLevel.Verbose, "Requesting Image: {0}", this, path); + + var imageBasePath = Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo" + Global.DirectorySeparator; + + var image = path.Split('/').Last(); + + var filePath = imageBasePath + image; + + Debug.LogMessage(LogEventLevel.Verbose, "Retrieving Image: {0}", this, filePath); + + if (File.Exists(filePath)) { - var path = req.RawUrl; - - Debug.LogMessage(LogEventLevel.Verbose, "Requesting Image: {0}", this, path); - - var imageBasePath = Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo" + Global.DirectorySeparator; - - var image = path.Split('/').Last(); - - var filePath = imageBasePath + image; - - Debug.LogMessage(LogEventLevel.Verbose, "Retrieving Image: {0}", this, filePath); - - if (File.Exists(filePath)) + if (filePath.EndsWith(".png")) { - if (filePath.EndsWith(".png")) - { - res.ContentType = "image/png"; - } - else if (filePath.EndsWith(".jpg")) - { - res.ContentType = "image/jpeg"; - } - else if (filePath.EndsWith(".gif")) - { - res.ContentType = "image/gif"; - } - else if (filePath.EndsWith(".svg")) - { - res.ContentType = "image/svg+xml"; - } - byte[] contents = File.ReadAllBytes(filePath); - res.ContentLength64 = contents.LongLength; - res.Close(contents, true); + res.ContentType = "image/png"; } - else + else if (filePath.EndsWith(".jpg")) { - res.StatusCode = (int)HttpStatusCode.NotFound; - res.Close(); + res.ContentType = "image/jpeg"; } - } - - /// - /// Handles requests to serve files for the Angular single page app - /// - /// - /// - /// - private void HandleUserAppRequest(HttpListenerRequest req, HttpListenerResponse res, string path) - { - this.LogVerbose("Requesting User app file"); - - string filePath = path.Split('?')[0]; - - // remove the token from the path if found - //string filePath = path.Replace(string.Format("?token={0}", token), ""); - - // if there's no file suffix strip any extra path data after the base href - if (filePath != _userAppBaseHref && !filePath.Contains(".") && (!filePath.EndsWith(_userAppBaseHref) || !filePath.EndsWith(_userAppBaseHref += "/"))) + else if (filePath.EndsWith(".gif")) { - var suffix = filePath.Substring(_userAppBaseHref.Length, filePath.Length - _userAppBaseHref.Length); - if (suffix != "/") - { - //Debug.Console(2, this, "Suffix: {0}", suffix); - filePath = filePath.Replace(suffix, ""); - } + res.ContentType = "image/gif"; } - - // swap the base href prefix for the file path prefix - filePath = filePath.Replace(_userAppBaseHref, _appPath); - - this.LogVerbose("filepath: {filePath}", filePath); - - - // append index.html if no specific file is specified - if (!filePath.Contains(".")) + else if (filePath.EndsWith(".svg")) { - if (filePath.EndsWith("/")) - { - filePath += "index.html"; - } - else - { - filePath += "/index.html"; - } + res.ContentType = "image/svg+xml"; } - - // Set ContentType based on file type - if (filePath.EndsWith(".html")) - { - this.LogVerbose("Client requesting User App"); - - res.ContentType = "text/html"; - } - else - { - if (path.EndsWith(".js")) - { - res.ContentType = "application/javascript"; - } - else if (path.EndsWith(".css")) - { - res.ContentType = "text/css"; - } - else if (path.EndsWith(".json")) - { - res.ContentType = "application/json"; - } - } - - this.LogVerbose("Attempting to serve file: {filePath}", filePath); - - var remoteIp = req.RemoteEndPoint.Address; - - // Check if the request is coming from the CS LAN and if so, send the CS config instead of the LAN config - if (csSubnetMask != null && csIpAddress != null && remoteIp.IsInSameSubnet(csIpAddress, csSubnetMask) && filePath.Contains(appConfigFileName)) - { - filePath = filePath.Replace(appConfigFileName, appConfigCsFileName); - } - - byte[] contents; - if (File.Exists(filePath)) - { - this.LogVerbose("File found: {filePath}", filePath); - contents = File.ReadAllBytes(filePath); - } - else - { - this.LogVerbose("File not found: {filePath}", filePath); - res.StatusCode = (int)HttpStatusCode.NotFound; - res.Close(); - return; - } - + byte[] contents = File.ReadAllBytes(filePath); res.ContentLength64 = contents.LongLength; res.Close(contents, true); } - - public void StopServer() + else { - this.LogVerbose("Stopping WebSocket Server"); - _server.Stop(CloseStatusCode.Normal, "Server Shutting Down"); + res.StatusCode = (int)HttpStatusCode.NotFound; + res.Close(); } + } - /// - /// Sends a message to all connectd clients - /// - /// - public void SendMessageToAllClients(string message) + /// + /// Handles requests to serve files for the Angular single page app + /// + /// + /// + /// + private void HandleUserAppRequest(HttpListenerRequest req, HttpListenerResponse res, string path) + { + this.LogVerbose("Requesting User app file"); + + string filePath = path.Split('?')[0]; + + // remove the token from the path if found + //string filePath = path.Replace(string.Format("?token={0}", token), ""); + + // if there's no file suffix strip any extra path data after the base href + if (filePath != _userAppBaseHref && !filePath.Contains(".") && (!filePath.EndsWith(_userAppBaseHref) || !filePath.EndsWith(_userAppBaseHref += "/"))) { - foreach (var clientContext in UiClients.Values) + var suffix = filePath.Substring(_userAppBaseHref.Length, filePath.Length - _userAppBaseHref.Length); + if (suffix != "/") { - if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) - { - clientContext.Client.Context.WebSocket.Send(message); - } + //Debug.Console(2, this, "Suffix: {0}", suffix); + filePath = filePath.Replace(suffix, ""); } } - /// - /// Sends a message to a specific client - /// - /// - /// - public void SendMessageToClient(object clientId, string message) + // swap the base href prefix for the file path prefix + filePath = filePath.Replace(_userAppBaseHref, _appPath); + + this.LogVerbose("filepath: {filePath}", filePath); + + + // append index.html if no specific file is specified + if (!filePath.Contains(".")) { - if (clientId == null) + if (filePath.EndsWith("/")) { - return; - } - - if (UiClients.TryGetValue((string)clientId, out UiClientContext clientContext)) - { - if (clientContext.Client != null) - { - var socket = clientContext.Client.Context.WebSocket; - - if (socket.IsAlive) - { - socket.Send(message); - } - } + filePath += "index.html"; } else { - this.LogWarning("Unable to find client with ID: {clientId}", clientId); + filePath += "/index.html"; + } + } + + // Set ContentType based on file type + if (filePath.EndsWith(".html")) + { + this.LogVerbose("Client requesting User App"); + + res.ContentType = "text/html"; + } + else + { + if (path.EndsWith(".js")) + { + res.ContentType = "application/javascript"; + } + else if (path.EndsWith(".css")) + { + res.ContentType = "text/css"; + } + else if (path.EndsWith(".json")) + { + res.ContentType = "application/json"; + } + } + + this.LogVerbose("Attempting to serve file: {filePath}", filePath); + + var remoteIp = req.RemoteEndPoint.Address; + + // Check if the request is coming from the CS LAN and if so, send the CS config instead of the LAN config + if (csSubnetMask != null && csIpAddress != null && remoteIp.IsInSameSubnet(csIpAddress, csSubnetMask) && filePath.Contains(appConfigFileName)) + { + filePath = filePath.Replace(appConfigFileName, appConfigCsFileName); + } + + byte[] contents; + if (File.Exists(filePath)) + { + this.LogVerbose("File found: {filePath}", filePath); + contents = File.ReadAllBytes(filePath); + } + else + { + this.LogVerbose("File not found: {filePath}", filePath); + res.StatusCode = (int)HttpStatusCode.NotFound; + res.Close(); + return; + } + + res.ContentLength64 = contents.LongLength; + res.Close(contents, true); + } + + public void StopServer() + { + this.LogVerbose("Stopping WebSocket Server"); + _server.Stop(CloseStatusCode.Normal, "Server Shutting Down"); + } + + /// + /// Sends a message to all connectd clients + /// + /// + public void SendMessageToAllClients(string message) + { + foreach (var clientContext in UiClients.Values) + { + if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) + { + clientContext.Client.Context.WebSocket.Send(message); } } } /// - /// Class to describe the server version info + /// Sends a message to a specific client /// - public class Version + /// + /// + public void SendMessageToClient(object clientId, string message) { - [JsonProperty("serverVersion")] - public string ServerVersion { get; set; } - - [JsonProperty("serverIsRunningOnProcessorHardware")] - public bool ServerIsRunningOnProcessorHardware { get; private set; } - - public Version() + if (clientId == null) { - ServerIsRunningOnProcessorHardware = true; - } - } - - /// - /// Represents an instance of a UiClient and the associated Token - /// - public class UiClientContext - { - public UiClient Client { get; private set; } - public JoinToken Token { get; private set; } - - public UiClientContext(JoinToken token) - { - Token = token; + return; } - public void SetClient(UiClient client) + if (UiClients.TryGetValue((string)clientId, out UiClientContext clientContext)) { - Client = client; + if (clientContext.Client != null) + { + var socket = clientContext.Client.Context.WebSocket; + + if (socket.IsAlive) + { + socket.Send(message); + } + } } - - } - - /// - /// Represents the data structure for the grant code and UiClient tokens to be stored in the secrets manager - /// - public class ServerTokenSecrets - { - public string GrantCode { get; set; } - - public Dictionary Tokens { get; set; } - - public ServerTokenSecrets(string grantCode) + else { - GrantCode = grantCode; - Tokens = new Dictionary(); + this.LogWarning("Unable to find client with ID: {clientId}", clientId); } } - - /// - /// Represents a join token with the associated properties - /// - public class JoinToken - { - public string Code { get; set; } - - public string RoomKey { get; set; } - - public string Uuid { get; set; } - - public string TouchpanelKey { get; set; } = ""; - - public string Token { get; set; } = null; - } - - /// - /// Represents the structure of the join response - /// - public class JoinResponse - { - [JsonProperty("clientId")] - public string ClientId { get; set; } - - [JsonProperty("roomKey")] - public string RoomKey { get; set; } - - [JsonProperty("systemUUid")] - public string SystemUuid { get; set; } - - [JsonProperty("roomUUid")] - public string RoomUuid { get; set; } - - [JsonProperty("config")] - public object Config { get; set; } - - [JsonProperty("codeExpires")] - public DateTime CodeExpires { get; set; } - - [JsonProperty("userCode")] - public string UserCode { get; set; } - - [JsonProperty("userAppUrl")] - public string UserAppUrl { get; set; } - - [JsonProperty("enableDebug")] - public bool EnableDebug { get; set; } - } +} + +/// +/// Class to describe the server version info +/// +public class Version +{ + [JsonProperty("serverVersion")] + public string ServerVersion { get; set; } + + [JsonProperty("serverIsRunningOnProcessorHardware")] + public bool ServerIsRunningOnProcessorHardware { get; private set; } + + public Version() + { + ServerIsRunningOnProcessorHardware = true; + } +} + +/// +/// Represents an instance of a UiClient and the associated Token +/// +public class UiClientContext +{ + public UiClient Client { get; private set; } + public JoinToken Token { get; private set; } + + public UiClientContext(JoinToken token) + { + Token = token; + } + + public void SetClient(UiClient client) + { + Client = client; + } + +} + +/// +/// Represents the data structure for the grant code and UiClient tokens to be stored in the secrets manager +/// +public class ServerTokenSecrets +{ + public string GrantCode { get; set; } + + public Dictionary Tokens { get; set; } + + public ServerTokenSecrets(string grantCode) + { + GrantCode = grantCode; + Tokens = new Dictionary(); + } +} + +/// +/// Represents a join token with the associated properties +/// +public class JoinToken +{ + public string Code { get; set; } + + public string RoomKey { get; set; } + + public string Uuid { get; set; } + + public string TouchpanelKey { get; set; } = ""; + + public string Token { get; set; } = null; +} + +/// +/// Represents the structure of the join response +/// +public class JoinResponse +{ + [JsonProperty("clientId")] + public string ClientId { get; set; } + + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("systemUUid")] + public string SystemUuid { get; set; } + + [JsonProperty("roomUUid")] + public string RoomUuid { get; set; } + + [JsonProperty("config")] + public object Config { get; set; } + + [JsonProperty("codeExpires")] + public DateTime CodeExpires { get; set; } + + [JsonProperty("userCode")] + public string UserCode { get; set; } + + [JsonProperty("userAppUrl")] + public string UserAppUrl { get; set; } + + [JsonProperty("enableDebug")] + public bool EnableDebug { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs index eb1cf7a1..5b30fab1 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs @@ -11,135 +11,134 @@ using WebSocketSharp.Server; using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; -namespace PepperDash.Essentials.WebSocketServer -{ - /// - /// Represents the behaviour to associate with a UiClient for WebSocket communication - /// - public class UiClient : WebSocketBehavior +namespace PepperDash.Essentials.WebSocketServer; + +/// +/// Represents the behaviour to associate with a UiClient for WebSocket communication +/// +public class UiClient : WebSocketBehavior +{ + public MobileControlSystemController Controller { get; set; } + + public string RoomKey { get; set; } + + private string _clientId; + + private DateTime _connectionTime; + + public TimeSpan ConnectedDuration { - public MobileControlSystemController Controller { get; set; } - - public string RoomKey { get; set; } - - private string _clientId; - - private DateTime _connectionTime; - - public TimeSpan ConnectedDuration + get { - get + if (Context.WebSocket.IsAlive) { - if (Context.WebSocket.IsAlive) - { - return DateTime.Now - _connectionTime; - } - else - { - return new TimeSpan(0); - } + return DateTime.Now - _connectionTime; } - } - - public UiClient() - { - - } - - protected override void OnOpen() - { - base.OnOpen(); - - var url = Context.WebSocket.Url; - Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, url); - - var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)"); - - if (!match.Success) + else { - _connectionTime = DateTime.Now; - return; + return new TimeSpan(0); } - - var clientId = match.Groups[1].Value; - _clientId = clientId; - - if (Controller == null) - { - Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Controller is null"); - _connectionTime = DateTime.Now; - } - - var clientJoinedMessage = new MobileControlMessage - { - Type = "/system/clientJoined", - Content = JToken.FromObject(new - { - clientId, - roomKey = RoomKey, - }) - }; - - Controller.HandleClientMessage(JsonConvert.SerializeObject(clientJoinedMessage)); - - var bridge = Controller.GetRoomBridge(RoomKey); - - if (bridge == null) return; - - SendUserCodeToClient(bridge, clientId); - - bridge.UserCodeChanged -= Bridge_UserCodeChanged; - bridge.UserCodeChanged += Bridge_UserCodeChanged; - - // TODO: Future: Check token to see if there's already an open session using that token and reject/close the session - } - - private void Bridge_UserCodeChanged(object sender, EventArgs e) - { - SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId); - } - - private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId) - { - var content = new - { - userCode = bridge.UserCode, - qrUrl = bridge.QrCodeUrl, - }; - - var message = new MobileControlMessage - { - Type = "/system/userCodeChanged", - ClientId = clientId, - Content = JToken.FromObject(content) - }; - - Controller.SendMessageObjectToDirectClient(message); - } - - protected override void OnMessage(MessageEventArgs e) - { - base.OnMessage(e); - - if (e.IsText && e.Data.Length > 0 && Controller != null) - { - // Forward the message to the controller to be put on the receive queue - Controller.HandleClientMessage(e.Data); - } - } - - protected override void OnClose(CloseEventArgs e) - { - base.OnClose(e); - - Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason); - } - - protected override void OnError(ErrorEventArgs e) - { - base.OnError(e); - - Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message); } } + + public UiClient() + { + + } + + protected override void OnOpen() + { + base.OnOpen(); + + var url = Context.WebSocket.Url; + Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, url); + + var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)"); + + if (!match.Success) + { + _connectionTime = DateTime.Now; + return; + } + + var clientId = match.Groups[1].Value; + _clientId = clientId; + + if (Controller == null) + { + Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Controller is null"); + _connectionTime = DateTime.Now; + } + + var clientJoinedMessage = new MobileControlMessage + { + Type = "/system/clientJoined", + Content = JToken.FromObject(new + { + clientId, + roomKey = RoomKey, + }) + }; + + Controller.HandleClientMessage(JsonConvert.SerializeObject(clientJoinedMessage)); + + var bridge = Controller.GetRoomBridge(RoomKey); + + if (bridge == null) return; + + SendUserCodeToClient(bridge, clientId); + + bridge.UserCodeChanged -= Bridge_UserCodeChanged; + bridge.UserCodeChanged += Bridge_UserCodeChanged; + + // TODO: Future: Check token to see if there's already an open session using that token and reject/close the session + } + + private void Bridge_UserCodeChanged(object sender, EventArgs e) + { + SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId); + } + + private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId) + { + var content = new + { + userCode = bridge.UserCode, + qrUrl = bridge.QrCodeUrl, + }; + + var message = new MobileControlMessage + { + Type = "/system/userCodeChanged", + ClientId = clientId, + Content = JToken.FromObject(content) + }; + + Controller.SendMessageObjectToDirectClient(message); + } + + protected override void OnMessage(MessageEventArgs e) + { + base.OnMessage(e); + + if (e.IsText && e.Data.Length > 0 && Controller != null) + { + // Forward the message to the controller to be put on the receive queue + Controller.HandleClientMessage(e.Data); + } + } + + protected override void OnClose(CloseEventArgs e) + { + base.OnClose(e); + + Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason); + } + + protected override void OnError(ErrorEventArgs e) + { + base.OnError(e); + + Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message); + } } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs index 1b797767..a238dc27 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs @@ -1,37 +1,34 @@ using Newtonsoft.Json; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.WebSocketServer +namespace PepperDash.Essentials.WebSocketServer; + +internal class WebSocketServerSecretProvider : CrestronLocalSecretsProvider { - internal class WebSocketServerSecretProvider : CrestronLocalSecretsProvider + public WebSocketServerSecretProvider(string key) + : base(key) { - public WebSocketServerSecretProvider(string key) - : base(key) - { - Key = key; - } + Key = key; + } +} + +public class WebSocketServerSecret : ISecret +{ + public ISecretProvider Provider { get; private set; } + + public string Key { get; private set; } + + public object Value { get; private set; } + + public WebSocketServerSecret(string key, object value, ISecretProvider provider) + { + Key = key; + Value = JsonConvert.SerializeObject(value); + Provider = provider; + } + + public ServerTokenSecrets DeserializeSecret() + { + return JsonConvert.DeserializeObject(Value.ToString()); } - - public class WebSocketServerSecret : ISecret - { - public ISecretProvider Provider { get; private set; } - - public string Key { get; private set; } - - public object Value { get; private set; } - - public WebSocketServerSecret(string key, object value, ISecretProvider provider) - { - Key = key; - Value = JsonConvert.SerializeObject(value); - Provider = provider; - } - - public ServerTokenSecrets DeserializeSecret() - { - return JsonConvert.DeserializeObject(Value.ToString()); - } - } - - } diff --git a/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 9c78c4aa..b6533089 100644 --- a/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -3,38 +3,37 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Fusion; + +public class EssentialsHuddleSpaceFusionSystemControllerBase { - public class EssentialsHuddleSpaceFusionSystemControllerBase + private ClientWebSocket _webSocket; + + public EssentialsHuddleSpaceFusionSystemControllerBase() { - private ClientWebSocket _webSocket; + _webSocket = new ClientWebSocket(); + } - public EssentialsHuddleSpaceFusionSystemControllerBase() - { - _webSocket = new ClientWebSocket(); - } + public async Task ConnectAsync(Uri uri) + { + await _webSocket.ConnectAsync(uri, CancellationToken.None); + } - public async Task ConnectAsync(Uri uri) - { - await _webSocket.ConnectAsync(uri, CancellationToken.None); - } + public async Task SendAsync(string message) + { + var buffer = System.Text.Encoding.UTF8.GetBytes(message); + await _webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None); + } - public async Task SendAsync(string message) - { - var buffer = System.Text.Encoding.UTF8.GetBytes(message); - await _webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None); - } + public async Task ReceiveAsync() + { + var buffer = new byte[1024]; + var result = await _webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count); + } - public async Task ReceiveAsync() - { - var buffer = new byte[1024]; - var result = await _webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); - return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count); - } - - public async Task CloseAsync() - { - await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); - } + public async Task CloseAsync() + { + await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } } diff --git a/src/PepperDash.Essentials/HttpLogoServer.cs b/src/PepperDash.Essentials/HttpLogoServer.cs index 1c7a4783..174ebd7e 100644 --- a/src/PepperDash.Essentials/HttpLogoServer.cs +++ b/src/PepperDash.Essentials/HttpLogoServer.cs @@ -7,118 +7,117 @@ using Crestron.SimplSharp.Net.Http; using PepperDash.Core; using Serilog.Events; -namespace PepperDash.Essentials +namespace PepperDash.Essentials; + +public class HttpLogoServer { - public class HttpLogoServer + /// + /// + /// + readonly HttpServer _server; + + /// + /// + /// + readonly string _fileDirectory; + + /// + /// + /// + public static Dictionary ExtensionContentTypes; + + /// + /// + /// + /// + /// + public HttpLogoServer(int port, string directory) { - /// - /// - /// - readonly HttpServer _server; - - /// - /// - /// - readonly string _fileDirectory; - - /// - /// - /// - public static Dictionary ExtensionContentTypes; - - /// - /// - /// - /// - /// - public HttpLogoServer(int port, string directory) - { - ExtensionContentTypes = new Dictionary + ExtensionContentTypes = new Dictionary { - //{ ".css", "text/css" }, - //{ ".htm", "text/html" }, - //{ ".html", "text/html" }, + //{ ".css", "text/css" }, + //{ ".htm", "text/html" }, + //{ ".html", "text/html" }, { ".jpg", "image/jpeg" }, { ".jpeg", "image/jpeg" }, - //{ ".js", "application/javascript" }, - //{ ".json", "application/json" }, - //{ ".map", "application/x-navimap" }, + //{ ".js", "application/javascript" }, + //{ ".json", "application/json" }, + //{ ".map", "application/x-navimap" }, { ".pdf", "application/pdf" }, { ".png", "image/png" }, - //{ ".txt", "text/plain" }, + //{ ".txt", "text/plain" }, }; - _server = new HttpServer {Port = port}; - _fileDirectory = directory; - _server.OnHttpRequest += Server_OnHttpRequest; - _server.Open(); + _server = new HttpServer {Port = port}; + _fileDirectory = directory; + _server.OnHttpRequest += Server_OnHttpRequest; + _server.Open(); - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - } + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + } - /// - /// - /// - void Server_OnHttpRequest(object sender, OnHttpRequestArgs args) + /// + /// + /// + void Server_OnHttpRequest(object sender, OnHttpRequestArgs args) + { + var path = args.Request.Path; + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "HTTP Request with path: '{requestPath:l}'", args.Request.Path); + + try { - var path = args.Request.Path; - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "HTTP Request with path: '{requestPath:l}'", args.Request.Path); - - try + if (File.Exists(_fileDirectory + path)) { - if (File.Exists(_fileDirectory + path)) - { - var filePath = path.Replace('/', '\\'); - var localPath = string.Format(@"{0}{1}", _fileDirectory, filePath); + var filePath = path.Replace('/', '\\'); + var localPath = string.Format(@"{0}{1}", _fileDirectory, filePath); - Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server attempting to find file: '{localPath:l}'", localPath); - if (File.Exists(localPath)) - { - args.Response.Header.ContentType = GetContentType(new FileInfo(localPath).Extension); - args.Response.ContentStream = new FileStream(localPath, FileMode.Open, FileAccess.Read); - } - else - { - Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server Cannot find file '{localPath:l}'", localPath); - args.Response.ContentString = string.Format("Not found: '{0}'", filePath); - args.Response.Code = 404; - } + Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server attempting to find file: '{localPath:l}'", localPath); + if (File.Exists(localPath)) + { + args.Response.Header.ContentType = GetContentType(new FileInfo(localPath).Extension); + args.Response.ContentStream = new FileStream(localPath, FileMode.Open, FileAccess.Read); } else { - Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server: '{file:l}' does not exist", _fileDirectory + path); - args.Response.ContentString = string.Format("Not found: '{0}'", _fileDirectory + path); + Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server Cannot find file '{localPath:l}'", localPath); + args.Response.ContentString = string.Format("Not found: '{0}'", filePath); args.Response.Code = 404; } } - catch (Exception ex) + else { - Debug.LogMessage(LogEventLevel.Error, "Exception getting file: {exception}", ex.Message, ex.StackTrace); - Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", ex.StackTrace); - - args.Response.Code = 400; - args.Response.ContentString = string.Format("invalid request"); + Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server: '{file:l}' does not exist", _fileDirectory + path); + args.Response.ContentString = string.Format("Not found: '{0}'", _fileDirectory + path); + args.Response.Code = 404; } } - - /// - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + catch (Exception ex) { - if (programEventType == eProgramStatusEventType.Stopping) - _server.Close(); - } + Debug.LogMessage(LogEventLevel.Error, "Exception getting file: {exception}", ex.Message, ex.StackTrace); + Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", ex.StackTrace); - /// - /// - /// - /// - /// - public static string GetContentType(string extension) - { - var type = ExtensionContentTypes.ContainsKey(extension) ? ExtensionContentTypes[extension] : "text/plain"; - return type; + args.Response.Code = 400; + args.Response.ContentString = string.Format("invalid request"); } } + + /// + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + _server.Close(); + } + + /// + /// + /// + /// + /// + public static string GetContentType(string extension) + { + var type = ExtensionContentTypes.ContainsKey(extension) ? ExtensionContentTypes[extension] : "text/plain"; + return type; + } } \ No newline at end of file