diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 265a150e..0af60e3d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -60,7 +60,7 @@ jobs: - name: Build Solution shell: powershell run: | - Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder:v1.4.1 c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)" + Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)" # Zip up the output files as needed - name: Zip Build Output shell: powershell diff --git a/.gitmodules b/.gitmodules index 0abbfb4e..2d6bfa38 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "essentials-framework/pepperdashcore-builds"] - path = essentials-framework/pepperdashcore-builds - url = https://github.com/ndorin/PepperDashCore-Builds.git [submodule "Essentials-Template-UI"] path = Essentials-Template-UI url = https://github.com/PepperDash/Essentials-Template-UI.git diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 8803dc6c..9802c176 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -327,7 +327,11 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(new PepperDash.Essentials.Core.Devices.CrestronProcessor("processor")); // Add global System Monitor device - DeviceManager.AddDevice(new PepperDash.Essentials.Core.Monitoring.SystemMonitorController("systemMonitor")); + if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) + { + DeviceManager.AddDevice( + new PepperDash.Essentials.Core.Monitoring.SystemMonitorController("systemMonitor")); + } foreach (var devConf in ConfigReader.ConfigObject.Devices) { diff --git a/PepperDashEssentials/Example Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json b/PepperDashEssentials/Example Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json index f66add0c..e3d40f4a 100644 --- a/PepperDashEssentials/Example Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json +++ b/PepperDashEssentials/Example Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json @@ -225,6 +225,14 @@ "2": "Output 2", "3": "Output 3", "4": "Output 4" + }, + "inputSlotSupportsHdcp2":{ + "1": "false", + "2": "false", + "3": "false", + "4": "false", + "5": "false", + "6": "false" } } }, diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index ed178abc..cd8062ce 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -75,10 +75,6 @@ False ..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll - - False - ..\essentials-framework\Essentials DM\Essentials_DM\bin\PepperDash_Essentials_DM.dll - False ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll @@ -215,6 +211,10 @@ {892B761C-E479-44CE-BD74-243E9214AF13} Essentials Devices Common + + {9199CE8A-0C9F-4952-8672-3EED798B284F} + PepperDash_Essentials_DM + diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index 20c8ae3d..97c1775e 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -13,6 +13,7 @@ using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.AudioCodec; +using PepperDash_Essentials_Core.DeviceTypeInterfaces; namespace PepperDash.Essentials { @@ -313,7 +314,7 @@ namespace PepperDash.Essentials VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate(); - VideoCodec.IsReadyChange += (o, a) => this.SetCodecExternalSources(); + VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); }; if (AudioCodec != null) AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate(); @@ -703,29 +704,36 @@ namespace PepperDash.Essentials { return; } - else - { - string codecTieLine = ""; - codecTieLine = ConfigReader.ConfigObject.TieLines.SingleOrDefault(x => x.DestinationKey == VideoCodec.Key).DestinationPort; - videoCodecWithExternalSwitching.ClearExternalSources(); - videoCodecWithExternalSwitching.RunRouteAction = RunRouteAction; - var srcList = ConfigReader.ConfigObject.SourceLists.SingleOrDefault(x => x.Key == SourceListKey).Value.OrderBy(kv => kv.Value.Order); ; - foreach (var kvp in srcList) - { - var srcConfig = kvp.Value; + string codecTieLine = ConfigReader.ConfigObject.TieLines.SingleOrDefault(x => x.DestinationKey == VideoCodec.Key).DestinationPort; + videoCodecWithExternalSwitching.ClearExternalSources(); + videoCodecWithExternalSwitching.RunRouteAction = RunRouteAction; + var srcList = ConfigReader.ConfigObject.SourceLists.SingleOrDefault(x => x.Key == SourceListKey).Value.OrderBy(kv => kv.Value.Order); ; - if (kvp.Key != DefaultCodecRouteString && kvp.Key != "roomOff") - { + foreach (var kvp in srcList) + { + var srcConfig = kvp.Value; - videoCodecWithExternalSwitching.AddExternalSource(codecTieLine, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop); - videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready); + if (kvp.Key != DefaultCodecRouteString && kvp.Key != "roomOff") + { + + videoCodecWithExternalSwitching.AddExternalSource(codecTieLine, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop); + videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready); - } - } - } + } + } } + + private void SetCodecBranding() + { + var vcWithBranding = VideoCodec as IHasBranding; + + if (vcWithBranding == null) return; + + Debug.Console(1, this, "Setting Codec Branding"); + vcWithBranding.InitializeBranding(Key); + } #region IPrivacy Members diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs index ec6c2ebe..151b5461 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.EthernetCommunication; using Newtonsoft.Json; @@ -82,9 +84,9 @@ namespace PepperDash.Essentials.Core.Bridges protected Dictionary JoinMaps { get; private set; } - public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc { get; private set; } + public BasicTriList Eisc { get; private set; } - public EiscApiAdvanced(DeviceConfig dc) : + public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : base(dc.Key) { JoinMaps = new Dictionary(); @@ -92,44 +94,52 @@ namespace PepperDash.Essentials.Core.Bridges PropertiesConfig = dc.Properties.ToObject(); //PropertiesConfig = JsonConvert.DeserializeObject(dc.Properties.ToString()); - Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(PropertiesConfig.Control.IpIdInt, PropertiesConfig.Control.TcpSshProperties.Address, Global.ControlSystem); + Eisc = eisc; Eisc.SigChange += Eisc_SigChange; - AddPostActivationAction( () => + AddPostActivationAction(LinkDevices); + } + + private void LinkDevices() + { + Debug.Console(1, this, "Linking Devices..."); + + foreach (var d in PropertiesConfig.Devices) { - Debug.Console(1, this, "Linking Devices..."); + var device = DeviceManager.GetDeviceForKey(d.DeviceKey); - foreach (var d in PropertiesConfig.Devices) + if (device == null) { - var device = DeviceManager.GetDeviceForKey(d.DeviceKey); - - if (device == null) continue; - - Debug.Console(1, this, "Linking Device: '{0}'", device.Key); - - if (!typeof (IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType())) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, - "{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.", - device.Key); - continue; - } - - var bridge = device as IBridgeAdvanced; - if (bridge != null) bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); + continue; } - var registerResult = Eisc.Register(); + Debug.Console(1, this, "Linking Device: '{0}'", device.Key); - if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) + if (!typeof (IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType())) { - Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Registration result: {0}", registerResult); - return; + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, + "{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.", + device.Key); + continue; } - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful"); - }); + var bridge = device as IBridgeAdvanced; + if (bridge != null) + { + bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); + } + } + + var registerResult = Eisc.Register(); + + if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) + { + Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Registration result: {0}", registerResult); + return; + } + + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful"); } /// @@ -152,7 +162,7 @@ namespace PepperDash.Essentials.Core.Bridges /// /// Prints all the join maps on this bridge /// - public void PrintJoinMaps() + public virtual void PrintJoinMaps() { Debug.Console(0, this, "Join Maps for EISC IPID: {0}", Eisc.ID.ToString("X")); @@ -247,7 +257,7 @@ namespace PepperDash.Essentials.Core.Bridges /// /// /// - void Eisc_SigChange(object currentDevice, SigEventArgs args) + protected void Eisc_SigChange(object currentDevice, SigEventArgs args) { try { @@ -299,15 +309,34 @@ namespace PepperDash.Essentials.Core.Bridges { public EiscApiAdvancedFactory() { - TypeNames = new List { "eiscapiadv", "eiscapiadvanced" }; + TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "vceiscapiadv", "vceiscapiadvanced" }; } public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.Console(1, "Factory Attempting to create new EiscApiAdvanced Device"); - return new EiscApiAdvanced(dc); - + var controlProperties = CommFactory.GetControlPropertiesConfig(dc); + + switch (dc.Type.ToLower()) + { + case "eiscapiadv": + case "eiscapiadvanced": + { + var eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt, + controlProperties.TcpSshProperties.Address, Global.ControlSystem); + return new EiscApiAdvanced(dc, eisc); + } + case "vceiscapiadv": + case "vceiscapiadvanced": + { + var eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, InitialParametersClass.RoomId, + Global.ControlSystem); + return new EiscApiAdvanced(dc, eisc); + } + default: + return null; + } } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs new file mode 100644 index 00000000..8054a077 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -0,0 +1,811 @@ +using System; +using PepperDash.Essentials.Core; + +namespace PepperDash_Essentials_Core.Bridges.JoinMaps +{ + public class VideoCodecControllerJoinMap : JoinMapBaseAdvanced + { + #region Status + + [JoinName("IsOnline")] public JoinDataComplete IsOnline = + new JoinDataComplete(new JoinData {JoinNumber = 1, JoinSpan = 1}, + new JoinMetadata + { + Description = "Device is Online", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + #endregion + + [JoinName("CallDirection")] public JoinDataComplete CallDirection = + new JoinDataComplete(new JoinData {JoinNumber = 22, JoinSpan = 1}, + new JoinMetadata + { + Description = "Current Call Direction", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CameraLayout")] public JoinDataComplete CameraLayout = + new JoinDataComplete(new JoinData {JoinNumber = 142, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Layout Toggle", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraLayoutStringFb")] public JoinDataComplete CameraLayoutStringFb = + new JoinDataComplete(new JoinData {JoinNumber = 141, JoinSpan = 1}, + new JoinMetadata + { + Description = "Current Layout Fb", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [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("CameraNumberSelect")] public JoinDataComplete CameraNumberSelect = + new JoinDataComplete(new JoinData {JoinNumber = 60, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Number Select/FB", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("CameraPanLeft")] public JoinDataComplete CameraPanLeft = + new JoinDataComplete(new JoinData {JoinNumber = 113, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Pan Left", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraPanRight")] public JoinDataComplete CameraPanRight = + new JoinDataComplete(new JoinData {JoinNumber = 114, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Pan Right", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraPresetNames")] public JoinDataComplete CameraPresetNames = + new JoinDataComplete(new JoinData {JoinNumber = 121, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Preset Names - XSIG, max of 15", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CameraPresetSelect")] public JoinDataComplete CameraPresetSelect = + new JoinDataComplete(new JoinData {JoinNumber = 121, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Preset Select", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("CameraPresetSave")] public JoinDataComplete CameraPresetSave = + new JoinDataComplete(new JoinData {JoinNumber = 121, JoinSpan = 1}, + new JoinMetadata + { + Description = "Save Selected Preset", + 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("CameraSupportsAutoMode")] public JoinDataComplete CameraSupportsAutoMode = + new JoinDataComplete(new JoinData {JoinNumber = 143, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Supports Auto Mode FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + 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.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.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraTiltUp")] public JoinDataComplete CameraTiltUp = + new JoinDataComplete(new JoinData {JoinNumber = 111, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Tilt Up", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraZoomIn")] public JoinDataComplete CameraZoomIn = + new JoinDataComplete(new JoinData {JoinNumber = 115, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Zoom In", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CameraZoomOut")] public JoinDataComplete CameraZoomOut = + new JoinDataComplete(new JoinData {JoinNumber = 116, JoinSpan = 1}, + new JoinMetadata + { + Description = "Camera Zoom Out", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CurrentCallName")] public JoinDataComplete CurrentCallData = + new JoinDataComplete(new JoinData {JoinNumber = 2, JoinSpan = 1}, + new JoinMetadata + { + Description = "Current Call Data - XSIG", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [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("CurrentParticipants")] public JoinDataComplete CurrentParticipants = + new JoinDataComplete(new JoinData {JoinNumber = 151, JoinSpan = 1}, + new JoinMetadata() + { + Description = "Current Participants XSig", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("CurrentSource")] public JoinDataComplete CurrentSource = + new JoinDataComplete(new JoinData {JoinNumber = 201, JoinSpan = 1}, + new JoinMetadata + { + Description = "Current Source", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DialMeeting1")] public JoinDataComplete DialMeeting1 = + new JoinDataComplete(new JoinData {JoinNumber = 161, JoinSpan = 1}, + new JoinMetadata + { + Description = "Join first meeting", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialMeeting2")] + public JoinDataComplete DialMeeting2 = + new JoinDataComplete(new JoinData { JoinNumber = 162, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Join second meeting", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialMeeting3")] + public JoinDataComplete DialMeeting3 = + new JoinDataComplete(new JoinData { JoinNumber = 163, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Join third meeting", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + 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.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryEntries")] public JoinDataComplete DirectoryEntries = + new JoinDataComplete(new JoinData {JoinNumber = 101, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory Entries - XSig, 255 entries", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectoryEntryIsContact")] public JoinDataComplete DirectoryEntryIsContact = + new JoinDataComplete(new JoinData {JoinNumber = 101, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory Selected Entry Is Contact FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryEntrySelectedName")] public JoinDataComplete DirectoryEntrySelectedName = + new JoinDataComplete(new JoinData {JoinNumber = 356, JoinSpan = 1}, + new JoinMetadata + { + Description = "Selected Directory Entry Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + 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.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectoryFolderBack")] public JoinDataComplete DirectoryFolderBack = + new JoinDataComplete(new JoinData {JoinNumber = 105, JoinSpan = 1}, + new JoinMetadata + { + Description = "Go back one directory level", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectoryHasChanged")] public JoinDataComplete DirectoryHasChanged = + new JoinDataComplete(new JoinData {JoinNumber = 103, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory has changed FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + 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.ToSIMPL, + 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("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("DirectoryRowCount")] public JoinDataComplete DirectoryRowCount = + new JoinDataComplete(new JoinData {JoinNumber = 101, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory Row Count FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("DirectorySearchBusy")] public JoinDataComplete DirectorySearchBusy = + new JoinDataComplete(new JoinData {JoinNumber = 100, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory Search Busy FB", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DirectorySearchString")] public JoinDataComplete DirectorySearchString = + new JoinDataComplete(new JoinData {JoinNumber = 100, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory Search String", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("DirectorySelectRow")] public JoinDataComplete DirectorySelectRow = + new JoinDataComplete(new JoinData {JoinNumber = 101, JoinSpan = 1}, + new JoinMetadata + { + Description = "Directory Select Row", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("DirectorySelectedFolderName")] public JoinDataComplete DirectorySelectedFolderName = + new JoinDataComplete(new JoinData {JoinNumber = 358, JoinSpan = 1}, + new JoinMetadata + { + Description = "Selected Directory Folder Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("0")] public JoinDataComplete Dtmf0 = + new JoinDataComplete(new JoinData {JoinNumber = 20, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 0", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("1")] public JoinDataComplete Dtmf1 = + new JoinDataComplete(new JoinData {JoinNumber = 11, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 1", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("2")] public JoinDataComplete Dtmf2 = + new JoinDataComplete(new JoinData {JoinNumber = 12, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 2", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("3")] public JoinDataComplete Dtmf3 = + new JoinDataComplete(new JoinData {JoinNumber = 13, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 3", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("4")] public JoinDataComplete Dtmf4 = + new JoinDataComplete(new JoinData {JoinNumber = 14, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 4", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("5")] public JoinDataComplete Dtmf5 = + new JoinDataComplete(new JoinData {JoinNumber = 15, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 5", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("6")] public JoinDataComplete Dtmf6 = + new JoinDataComplete(new JoinData {JoinNumber = 16, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 6", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("7")] public JoinDataComplete Dtmf7 = + new JoinDataComplete(new JoinData {JoinNumber = 17, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 7", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("8")] public JoinDataComplete Dtmf8 = + new JoinDataComplete(new JoinData {JoinNumber = 18, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 8", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("9")] public JoinDataComplete Dtmf9 = + new JoinDataComplete(new JoinData {JoinNumber = 19, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF 9", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("#")] public JoinDataComplete DtmfPound = + new JoinDataComplete(new JoinData {JoinNumber = 22, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF #", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("*")] public JoinDataComplete DtmfStar = + new JoinDataComplete(new JoinData {JoinNumber = 21, JoinSpan = 1}, + new JoinMetadata + { + Description = "DTMF *", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("EndCall")] public JoinDataComplete EndCall = + new JoinDataComplete(new JoinData {JoinNumber = 24, JoinSpan = 1}, + new JoinMetadata + { + Description = "Hang Up", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("HookState")] public JoinDataComplete HookState = + new JoinDataComplete(new JoinData {JoinNumber = 31, JoinSpan = 1}, + new JoinMetadata + { + Description = "Current Hook State", + 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.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingCall")] public JoinDataComplete IncomingCall = + new JoinDataComplete(new JoinData {JoinNumber = 50, JoinSpan = 1}, + new JoinMetadata + { + Description = "Incoming Call", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("IncomingCallName")] public JoinDataComplete IncomingCallName = + new JoinDataComplete(new JoinData {JoinNumber = 51, JoinSpan = 1}, + new JoinMetadata + { + Description = "Incoming Call Name", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("IncomingCallNumber")] public JoinDataComplete IncomingCallNumber = + new JoinDataComplete(new JoinData {JoinNumber = 52, JoinSpan = 1}, + new JoinMetadata + { + Description = "Incoming Call Number", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("IncomingReject")] public JoinDataComplete IncomingReject = + new JoinDataComplete(new JoinData {JoinNumber = 52, JoinSpan = 1}, + new JoinMetadata + { + Description = "Reject Incoming Call", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + + [JoinName("ManualDial")] public JoinDataComplete ManualDial = + new JoinDataComplete(new JoinData {JoinNumber = 71, JoinSpan = 1}, + new JoinMetadata + { + Description = "Dial manual string", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("Meeting Count Fb")] public JoinDataComplete MeetingCount = + new JoinDataComplete(new JoinData {JoinNumber = 161, JoinSpan = 1}, + new JoinMetadata + { + Description = "Meeting Count", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("MicMuteOff")] public JoinDataComplete MicMuteOff = + new JoinDataComplete(new JoinData {JoinNumber = 172, JoinSpan = 1}, + new JoinMetadata + { + Description = "Mic Mute Off", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("MicMuteOn")] public JoinDataComplete MicMuteOn = + new JoinDataComplete(new JoinData {JoinNumber = 171, JoinSpan = 1}, + new JoinMetadata + { + Description = "Mic Mute On", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("MicMuteToggle")] public JoinDataComplete MicMuteToggle = + new JoinDataComplete(new JoinData {JoinNumber = 173, JoinSpan = 1}, + new JoinMetadata + { + Description = "Mic Mute Toggle", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("MinutesBeforeMeetingStart")] public JoinDataComplete MinutesBeforeMeetingStart = + new JoinDataComplete(new JoinData {JoinNumber = 41, JoinSpan = 1}, + new JoinMetadata + { + Description = "Minutes before meeting start that a meeting is joinable", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("ParticipantCount")] public JoinDataComplete ParticipantCount = + new JoinDataComplete(new JoinData {JoinNumber = 151, JoinSpan = 1}, + new JoinMetadata + { + Description = "Current Participant Count", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("Schedule")] public JoinDataComplete Schedule = + new JoinDataComplete(new JoinData {JoinNumber = 102, JoinSpan = 1}, + new JoinMetadata + { + Description = "Schedule Data - XSIG", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [JoinName("AutoShareWhileInCall")] public JoinDataComplete SourceShareAutoStart = + new JoinDataComplete(new JoinData {JoinNumber = 203, JoinSpan = 1}, + new JoinMetadata + { + Description = "When high, will autostart sharing when a call is joined", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SourceShareEnd")] public JoinDataComplete SourceShareEnd = + new JoinDataComplete(new JoinData {JoinNumber = 202, JoinSpan = 1}, + new JoinMetadata + { + Description = "Stop Sharing & Feedback", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SourceShareStart")] public JoinDataComplete SourceShareStart = + new JoinDataComplete(new JoinData {JoinNumber = 201, JoinSpan = 1}, + new JoinMetadata + { + Description = "Start Sharing & Feedback", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("RecievingContent")] public JoinDataComplete RecievingContent = + new JoinDataComplete(new JoinData {JoinNumber = 204, JoinSpan = 1}, + new JoinMetadata + { + Description = "Recieving content from the far end", + JoinType = eJoinType.Digital, + JoinCapabilities = eJoinCapabilities.ToSIMPL + }); + + [JoinName("SelfviewPosition")] public JoinDataComplete SelfviewPosition = + new JoinDataComplete(new JoinData {JoinNumber = 211, JoinSpan = 1}, + new JoinMetadata + { + Description = "advance selfview position", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SelfviewPositionFb")] + public JoinDataComplete SelfviewPositionFb = + new JoinDataComplete(new JoinData { JoinNumber = 211, JoinSpan = 1 }, + new JoinMetadata + { + Description = "advance selfview position", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Serial + }); + + [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("UpdateMeetings")] public JoinDataComplete UpdateMeetings = + new JoinDataComplete(new JoinData {JoinNumber = 160, JoinSpan = 1}, + new JoinMetadata + { + Description = "Update Meetings", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("VolumeDown")] public JoinDataComplete VolumeDown = + new JoinDataComplete(new JoinData {JoinNumber = 175, JoinSpan = 1}, + new JoinMetadata + { + Description = "Volume Down", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("VolumeLevel")] public JoinDataComplete VolumeLevel = + new JoinDataComplete(new JoinData {JoinNumber = 174, JoinSpan = 1}, + new JoinMetadata + { + Description = "Volume Level", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Analog + }); + + [JoinName("VolumeMuteOff")] public JoinDataComplete VolumeMuteOff = + new JoinDataComplete(new JoinData {JoinNumber = 177, JoinSpan = 1}, + new JoinMetadata + { + Description = "Volume Mute Off", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("VolumeMuteOn")] public JoinDataComplete VolumeMuteOn = + new JoinDataComplete(new JoinData {JoinNumber = 176, JoinSpan = 1}, + new JoinMetadata + { + Description = "Volume Mute On", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("VolumeMuteToggle")] public JoinDataComplete VolumeMuteToggle = + new JoinDataComplete(new JoinData {JoinNumber = 178, JoinSpan = 1}, + new JoinMetadata + { + Description = "Volume Mute Toggle", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("VolumeUp")] public JoinDataComplete VolumeUp = + new JoinDataComplete(new JoinData {JoinNumber = 174, JoinSpan = 1}, + new JoinMetadata + { + Description = "Volume Up", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("DialPhoneCall")] + public JoinDataComplete DialPhone = + new JoinDataComplete(new JoinData { JoinNumber = 72, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Dial Phone", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PhoneHookState")] + public JoinDataComplete PhoneHookState = + new JoinDataComplete(new JoinData { JoinNumber = 72, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Dial Phone", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("EndPhoneCall")] + public JoinDataComplete HangUpPhone = + new JoinDataComplete(new JoinData { JoinNumber = 73, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Hang Up PHone", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("PhoneString")] + public JoinDataComplete PhoneDialString = + new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, + new JoinMetadata + { + Description = "Phone Dial String", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Serial + }); + + public VideoCodecControllerJoinMap(uint joinStart) : base(joinStart, typeof (VideoCodecControllerJoinMap)) + { + } + + public VideoCodecControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) + { + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs index 7556cbcd..a8fa67e4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs @@ -1,120 +1,120 @@ -using System; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; - -namespace PepperDash.Essentials.Core -{ - /// - /// - /// - public class CommFactory - { - public static EssentialsControlPropertiesConfig GetControlPropertiesConfig(DeviceConfig deviceConfig) - { - try - { - return JsonConvert.DeserializeObject - (deviceConfig.Properties["control"].ToString()); - //Debug.Console(2, "Control TEST: {0}", JsonConvert.SerializeObject(controlConfig)); - } - catch (Exception e) - { - - Debug.Console(0, "ERROR: [{0}] Control properties deserialize failed:\r{1}", deviceConfig.Key, e); - return null; - } - } - - - /// - /// Returns a comm method of either com port, TCP, SSH, and puts this into the DeviceManager - /// - /// The Device config object - public static IBasicCommunication CreateCommForDevice(DeviceConfig deviceConfig) - { - EssentialsControlPropertiesConfig controlConfig = GetControlPropertiesConfig(deviceConfig); - if (controlConfig == null) - return null; - - IBasicCommunication comm = null; - try - { - var c = controlConfig.TcpSshProperties; - switch (controlConfig.Method) - { - case eControlMethod.Com: - comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams, 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.Telnet: - break; - default: - break; - } - } - catch (Exception e) - { - Debug.Console(0, "Cannot create communication from JSON:\r{0}\r\rException:\r{1}", - deviceConfig.Properties.ToString(), e); - } - - // put it in the device manager if it's the right flavor - var comDev = comm as Device; - if (comDev != null) - DeviceManager.AddDevice(comDev); - return comm; - } - - public static ComPort GetComPort(EssentialsControlPropertiesConfig config) - { - var comPar = config.ComParams; - var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey); - if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts) - return dev.ComPorts[config.ControlPortNumber]; - Debug.Console(0, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); - return null; - } - - /// - /// Gets an ICec port from a RoutingInput or RoutingOutput on a device - /// - /// - /// - public static ICec GetCecPort(ControlPropertiesConfig config) - { +using System; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DM; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core +{ + /// + /// + /// + public class CommFactory + { + public static EssentialsControlPropertiesConfig GetControlPropertiesConfig(DeviceConfig deviceConfig) + { + try + { + return JsonConvert.DeserializeObject + (deviceConfig.Properties["control"].ToString()); + //Debug.Console(2, "Control TEST: {0}", JsonConvert.SerializeObject(controlConfig)); + } + catch (Exception e) + { + + Debug.Console(0, "ERROR: [{0}] Control properties deserialize failed:\r{1}", deviceConfig.Key, e); + return null; + } + } + + + /// + /// Returns a comm method of either com port, TCP, SSH, and puts this into the DeviceManager + /// + /// The Device config object + public static IBasicCommunication CreateCommForDevice(DeviceConfig deviceConfig) + { + EssentialsControlPropertiesConfig controlConfig = GetControlPropertiesConfig(deviceConfig); + if (controlConfig == null) + return null; + + IBasicCommunication comm = null; + try + { + var c = controlConfig.TcpSshProperties; + switch (controlConfig.Method) + { + case eControlMethod.Com: + comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams, 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.Telnet: + break; + default: + break; + } + } + catch (Exception e) + { + Debug.Console(0, "Cannot create communication from JSON:\r{0}\r\rException:\r{1}", + deviceConfig.Properties.ToString(), e); + } + + // put it in the device manager if it's the right flavor + var comDev = comm as Device; + if (comDev != null) + DeviceManager.AddDevice(comDev); + return comm; + } + + public static ComPort GetComPort(EssentialsControlPropertiesConfig config) + { + var comPar = config.ComParams; + var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey); + if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts) + return dev.ComPorts[config.ControlPortNumber]; + Debug.Console(0, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); + return null; + } + + /// + /// Gets an ICec port from a RoutingInput or RoutingOutput on a device + /// + /// + /// + public static ICec GetCecPort(ControlPropertiesConfig config) + { var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey); if (dev != null) @@ -147,64 +147,64 @@ namespace PepperDash.Essentials.Core Debug.Console(0, "GetCecPort: '{0}' - Configuration missing 'ControlPortName'", config.ControlPortDevKey); } } - Debug.Console(0, "GetCecPort: Device '{0}' is not a valid device.", config.ControlPortDevKey); - - return null; - } - - /// - /// Helper to grab the IComPorts device for this PortDeviceKey. Key "controlSystem" will - /// return the ControlSystem object from the Global class. - /// - /// IComPorts device or null if the device is not found or does not implement IComPorts - public static IComPorts GetIComPortsDeviceFromManagedDevice(string ComPortDevKey) - { - if ((ComPortDevKey.Equals("controlSystem", System.StringComparison.OrdinalIgnoreCase) - || ComPortDevKey.Equals("processor", System.StringComparison.OrdinalIgnoreCase)) - && Global.ControlSystem is IComPorts) - return Global.ControlSystem; - else - { - var dev = DeviceManager.GetDeviceForKey(ComPortDevKey) as IComPorts; - if (dev == null) - Debug.Console(0, "ComPortConfig: Cannot find com port device '{0}'", ComPortDevKey); - return dev; - } - } - } - - /// - /// - /// - public class EssentialsControlPropertiesConfig : - PepperDash.Core.ControlPropertiesConfig - { - - [JsonConverter(typeof(ComSpecJsonConverter))] - public ComPort.ComPortSpec ComParams { get; set; } - - public string CresnetId { get; set; } - - /// - /// Attempts to provide uint conversion of string CresnetId - /// - public uint CresnetIdInt - { - get - { - 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)); - } - } + Debug.Console(0, "GetCecPort: Device '{0}' is not a valid device.", config.ControlPortDevKey); + + return null; } - public string InfinetId { get; set; } - + /// + /// Helper to grab the IComPorts device for this PortDeviceKey. Key "controlSystem" will + /// return the ControlSystem object from the Global class. + /// + /// IComPorts device or null if the device is not found or does not implement IComPorts + public static IComPorts GetIComPortsDeviceFromManagedDevice(string ComPortDevKey) + { + if ((ComPortDevKey.Equals("controlSystem", System.StringComparison.OrdinalIgnoreCase) + || ComPortDevKey.Equals("processor", System.StringComparison.OrdinalIgnoreCase)) + && Global.ControlSystem is IComPorts) + return Global.ControlSystem; + else + { + var dev = DeviceManager.GetDeviceForKey(ComPortDevKey) as IComPorts; + if (dev == null) + Debug.Console(0, "ComPortConfig: Cannot find com port device '{0}'", ComPortDevKey); + return dev; + } + } + } + + /// + /// + /// + public class EssentialsControlPropertiesConfig : + PepperDash.Core.ControlPropertiesConfig + { + + [JsonConverter(typeof(ComSpecJsonConverter))] + public ComPort.ComPortSpec ComParams { get; set; } + + public string CresnetId { get; set; } + + /// + /// Attempts to provide uint conversion of string CresnetId + /// + public uint CresnetIdInt + { + get + { + 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)); + } + } + } + + public string InfinetId { get; set; } + /// /// Attepmts to provide uiont conversion of string InifinetId /// @@ -221,13 +221,13 @@ namespace PepperDash.Essentials.Core 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; } - } + } + } + + 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/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/ConfigReader.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/ConfigReader.cs index b3fc7d89..48a026c2 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/ConfigReader.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/ConfigReader.cs @@ -1,5 +1,6 @@ using System; -using System.Linq; +using System.Linq; +using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; @@ -12,8 +13,14 @@ namespace PepperDash.Essentials.Core.Config /// /// Loads the ConfigObject from the file /// - public class ConfigReader - { + public class ConfigReader + { + public const string LocalConfigPresent = + @" +*************************************************** +************* Using Local config file ************* +***************************************************"; + public static EssentialsConfig ConfigObject { get; private set; } public static bool LoadConfig2() @@ -40,10 +47,10 @@ namespace PepperDash.Essentials.Core.Config "****Error: Multiple Local Configuration files present. Please ensure only a single file exists and reset program.****"); return false; } - else if(configFiles.Length == 1) + if(configFiles.Length == 1) { - localConfigFound = true; - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Found Local config file: '{0}'", filePath); + localConfigFound = true; + } } else @@ -91,7 +98,13 @@ namespace PepperDash.Essentials.Core.Config } // Get the actual file path - filePath = configFiles[0].FullName; + filePath = configFiles[0].FullName; + + // Generate debug statement if using a local file. + if (localConfigFound) + { + GetLocalFileMessage(filePath); + } // Read the file using (StreamReader fs = new StreamReader(filePath)) @@ -177,7 +190,65 @@ namespace PepperDash.Essentials.Core.Config { 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; + + 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 + .Append(new string('*', debugStringWidth)) + .Append(CrestronEnvironment.NewLine) + // Line 2 + .Append(new string('*', debugStringWidth)) + .Append(CrestronEnvironment.NewLine) + // Line 3 + .Append(new string('*', 2)) + .Append(new string(' ', debugStringWidth - 4)) + .Append(new string('*', 2)) + .Append(CrestronEnvironment.NewLine) + // 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 + .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 + .Append(new string('*', 2)) + .Append(new string(' ', debugStringWidth - 4)) + .Append(new string('*', 2)) + .Append(CrestronEnvironment.NewLine) + // Line 7 + .Append(new string('*', debugStringWidth)) + .Append(CrestronEnvironment.NewLine) + // Line 8 + .Append(new string('*', debugStringWidth)); + + Debug.Console(2, Debug.ErrorLogLevel.Notice, "Found Local config file: '{0}'", filePath); + Debug.Console(0, newDebugString.ToString()); + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/InfoConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/InfoConfig.cs index d5cf16f1..3191a8f6 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/InfoConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/InfoConfig.cs @@ -1,5 +1,5 @@ using System; - +using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; @@ -81,7 +81,7 @@ namespace PepperDash.Essentials.Core.Config // } //} - /// + /// , /// The OS Version of the processor (Firmware Version) /// [JsonProperty("osVersion")] @@ -92,5 +92,18 @@ namespace PepperDash.Essentials.Core.Config // return Crestron.SimplSharp.CrestronEnvironment.OSVersion.Firmware; // } //} + + /// + /// The information gathered by the processor at runtime about it's NICs and their IP addresses. + /// + [JsonProperty("ipInfo")] + public Dictionary IpInfo + { + get + { + return Global.EthernetAdapterInfoCollection; + } + } } + } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Cards/InternalCardCageController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Cards/InternalCardCageController.cs index b362a78d..964edd5c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Cards/InternalCardCageController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Cards/InternalCardCageController.cs @@ -73,21 +73,21 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards string cardType; if (!_config.Cards.TryGetValue(i, out cardType)) { - Debug.Console(1, this, "No card found for slot {0}", i); + Debug.Console(0, this, "No card found for slot {0}", i); continue; } if (String.IsNullOrEmpty(cardType)) { Debug.Console(0, this, "No card specified for slot {0}", i); - return; + continue; } Func cardBuilder; if (!_cardDict.TryGetValue(cardType.ToLower(), out cardBuilder)) { Debug.Console(0, "Unable to find factory for 3-Series card type {0}.", cardType); - return; + continue; } try diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs index 9db81122..56b36791 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron/CrestronGenericBaseDevice.cs @@ -179,7 +179,7 @@ namespace PepperDash.Essentials.Core { public static eDeviceRegistrationUnRegistrationResponse RegisterWithLogging(this GenericBase device, string key) { - var result = device.Register(); + var result = device.Register(); var level = result == eDeviceRegistrationUnRegistrationResponse.Success ? Debug.ErrorLogLevel.Notice : Debug.ErrorLogLevel.Error; Debug.Console(0, level, "Register device result: '{0}', type '{1}', result {2}", key, device, result); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasBranding.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasBranding.cs new file mode 100644 index 00000000..d5c95c47 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasBranding.cs @@ -0,0 +1,8 @@ +namespace PepperDash_Essentials_Core.DeviceTypeInterfaces +{ + public interface IHasBranding + { + bool BrandingEnabled { get; } + void InitializeBranding(string roomKey); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasFarEndContentStatus.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasFarEndContentStatus.cs new file mode 100644 index 00000000..21bde91f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasFarEndContentStatus.cs @@ -0,0 +1,7 @@ +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + public interface IHasFarEndContentStatus + { + BoolFeedback ReceivingContent { get; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasPhoneDialing.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasPhoneDialing.cs new file mode 100644 index 00000000..2b7af8ad --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IHasPhoneDialing.cs @@ -0,0 +1,14 @@ +using PepperDash.Essentials.Core; + +namespace PepperDash_Essentials_Core.DeviceTypeInterfaces +{ + public interface IHasPhoneDialing + { + 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/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ILanguageDefinition.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ILanguageDefinition.cs new file mode 100644 index 00000000..f124240d --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ILanguageDefinition.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace PepperDash_Essentials_Core.DeviceTypeInterfaces +{ + 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; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ILanguageProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ILanguageProvider.cs new file mode 100644 index 00000000..2ae483f6 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ILanguageProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace PepperDash_Essentials_Core.DeviceTypeInterfaces +{ + public interface ILanguageProvider + { + ILanguageDefinition CurrentLanguage { get; set; } + + event EventHandler CurrentLanguageChanged; + } + +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/LanguageLabel.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/LanguageLabel.cs new file mode 100644 index 00000000..345da2ed --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/LanguageLabel.cs @@ -0,0 +1,12 @@ +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.DeviceTypeInterfaces +{ + public class LanguageLabel + { + 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/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/GenericIRController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/GenericIRController.cs new file mode 100644 index 00000000..bf4544de --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/GenericIRController.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash_Essentials_Core.Devices +{ + 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) + { + _port = irPort; + + if (_port == null) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "IR Port is null, device will not function"); + return; + } + DeviceManager.AddDevice(_port); + + _port.DriverLoaded.OutputChange += DriverLoadedOnOutputChange; + } + + private void DriverLoadedOnOutputChange(object sender, FeedbackEventArgs args) + { + if (!args.BoolValue) + { + return; + } + + if (_trilist == null || _bridge == null) + { + return; + } + + LinkToApi(_trilist, _joinStart, _joinMapKey, _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) + { + _trilist = trilist; + _joinStart = joinStart; + _joinMapKey = joinMapKey; + _bridge = bridge; + return; + } + + var joinMap = new GenericIrControllerJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + + for (uint i = 0; i < _port.IrFileCommands.Length; i++) + { + var cmd = _port.IrFileCommands[i]; + var joinData = new JoinDataComplete(new JoinData {JoinNumber = i, JoinSpan = 1}, + new JoinMetadata + { + Description = cmd, + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + joinData.SetJoinOffset(joinStart); + + joinMap.Joins.Add(cmd,joinData); + + trilist.SetBoolSigAction(joinData.JoinNumber, (b) => Press(cmd, b)); + } + + joinMap.PrintJoinMapInfo(); + + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + else + { + Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + } + } + + #endregion + + public void Press(string command, bool pressRelease) + { + _port.PressRelease(command, pressRelease); + } + } + + public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced + { + public GenericIrControllerJoinMap(uint joinStart) : base(joinStart) + { + } + } + + public class GenericIrControllerFactory : EssentialsDeviceFactory + { + public GenericIrControllerFactory() + { + TypeNames = new List {"genericIrController"}; + } + #region Overrides of EssentialsDeviceFactory + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "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/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IDspPreset.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IDspPreset.cs new file mode 100644 index 00000000..2ec63fcb --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IDspPreset.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace PepperDash.Essentials.Core +{ + public interface IHasDspPresets + { + List Presets { get; } + + void RecallPreset(IDspPreset preset); + + } + + public interface IDspPreset + { + string Name { get; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IrOutputPortController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IrOutputPortController.cs index ff884007..cce1d46e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IrOutputPortController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IrOutputPortController.cs @@ -21,6 +21,8 @@ namespace PepperDash.Essentials.Core uint IrPortUid; IROutputPort IrPort; + public BoolFeedback DriverLoaded { get; private set; } + public ushort StandardIrPulseTime { get; set; } public string DriverFilepath { get; private set; } public bool DriverIsLoaded { get; private set; } @@ -35,6 +37,8 @@ namespace PepperDash.Essentials.Core : base(key) { //if (port == null) throw new ArgumentNullException("port"); + + DriverLoaded = new BoolFeedback(() => DriverIsLoaded); IrPort = port; if (port == null) { @@ -48,6 +52,7 @@ namespace PepperDash.Essentials.Core DeviceConfig config) : base(key) { + DriverLoaded = new BoolFeedback(() => DriverIsLoaded); AddPostActivationAction(() => { IrPort = postActivationFunc(config); @@ -59,7 +64,7 @@ namespace PepperDash.Essentials.Core } var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); - Debug.Console(1, "*************Attemting to load IR file: {0}***************", filePath); + Debug.Console(1, "*************Attempting to load IR file: {0}***************", filePath); LoadDriver(filePath); @@ -91,13 +96,15 @@ namespace PepperDash.Essentials.Core DriverFilepath = path; StandardIrPulseTime = 200; DriverIsLoaded = true; + + DriverLoaded.FireUpdate(); } catch { DriverIsLoaded = false; var message = string.Format("WARNING IR Driver '{0}' failed to load", path); - Debug.Console(0, this, message); - ErrorLog.Error(message); + Debug.Console(0, this, Debug.ErrorLogLevel.Error, message); + DriverLoaded.FireUpdate(); } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Gateways/CenCn2Controller.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Gateways/CenCn2Controller.cs new file mode 100644 index 00000000..bdd53bde --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Gateways/CenCn2Controller.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash_Essentials_Core.Gateways +{ + public class CenCn2Controller + { + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/EthernetAdapterInfo.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/EthernetAdapterInfo.cs new file mode 100644 index 00000000..c21df098 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/EthernetAdapterInfo.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + 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; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Global.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Global.cs index b540b3d6..4a846df7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Global.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Global.cs @@ -1,175 +1,180 @@ -using System; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharp.CrestronDataStore; -using Crestron.SimplSharpPro; - -using PepperDash.Core; -using PepperDash.Essentials.License; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Schema; - - -namespace PepperDash.Essentials.Core -{ - public static class Global - { +using System; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using System.Collections.Generic; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharp.CrestronDataStore; +using Crestron.SimplSharpPro; + +using PepperDash.Core; +using PepperDash.Essentials.License; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; + + +namespace PepperDash.Essentials.Core +{ + public static class Global + { public static CrestronControlSystem ControlSystem { get; set; } - public static LicenseManager LicenseManager { get; 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 - { - get - { - return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); - } - } - - /// - /// Returns the directory separator character based on the running OS - /// - public static char DirectorySeparator - { - get - { - return System.IO.Path.DirectorySeparatorChar; - } - } - - /// - /// Wildcarded config file name for global reference - /// - public const string ConfigFileName = "*configurationFile*.json"; - - /// - /// Sets the file path prefix - /// - /// - public static void SetFilePathPrefix(string prefix) - { - FilePathPrefix = prefix; - } - - static string _AssemblyVersion; - - /// - /// Gets the Assembly Version of Essentials - /// - /// The Assembly Version at Runtime - public static string AssemblyVersion - { - get - { - return _AssemblyVersion; - } - private set - { - _AssemblyVersion = value; - } - } - - /// - /// Sets the Assembly version to the version of the Essentials Library - /// - /// - public static void SetAssemblyVersion(string assemblyVersion) - { - AssemblyVersion = assemblyVersion; - } - - /// - /// 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.Console(2, "Comparing running version '{0}' to minimum version '{1}'", AssemblyVersion, minimumVersion); - - if (String.IsNullOrEmpty(minimumVersion)) - { - Debug.Console(0,"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.Console(2, "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.Console(2, "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() - { - // Fire up CrestronDataStoreStatic - var err = CrestronDataStoreStatic.InitCrestronDataStore(); - if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - { - CrestronConsole.PrintLine("Error starting CrestronDataStoreStatic: {0}", err); - return; - } - } - - } + public static eDevicePlatform Platform { get { return CrestronEnvironment.DevicePlatform; } } + + public static Dictionary EthernetAdapterInfoCollection { get; private set; } + + public static LicenseManager LicenseManager { get; 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 + { + get + { + return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); + } + } + + /// + /// Returns the directory separator character based on the running OS + /// + public static char DirectorySeparator + { + get + { + return System.IO.Path.DirectorySeparatorChar; + } + } + + /// + /// Wildcarded config file name for global reference + /// + public const string ConfigFileName = "*configurationFile*.json"; + + /// + /// Sets the file path prefix + /// + /// + public static void SetFilePathPrefix(string prefix) + { + FilePathPrefix = prefix; + } + + static string _AssemblyVersion; + + /// + /// Gets the Assembly Version of Essentials + /// + /// The Assembly Version at Runtime + public static string AssemblyVersion + { + get + { + return _AssemblyVersion; + } + private set + { + _AssemblyVersion = value; + } + } + + /// + /// Sets the Assembly version to the version of the Essentials Library + /// + /// + public static void SetAssemblyVersion(string assemblyVersion) + { + AssemblyVersion = assemblyVersion; + } + + /// + /// 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.Console(2, "Comparing running version '{0}' to minimum version '{1}'", AssemblyVersion, minimumVersion); + + if (String.IsNullOrEmpty(minimumVersion)) + { + Debug.Console(0,"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.Console(2, "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.Console(2, "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() + { + // Fire up CrestronDataStoreStatic + var err = CrestronDataStoreStatic.InitCrestronDataStore(); + if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + { + CrestronConsole.PrintLine("Error starting CrestronDataStoreStatic: {0}", err); + return; + } + } + + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index c31a46b8..2b45030c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -48,48 +48,39 @@ False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DeviceSupport.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DeviceSupport.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DM.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DM.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.EthernetCommunications.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.EthernetCommunications.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Fusion.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Fusion.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Gateways.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Gateways.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Remotes.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Remotes.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.ThreeSeriesCards.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.ThreeSeriesCards.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll @@ -98,33 +89,30 @@ False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll False False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll False False - ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll False - ..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe False False - ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll False - ..\..\..\..\ProgramData\Crestron\SDK\SimplSharpTimerEventInterface.dll - True + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpTimerEventInterface.dll @@ -158,6 +146,7 @@ + @@ -200,11 +189,19 @@ + + + + + + + + @@ -222,8 +219,13 @@ + + + + + @@ -238,6 +240,7 @@ + @@ -313,6 +316,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ComsMessage.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ComsMessage.cs new file mode 100644 index 00000000..92c97248 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ComsMessage.cs @@ -0,0 +1,73 @@ +using System; +using PepperDash.Core; + +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; + + /// + /// Constructor for a string message + /// + /// IBasicCommunication to send the message + /// Message to send + public ComsMessage(IBasicCommunication coms, string message) + { + Validate(coms, message); + _coms = 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) + { + _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; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs new file mode 100644 index 00000000..1f27fe1e --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/GenericQueue.cs @@ -0,0 +1,144 @@ +using System; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.CrestronThread; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + /// + /// Threadsafe processing of queued items with pacing if required + /// + public class GenericQueue : IQueue + { + private readonly string _key; + protected readonly CrestronQueue _queue; + protected readonly Thread _worker; + protected readonly CEvent _waitHandle = new CEvent(); + + private readonly bool _delayEnabled; + private readonly int _delayTime; + + /// + /// If the instance has been disposed. + /// + public bool Disposed { get; private set; } + + /// + /// Constructor for generic queue with no pacing + /// + /// Key + public GenericQueue(string key) + { + _key = key; + _queue = new CrestronQueue(); + _worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running); + + CrestronEnvironment.ProgramStatusEventHandler += programEvent => + { + if (programEvent != eProgramStatusEventType.Stopping) + return; + + Dispose(); + }; + } + + /// + /// Constructor for generic queue with no pacing + /// + /// Key + /// Pacing in ms between actions + public GenericQueue(string key, int pacing) + : this(key) + { + _delayEnabled = pacing > 0; + _delayTime = pacing; + } + + /// + /// Thread callback + /// + /// The action used to process dequeued items + /// Null when the thread is exited + private object ProcessQueue(object obj) + { + while (true) + { + IQueueMessage item = null; + + if (_queue.Count > 0) + { + item = _queue.Dequeue(); + if (item == null) + break; + } + if (item != null) + { + try + { + Debug.Console(2, this, "Processing queue item: '{0}'", item.ToString()); + item.Dispatch(); + + if (_delayEnabled) + Thread.Sleep(_delayTime); + } + catch (Exception ex) + { + Debug.ConsoleWithLog(0, this, "Caught an exception in the Queue {0}\r{1}\r{2}", ex.Message, ex.InnerException, ex.StackTrace); + } + } + else _waitHandle.Wait(); + } + + return null; + } + + public void Enqueue(IQueueMessage item) + { + _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) + { + Enqueue(null); + _worker.Join(); + _waitHandle.Close(); + } + + Disposed = true; + } + + ~GenericQueue() + { + Dispose(false); + } + + /// + /// Key + /// + public string Key + { + get { return _key; } + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueue.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueue.cs new file mode 100644 index 00000000..852542d5 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueue.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + public interface IQueue : IKeyed, IDisposable where T : class + { + void Enqueue(T item); + bool Disposed { get; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueueMessage.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueueMessage.cs new file mode 100644 index 00000000..ee0d87d2 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/IQueueMessage.cs @@ -0,0 +1,7 @@ +namespace PepperDash_Essentials_Core.Queues +{ + public interface IQueueMessage + { + void Dispatch(); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ProcessStringMessage.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ProcessStringMessage.cs new file mode 100644 index 00000000..a15f7231 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/ProcessStringMessage.cs @@ -0,0 +1,44 @@ +using System; + +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; + + /// + /// 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; + + _action(_message); + } + + /// + /// To string + /// + /// The current message + public override string ToString() + { + return _message ?? String.Empty; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs new file mode 100644 index 00000000..7f6477a3 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Queues/StringResponseProcessor.cs @@ -0,0 +1,106 @@ +using System; +using Crestron.SimplSharp; +using PepperDash.Core; + +namespace PepperDash_Essentials_Core.Queues +{ + 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) + { + _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) + return; + + if (disposing) + { + if (_coms != null) + _coms.TextReceived -= OnResponseReceived; + + if (_gather != null) + { + _gather.LineReceived -= OnResponseReceived; + _gather.Stop(); + } + + _queue.Dispose(); + } + + Disposed = true; + } + + /// + /// 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); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Remotes/Hrxx0WirelessRemoteController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Remotes/Hrxx0WirelessRemoteController.cs index e2dfadbc..161cba45 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Remotes/Hrxx0WirelessRemoteController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Remotes/Hrxx0WirelessRemoteController.cs @@ -18,32 +18,29 @@ using PepperDash.Essentials.Core.Bridges; namespace PepperDash.Essentials.Core { - [Description("Wrapper class for all HR-Series remotes")] - public class Hrxx0WirelessRemoteController : EssentialsBridgeableDevice, IHasFeedback + [Description("Wrapper class for all HR-Series remotes")] + public class Hrxx0WirelessRemoteController : EssentialsBridgeableDevice, IHasFeedback, IHR52Button { private CenRfgwController _gateway; private GatewayBase _gatewayBase; - - private Hr1x0WirelessRemoteBase _remote; - + private Hr1x0WirelessRemoteBase _remote; + public FeedbackCollection Feedbacks { get; set; } public CrestronCollection /// /// - void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) + private void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args) { //if (CommDebuggingIsOn) // Debug.Console(1, this, "Gathered: '{0}'", args.Text); - ReceiveQueue.Enqueue(args.Text); + _receiveQueue.Enqueue(args.Text); // If the receive thread has for some reason stopped, this will restart it - if (ReceiveThread.ThreadState != Thread.eThreadStates.ThreadRunning) + if (_receiveThread.ThreadState != Thread.eThreadStates.ThreadRunning) { - ReceiveThread.Start(); + _receiveThread.Start(); } } @@ -412,13 +666,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// Runs in it's own thread to dequeue messages in the order they were received to be processed /// /// - object ProcessQueue() + private object ProcessQueue() { try { while (true) { - var message = ReceiveQueue.Dequeue(); + var message = _receiveQueue.Dequeue(); ProcessMessage(message); } @@ -435,97 +689,121 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// /// Queues the initial queries to be sent upon connection /// - void SetUpSyncQueries() + private void SetUpSyncQueries() { // zStatus - SyncState.AddQueryToQueue("zStatus Call Status"); - SyncState.AddQueryToQueue("zStatus Audio Input Line"); - SyncState.AddQueryToQueue("zStatus Audio Output Line"); - SyncState.AddQueryToQueue("zStatus Video Camera Line"); - SyncState.AddQueryToQueue("zStatus Video Optimizable"); - SyncState.AddQueryToQueue("zStatus Capabilities"); - SyncState.AddQueryToQueue("zStatus Sharing"); - SyncState.AddQueryToQueue("zStatus CameraShare"); - SyncState.AddQueryToQueue("zStatus Call Layout"); - SyncState.AddQueryToQueue("zStatus Call ClosedCaption Available"); - SyncState.AddQueryToQueue("zStatus NumberOfScreens"); + _syncState.AddQueryToQueue("zStatus Call Status"); + _syncState.AddQueryToQueue("zStatus Audio Input Line"); + _syncState.AddQueryToQueue("zStatus Audio Output Line"); + _syncState.AddQueryToQueue("zStatus Video Camera Line"); + _syncState.AddQueryToQueue("zStatus Video Optimizable"); + _syncState.AddQueryToQueue("zStatus Capabilities"); + _syncState.AddQueryToQueue("zStatus Sharing"); + _syncState.AddQueryToQueue("zStatus CameraShare"); + _syncState.AddQueryToQueue("zStatus Call Layout"); + _syncState.AddQueryToQueue("zStatus Call ClosedCaption Available"); + _syncState.AddQueryToQueue("zStatus NumberOfScreens"); // zConfiguration - SyncState.AddQueryToQueue("zConfiguration Call Sharing optimize_video_sharing"); - SyncState.AddQueryToQueue("zConfiguration Call Microphone Mute"); - SyncState.AddQueryToQueue("zConfiguration Call Camera Mute"); - SyncState.AddQueryToQueue("zConfiguration Audio Input SelectedId"); - SyncState.AddQueryToQueue("zConfiguration Audio Input is_sap_disabled"); - SyncState.AddQueryToQueue("zConfiguration Audio Input reduce_reverb"); - SyncState.AddQueryToQueue("zConfiguration Audio Input volume"); - SyncState.AddQueryToQueue("zConfiguration Audio Output selectedId"); - SyncState.AddQueryToQueue("zConfiguration Audio Output volume"); - SyncState.AddQueryToQueue("zConfiguration Video hide_conf_self_video"); - SyncState.AddQueryToQueue("zConfiguration Video Camera selectedId"); - SyncState.AddQueryToQueue("zConfiguration Video Camera Mirror"); - SyncState.AddQueryToQueue("zConfiguration Client appVersion"); - SyncState.AddQueryToQueue("zConfiguration Client deviceSystem"); - SyncState.AddQueryToQueue("zConfiguration Call Layout ShareThumb"); - SyncState.AddQueryToQueue("zConfiguration Call Layout Style"); - SyncState.AddQueryToQueue("zConfiguration Call Layout Size"); - SyncState.AddQueryToQueue("zConfiguration Call Layout Position"); - SyncState.AddQueryToQueue("zConfiguration Call Lock Enable"); - SyncState.AddQueryToQueue("zConfiguration Call MuteUserOnEntry Enable"); - SyncState.AddQueryToQueue("zConfiguration Call ClosedCaption FontSize "); - SyncState.AddQueryToQueue("zConfiguration Call ClosedCaption Visible"); + _syncState.AddQueryToQueue("zConfiguration Call Sharing optimize_video_sharing"); + _syncState.AddQueryToQueue("zConfiguration Call Microphone Mute"); + _syncState.AddQueryToQueue("zConfiguration Call Camera Mute"); + _syncState.AddQueryToQueue("zConfiguration Audio Input SelectedId"); + _syncState.AddQueryToQueue("zConfiguration Audio Input is_sap_disabled"); + _syncState.AddQueryToQueue("zConfiguration Audio Input reduce_reverb"); + _syncState.AddQueryToQueue("zConfiguration Audio Input volume"); + _syncState.AddQueryToQueue("zConfiguration Audio Output selectedId"); + _syncState.AddQueryToQueue("zConfiguration Audio Output volume"); + _syncState.AddQueryToQueue("zConfiguration Video hide_conf_self_video"); + _syncState.AddQueryToQueue("zConfiguration Video Camera selectedId"); + _syncState.AddQueryToQueue("zConfiguration Video Camera Mirror"); + _syncState.AddQueryToQueue("zConfiguration Client appVersion"); + _syncState.AddQueryToQueue("zConfiguration Client deviceSystem"); + _syncState.AddQueryToQueue("zConfiguration Call Layout ShareThumb"); + _syncState.AddQueryToQueue("zConfiguration Call Layout Style"); + _syncState.AddQueryToQueue("zConfiguration Call Layout Size"); + _syncState.AddQueryToQueue("zConfiguration Call Layout Position"); + _syncState.AddQueryToQueue("zConfiguration Call Lock Enable"); + _syncState.AddQueryToQueue("zConfiguration Call MuteUserOnEntry Enable"); + _syncState.AddQueryToQueue("zConfiguration Call ClosedCaption FontSize "); + _syncState.AddQueryToQueue("zConfiguration Call ClosedCaption Visible"); // zCommand - SyncState.AddQueryToQueue("zCommand Phonebook List Offset: 0 Limit: 512"); - SyncState.AddQueryToQueue("zCommand Bookings List"); + if (!_props.DisablePhonebookAutoDownload) + { + _syncState.AddQueryToQueue("zCommand Phonebook List Offset: 0 Limit: 512"); + } + + _syncState.AddQueryToQueue("zCommand Bookings List"); + _syncState.AddQueryToQueue("zCommand Call ListParticipants"); + _syncState.AddQueryToQueue("zCommand Call Info"); - SyncState.StartSync(); + _syncState.StartSync(); } /// /// Processes messages as they are dequeued /// /// - void ProcessMessage(string message) - { + private void ProcessMessage(string message) + { // Counts the curly braces - if(message.Contains('{')) - JsonCurlyBraceCounter++; - - if (message.Contains('}')) - JsonCurlyBraceCounter--; - - Debug.Console(2, this, "JSON Curly Brace Count: {0}", JsonCurlyBraceCounter); - - if (!JsonFeedbackMessageIsIncoming && message.Trim('\x20') == "{" + Delimiter) // Check for the beginning of a new JSON message + if (message.Contains("client_loop: send disconnect: Broken pipe")) { - JsonFeedbackMessageIsIncoming = true; - JsonCurlyBraceCounter = 1; // reset the counter for each new message - - JsonMessage = new StringBuilder(); - - JsonMessage.Append(message); - - if (CommDebuggingIsOn) - Debug.Console(2, this, "Incoming JSON message..."); + Debug.Console(0, this, Debug.ErrorLogLevel.Error, + "Zoom Room Controller or App connected. Essentials will NOT control the Zoom Room until it is disconnected."); return; } - else if (JsonFeedbackMessageIsIncoming && message.Trim('\x20') == "}" + Delimiter) // Check for the end of a JSON message - { - JsonMessage.Append(message); - if(JsonCurlyBraceCounter == 0) + if (message.Contains('{')) + { + _jsonCurlyBraceCounter++; + } + + if (message.Contains('}')) + { + _jsonCurlyBraceCounter--; + } + + Debug.Console(2, this, "JSON Curly Brace Count: {0}", _jsonCurlyBraceCounter); + + if (!_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "{" + Delimiter) + // Check for the beginning of a new JSON message + { + _jsonFeedbackMessageIsIncoming = true; + _jsonCurlyBraceCounter = 1; // reset the counter for each new message + + _jsonMessage = new StringBuilder(); + + _jsonMessage.Append(message); + + if (CommDebuggingIsOn) { - JsonFeedbackMessageIsIncoming = false; + Debug.Console(2, this, "Incoming JSON message..."); + } + + return; + } + if (_jsonFeedbackMessageIsIncoming && message.Trim('\x20') == "}" + Delimiter) + // Check for the end of a JSON message + { + _jsonMessage.Append(message); + + if (_jsonCurlyBraceCounter == 0) + { + _jsonFeedbackMessageIsIncoming = false; if (CommDebuggingIsOn) - Debug.Console(2, this, "Complete JSON Received:\n{0}", JsonMessage.ToString()); + { + Debug.Console(2, this, "Complete JSON Received:\n{0}", _jsonMessage.ToString()); + } // Forward the complete message to be deserialized - DeserializeResponse(JsonMessage.ToString()); + DeserializeResponse(_jsonMessage.ToString()); } //JsonMessage = new StringBuilder(); @@ -534,45 +812,52 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom // NOTE: This must happen after the above conditions have been checked // Append subsequent partial JSON fragments to the string builder - if (JsonFeedbackMessageIsIncoming) + if (_jsonFeedbackMessageIsIncoming) { - JsonMessage.Append(message); + _jsonMessage.Append(message); //Debug.Console(1, this, "Building JSON:\n{0}", JsonMessage.ToString()); return; } if (CommDebuggingIsOn) + { Debug.Console(1, this, "Non-JSON response: '{0}'", message); + } - JsonCurlyBraceCounter = 0; // reset on non-JSON response + _jsonCurlyBraceCounter = 0; // reset on non-JSON response - if (!SyncState.InitialSyncComplete) + if (!_syncState.InitialSyncComplete) { switch (message.Trim().ToLower()) // remove the whitespace { case "*r login successful": + { + _syncState.LoginMessageReceived(); + + // Fire up a thread to send the intial commands. + CrestronInvoke.BeginInvoke(o => { - SyncState.LoginMessageReceived(); + Thread.Sleep(100); + // disable echo of commands + SendText("echo off"); + Thread.Sleep(100); + // set feedback exclusions + SendText("zFeedback Register Op: ex Path: /Event/InfoResult/info/callin_country_list"); + Thread.Sleep(100); + SendText("zFeedback Register Op: ex Path: /Event/InfoResult/info/callout_country_list"); + Thread.Sleep(100); - // Fire up a thread to send the intial commands. - CrestronInvoke.BeginInvoke((o) => - { - Thread.Sleep(100); - // disable echo of commands - SendText("echo off"); - Thread.Sleep(100); - // set feedback exclusions - SendText("zFeedback Register Op: ex Path: /Event/InfoResult/info/callin_country_list"); - Thread.Sleep(100); - SendText("zFeedback Register Op: ex Path: /Event/InfoResult/info/callout_country_list"); - Thread.Sleep(100); - // switch to json format - SendText("format json"); - }); + if (!_props.DisablePhonebookAutoDownload) + { + SendText("zFeedback Register Op: ex Path: /Event/Phonebook/AddedContact"); + } + // switch to json format + SendText("format json"); + }); - break; - } + break; + } } } } @@ -581,18 +866,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// Deserializes a JSON formatted response /// /// - void DeserializeResponse(string response) + private void DeserializeResponse(string response) { try { var trimmedResponse = response.Trim(); if (trimmedResponse.Length <= 0) + { return; + } var message = JObject.Parse(trimmedResponse); - eZoomRoomResponseType eType = (eZoomRoomResponseType)Enum.Parse(typeof(eZoomRoomResponseType), message["type"].Value(), true); + var eType = + (eZoomRoomResponseType) + Enum.Parse(typeof (eZoomRoomResponseType), message["type"].Value(), true); var topKey = message["topKey"].Value(); @@ -603,385 +892,432 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom switch (eType) { case eZoomRoomResponseType.zConfiguration: + { + switch (topKey.ToLower()) { - switch (topKey.ToLower()) + case "call": { - case "call": - { - JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Call); + JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Call); - break; - } - case "audio": - { - JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Audio); - - break; - } - case "video": - { - JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Video); - - break; - } - case "client": - { - JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Client); - - break; - } - default: - { - break; - } + break; } - break; - } - case eZoomRoomResponseType.zCommand: - { - switch (topKey.ToLower()) + case "audio": { - case "phonebooklistresult": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Phonebook); + JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Audio); - if(!PhonebookSyncState.InitialSyncComplete) - { - PhonebookSyncState.InitialPhonebookFoldersReceived(); - PhonebookSyncState.PhonebookRootEntriesReceived(); - PhonebookSyncState.SetPhonebookHasFolders(false); - PhonebookSyncState.SetNumberOfContacts(Status.Phonebook.Contacts.Count); - } + break; + } + case "video": + { + JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Video); - var directoryResults = new CodecDirectory(); + break; + } + case "client": + { + JsonConvert.PopulateObject(responseObj.ToString(), Configuration.Client); - directoryResults = zStatus.Phonebook.ConvertZoomContactsToGeneric(Status.Phonebook.Contacts); + break; + } + default: + { + break; + } + } + break; + } + case eZoomRoomResponseType.zCommand: + { + switch (topKey.ToLower()) + { + case "inforesult": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.Info); + break; + } + case "phonebooklistresult": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Phonebook); - DirectoryRoot = directoryResults; + if (!PhonebookSyncState.InitialSyncComplete) + { + PhonebookSyncState.InitialPhonebookFoldersReceived(); + PhonebookSyncState.PhonebookRootEntriesReceived(); + PhonebookSyncState.SetPhonebookHasFolders(false); + PhonebookSyncState.SetNumberOfContacts(Status.Phonebook.Contacts.Count); + } - OnDirectoryResultReturned(directoryResults); + var directoryResults = + zStatus.Phonebook.ConvertZoomContactsToGeneric(Status.Phonebook.Contacts); + DirectoryRoot = directoryResults; + + _currentDirectoryResult = DirectoryRoot; + + OnDirectoryResultReturned(directoryResults); + + break; + } + case "listparticipantsresult": + { + Debug.Console(1, this, "JTokenType: {0}", responseObj.Type); + + switch (responseObj.Type) + { + case JTokenType.Array: + Status.Call.Participants = + JsonConvert.DeserializeObject>( + responseObj.ToString()); break; - } - case "listparticipantsresult": + case JTokenType.Object: { - Debug.Console(1, this, "JTokenType: {0}", responseObj.Type); + // this is a single participant event notification - if (responseObj.Type == JTokenType.Array) + var participant = + JsonConvert.DeserializeObject( + responseObj.ToString()); + + if (participant != null) { - // if the type is array this must be the complete list - Status.Call.Participants = JsonConvert.DeserializeObject>(responseObj.ToString()); - } - else if (responseObj.Type == JTokenType.Object) - { - // this is a single participant event notification - - var participant = JsonConvert.DeserializeObject(responseObj.ToString()); - - if (participant != null) + switch (participant.Event) { - if (participant.Event == "ZRCUserChangedEventLeftMeeting" || participant.Event == "ZRCUserChangedEventUserInfoUpdated") + case "ZRCUserChangedEventUserInfoUpdated": + case "ZRCUserChangedEventLeftMeeting": { - var existingParticipant = Status.Call.Participants.FirstOrDefault(p => p.UserId.Equals(participant.UserId)); + var existingParticipant = + Status.Call.Participants.FirstOrDefault( + p => p.UserId.Equals(participant.UserId)); if (existingParticipant != null) { - if (participant.Event == "ZRCUserChangedEventLeftMeeting") + switch (participant.Event) { - // Remove participant - Status.Call.Participants.Remove(existingParticipant); - } - else if (participant.Event == "ZRCUserChangedEventUserInfoUpdated") - { - // Update participant - JsonConvert.PopulateObject(responseObj.ToString(), existingParticipant); + case "ZRCUserChangedEventLeftMeeting": + Status.Call.Participants.Remove(existingParticipant); + break; + case "ZRCUserChangedEventUserInfoUpdated": + JsonConvert.PopulateObject(responseObj.ToString(), + existingParticipant); + break; } } } - else if(participant.Event == "ZRCUserChangedEventJoinedMeeting") - { + break; + case "ZRCUserChangedEventJoinedMeeting": Status.Call.Participants.Add(participant); - } + break; } } - - PrintCurrentCallParticipants(); - - break; } - default: - { break; - } + } + + var participants = + zCommand.ListParticipant.GetGenericParticipantListFromParticipantsResult( + Status.Call.Participants); + + Participants.CurrentParticipants = participants; + + PrintCurrentCallParticipants(); + + break; + } + default: + { + break; } - break; } + break; + } case eZoomRoomResponseType.zEvent: + { + switch (topKey.ToLower()) { - switch (topKey.ToLower()) + case "phonebook": { - case "phonebook": + if (responseObj["Updated Contact"] != null) + { + var updatedContact = + JsonConvert.DeserializeObject( + responseObj["Updated Contact"].ToString()); + + var existingContact = + Status.Phonebook.Contacts.FirstOrDefault(c => c.Jid.Equals(updatedContact.Jid)); + + if (existingContact != null) { - if (responseObj["Updated Contact"] != null) - { - var updatedContact = JsonConvert.DeserializeObject(responseObj["Updated Contact"].ToString()); - - var existingContact = Status.Phonebook.Contacts.FirstOrDefault(c => c.Jid.Equals(updatedContact.Jid)); - - if (existingContact != null) - { - // Update existing contact - JsonConvert.PopulateObject(responseObj["Updated Contact"].ToString(), existingContact); - } - } - else if (responseObj["Added Contact"] != null) - { - var newContact = JsonConvert.DeserializeObject(responseObj["Updated Contact"].ToString()); - - // Add a new contact - Status.Phonebook.Contacts.Add(newContact); - } - - break; + // Update existing contact + JsonConvert.PopulateObject(responseObj["Updated Contact"].ToString(), + existingContact); } - case "bookingslistresult": + } + else if (responseObj["Added Contact"] != null) + { + var jToken = responseObj["Updated Contact"]; + if (jToken != null) { - if (!SyncState.InitialSyncComplete) - SyncState.LastQueryResponseReceived(); + var newContact = + JsonConvert.DeserializeObject( + jToken.ToString()); - var codecBookings = new List(); - - codecBookings = JsonConvert.DeserializeObject < List>(responseObj.ToString()); - - if (codecBookings != null && codecBookings.Count > 0) - { - CodecSchedule.Meetings = zCommand.GetGenericMeetingsFromBookingResult(codecBookings); - } - - break; + // Add a new contact + Status.Phonebook.Contacts.Add(newContact); } - case "bookings": - { - // Bookings have been updated, trigger a query to retreive the new bookings - if (responseObj["Updated"] != null) - GetBookings(); + } - break; - } - case "sharingstate": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.Sharing); - - break; - } - case "incomingcallindication": - { - var incomingCall = JsonConvert.DeserializeObject(responseObj.ToString()); - - if (incomingCall != null) - { - var newCall = new CodecActiveCallItem(); - - newCall.Direction = eCodecCallDirection.Incoming; - newCall.Status = eCodecCallStatus.Ringing; - newCall.Type = eCodecCallType.Unknown; - newCall.Name = incomingCall.callerName; - newCall.Id = incomingCall.callerJID; - - ActiveCalls.Add(newCall); - - OnCallStatusChange(newCall); - } - - break; - } - case "treatedincomingcallindication": - { - var incomingCall = JsonConvert.DeserializeObject(responseObj.ToString()); - - if (incomingCall != null) - { - var existingCall = ActiveCalls.FirstOrDefault(c => c.Id.Equals(incomingCall.callerJID)); - - if (existingCall != null) - { - if (!incomingCall.accepted) - { - existingCall.Status = eCodecCallStatus.Disconnected; - } - else - { - existingCall.Status = eCodecCallStatus.Connecting; - } - - OnCallStatusChange(existingCall); - } - - UpdateCallStatus(); - } - - break; - } - case "calldisconnect": - { - var disconnectEvent = JsonConvert.DeserializeObject(responseObj.ToString()); - - if (disconnectEvent.Successful) - { - if (ActiveCalls.Count > 0) - { - var activeCall = ActiveCalls.FirstOrDefault(c => c.IsActiveCall); - - if (activeCall != null) - { - activeCall.Status = eCodecCallStatus.Disconnected; - - OnCallStatusChange(activeCall); - } - } - } - - UpdateCallStatus(); - break; - } - case "callconnecterror": - { - UpdateCallStatus(); - break; - } - case "videounmuterequest": - { - // TODO: notify room of a request to unmute video - break; - } - case "meetingneedspassword": - { - // TODO: notify user to enter a password - break; - } - case "needwaitforhost": - { - var needWait = JsonConvert.DeserializeObject(responseObj.ToString()); - - if (needWait.Wait) - { - // TODO: notify user to wait for host - } - - break; - } - case "openvideofailforhoststop": - { - // TODO: notify user that host has disabled unmuting video - break; - } - case "updatedcallrecordinfo": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.CallRecordInfo); - - break; - } - default: - { - break; - } + break; + } + case "bookingslistresult": + { + if (!_syncState.InitialSyncComplete) + { + _syncState.LastQueryResponseReceived(); + } + + var codecBookings = JsonConvert.DeserializeObject>( + responseObj.ToString()); + + if (codecBookings != null && codecBookings.Count > 0) + { + CodecSchedule.Meetings = zCommand.GetGenericMeetingsFromBookingResult( + codecBookings, CodecSchedule.MeetingWarningMinutes); + } + + break; + } + case "bookings updated": + { + GetBookings(); + + break; + } + case "sharingstate": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.Sharing); + + SetLayout(); + + break; + } + case "incomingcallindication": + { + var incomingCall = + JsonConvert.DeserializeObject(responseObj.ToString()); + + if (incomingCall != null) + { + var newCall = new CodecActiveCallItem + { + Direction = eCodecCallDirection.Incoming, + Status = eCodecCallStatus.Ringing, + Type = eCodecCallType.Unknown, + Name = incomingCall.callerName, + Id = incomingCall.callerJID + }; + + ActiveCalls.Add(newCall); + + OnCallStatusChange(newCall); + } + + break; + } + case "treatedincomingcallindication": + { + var incomingCall = + JsonConvert.DeserializeObject(responseObj.ToString()); + + if (incomingCall != null) + { + var existingCall = + ActiveCalls.FirstOrDefault(c => c.Id.Equals(incomingCall.callerJID)); + + if (existingCall != null) + { + existingCall.Status = !incomingCall.accepted + ? eCodecCallStatus.Disconnected + : eCodecCallStatus.Connecting; + + OnCallStatusChange(existingCall); + } + + UpdateCallStatus(); + } + + break; + } + case "calldisconnect": + { + var disconnectEvent = + JsonConvert.DeserializeObject(responseObj.ToString()); + + if (disconnectEvent.Successful) + { + if (ActiveCalls.Count > 0) + { + var activeCall = ActiveCalls.FirstOrDefault(c => c.IsActiveCall); + + if (activeCall != null) + { + activeCall.Status = eCodecCallStatus.Disconnected; + + OnCallStatusChange(activeCall); + } + } + var emptyList = new List(); + Participants.CurrentParticipants = emptyList; + } + + UpdateCallStatus(); + break; + } + case "callconnecterror": + { + UpdateCallStatus(); + break; + } + case "videounmuterequest": + { + // TODO: notify room of a request to unmute video + break; + } + case "meetingneedspassword": + { + // TODO: notify user to enter a password + break; + } + case "needwaitforhost": + { + var needWait = + JsonConvert.DeserializeObject(responseObj.ToString()); + + if (needWait.Wait) + { + // TODO: notify user to wait for host + } + + break; + } + case "openvideofailforhoststop": + { + // TODO: notify user that host has disabled unmuting video + break; + } + case "updatedcallrecordinfo": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Call.CallRecordInfo); + + break; + } + case "phonecallstatus": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.PhoneCall); + break; + } + default: + { + break; } - break; } + break; + } case eZoomRoomResponseType.zStatus: + { + switch (topKey.ToLower()) { - switch (topKey.ToLower()) + case "login": { - case "login": - { - SyncState.LoginMessageReceived(); + _syncState.LoginMessageReceived(); - if (!SyncState.InitialQueryMessagesWereSent) - SetUpSyncQueries(); + if (!_syncState.InitialQueryMessagesWereSent) + { + SetUpSyncQueries(); + } - JsonConvert.PopulateObject(responseObj.ToString(), Status.Login); + JsonConvert.PopulateObject(responseObj.ToString(), Status.Login); - break; - } - case "systemunit": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.SystemUnit); - - break; - } - case "call": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Call); - - UpdateCallStatus(); - - break; - } - case "capabilities": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Capabilities); - break; - } - case "sharing": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Sharing); - - break; - } - case "numberofscreens": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.NumberOfScreens); - break; - } - case "video": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Video); - break; - } - case "camerashare": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.CameraShare); - break; - } - case "layout": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Layout); - break; - } - case "audio input line": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.AudioInputs); - break; - } - case "audio output line": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.AudioOuputs); - break; - } - case "video camera line": - { - JsonConvert.PopulateObject(responseObj.ToString(), Status.Cameras); - - if(!SyncState.CamerasHaveBeenSetUp) - SetUpCameras(); - - break; - } - default: - { - break; - } + break; } + case "systemunit": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.SystemUnit); - break; + break; + } + case "call": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Call); + + UpdateCallStatus(); + + break; + } + case "capabilities": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Capabilities); + break; + } + case "sharing": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Sharing); + + break; + } + case "numberofscreens": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.NumberOfScreens); + break; + } + case "video": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Video); + break; + } + case "camerashare": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.CameraShare); + break; + } + case "layout": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Layout); + break; + } + case "audio input line": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.AudioInputs); + break; + } + case "audio output line": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.AudioOuputs); + break; + } + case "video camera line": + { + JsonConvert.PopulateObject(responseObj.ToString(), Status.Cameras); + + if (!_syncState.CamerasHaveBeenSetUp) + { + SetUpCameras(); + } + + break; + } + default: + { + break; + } } + + break; + } default: - { - Debug.Console(1, "Unknown Response Type:"); - break; - } + { + Debug.Console(1, "Unknown Response Type:"); + break; + } } - } catch (Exception ex) { @@ -989,23 +1325,44 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } } + private void SetLayout() + { + if (!_props.AutoDefaultLayouts) return; + + if ( + (Status.Call.Sharing.State == zEvent.eSharingState.Receiving || + Status.Call.Sharing.State == zEvent.eSharingState.Sending)) + { + SendText(String.Format("zconfiguration call layout style: {0}", + _props.DefaultSharingLayout)); + } + else + { + SendText(String.Format("zconfiguration call layout style: {0}", + _props.DefaultCallLayout)); + } + } + public void PrintCurrentCallParticipants() { - if (Debug.Level > 0) + if (Debug.Level <= 0) { - Debug.Console(1, this, "****************************Call Participants***************************"); - foreach (var participant in Status.Call.Participants) - { - Debug.Console(1, this, "Name: {0} Audio: {1} IsHost: {2}", participant.UserName, participant.AudioStatusState, participant.IsHost); - } - Debug.Console(1, this, "************************************************************************"); + return; } + + Debug.Console(1, this, "****************************Call Participants***************************"); + foreach (var participant in Participants.CurrentParticipants) + { + Debug.Console(1, this, "Name: {0} Audio: {1} IsHost: {2}", participant.Name, + participant.AudioMuteFb, participant.IsHost); + } + Debug.Console(1, this, "************************************************************************"); } /// /// Retrieves bookings list /// - void GetBookings() + private void GetBookings() { SendText("zCommand Bookings List"); } @@ -1014,28 +1371,38 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// /// Updates the current call status /// - void UpdateCallStatus() + private void UpdateCallStatus() { - zStatus.eCallStatus callStatus; - if (Status.Call != null) { - callStatus = Status.Call.Status; + var callStatus = Status.Call.Status; // If not currently in a meeting, intialize the call object if (callStatus != zStatus.eCallStatus.IN_MEETING || callStatus != zStatus.eCallStatus.CONNECTING_MEETING) { - Status.Call = new zStatus.Call(); - Status.Call.Status = callStatus; // set the status after initializing the object + Status.Call = new zStatus.Call {Status = callStatus}; + + SetUpCallFeedbackActions(); } if (ActiveCalls.Count == 0) { - if(callStatus == zStatus.eCallStatus.CONNECTING_MEETING) + if (callStatus == zStatus.eCallStatus.CONNECTING_MEETING || + callStatus == zStatus.eCallStatus.IN_MEETING) { - var newCall = new CodecActiveCallItem(); + var newStatus = eCodecCallStatus.Unknown; - newCall.Status = eCodecCallStatus.Connecting; + switch (callStatus) + { + case zStatus.eCallStatus.CONNECTING_MEETING: + newStatus = eCodecCallStatus.Connecting; + break; + case zStatus.eCallStatus.IN_MEETING: + newStatus = eCodecCallStatus.Connected; + break; + } + + var newCall = new CodecActiveCallItem {Status = newStatus}; ActiveCalls.Add(newCall); @@ -1046,18 +1413,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { var existingCall = ActiveCalls.FirstOrDefault(c => !c.Status.Equals(eCodecCallStatus.Ringing)); - if (callStatus == zStatus.eCallStatus.IN_MEETING) + switch (callStatus) { - existingCall.Status = eCodecCallStatus.Connected; - } - else if (callStatus == zStatus.eCallStatus.NOT_IN_MEETING) - { - existingCall.Status = eCodecCallStatus.Disconnected; + case zStatus.eCallStatus.IN_MEETING: + existingCall.Status = eCodecCallStatus.Connected; + break; + case zStatus.eCallStatus.NOT_IN_MEETING: + existingCall.Status = eCodecCallStatus.Disconnected; + break; } OnCallStatusChange(existingCall); } - } Debug.Console(1, this, "****************************Active Calls*********************************"); @@ -1067,7 +1434,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { var call = ActiveCalls[i]; - Debug.Console(1, this, + Debug.Console(1, this, @"Name: {0} ID: {1} IsActive: {2} @@ -1080,14 +1447,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom ActiveCalls.Remove(call); } } - Debug.Console(1, this, "**************************************************************************"); + //clear participants list after call cleanup + if (ActiveCalls.Count == 0) + { + Participants.CurrentParticipants = new List(); + } + } + + protected override void OnCallStatusChange(CodecActiveCallItem item) + { + base.OnCallStatusChange(item); + + if (_props.AutoDefaultLayouts) + { + SetLayout(); + } } public override void StartSharing() { - throw new NotImplementedException(); + SendText("zCommand Call Sharing HDMI Start"); } /// @@ -1111,19 +1492,23 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public override void PrivacyModeToggle() { if (PrivacyModeIsOnFeedback.BoolValue) + { PrivacyModeOff(); + } else + { PrivacyModeOn(); + } } public override void MuteOff() { - SetVolume((ushort)PreviousVolumeLevel); + SetVolume((ushort) _previousVolumeLevel); } public override void MuteOn() { - PreviousVolumeLevel = Configuration.Audio.Output.Volume; // Store the previous level for recall + _previousVolumeLevel = Configuration.Audio.Output.Volume; // Store the previous level for recall SetVolume(0); } @@ -1131,18 +1516,23 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public override void MuteToggle() { if (MuteFeedback.BoolValue) + { MuteOff(); + } else + { MuteOn(); + } } + /// /// Increments the voluem /// /// public override void VolumeUp(bool pressRelease) { - // TODO: Implment volume increment that calls SetVolume() + // TODO: Implment volume decrement that calls SetVolume() } /// @@ -1169,7 +1559,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// public void VolumeSetToDefault() { - } /// @@ -1188,26 +1577,60 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom // No corresponding function on device } - public override void ExecuteSwitch(object selector) + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { - (selector as Action)(); + LinkVideoCodecToApi(this, trilist, joinStart, joinMapKey, bridge); } - public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) + public override void ExecuteSwitch(object selector) { - ExecuteSwitch(inputSelector); + var action = selector as Action; + if (action == null) + { + return; + } + + action(); + } + + public void AcceptCall() + { + var incomingCall = + ActiveCalls.FirstOrDefault( + c => c.Status.Equals(eCodecCallStatus.Ringing) && c.Direction.Equals(eCodecCallDirection.Incoming)); + + AcceptCall(incomingCall); } public override void AcceptCall(CodecActiveCallItem call) { - var incomingCall = ActiveCalls.FirstOrDefault(c => c.Status.Equals(eCodecCallStatus.Ringing) && c.Direction.Equals(eCodecCallDirection.Incoming)); - SendText(string.Format("zCommand Call Accept callerJID: {0}", incomingCall.Id)); + SendText(string.Format("zCommand Call Accept callerJID: {0}", call.Id)); + + call.Status = eCodecCallStatus.Connected; + + OnCallStatusChange(call); + + UpdateCallStatus(); + } + + public void RejectCall() + { + var incomingCall = + ActiveCalls.FirstOrDefault( + c => c.Status.Equals(eCodecCallStatus.Ringing) && c.Direction.Equals(eCodecCallDirection.Incoming)); + + RejectCall(incomingCall); } public override void RejectCall(CodecActiveCallItem call) { - var incomingCall = ActiveCalls.FirstOrDefault(c => c.Status.Equals(eCodecCallStatus.Ringing) && c.Direction.Equals(eCodecCallDirection.Incoming)); - SendText(string.Format("zCommand Call Reject callerJID: {0}", incomingCall.Id)); + SendText(string.Format("zCommand Call Reject callerJID: {0}", call.Id)); + + call.Status = eCodecCallStatus.Disconnected; + + OnCallStatusChange(call); + + UpdateCallStatus(); } public override void Dial(Meeting meeting) @@ -1234,9 +1657,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Debug.Console(1, this, "Attempting to Dial (Invite): {0}", ic.Name); if (!IsInCall) - SendText(string.Format("zCommand Invite Duration: {0} user: {1}", DefaultMeetingDurationMin, ic.ContactId)); + { + SendText(string.Format("zCommand Invite Duration: {0} user: {1}", DefaultMeetingDurationMin, + ic.ContactId)); + } else + { SendText(string.Format("zCommand Call invite user: {0}", ic.ContactId)); + } } } @@ -1252,42 +1680,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public override void SendDtmf(string s) { - throw new NotImplementedException(); + SendDtmfToPhone(s); } - - #region IHasCodecSelfView Members - - public BoolFeedback SelfviewIsOnFeedback { get; private set; } - - public void SelfViewModeOn() - { - SendText("zConfiguration Video hide_conf_self_video: off"); - } - - public void SelfViewModeOff() - { - SendText("zConfiguration Video hide_conf_self_video: on"); - } - - public void SelfViewModeToggle() - { - if (SelfviewIsOnFeedback.BoolValue) - SelfViewModeOff(); - else - SelfViewModeOn(); - } - - #endregion - - #region IHasDirectory Members - - public event EventHandler DirectoryResultReturned; - + /// /// Call when directory results are updated /// /// - void OnDirectoryResultReturned(CodecDirectory result) + private void OnDirectoryResultReturned(CodecDirectory result) { CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); @@ -1295,7 +1695,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom var handler = DirectoryResultReturned; if (handler != null) { - handler(this, new DirectoryEventArgs() + handler(this, new DirectoryEventArgs { Directory = result, DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue @@ -1305,94 +1705,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom //PrintDirectory(result); } - public CodecDirectory DirectoryRoot { get; private set; } - - public CodecDirectory CurrentDirectoryResult - { - get - { - if (DirectoryBrowseHistory.Count > 0) - return DirectoryBrowseHistory[DirectoryBrowseHistory.Count - 1]; - else - return DirectoryRoot; - } - } - - public CodecPhonebookSyncState PhonebookSyncState { get; private set; } - - public void SearchDirectory(string searchString) - { - var directoryResults = new CodecDirectory(); - - directoryResults.AddContactsToDirectory(DirectoryRoot.CurrentDirectoryResults.FindAll(c => c.Name.IndexOf(searchString, 0, StringComparison.OrdinalIgnoreCase) > -1)); - - DirectoryBrowseHistory.Add(directoryResults); - - OnDirectoryResultReturned(directoryResults); - } - - public void GetDirectoryFolderContents(string folderId) - { - var directoryResults = new CodecDirectory(); - - directoryResults.ResultsFolderId = folderId; - directoryResults.AddContactsToDirectory(DirectoryRoot.CurrentDirectoryResults.FindAll(c => c.FolderId.Equals(folderId))); - - DirectoryBrowseHistory.Add(directoryResults); - - OnDirectoryResultReturned(directoryResults); - } - - 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; } - - #endregion - - #region IHasScheduleAwareness Members - - public CodecScheduleAwareness CodecSchedule { get; private set; } - - public void GetSchedule() - { - GetBookings(); - } - - #endregion - /// /// Builds the cameras List by using the Zoom Room zStatus.Cameras data. Could later be modified to build from config data /// - void SetUpCameras() + private void SetUpCameras() { SelectedCameraFeedback = new StringFeedback(() => Configuration.Video.Camera.SelectedId); @@ -1405,76 +1721,139 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Cameras.Add(camera); if (cam.Selected) - SelectedCamera = camera; + { + SelectedCamera = camera; + } } if (IsInCall) + { UpdateFarEndCameras(); + } - SyncState.CamerasSetUp(); + _syncState.CamerasSetUp(); } /// /// Dynamically creates far end cameras for call participants who have far end control enabled. /// - void UpdateFarEndCameras() + private void UpdateFarEndCameras() { // TODO: set up far end cameras for the current call } - #region IHasCameras Members + #region Implementation of IHasParticipants - public event EventHandler CameraSelected; + public CodecParticipants Participants { get; private set; } - public List Cameras { get; private set; } + #endregion - private CameraBase _selectedCamera; + #region Implementation of IHasCameraOff - public CameraBase SelectedCamera + public BoolFeedback CameraIsOffFeedback { get; private set; } + + public void CameraOff() { - 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) - { - if(Cameras != null) - { - var camera = Cameras.FirstOrDefault(c => c.Key.IndexOf(key, StringComparison.OrdinalIgnoreCase) > -1); - if (camera != null) - { - Debug.Console(1, this, "Selected Camera with key: '{0}'", camera.Key); - SelectedCamera = camera; - } - else - Debug.Console(1, this, "Unable to select camera with key: '{0}'", key); - } + SendText("zConfiguration Call Camera Mute: On"); } #endregion - #region IHasFarEndCameraControl Members + #region Implementation of IHasCameraAutoMode - public CameraBase FarEndCamera { get; private set; } + //Zoom doesn't support camera auto modes. Setting this to just unmute video + public void CameraAutoModeOn() + { + throw new NotImplementedException("Zoom Room Doesn't support camera auto mode"); + } - public BoolFeedback ControllingFarEndCameraFeedback { get; private set; } + //Zoom doesn't support camera auto modes. Setting this to just unmute video + public void CameraAutoModeOff() + { + SendText("zConfiguration Call Camera Mute: Off"); + } + + public void CameraAutoModeToggle() + { + throw new NotImplementedException("Zoom Room doesn't support camera auto mode"); + } + + public BoolFeedback CameraAutoModeIsOnFeedback { get; private set; } + + #endregion + + #region Implementation of IHasFarEndContentStatus + + public BoolFeedback ReceivingContent { get; private set; } + + #endregion + + #region Implementation of IHasSelfviewPosition + + private CodecCommandWithLabel _currentSelfviewPipPosition; + + public StringFeedback SelfviewPipPositionFeedback { get; private set; } + + public void SelfviewPipPositionSet(CodecCommandWithLabel position) + { + SendText(String.Format("zConfiguration Call Layout Position: {0}", position.Command)); + } + + public void SelfviewPipPositionToggle() + { + if (_currentSelfviewPipPosition != null) + { + var nextPipPositionIndex = SelfviewPipPositions.IndexOf(_currentSelfviewPipPosition) + 1; + + if (nextPipPositionIndex >= SelfviewPipPositions.Count) + // Check if we need to loop back to the first item in the list + nextPipPositionIndex = 0; + + SelfviewPipPositionSet(SelfviewPipPositions[nextPipPositionIndex]); + } + } + + public List SelfviewPipPositions = new List() + { + new CodecCommandWithLabel("UpLeft", "Center Left"), + new CodecCommandWithLabel("UpRight", "Center Right"), + new CodecCommandWithLabel("DownRight", "Lower Right"), + new CodecCommandWithLabel("DownLeft", "Lower Left") + }; + + private void ComputeSelfviewPipStatus() + { + _currentSelfviewPipPosition = + SelfviewPipPositions.FirstOrDefault( + p => p.Command.ToLower().Equals(Configuration.Call.Layout.Position.ToString().ToLower())); + } + + #endregion + + #region Implementation of IHasPhoneDialing + + private Func PhoneOffHookFeedbackFunc {get {return () => Status.PhoneCall.OffHook; }} + private Func CallerIdNameFeedbackFunc { get { return () => Status.PhoneCall.PeerDisplayName; } } + private Func CallerIdNumberFeedbackFunc { get { return () => Status.PhoneCall.PeerNumber; } } + + public BoolFeedback PhoneOffHookFeedback { get; private set; } + public StringFeedback CallerIdNameFeedback { get; private set; } + public StringFeedback CallerIdNumberFeedback { get; private set; } + + public void DialPhoneCall(string number) + { + SendText(String.Format("zCommand Dial PhoneCallOut Number: {0}", number)); + } + + public void EndPhoneCall() + { + SendText(String.Format("zCommand Dial PhoneHangUp CallId: {0}", Status.PhoneCall.CallId)); + } + + public void SendDtmfToPhone(string digit) + { + SendText(String.Format("zCommand SendSipDTMF CallId: {0} Key: {1}", Status.PhoneCall.CallId, digit)); + } #endregion } @@ -1484,15 +1863,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// public class ZoomRoomInfo : VideoCodecInfo { + public ZoomRoomInfo(ZoomRoomStatus status, ZoomRoomConfiguration configuration) + { + Status = status; + Configuration = configuration; + } + public ZoomRoomStatus Status { get; private set; } public ZoomRoomConfiguration Configuration { get; private set; } public override bool AutoAnswerEnabled { - get - { - return Status.SystemUnit.RoomInfo.AutoAnswerIsEnabled; - } + get { return Status.SystemUnit.RoomInfo.AutoAnswerIsEnabled; } } public override string E164Alias @@ -1500,9 +1882,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom get { if (!string.IsNullOrEmpty(Status.SystemUnit.MeetingNumber)) + { return Status.SystemUnit.MeetingNumber; - else - return string.Empty; + } + return string.Empty; } } @@ -1511,9 +1894,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom get { if (!string.IsNullOrEmpty(Status.Call.Info.meeting_list_item.third_party.h323_address)) + { return Status.Call.Info.meeting_list_item.third_party.h323_address; - else - return string.Empty; + } + return string.Empty; } } @@ -1522,9 +1906,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom get { if (!string.IsNullOrEmpty(Status.SystemUnit.RoomInfo.AccountEmail)) + { return Status.SystemUnit.RoomInfo.AccountEmail; - else - return string.Empty; + } + return string.Empty; } } @@ -1538,9 +1923,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom get { if (!string.IsNullOrEmpty(Status.Call.Info.dialIn)) + { return Status.Call.Info.dialIn; - else - return string.Empty; + } + return string.Empty; } } @@ -1549,17 +1935,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom get { if (!string.IsNullOrEmpty(Status.Call.Info.meeting_list_item.third_party.sip_address)) + { return Status.Call.Info.meeting_list_item.third_party.sip_address; - else - return string.Empty; + } + return string.Empty; } } - - public ZoomRoomInfo(ZoomRoomStatus status, ZoomRoomConfiguration configuration) - { - Status = status; - Configuration = configuration; - } } /// @@ -1567,28 +1948,32 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// public class ZoomRoomSyncState : IKeyed { - bool _InitialSyncComplete; + private readonly ZoomRoom _parent; + private readonly CrestronQueue _syncQueries; + private bool _initialSyncComplete; - public event EventHandler InitialSyncCompleted; - - private CrestronQueue SyncQueries; - - private ZoomRoom Parent; - - public string Key { get; private set; } + public ZoomRoomSyncState(string key, ZoomRoom parent) + { + _parent = parent; + Key = key; + _syncQueries = new CrestronQueue(50); + CodecDisconnected(); + } public bool InitialSyncComplete { - get { return _InitialSyncComplete; } + get { return _initialSyncComplete; } private set { - if (value == true) + if (value) { var handler = InitialSyncCompleted; if (handler != null) + { handler(this, new EventArgs()); + } } - _InitialSyncComplete = value; + _initialSyncComplete = value; } } @@ -1598,28 +1983,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public bool LastQueryResponseWasReceived { get; private set; } - public bool CamerasHaveBeenSetUp { get; private set;} + public bool CamerasHaveBeenSetUp { get; private set; } - public ZoomRoomSyncState(string key, ZoomRoom parent) - { - Parent = parent; - Key = key; - SyncQueries = new CrestronQueue(50); - CodecDisconnected(); - } + #region IKeyed Members + + public string Key { get; private set; } + + #endregion + + public event EventHandler InitialSyncCompleted; public void StartSync() { DequeueQueries(); } - void DequeueQueries() + private void DequeueQueries() { - while (!SyncQueries.IsEmpty) + while (!_syncQueries.IsEmpty) { - var query = SyncQueries.Dequeue(); + var query = _syncQueries.Dequeue(); - Parent.SendText(query); + _parent.SendText(query); } InitialQueryMessagesSent(); @@ -1627,7 +2012,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public void AddQueryToQueue(string query) { - SyncQueries.Enqueue(query); + _syncQueries.Enqueue(query); } public void LoginMessageReceived() @@ -1660,7 +2045,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public void CodecDisconnected() { - SyncQueries.Clear(); + _syncQueries.Clear(); LoginMessageWasReceived = false; InitialQueryMessagesWereSent = false; LastQueryResponseWasReceived = false; @@ -1668,15 +2053,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom InitialSyncComplete = false; } - void CheckSyncStatus() + private void CheckSyncStatus() { - if (LoginMessageWasReceived && InitialQueryMessagesWereSent && LastQueryResponseWasReceived && CamerasHaveBeenSetUp) + if (LoginMessageWasReceived && InitialQueryMessagesWereSent && LastQueryResponseWasReceived && + CamerasHaveBeenSetUp) { InitialSyncComplete = true; Debug.Console(1, this, "Initial Codec Sync Complete!"); } else + { InitialSyncComplete = false; + } } } @@ -1684,15 +2072,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { public ZoomRoomFactory() { - TypeNames = new List() { "zoomroom" }; + TypeNames = new List {"zoomroom"}; } public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.Console(1, "Factory Attempting to create new ZoomRoom Device"); var comm = CommFactory.CreateCommForDevice(dc); - return new VideoCodec.ZoomRoom.ZoomRoom(dc, comm); + return new ZoomRoom(dc, comm); } } - } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs index 4fa377ae..7a3abdaa 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomCamera.cs @@ -68,7 +68,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom /// /// Builds the command and triggers the parent ZoomRoom to send it /// - /// /// /// void SendCommand(eZoomRoomCameraState state, eZoomRoomCameraAction action) @@ -79,23 +78,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom void StartContinueTimer() { - if(ContinueTimer == null) - ContinueTimer = new CTimer((o) => SendContinueAction(LastAction), ContinueTime); + if (ContinueTimer == null) + ContinueTimer = new CTimer((o) => SendContinueAction(LastAction), null, ContinueTime, ContinueTime); } void SendContinueAction(eZoomRoomCameraAction action) { SendCommand(eZoomRoomCameraState.Continue, action); - ContinueTimer.Reset(); } void StopContinueTimer() { - if (ContinueTimer != null) + if (ContinueTimer == null) { - ContinueTimer.Stop(); - ContinueTimer.Dispose(); + return; } + + ContinueTimer.Stop(); + ContinueTimer.Dispose(); + ContinueTimer = null; } #region IHasCameraPtzControl Members @@ -111,22 +112,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public void PanLeft() { - if (!isMoving) + if (isMoving) { - SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Left); - StartContinueTimer(); - isPanning = true; + return; } + + SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Left); + StartContinueTimer(); + isPanning = true; } public void PanRight() { - if (!isMoving) + if (isMoving) { - SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Right); - StartContinueTimer(); - isPanning = true; + return; } + + SendCommand(eZoomRoomCameraState.Start, eZoomRoomCameraAction.Right); + StartContinueTimer(); + isPanning = true; } public void PanStop() diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs index d60b63c2..38238023 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomPropertiesConfig.cs @@ -12,5 +12,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom public class ZoomRoomPropertiesConfig { public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } + + public bool DisablePhonebookAutoDownload { get; set; } + public bool SupportsCameraAutoMode { get; set; } + public bool SupportsCameraOff { get; set; } + + //if true, the layouts will be set automatically when sharing starts/ends or a call is joined + public bool AutoDefaultLayouts { get; set; } + + /* This layout will be selected when Sharing starts (either from Far end or locally)*/ + public string DefaultSharingLayout { get; set; } + + //This layout will be selected when a call is connected and no content is being shared + public string DefaultCallLayout { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/pepperdashcore-builds b/essentials-framework/pepperdashcore-builds deleted file mode 160000 index 18cb0c27..00000000 --- a/essentials-framework/pepperdashcore-builds +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 18cb0c273eb8b750f657d74160ad82eff1b24bca diff --git a/packages.config b/packages.config index 11087174..296413b6 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file