diff --git a/PepperDashEssentials/AppServer/Messengers/CameraBaseMessenger.cs b/PepperDashEssentials/AppServer/Messengers/CameraBaseMessenger.cs new file mode 100644 index 00000000..043341a9 --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/CameraBaseMessenger.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Cameras; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class CameraBaseMessenger : MessengerBase + { + /// + /// Device being bridged + /// + public CameraBase Camera { get; set; } + + /// + /// Constructor + /// + /// + /// + /// + public CameraBaseMessenger(string key, CameraBase camera, string messagePath) + : base(key, messagePath) + { + if (camera == null) + throw new ArgumentNullException("camera"); + + Camera = camera; + + var presetsCamera = Camera as IHasCameraPresets; + + if (presetsCamera != null) + { + presetsCamera.PresetsListHasChanged += new EventHandler(presetsCamera_PresetsListHasChanged); + } + + } + + void presetsCamera_PresetsListHasChanged(object sender, EventArgs e) + { + var presetsCamera = Camera as IHasCameraPresets; + + var presetList = new List(); + + if (presetsCamera != null) + presetList = presetsCamera.Presets; + + PostStatusMessage(new + { + presets = presetList + }); + } + + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) + { + appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendCameraFullMessageObject)); + + var ptzCamera = Camera as IHasCameraPtzControl; + + if (ptzCamera != null) + { + + // Need to evaluate how to pass through these P&H actions. Need a method that takes a bool maybe? + AppServerController.AddAction(MessagePath + "/cameraUp", new PressAndHoldAction((b) => + { + if (b) + ptzCamera.TiltUp(); + else + ptzCamera.TiltStop(); + })); + AppServerController.AddAction(MessagePath + "/cameraDown", new PressAndHoldAction((b) => + { + if (b) + ptzCamera.TiltDown(); + else + ptzCamera.TiltStop(); + })); + AppServerController.AddAction(MessagePath + "/cameraLeft", new PressAndHoldAction((b) => + { + if (b) + ptzCamera.PanLeft(); + else + ptzCamera.PanStop(); + })); + AppServerController.AddAction(MessagePath + "/cameraRight", new PressAndHoldAction((b) => + { + if (b) + ptzCamera.PanRight(); + else + ptzCamera.PanStop(); + })); + AppServerController.AddAction(MessagePath + "/cameraZoomIn", new PressAndHoldAction((b) => + { + if (b) + ptzCamera.ZoomIn(); + else + ptzCamera.ZoomStop(); + })); + AppServerController.AddAction(MessagePath + "/cameraZoomOut", new PressAndHoldAction((b) => + { + if (b) + ptzCamera.ZoomOut(); + else + ptzCamera.ZoomStop(); + })); + } + + if (Camera is IHasCameraAutoMode) + { + appServerController.AddAction(MessagePath + "/cameraModeAuto", new Action((Camera as IHasCameraAutoMode).CameraAutoModeOn)); + appServerController.AddAction(MessagePath + "/cameraModeManual", new Action((Camera as IHasCameraAutoMode).CameraAutoModeOff)); + } + + if (Camera is IPower) + { + appServerController.AddAction(MessagePath + "/cameraModeOff", new Action((Camera as IPower).PowerOff)); + } + + var presetsCamera = Camera as IHasCameraPresets; + + if (presetsCamera != null) + { + for(int i = 1; i <= 6; i++) + { + var preset = i; + appServerController.AddAction(MessagePath + "/cameraPreset" + i, new Action((p) => presetsCamera.PresetSelect(preset))); + } + } + } + + /// + /// Helper method to update the full status of the camera + /// + void SendCameraFullMessageObject() + { + var presetsCamera = Camera as IHasCameraPresets; + + var presetList = new List(); + + if (presetsCamera != null) + presetList = presetsCamera.Presets; + + PostStatusMessage(new + { + cameraMode = GetCameraMode(), + hasPresets = Camera is IHasCameraPresets, + presets = presetList + }); + } + + /// + /// Computes the current camera mode + /// + /// + string GetCameraMode() + { + string m; + if (Camera is IHasCameraAutoMode && (Camera as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.BoolValue) + m = eCameraControlMode.Auto.ToString().ToLower(); + else if (Camera is IPower && !(Camera as IPower).PowerIsOnFeedback.BoolValue) + m = eCameraControlMode.Off.ToString().ToLower(); + else + m = eCameraControlMode.Manual.ToString().ToLower(); + return m; + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs b/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs deleted file mode 100644 index eee94350..00000000 --- a/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; -using Crestron.SimplSharpPro.EthernetCommunication; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.Codec; - -namespace PepperDash.Essentials.AppServer.Messengers -{ - public class Ddvc01AtcMessenger : MessengerBase - { - BasicTriList EISC; - - /// - /// 221 - /// - const uint BDialHangupOnHook = 221; - - /// - /// 251 - /// - const uint BIncomingAnswer = 251; - /// - /// 252 - /// - const uint BIncomingReject = 252; - /// - /// 241 - /// - const uint BSpeedDial1 = 241; - /// - /// 242 - /// - const uint BSpeedDial2 = 242; - /// - /// 243 - /// - const uint BSpeedDial3 = 243; - /// - /// 244 - /// - const uint BSpeedDial4 = 244; - - /// - /// 201 - /// - const uint SCurrentDialString = 201; - /// - /// 211 - /// - const uint SCurrentCallNumber = 211; - /// - /// 212 - /// - const uint SCurrentCallName = 212; - /// - /// 221 - /// - const uint SHookState = 221; - /// - /// 222 - /// - const uint SCallDirection = 222; - - /// - /// 201-212 0-9*# - /// - Dictionary DTMFMap = new Dictionary - { - { "1", 201 }, - { "2", 202 }, - { "3", 203 }, - { "4", 204 }, - { "5", 205 }, - { "6", 206 }, - { "7", 207 }, - { "8", 208 }, - { "9", 209 }, - { "0", 210 }, - { "*", 211 }, - { "#", 212 }, - }; - - /// - /// - /// - CodecActiveCallItem CurrentCallItem; - - - /// - /// - /// - /// - /// - public Ddvc01AtcMessenger(string key, BasicTriList eisc, string messagePath) - : base(key, messagePath) - { - EISC = eisc; - - CurrentCallItem = new CodecActiveCallItem(); - CurrentCallItem.Type = eCodecCallType.Audio; - CurrentCallItem.Id = "-audio-"; - } - - /// - /// - /// - void SendFullStatus() - { - - - this.PostStatusMessage(new - { - calls = GetCurrentCallList(), - currentCallString = EISC.GetString(SCurrentCallNumber), - currentDialString = EISC.GetString(SCurrentDialString), - isInCall = EISC.GetString(SHookState) == "Connected" - }); - } - - /// - /// - /// - /// - protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) - { - //EISC.SetStringSigAction(SCurrentDialString, s => PostStatusMessage(new { currentDialString = s })); - - EISC.SetStringSigAction(SHookState, s => - { - CurrentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); - //GetCurrentCallList(); - SendFullStatus(); - }); - - EISC.SetStringSigAction(SCurrentCallNumber, s => - { - CurrentCallItem.Number = s; - SendCallsList(); - }); - - EISC.SetStringSigAction(SCurrentCallName, s => - { - CurrentCallItem.Name = s; - SendCallsList(); - }); - - EISC.SetStringSigAction(SCallDirection, s => - { - CurrentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); - SendCallsList(); - }); - - // Add press and holds using helper - Action addPHAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); - - // Add straight pulse calls - Action addAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); - addAction("/endCallById", BDialHangupOnHook); - addAction("/endAllCalls", BDialHangupOnHook); - addAction("/acceptById", BIncomingAnswer); - addAction("/rejectById", BIncomingReject); - addAction("/speedDial1", BSpeedDial1); - addAction("/speedDial2", BSpeedDial2); - addAction("/speedDial3", BSpeedDial3); - addAction("/speedDial4", BSpeedDial4); - - // Get status - AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); - // Dial on string - AppServerController.AddAction(MessagePath + "/dial", new Action(s => EISC.SetString(SCurrentDialString, s))); - // Pulse DTMF - AppServerController.AddAction(MessagePath + "/dtmf", new Action(s => - { - if (DTMFMap.ContainsKey(s)) - { - EISC.PulseBool(DTMFMap[s], 100); - } - })); - } - - /// - /// - /// - void SendCallsList() - { - PostStatusMessage(new - { - calls = GetCurrentCallList(), - }); - } - - /// - /// Turns the - /// - /// - List GetCurrentCallList() - { - if (CurrentCallItem.Status == eCodecCallStatus.Disconnected) - { - return new List(); - } - else - { - return new List() { CurrentCallItem }; - } - } - } -} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs b/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs deleted file mode 100644 index e3de11d0..00000000 --- a/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs +++ /dev/null @@ -1,648 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; -using Crestron.SimplSharpPro.EthernetCommunication; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.Codec; - -namespace PepperDash.Essentials.AppServer.Messengers -{ - public class Ddvc01VtcMessenger : MessengerBase - { - BasicTriList EISC; - - /********* Bools *********/ - /// - /// 724 - /// - const uint BDialHangup = 724; - /// - /// 750 - /// - const uint BCallIncoming = 750; - /// - /// 751 - /// - const uint BIncomingAnswer = 751; - /// - /// 752 - /// - const uint BIncomingReject = 752; - /// - /// 741 - /// - const uint BSpeedDial1 = 741; - /// - /// 742 - /// - const uint BSpeedDial2 = 742; - /// - /// 743 - /// - const uint BSpeedDial3 = 743; - /// - /// 744 - /// - const uint BSpeedDial4 = 744; - /// - /// 800 - /// - const uint BDirectorySearchBusy = 800; - /// - /// 801 - /// - const uint BDirectoryLineSelected = 801; - /// - /// 801 when selected entry is a contact - /// - const uint BDirectoryEntryIsContact = 801; - /// - /// 802 To show/hide back button - /// - const uint BDirectoryIsRoot = 802; - /// - /// 803 Pulse from system to inform us when directory is ready - /// - const uint DDirectoryHasChanged = 803; - /// - /// 804 - /// - const uint BDirectoryRoot = 804; - /// - /// 805 - /// - const uint BDirectoryFolderBack = 805; - /// - /// 806 - /// - const uint BDirectoryDialSelectedLine = 806; - /// - /// 811 - /// - const uint BCameraControlUp = 811; - /// - /// 812 - /// - const uint BCameraControlDown = 812; - /// - /// 813 - /// - const uint BCameraControlLeft = 813; - /// - /// 814 - /// - const uint BCameraControlRight = 814; - /// - /// 815 - /// - const uint BCameraControlZoomIn = 815; - /// - /// 816 - /// - const uint BCameraControlZoomOut = 816; - /// - /// 821 - 826 - /// - const uint BCameraPresetStart = 821; - - /// - /// 831 - /// - const uint BCameraModeAuto = 831; - /// - /// 832 - /// - const uint BCameraModeManual = 832; - /// - /// 833 - /// - const uint BCameraModeOff = 833; - - /// - /// 841 - /// - const uint BCameraSelfView = 841; - - /// - /// 842 - /// - const uint BCameraLayout = 842; - /// - /// 843 - /// - const uint BCameraSupportsAutoMode = 843; - /// - /// 844 - /// - const uint BCameraSupportsOffMode = 844; - - - /********* Ushorts *********/ - /// - /// 760 - /// - const uint UCameraNumberSelect = 760; - /// - /// 801 - /// - const uint UDirectorySelectRow = 801; - /// - /// 801 - /// - const uint UDirectoryRowCount = 801; - - - - /********* Strings *********/ - /// - /// 701 - /// - const uint SCurrentDialString = 701; - /// - /// 702 - /// - const uint SCurrentCallName = 702; - /// - /// 703 - /// - const uint SCurrentCallNumber = 703; - /// - /// 731 - /// - const uint SHookState = 731; - /// - /// 722 - /// - const uint SCallDirection = 722; - /// - /// 751 - /// - const uint SIncomingCallName = 751; - /// - /// 752 - /// - const uint SIncomingCallNumber = 752; - - /// - /// 800 - /// - const uint SDirectorySearchString = 800; - /// - /// 801-1055 - /// - const uint SDirectoryEntriesStart = 801; - /// - /// 1056 - /// - const uint SDirectoryEntrySelectedName = 1056; - /// - /// 1057 - /// - const uint SDirectoryEntrySelectedNumber = 1057; - /// - /// 1058 - /// - const uint SDirectorySelectedFolderName = 1058; - - - /// - /// 701-712 0-9*# - /// - Dictionary DTMFMap = new Dictionary - { - { "1", 701 }, - { "2", 702 }, - { "3", 703 }, - { "4", 704 }, - { "5", 705 }, - { "6", 706 }, - { "7", 707 }, - { "8", 708 }, - { "9", 709 }, - { "0", 710 }, - { "*", 711 }, - { "#", 712 }, - }; - - CodecActiveCallItem CurrentCallItem; - CodecActiveCallItem IncomingCallItem; - - ushort PreviousDirectoryLength = 0; - - /// - /// - /// - /// - /// - public Ddvc01VtcMessenger(string key, BasicTriList eisc, string messagePath) - : base(key, messagePath) - { - EISC = eisc; - - CurrentCallItem = new CodecActiveCallItem(); - CurrentCallItem.Type = eCodecCallType.Video; - CurrentCallItem.Id = "-video-"; - } - - /// - /// - /// - /// - protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) - { - var asc = appServerController; - EISC.SetStringSigAction(SHookState, s => - { - CurrentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); - PostFullStatus(); // SendCallsList(); - }); - - EISC.SetStringSigAction(SCurrentCallNumber, s => - { - CurrentCallItem.Number = s; - PostCallsList(); - }); - - EISC.SetStringSigAction(SCurrentCallName, s => - { - CurrentCallItem.Name = s; - PostCallsList(); - }); - - EISC.SetStringSigAction(SCallDirection, s => - { - CurrentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); - PostCallsList(); - }); - - EISC.SetBoolSigAction(BCallIncoming, b => - { - if (b) - { - var ica = new CodecActiveCallItem() - { - Direction = eCodecCallDirection.Incoming, - Id = "-video-incoming", - Name = EISC.GetString(SIncomingCallName), - Number = EISC.GetString(SIncomingCallNumber), - Status = eCodecCallStatus.Ringing, - Type = eCodecCallType.Video - }; - IncomingCallItem = ica; - } - else - { - IncomingCallItem = null; - } - PostCallsList(); - }); - - EISC.SetBoolSigAction(BCameraSupportsAutoMode, b => - { - PostStatusMessage(new - { - cameraSupportsAutoMode = b - }); - }); - EISC.SetBoolSigAction(BCameraSupportsOffMode, b => - { - PostStatusMessage(new - { - cameraSupportsOffMode = b - }); - }); - - // Directory insanity - EISC.SetUShortSigAction(UDirectoryRowCount, u => - { - // The length of the list comes in before the list does. - // Splice the sig change operation onto the last string sig that will be changing - // when the directory entries make it through. - if (PreviousDirectoryLength > 0) - { - EISC.ClearStringSigAction(SDirectoryEntriesStart + PreviousDirectoryLength - 1); - } - EISC.SetStringSigAction(SDirectoryEntriesStart + u - 1, s => PostDirectory()); - PreviousDirectoryLength = u; - }); - - EISC.SetStringSigAction(SDirectoryEntrySelectedName, s => - { - PostStatusMessage(new - { - directoryContactSelected = new - { - name = EISC.GetString(SDirectoryEntrySelectedName), - } - }); - }); - - EISC.SetStringSigAction(SDirectoryEntrySelectedNumber, s => - { - PostStatusMessage(new - { - directoryContactSelected = new - { - number = EISC.GetString(SDirectoryEntrySelectedNumber), - } - }); - }); - - EISC.SetStringSigAction(SDirectorySelectedFolderName, s => PostStatusMessage(new - { - directorySelectedFolderName = EISC.GetString(SDirectorySelectedFolderName) - })); - - EISC.SetSigTrueAction(BCameraModeAuto, () => PostCameraMode()); - EISC.SetSigTrueAction(BCameraModeManual, () => PostCameraMode()); - EISC.SetSigTrueAction(BCameraModeOff, () => PostCameraMode()); - - EISC.SetBoolSigAction(BCameraSelfView, b => PostStatusMessage(new - { - cameraSelfView = b - })); - - EISC.SetUShortSigAction(UCameraNumberSelect, (u) => PostSelectedCamera()); - - - // Add press and holds using helper action - Action addPHAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); - addPHAction("/cameraUp", BCameraControlUp); - addPHAction("/cameraDown", BCameraControlDown); - addPHAction("/cameraLeft", BCameraControlLeft); - addPHAction("/cameraRight", BCameraControlRight); - addPHAction("/cameraZoomIn", BCameraControlZoomIn); - addPHAction("/cameraZoomOut", BCameraControlZoomOut); - - // Add straight pulse calls using helper action - Action addAction = (s, u) => - AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); - addAction("/endCallById", BDialHangup); - addAction("/endAllCalls", BDialHangup); - addAction("/acceptById", BIncomingAnswer); - addAction("/rejectById", BIncomingReject); - addAction("/speedDial1", BSpeedDial1); - addAction("/speedDial2", BSpeedDial2); - addAction("/speedDial3", BSpeedDial3); - addAction("/speedDial4", BSpeedDial4); - addAction("/cameraModeAuto", BCameraModeAuto); - addAction("/cameraModeManual", BCameraModeManual); - addAction("/cameraModeOff", BCameraModeOff); - addAction("/cameraSelfView", BCameraSelfView); - addAction("/cameraLayout", BCameraLayout); - - asc.AddAction("/cameraSelect", new Action(SelectCamera)); - - // camera presets - for(uint i = 0; i < 6; i++) - { - addAction("/cameraPreset" + (i + 1), BCameraPresetStart + i); - } - - asc.AddAction(MessagePath + "/isReady", new Action(PostIsReady)); - // Get status - asc.AddAction(MessagePath + "/fullStatus", new Action(PostFullStatus)); - // Dial on string - asc.AddAction(MessagePath + "/dial", new Action(s => - EISC.SetString(SCurrentDialString, s))); - // Pulse DTMF - asc.AddAction(MessagePath + "/dtmf", new Action(s => - { - if (DTMFMap.ContainsKey(s)) - { - EISC.PulseBool(DTMFMap[s], 100); - } - })); - - // Directory madness - asc.AddAction(MessagePath + "/directoryRoot", new Action(() => EISC.PulseBool(BDirectoryRoot))); - asc.AddAction(MessagePath + "/directoryBack", new Action(() => EISC.PulseBool(BDirectoryFolderBack))); - asc.AddAction(MessagePath + "/directoryById", new Action(s => - { - // the id should contain the line number to forward to simpl - try - { - var u = ushort.Parse(s); - EISC.SetUshort(UDirectorySelectRow, u); - EISC.PulseBool(BDirectoryLineSelected); - } - catch (Exception) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, - "/directoryById request contains non-numeric ID incompatible with DDVC bridge"); - } - - })); - asc.AddAction(MessagePath + "/directorySelectContact", new Action(s => - { - try - { - var u = ushort.Parse(s); - EISC.SetUshort(UDirectorySelectRow, u); - EISC.PulseBool(BDirectoryLineSelected); - } - catch - { - - } - })); - asc.AddAction(MessagePath + "/directoryDialContact", new Action(() => { - EISC.PulseBool(BDirectoryDialSelectedLine); - })); - asc.AddAction(MessagePath + "/getDirectory", new Action(() => - { - if (EISC.GetUshort(UDirectoryRowCount) > 0) - { - PostDirectory(); - } - else - { - EISC.PulseBool(BDirectoryRoot); - } - })); - } - - /// - /// - /// - void PostFullStatus() - { - this.PostStatusMessage(new - { - calls = GetCurrentCallList(), - cameraMode = GetCameraMode(), - cameraSelfView = EISC.GetBool(BCameraSelfView), - cameraSupportsAutoMode = EISC.GetBool(BCameraSupportsAutoMode), - cameraSupportsOffMode = EISC.GetBool(BCameraSupportsOffMode), - currentCallString = EISC.GetString(SCurrentCallNumber), - currentDialString = EISC.GetString(SCurrentDialString), - directoryContactSelected = new - { - name = EISC.GetString(SDirectoryEntrySelectedName), - number = EISC.GetString(SDirectoryEntrySelectedNumber) - }, - directorySelectedFolderName = EISC.GetString(SDirectorySelectedFolderName), - isInCall = EISC.GetString(SHookState) == "Connected", - hasDirectory = true, - hasDirectorySearch = false, - hasRecents = !EISC.BooleanOutput[502].BoolValue, - hasCameras = true, - showCamerasWhenNotInCall = EISC.BooleanOutput[503].BoolValue, - selectedCamera = GetSelectedCamera(), - }); - } - - /// - /// - /// - void PostDirectory() - { - var u = EISC.GetUshort(UDirectoryRowCount); - var items = new List(); - for (uint i = 0; i < u; i++) - { - var name = EISC.GetString(SDirectoryEntriesStart + i); - var id = (i + 1).ToString(); - // is folder or contact? - if (name.StartsWith("[+]")) - { - items.Add(new - { - folderId = id, - name = name - }); - } - else - { - items.Add(new - { - contactId = id, - name = name - }); - } - } - - var directoryMessage = new - { - currentDirectory = new - { - isRootDirectory = EISC.GetBool(BDirectoryIsRoot), - directoryResults = items - } - }; - PostStatusMessage(directoryMessage); - } - - /// - /// - /// - void PostCameraMode() - { - PostStatusMessage(new - { - cameraMode = GetCameraMode() - }); - } - - /// - /// - /// - /// - string GetCameraMode() - { - string m; - if (EISC.GetBool(BCameraModeAuto)) m = "auto"; - else if (EISC.GetBool(BCameraModeManual)) m = "manual"; - else m = "off"; - return m; - } - - void PostSelectedCamera() - { - PostStatusMessage(new - { - selectedCamera = GetSelectedCamera() - }); - } - - /// - /// - /// - string GetSelectedCamera() - { - var num = EISC.GetUshort(UCameraNumberSelect); - string m; - if (num == 100) - { - m = "cameraFar"; - } - else - { - m = "camera" + num; - } - return m; - } - - /// - /// - /// - void PostIsReady() - { - PostStatusMessage(new - { - isReady = true - }); - } - - /// - /// - /// - void PostCallsList() - { - PostStatusMessage(new - { - calls = GetCurrentCallList(), - }); - } - - /// - /// - /// - /// - void SelectCamera(string s) - { - var cam = s.Substring(6); - if (cam.ToLower() == "far") - { - EISC.SetUshort(UCameraNumberSelect, 100); - } - else - { - EISC.SetUshort(UCameraNumberSelect, UInt16.Parse(cam)); - } - } - - /// - /// Turns the - /// - /// - List GetCurrentCallList() - { - var list = new List(); - if (CurrentCallItem.Status != eCodecCallStatus.Disconnected) - { - list.Add(CurrentCallItem); - } - if (EISC.GetBool(BCallIncoming)) { - - } - return list; - } - } -} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/IRunRouteActionMessenger.cs b/PepperDashEssentials/AppServer/Messengers/IRunRouteActionMessenger.cs new file mode 100644 index 00000000..c39d1dfb --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/IRunRouteActionMessenger.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class IRunRouteActionMessenger : MessengerBase + { + /// + /// Device being bridged + /// + public IRunRouteAction RoutingDevice {get; private set;} + + public IRunRouteActionMessenger(string key, IRunRouteAction routingDevice, string messagePath) + : base(key, messagePath) + { + if (routingDevice == null) + throw new ArgumentNullException("routingDevice"); + + RoutingDevice = routingDevice; + + var routingSink = RoutingDevice as IRoutingSinkNoSwitching; + + if (routingSink != null) + { + routingSink.CurrentSourceChange += new SourceInfoChangeHandler(routingSink_CurrentSourceChange); + } + } + + void routingSink_CurrentSourceChange(SourceListItem info, ChangeType type) + { + SendRoutingFullMessageObject(); + } + + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) + { + appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendRoutingFullMessageObject)); + + appServerController.AddAction(MessagePath + "/source", new Action(c => + { + RoutingDevice.RunRouteAction(c.SourceListItem, c.SourceListKey); + })); + + var sinkDevice = RoutingDevice as IRoutingSinkNoSwitching; + if(sinkDevice != null) + { + sinkDevice.CurrentSourceChange += new SourceInfoChangeHandler((o, a) => + { + SendRoutingFullMessageObject(); + }); + } + } + + /// + /// Helper method to update full status of the routing device + /// + void SendRoutingFullMessageObject() + { + var sinkDevice = RoutingDevice as IRoutingSinkNoSwitching; + + if(sinkDevice != null) + { + var sourceKey = sinkDevice.CurrentSourceInfoKey; + + if (string.IsNullOrEmpty(sourceKey)) + sourceKey = "none"; + + PostStatusMessage(new + { + selectedSourceKey = sourceKey + }); + } + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/SIMPLAtcMessenger.cs b/PepperDashEssentials/AppServer/Messengers/SIMPLAtcMessenger.cs new file mode 100644 index 00000000..5bf042b9 --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/SIMPLAtcMessenger.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.EthernetCommunication; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Codec; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class SIMPLAtcMessenger : MessengerBase + { + BasicTriList EISC; + + public SIMPLAtcJoinMap JoinMap {get; private set;} + + ///// + ///// 221 + ///// + //const uint BDialHangupOnHook = 221; + + ///// + ///// 251 + ///// + //const uint BIncomingAnswer = 251; + ///// + ///// 252 + ///// + //const uint BIncomingReject = 252; + ///// + ///// 241 + ///// + //const uint BSpeedDial1 = 241; + ///// + ///// 242 + ///// + //const uint BSpeedDial2 = 242; + ///// + ///// 243 + ///// + //const uint BSpeedDial3 = 243; + ///// + ///// 244 + ///// + //const uint BSpeedDial4 = 244; + + ///// + ///// 201 + ///// + //const uint SCurrentDialString = 201; + ///// + ///// 211 + ///// + //const uint SCurrentCallNumber = 211; + ///// + ///// 212 + ///// + //const uint SCurrentCallName = 212; + ///// + ///// 221 + ///// + //const uint SHookState = 221; + ///// + ///// 222 + ///// + //const uint SCallDirection = 222; + + ///// + ///// 201-212 0-9*# + ///// + //Dictionary DTMFMap = new Dictionary + //{ + // { "1", 201 }, + // { "2", 202 }, + // { "3", 203 }, + // { "4", 204 }, + // { "5", 205 }, + // { "6", 206 }, + // { "7", 207 }, + // { "8", 208 }, + // { "9", 209 }, + // { "0", 210 }, + // { "*", 211 }, + // { "#", 212 }, + //}; + + /// + /// + /// + CodecActiveCallItem CurrentCallItem; + + + /// + /// + /// + /// + /// + public SIMPLAtcMessenger(string key, BasicTriList eisc, string messagePath) + : base(key, messagePath) + { + EISC = eisc; + + JoinMap = new SIMPLAtcJoinMap(201); + + CurrentCallItem = new CodecActiveCallItem(); + CurrentCallItem.Type = eCodecCallType.Audio; + CurrentCallItem.Id = "-audio-"; + } + + /// + /// + /// + void SendFullStatus() + { + + + this.PostStatusMessage(new + { + calls = GetCurrentCallList(), + currentCallString = EISC.GetString(JoinMap.CurrentCallName.JoinNumber), + currentDialString = EISC.GetString(JoinMap.CurrentDialString.JoinNumber), + isInCall = EISC.GetString(JoinMap.HookState.JoinNumber) == "Connected" + }); + } + + /// + /// + /// + /// + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) + { + //EISC.SetStringSigAction(SCurrentDialString, s => PostStatusMessage(new { currentDialString = s })); + + EISC.SetStringSigAction(JoinMap.HookState.JoinNumber, s => + { + CurrentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); + //GetCurrentCallList(); + SendFullStatus(); + }); + + EISC.SetStringSigAction(JoinMap.CurrentCallNumber.JoinNumber, s => + { + CurrentCallItem.Number = s; + SendCallsList(); + }); + + EISC.SetStringSigAction(JoinMap.CurrentCallName.JoinNumber, s => + { + CurrentCallItem.Name = s; + SendCallsList(); + }); + + EISC.SetStringSigAction(JoinMap.CallDirection.JoinNumber, s => + { + CurrentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); + SendCallsList(); + }); + + // Add press and holds using helper + Action addPHAction = (s, u) => + AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); + + // Add straight pulse calls + Action addAction = (s, u) => + AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); + addAction("/endCallById", JoinMap.EndCall.JoinNumber); + addAction("/endAllCalls", JoinMap.EndCall.JoinNumber); + addAction("/acceptById", JoinMap.IncomingAnswer.JoinNumber); + addAction("/rejectById", JoinMap.IncomingReject.JoinNumber); + + var speeddialStart = JoinMap.SpeedDialStart.JoinNumber; + var speeddialEnd = JoinMap.SpeedDialStart.JoinNumber + JoinMap.SpeedDialStart.JoinSpan; + + var speedDialIndex = 1; + for (uint i = speeddialStart; i < speeddialEnd; i++) + { + addAction(string.Format("/speedDial{0}", speedDialIndex), i); + speedDialIndex++; + } + + // Get status + AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); + // Dial on string + AppServerController.AddAction(MessagePath + "/dial", new Action(s => EISC.SetString(JoinMap.CurrentDialString.JoinNumber, s))); + // Pulse DTMF + AppServerController.AddAction(MessagePath + "/dtmf", new Action(s => + { + var join = JoinMap.Joins[s]; + if (join != null) + { + if (join.JoinNumber > 0) + { + EISC.PulseBool(join.JoinNumber, 100); + } + } + })); + } + + /// + /// + /// + void SendCallsList() + { + PostStatusMessage(new + { + calls = GetCurrentCallList(), + }); + } + + /// + /// Turns the + /// + /// + List GetCurrentCallList() + { + if (CurrentCallItem.Status == eCodecCallStatus.Disconnected) + { + return new List(); + } + else + { + return new List() { CurrentCallItem }; + } + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/SIMPLCameraMessenger.cs b/PepperDashEssentials/AppServer/Messengers/SIMPLCameraMessenger.cs new file mode 100644 index 00000000..9cf6456f --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/SIMPLCameraMessenger.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.EthernetCommunication; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Bridges; +using PepperDash.Essentials.Devices.Common.Cameras; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class SIMPLCameraMessenger : MessengerBase + { + BasicTriList EISC; + + CameraControllerJoinMap JoinMap; + + + public SIMPLCameraMessenger(string key, BasicTriList eisc, string messagePath, uint joinStart) + : base(key, messagePath) + { + EISC = eisc; + + JoinMap = new CameraControllerJoinMap(joinStart); + + EISC.SetUShortSigAction(JoinMap.NumberOfPresets.JoinNumber, (u) => SendCameraFullMessageObject()); + + EISC.SetBoolSigAction(JoinMap.CameraModeAuto.JoinNumber, (b) => PostCameraMode()); + EISC.SetBoolSigAction(JoinMap.CameraModeManual.JoinNumber, (b) => PostCameraMode()); + EISC.SetBoolSigAction(JoinMap.CameraModeOff.JoinNumber, (b) => PostCameraMode()); + } + + + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) + { + var asc = appServerController; + + asc.AddAction(MessagePath + "/fullStatus", new Action(SendCameraFullMessageObject)); + + // Add press and holds using helper action + Action addPHAction = (s, u) => + asc.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); + addPHAction("/cameraUp", JoinMap.TiltUp.JoinNumber); + addPHAction("/cameraDown", JoinMap.TiltDown.JoinNumber); + addPHAction("/cameraLeft", JoinMap.PanLeft.JoinNumber); + addPHAction("/cameraRight", JoinMap.PanRight.JoinNumber); + addPHAction("/cameraZoomIn", JoinMap.ZoomIn.JoinNumber); + addPHAction("/cameraZoomOut", JoinMap.ZoomOut.JoinNumber); + + Action addAction = (s, u) => + asc.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); + + addAction("/cameraModeAuto", JoinMap.CameraModeAuto.JoinNumber); + addAction("/cameraModeManual", JoinMap.CameraModeManual.JoinNumber); + addAction("/cameraModeOff", JoinMap.CameraModeOff.JoinNumber); + + var presetStart = JoinMap.PresetRecallStart.JoinNumber; + var presetEnd = JoinMap.PresetRecallStart.JoinNumber + JoinMap.PresetRecallStart.JoinSpan; + + int presetId = 1; + // camera presets + for (uint i = presetStart; i <= presetEnd; i++) + { + addAction("/cameraPreset" + (presetId), i); + presetId++; + } + } + + public void CustomUnregsiterWithAppServer(MobileControlSystemController appServerController) + { + appServerController.RemoveAction(MessagePath + "/fullStatus"); + + appServerController.RemoveAction(MessagePath + "/cameraUp"); + appServerController.RemoveAction(MessagePath + "/cameraDown"); + appServerController.RemoveAction(MessagePath + "/cameraLeft"); + appServerController.RemoveAction(MessagePath + "/cameraRight"); + appServerController.RemoveAction(MessagePath + "/cameraZoomIn"); + appServerController.RemoveAction(MessagePath + "/cameraZoomOut"); + appServerController.RemoveAction(MessagePath + "/cameraModeAuto"); + appServerController.RemoveAction(MessagePath + "/cameraModeManual"); + appServerController.RemoveAction(MessagePath + "/cameraModeOff"); + + EISC.SetUShortSigAction(JoinMap.NumberOfPresets.JoinNumber, null); + + EISC.SetBoolSigAction(JoinMap.CameraModeAuto.JoinNumber, null); + EISC.SetBoolSigAction(JoinMap.CameraModeManual.JoinNumber, null); + EISC.SetBoolSigAction(JoinMap.CameraModeOff.JoinNumber, null); + } + + /// + /// Helper method to update the full status of the camera + /// + void SendCameraFullMessageObject() + { + var presetList = new List(); + + // Build a list of camera presets based on the names and count + if (EISC.GetBool(JoinMap.SupportsPresets.JoinNumber)) + { + var presetStart = JoinMap.PresetLabelStart.JoinNumber; + var presetEnd = JoinMap.PresetLabelStart.JoinNumber + JoinMap.NumberOfPresets.JoinNumber; + + var presetId = 1; + for (uint i = presetStart; i < presetEnd; i++) + { + var presetName = EISC.GetString(i); + var preset = new CameraPreset(presetId, presetName, string.IsNullOrEmpty(presetName), true); + presetList.Add(preset); + presetId++; + } + } + + PostStatusMessage(new + { + cameraMode = GetCameraMode(), + hasPresets = EISC.GetBool(JoinMap.SupportsPresets.JoinNumber), + presets = presetList + }); + } + + /// + /// + /// + void PostCameraMode() + { + PostStatusMessage(new + { + cameraMode = GetCameraMode() + }); + } + + /// + /// Computes the current camera mode + /// + /// + string GetCameraMode() + { + string m; + if (EISC.GetBool(JoinMap.CameraModeAuto.JoinNumber)) m = eCameraControlMode.Auto.ToString().ToLower(); + else if (EISC.GetBool(JoinMap.CameraModeManual.JoinNumber)) m = eCameraControlMode.Manual.ToString().ToLower(); + else m = eCameraControlMode.Off.ToString().ToLower(); + return m; + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/SIMPLRouteMessenger.cs b/PepperDashEssentials/AppServer/Messengers/SIMPLRouteMessenger.cs new file mode 100644 index 00000000..7b8c26d4 --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/SIMPLRouteMessenger.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; + +using PepperDash.Core; +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class SIMPLRouteMessenger : MessengerBase + { + BasicTriList EISC; + + uint JoinStart; + + public class StringJoin + { + /// + /// 1 + /// + public const uint CurrentSource = 1; + } + + public SIMPLRouteMessenger(string key, BasicTriList eisc, string messagePath, uint joinStart) + : base(key, messagePath) + { + EISC = eisc; + JoinStart = joinStart - 1; + + EISC.SetStringSigAction(JoinStart + StringJoin.CurrentSource, (s) => SendRoutingFullMessageObject(s)); + } + + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) + { + appServerController.AddAction(MessagePath + "/fullStatus", new Action(() => + { + SendRoutingFullMessageObject(EISC.GetString(JoinStart + StringJoin.CurrentSource)); + })); + + appServerController.AddAction(MessagePath +"/source", new Action(c => + { + EISC.SetString(JoinStart + StringJoin.CurrentSource, c.SourceListItem); + })); + + } + + public void CustomUnregsiterWithAppServer(MobileControlSystemController appServerController) + { + appServerController.RemoveAction(MessagePath + "/fullStatus"); + appServerController.RemoveAction(MessagePath + "/source"); + + EISC.SetStringSigAction(JoinStart + StringJoin.CurrentSource, null); + } + + /// + /// Helper method to update full status of the routing device + /// + void SendRoutingFullMessageObject(string sourceKey) + { + if (string.IsNullOrEmpty(sourceKey)) + sourceKey = "none"; + + PostStatusMessage(new + { + selectedSourceKey = sourceKey + }); + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/SIMPLVtcMessenger.cs b/PepperDashEssentials/AppServer/Messengers/SIMPLVtcMessenger.cs new file mode 100644 index 00000000..c67e335e --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/SIMPLVtcMessenger.cs @@ -0,0 +1,665 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.EthernetCommunication; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.Cameras; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class SIMPLVtcMessenger : MessengerBase + { + BasicTriList EISC; + + public SIMPLVtcJoinMap JoinMap { get; private set; } + + ///********* Bools *********/ + ///// + ///// 724 + ///// + //const uint BDialHangup = 724; + ///// + ///// 750 + ///// + //const uint BCallIncoming = 750; + ///// + ///// 751 + ///// + //const uint BIncomingAnswer = 751; + ///// + ///// 752 + ///// + //const uint BIncomingReject = 752; + ///// + ///// 741 + ///// + //const uint BSpeedDial1 = 741; + ///// + ///// 742 + ///// + //const uint BSpeedDial2 = 742; + ///// + ///// 743 + ///// + //const uint BSpeedDial3 = 743; + ///// + ///// 744 + ///// + //const uint BSpeedDial4 = 744; + ///// + ///// 800 + ///// + //const uint BDirectorySearchBusy = 800; + ///// + ///// 801 + ///// + //const uint BDirectoryLineSelected = 801; + ///// + ///// 801 when selected entry is a contact + ///// + //const uint BDirectoryEntryIsContact = 801; + ///// + ///// 802 To show/hide back button + ///// + //const uint BDirectoryIsRoot = 802; + ///// + ///// 803 Pulse from system to inform us when directory is ready + ///// + //const uint BDirectoryHasChanged = 803; + ///// + ///// 804 + ///// + //const uint BDirectoryRoot = 804; + ///// + ///// 805 + ///// + //const uint BDirectoryFolderBack = 805; + ///// + ///// 806 + ///// + //const uint BDirectoryDialSelectedLine = 806; + ///// + ///// 811 + ///// + //const uint BCameraControlUp = 811; + ///// + ///// 812 + ///// + //const uint BCameraControlDown = 812; + ///// + ///// 813 + ///// + //const uint BCameraControlLeft = 813; + ///// + ///// 814 + ///// + //const uint BCameraControlRight = 814; + ///// + ///// 815 + ///// + //const uint BCameraControlZoomIn = 815; + ///// + ///// 816 + ///// + //const uint BCameraControlZoomOut = 816; + ///// + ///// 821 - 826 + ///// + //const uint BCameraPresetStart = 821; + + ///// + ///// 831 + ///// + //const uint BCameraModeAuto = 831; + ///// + ///// 832 + ///// + //const uint BCameraModeManual = 832; + ///// + ///// 833 + ///// + //const uint BCameraModeOff = 833; + + ///// + ///// 841 + ///// + //const uint BCameraSelfView = 841; + + ///// + ///// 842 + ///// + //const uint BCameraLayout = 842; + ///// + ///// 843 + ///// + //const uint BCameraSupportsAutoMode = 843; + ///// + ///// 844 + ///// + //const uint BCameraSupportsOffMode = 844; + + + ///********* Ushorts *********/ + ///// + ///// 760 + ///// + //const uint UCameraNumberSelect = 760; + ///// + ///// 801 + ///// + //const uint UDirectorySelectRow = 801; + ///// + ///// 801 + ///// + //const uint UDirectoryRowCount = 801; + + + + ///********* Strings *********/ + ///// + ///// 701 + ///// + //const uint SCurrentDialString = 701; + ///// + ///// 702 + ///// + //const uint SCurrentCallName = 702; + ///// + ///// 703 + ///// + //const uint SCurrentCallNumber = 703; + ///// + ///// 731 + ///// + //const uint SHookState = 731; + ///// + ///// 722 + ///// + //const uint SCallDirection = 722; + ///// + ///// 751 + ///// + //const uint SIncomingCallName = 751; + ///// + ///// 752 + ///// + //const uint SIncomingCallNumber = 752; + + ///// + ///// 800 + ///// + //const uint SDirectorySearchString = 800; + ///// + ///// 801-1055 + ///// + //const uint SDirectoryEntriesStart = 801; + ///// + ///// 1056 + ///// + //const uint SDirectoryEntrySelectedName = 1056; + ///// + ///// 1057 + ///// + //const uint SDirectoryEntrySelectedNumber = 1057; + ///// + ///// 1058 + ///// + //const uint SDirectorySelectedFolderName = 1058; + + + ///// + ///// 701-712 0-9*# + ///// + //Dictionary DTMFMap = new Dictionary + //{ + // { "1", 701 }, + // { "2", 702 }, + // { "3", 703 }, + // { "4", 704 }, + // { "5", 705 }, + // { "6", 706 }, + // { "7", 707 }, + // { "8", 708 }, + // { "9", 709 }, + // { "0", 710 }, + // { "*", 711 }, + // { "#", 712 }, + //}; + + CodecActiveCallItem CurrentCallItem; + CodecActiveCallItem IncomingCallItem; + + ushort PreviousDirectoryLength = 701; + + /// + /// + /// + /// + /// + public SIMPLVtcMessenger(string key, BasicTriList eisc, string messagePath) + : base(key, messagePath) + { + EISC = eisc; + + JoinMap = new SIMPLVtcJoinMap(701); + + CurrentCallItem = new CodecActiveCallItem(); + CurrentCallItem.Type = eCodecCallType.Video; + CurrentCallItem.Id = "-video-"; + } + + /// + /// + /// + /// + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) + { + var asc = appServerController; + EISC.SetStringSigAction(JoinMap.HookState.JoinNumber, s => + { + CurrentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); + PostFullStatus(); // SendCallsList(); + }); + + EISC.SetStringSigAction(JoinMap.CurrentCallNumber.JoinNumber, s => + { + CurrentCallItem.Number = s; + PostCallsList(); + }); + + EISC.SetStringSigAction(JoinMap.CurrentCallName.JoinNumber, s => + { + CurrentCallItem.Name = s; + PostCallsList(); + }); + + EISC.SetStringSigAction(JoinMap.CallDirection.JoinNumber, s => + { + CurrentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); + PostCallsList(); + }); + + EISC.SetBoolSigAction(JoinMap.IncomingCall.JoinNumber, b => + { + if (b) + { + var ica = new CodecActiveCallItem() + { + Direction = eCodecCallDirection.Incoming, + Id = "-video-incoming", + Name = EISC.GetString(JoinMap.IncomingCallName.JoinNumber), + Number = EISC.GetString(JoinMap.IncomingCallNumber.JoinNumber), + Status = eCodecCallStatus.Ringing, + Type = eCodecCallType.Video + }; + IncomingCallItem = ica; + } + else + { + IncomingCallItem = null; + } + PostCallsList(); + }); + + EISC.SetBoolSigAction(JoinMap.CameraSupportsAutoMode.JoinNumber, b => + { + PostStatusMessage(new + { + cameraSupportsAutoMode = b + }); + }); + EISC.SetBoolSigAction(JoinMap.CameraSupportsOffMode.JoinNumber, b => + { + PostStatusMessage(new + { + cameraSupportsOffMode = b + }); + }); + + // Directory insanity + EISC.SetUShortSigAction(JoinMap.DirectoryRowCount.JoinNumber, u => + { + // The length of the list comes in before the list does. + // Splice the sig change operation onto the last string sig that will be changing + // when the directory entries make it through. + if (PreviousDirectoryLength > 0) + { + EISC.ClearStringSigAction(JoinMap.DirectoryEntriesStart.JoinNumber + PreviousDirectoryLength - 1); + } + EISC.SetStringSigAction(JoinMap.DirectoryEntriesStart.JoinNumber + u - 1, s => PostDirectory()); + PreviousDirectoryLength = u; + }); + + EISC.SetStringSigAction(JoinMap.DirectoryEntrySelectedName.JoinNumber, s => + { + PostStatusMessage(new + { + directoryContactSelected = new + { + name = EISC.GetString(JoinMap.DirectoryEntrySelectedName.JoinNumber), + } + }); + }); + + EISC.SetStringSigAction(JoinMap.DirectoryEntrySelectedNumber.JoinNumber, s => + { + PostStatusMessage(new + { + directoryContactSelected = new + { + number = EISC.GetString(JoinMap.DirectoryEntrySelectedNumber.JoinNumber), + } + }); + }); + + EISC.SetStringSigAction(JoinMap.DirectorySelectedFolderName.JoinNumber, s => PostStatusMessage(new + { + directorySelectedFolderName = EISC.GetString(JoinMap.DirectorySelectedFolderName.JoinNumber) + })); + + EISC.SetSigTrueAction(JoinMap.CameraModeAuto.JoinNumber, () => PostCameraMode()); + EISC.SetSigTrueAction(JoinMap.CameraModeManual.JoinNumber, () => PostCameraMode()); + EISC.SetSigTrueAction(JoinMap.CameraModeOff.JoinNumber, () => PostCameraMode()); + + EISC.SetBoolSigAction(JoinMap.CameraSelfView.JoinNumber, b => PostStatusMessage(new + { + cameraSelfView = b + })); + + EISC.SetUShortSigAction(JoinMap.CameraNumberSelect.JoinNumber, (u) => PostSelectedCamera()); + + + // Add press and holds using helper action + Action addPHAction = (s, u) => + AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); + addPHAction("/cameraUp", JoinMap.CameraTiltUp.JoinNumber); + addPHAction("/cameraDown", JoinMap.CameraTiltDown.JoinNumber); + addPHAction("/cameraLeft", JoinMap.CameraPanLeft.JoinNumber); + addPHAction("/cameraRight", JoinMap.CameraPanRight.JoinNumber); + addPHAction("/cameraZoomIn", JoinMap.CameraZoomIn.JoinNumber); + addPHAction("/cameraZoomOut", JoinMap.CameraZoomOut.JoinNumber); + + // Add straight pulse calls using helper action + Action addAction = (s, u) => + AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); + addAction("/endCallById", JoinMap.EndCall.JoinNumber); + addAction("/endAllCalls", JoinMap.EndCall.JoinNumber); + addAction("/acceptById", JoinMap.IncomingAnswer.JoinNumber); + addAction("/rejectById", JoinMap.IncomingReject.JoinNumber); + + var speeddialStart = JoinMap.SpeedDialStart.JoinNumber; + var speeddialEnd = JoinMap.SpeedDialStart.JoinNumber + JoinMap.SpeedDialStart.JoinSpan; + + var speedDialIndex = 1; + for (uint i = speeddialStart; i < speeddialEnd; i++) + { + addAction(string.Format("/speedDial{0}", speedDialIndex), i); + speedDialIndex++; + } + + addAction("/cameraModeAuto", JoinMap.CameraModeAuto.JoinNumber); + addAction("/cameraModeManual", JoinMap.CameraModeManual.JoinNumber); + addAction("/cameraModeOff", JoinMap.CameraModeOff.JoinNumber); + addAction("/cameraSelfView", JoinMap.CameraSelfView.JoinNumber); + addAction("/cameraLayout", JoinMap.CameraLayout.JoinNumber); + + asc.AddAction("/cameraSelect", new Action(SelectCamera)); + + // camera presets + for(uint i = 0; i < 6; i++) + { + addAction("/cameraPreset" + (i + 1), JoinMap.CameraPresetStart.JoinNumber + i); + } + + asc.AddAction(MessagePath + "/isReady", new Action(PostIsReady)); + // Get status + asc.AddAction(MessagePath + "/fullStatus", new Action(PostFullStatus)); + // Dial on string + asc.AddAction(MessagePath + "/dial", new Action(s => + EISC.SetString(JoinMap.CurrentDialString.JoinNumber, s))); + // Pulse DTMF + AppServerController.AddAction(MessagePath + "/dtmf", new Action(s => + { + var join = JoinMap.Joins[s]; + if (join != null) + { + if (join.JoinNumber > 0) + { + EISC.PulseBool(join.JoinNumber, 100); + } + } + })); + + // Directory madness + asc.AddAction(MessagePath + "/directoryRoot", new Action(() => EISC.PulseBool(JoinMap.DirectoryRoot.JoinNumber))); + asc.AddAction(MessagePath + "/directoryBack", new Action(() => EISC.PulseBool(JoinMap.DirectoryFolderBack.JoinNumber))); + asc.AddAction(MessagePath + "/directoryById", new Action(s => + { + // the id should contain the line number to forward to simpl + try + { + var u = ushort.Parse(s); + EISC.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u); + EISC.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber); + } + catch (Exception) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, + "/directoryById request contains non-numeric ID incompatible with DDVC bridge"); + } + + })); + asc.AddAction(MessagePath + "/directorySelectContact", new Action(s => + { + try + { + var u = ushort.Parse(s); + EISC.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u); + EISC.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber); + } + catch + { + + } + })); + asc.AddAction(MessagePath + "/directoryDialContact", new Action(() => { + EISC.PulseBool(JoinMap.DirectoryDialSelectedLine.JoinNumber); + })); + asc.AddAction(MessagePath + "/getDirectory", new Action(() => + { + if (EISC.GetUshort(JoinMap.DirectoryRowCount.JoinNumber) > 0) + { + PostDirectory(); + } + else + { + EISC.PulseBool(JoinMap.DirectoryRoot.JoinNumber); + } + })); + } + + /// + /// + /// + void PostFullStatus() + { + this.PostStatusMessage(new + { + calls = GetCurrentCallList(), + cameraMode = GetCameraMode(), + cameraSelfView = EISC.GetBool(JoinMap.CameraSelfView.JoinNumber), + cameraSupportsAutoMode = EISC.GetBool(JoinMap.CameraSupportsAutoMode.JoinNumber), + cameraSupportsOffMode = EISC.GetBool(JoinMap.CameraSupportsOffMode.JoinNumber), + currentCallString = EISC.GetString(JoinMap.CurrentCallNumber.JoinNumber), + currentDialString = EISC.GetString(JoinMap.CurrentDialString.JoinNumber), + directoryContactSelected = new + { + name = EISC.GetString(JoinMap.DirectoryEntrySelectedName.JoinNumber), + number = EISC.GetString(JoinMap.DirectoryEntrySelectedNumber.JoinNumber) + }, + directorySelectedFolderName = EISC.GetString(JoinMap.DirectorySelectedFolderName.JoinNumber), + isInCall = EISC.GetString(JoinMap.HookState.JoinNumber) == "Connected", + hasDirectory = true, + hasDirectorySearch = false, + hasRecents = !EISC.BooleanOutput[502].BoolValue, + hasCameras = true, + showCamerasWhenNotInCall = EISC.BooleanOutput[503].BoolValue, + selectedCamera = GetSelectedCamera(), + }); + } + + /// + /// + /// + void PostDirectory() + { + var u = EISC.GetUshort(JoinMap.DirectoryRowCount.JoinNumber); + var items = new List(); + for (uint i = 0; i < u; i++) + { + var name = EISC.GetString(JoinMap.DirectoryEntriesStart.JoinNumber + i); + var id = (i + 1).ToString(); + // is folder or contact? + if (name.StartsWith("[+]")) + { + items.Add(new + { + folderId = id, + name = name + }); + } + else + { + items.Add(new + { + contactId = id, + name = name + }); + } + } + + var directoryMessage = new + { + currentDirectory = new + { + isRootDirectory = EISC.GetBool(JoinMap.DirectoryIsRoot.JoinNumber), + directoryResults = items + } + }; + PostStatusMessage(directoryMessage); + } + + /// + /// + /// + void PostCameraMode() + { + PostStatusMessage(new + { + cameraMode = GetCameraMode() + }); + } + + /// + /// + /// + /// + string GetCameraMode() + { + string m; + if (EISC.GetBool(JoinMap.CameraModeAuto.JoinNumber)) m = eCameraControlMode.Auto.ToString().ToLower(); + else if (EISC.GetBool(JoinMap.CameraModeManual.JoinNumber)) m = eCameraControlMode.Manual.ToString().ToLower(); + else m = eCameraControlMode.Off.ToString().ToLower(); + return m; + } + + void PostSelectedCamera() + { + PostStatusMessage(new + { + selectedCamera = GetSelectedCamera() + }); + } + + /// + /// + /// + string GetSelectedCamera() + { + var num = EISC.GetUshort(JoinMap.CameraNumberSelect.JoinNumber); + string m; + if (num == 100) + { + m = "cameraFar"; + } + else + { + m = "camera" + num; + } + return m; + } + + /// + /// + /// + void PostIsReady() + { + PostStatusMessage(new + { + isReady = true + }); + } + + /// + /// + /// + void PostCallsList() + { + PostStatusMessage(new + { + calls = GetCurrentCallList(), + }); + } + + /// + /// + /// + /// + void SelectCamera(string s) + { + var cam = s.Substring(6); + if (cam.ToLower() == "far") + { + EISC.SetUshort(JoinMap.CameraNumberSelect.JoinNumber, 100); + } + else + { + EISC.SetUshort(JoinMap.CameraNumberSelect.JoinNumber, UInt16.Parse(cam)); + } + } + + /// + /// Turns the + /// + /// + List GetCurrentCallList() + { + var list = new List(); + if (CurrentCallItem.Status != eCodecCallStatus.Disconnected) + { + list.Add(CurrentCallItem); + } + if (EISC.GetBool(JoinMap.IncomingCall.JoinNumber)) + { + + } + return list; + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/SimplMessengerPropertiesConfig.cs b/PepperDashEssentials/AppServer/Messengers/SimplMessengerPropertiesConfig.cs new file mode 100644 index 00000000..9ee7407e --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/SimplMessengerPropertiesConfig.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Bridges; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Properties to configure a SIMPL Messenger + /// + public class SimplMessengerPropertiesConfig : EiscApiPropertiesConfig.ApiDevicePropertiesConfig + { + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs b/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs index 29c80085..0ee943c9 100644 --- a/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs @@ -7,6 +7,8 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using PepperDash.Core; + using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.VideoCodec; @@ -202,6 +204,59 @@ namespace PepperDash.Essentials.AppServer.Messengers { appServerController.AddAction(MessagePath + "/getCallHistory", new Action(GetCallHistory)); } + var cameraCodec = Codec as IHasCodecCameras; + if (cameraCodec != null) + { + Debug.Console(2, this, "Adding IHasCodecCameras Actions"); + + cameraCodec.CameraSelected += new EventHandler(cameraCodec_CameraSelected); + + appServerController.AddAction(MessagePath + "/cameraSelect", new Action(s => cameraCodec.SelectCamera(s))); + + MapCameraActions(); + + var presetsCodec = Codec as IHasCodecRoomPresets; + if (presetsCodec != null) + { + Debug.Console(2, this, "Adding IHasCodecRoomPresets Actions"); + + presetsCodec.CodecRoomPresetsListHasChanged += new EventHandler(presetsCodec_CameraPresetsListHasChanged); + + appServerController.AddAction(MessagePath + "/cameraPreset", new Action(u => presetsCodec.CodecRoomPresetSelect(u))); + appServerController.AddAction(MessagePath + "/cameraPresetStore", new Action(p => presetsCodec.CodecRoomPresetStore(p.ID, p.Description))); + } + + var speakerTrackCodec = Codec as IHasCameraAutoMode; + if (speakerTrackCodec != null) + { + Debug.Console(2, this, "Adding IHasCameraAutoMode Actions"); + + speakerTrackCodec.CameraAutoModeIsOnFeedback.OutputChange += new EventHandler(CameraAutoModeIsOnFeedback_OutputChange); + + appServerController.AddAction(MessagePath + "/cameraAuto", new Action(speakerTrackCodec.CameraAutoModeOn)); + appServerController.AddAction(MessagePath + "/cameraManual", new Action(speakerTrackCodec.CameraAutoModeOff)); + } + } + + var selfViewCodec = Codec as IHasCodecSelfView; + + if (selfViewCodec != null) + { + Debug.Console(2, this, "Adding IHasCodecSelfView Actions"); + + appServerController.AddAction(MessagePath + "/cameraSelfView", new Action(selfViewCodec.SelfViewModeToggle)); + } + + var layoutsCodec = Codec as IHasCodecLayouts; + + if (layoutsCodec != null) + { + Debug.Console(2, this, "Adding IHasCodecLayouts Actions"); + + appServerController.AddAction(MessagePath + "/cameraRemoteView", new Action(layoutsCodec.LocalLayoutToggle)); + } + + Debug.Console(2, this, "Adding Privacy & Standby Actions"); appServerController.AddAction(MessagePath + "/privacyModeOn", new Action(Codec.PrivacyModeOn)); appServerController.AddAction(MessagePath + "/privacyModeOff", new Action(Codec.PrivacyModeOff)); @@ -212,6 +267,89 @@ namespace PepperDash.Essentials.AppServer.Messengers appServerController.AddAction(MessagePath + "/standbyOff", new Action(Codec.StandbyDeactivate)); } + void presetsCodec_CameraPresetsListHasChanged(object sender, EventArgs e) + { + PostCameraPresets(); + } + + void CameraAutoModeIsOnFeedback_OutputChange(object sender, PepperDash.Essentials.Core.FeedbackEventArgs e) + { + PostCameraMode(); + } + + + void cameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e) + { + MapCameraActions(); + PostSelectedCamera(); + } + + /// + /// Maps the camera control actions to the current selected camera on the codec + /// + void MapCameraActions() + { + var cameraCodec = Codec as IHasCameras; + + if (cameraCodec != null && cameraCodec.SelectedCamera != null) + { + + AppServerController.RemoveAction(MessagePath + "/cameraUp"); + AppServerController.RemoveAction(MessagePath + "/cameraDown"); + AppServerController.RemoveAction(MessagePath + "/cameraLeft"); + AppServerController.RemoveAction(MessagePath + "/cameraRight"); + AppServerController.RemoveAction(MessagePath + "/cameraZoomIn"); + AppServerController.RemoveAction(MessagePath + "/cameraZoomOut"); + AppServerController.RemoveAction(MessagePath + "/cameraHome"); + + var camera = cameraCodec.SelectedCamera as IHasCameraPtzControl; + if (camera != null) + { + AppServerController.AddAction(MessagePath + "/cameraUp", new PressAndHoldAction(new Action(b => { if (b)camera.TiltUp(); else camera.TiltStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraDown", new PressAndHoldAction(new Action(b => { if (b)camera.TiltDown(); else camera.TiltStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraLeft", new PressAndHoldAction(new Action(b => { if (b)camera.PanLeft(); else camera.PanStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraRight", new PressAndHoldAction(new Action(b => { if (b)camera.PanRight(); else camera.PanStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraZoomIn", new PressAndHoldAction(new Action(b => { if (b)camera.ZoomIn(); else camera.ZoomStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraZoomOut", new PressAndHoldAction(new Action(b => { if (b)camera.ZoomOut(); else camera.ZoomStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraHome", new Action(camera.PositionHome)); + + var focusCamera = cameraCodec as IHasCameraFocusControl; + + AppServerController.RemoveAction(MessagePath + "/cameraAutoFocus"); + AppServerController.RemoveAction(MessagePath + "/cameraFocusNear"); + AppServerController.RemoveAction(MessagePath + "/cameraFocusFar"); + + if (focusCamera != null) + { + AppServerController.AddAction(MessagePath + "/cameraAutoFocus", new Action(focusCamera.TriggerAutoFocus)); + AppServerController.AddAction(MessagePath + "/cameraFocusNear", new PressAndHoldAction(new Action(b => { if (b)focusCamera.FocusNear(); else focusCamera.FocusStop(); }))); + AppServerController.AddAction(MessagePath + "/cameraFocusFar", new PressAndHoldAction(new Action(b => { if (b)focusCamera.FocusFar(); else focusCamera.FocusStop(); }))); + } + } + } + } + + string GetCameraMode() + { + string m = ""; + + var speakerTrackCodec = Codec as IHasCameraAutoMode; + if (speakerTrackCodec != null) + { + if (speakerTrackCodec.CameraAutoModeIsOnFeedback.BoolValue) m = eCameraControlMode.Auto.ToString(); + else m = eCameraControlMode.Manual.ToString(); + } + + var cameraOffCodec = Codec as IHasCameraOff; + if (cameraOffCodec != null) + { + if (cameraOffCodec.CameraIsOffFeedback.BoolValue) + m = eCameraControlMode.Off.ToString(); + } + + return m; + } + void GetCallHistory() { var codec = (Codec as IHasCallHistory); @@ -344,6 +482,22 @@ namespace PepperDash.Essentials.AppServer.Messengers return; } + object cameraInfo = null; + + var camerasCodec = Codec as IHasCodecCameras; + if (camerasCodec != null) + { + cameraInfo = new + { + cameraManualSupported = true, // For now, we assume manual mode is supported and selectively hide controls based on camera selection + cameraAutoSupported = Codec is IHasCameraAutoMode, + cameraOffSupported = Codec is IHasCameraOff, + cameraMode = GetCameraMode(), + cameraList = camerasCodec.Cameras, + selectedCamera = GetSelectedCamera(camerasCodec) + }; + } + var info = Codec.CodecInfo; PostStatusMessage(new { @@ -366,8 +520,77 @@ namespace PepperDash.Essentials.AppServer.Messengers hasDirectory = Codec is IHasDirectory, hasDirectorySearch = true, hasRecents = Codec is IHasCallHistory, - hasCameras = Codec is IHasCodecCameras + hasCameras = Codec is IHasCameras, + cameras = cameraInfo, + presets = GetCurrentPresets() }); } + + /// + /// + /// + void PostCameraMode() + { + PostStatusMessage(new + { + cameras = new + { + cameraMode = GetCameraMode() + } + }); + } + + void PostSelectedCamera() + { + var camerasCodec = Codec as IHasCodecCameras; + + PostStatusMessage(new + { + cameras = new + { + selectedCamera = GetSelectedCamera(camerasCodec) + }, + presets = GetCurrentPresets() + }); + } + + void PostCameraPresets() + { + + PostStatusMessage(new + { + presets = GetCurrentPresets() + }); + } + + object GetSelectedCamera(IHasCodecCameras camerasCodec) + { + return new + { + key = camerasCodec.SelectedCameraFeedback.StringValue, + isFarEnd = camerasCodec.ControllingFarEndCameraFeedback.BoolValue, + capabilites = new + { + canPan = camerasCodec.SelectedCamera.CanPan, + canTilt = camerasCodec.SelectedCamera.CanTilt, + canZoom = camerasCodec.SelectedCamera.CanZoom, + canFocus = camerasCodec.SelectedCamera.CanFocus + } + }; + } + + List GetCurrentPresets() + { + var presetsCodec = Codec as IHasCodecRoomPresets; + + List currentPresets = null; + + if (presetsCodec != null && Codec is IHasFarEndCameraControl && (Codec as IHasFarEndCameraControl).ControllingFarEndCameraFeedback.BoolValue) + currentPresets = presetsCodec.FarEndRoomPresets; + else + currentPresets = presetsCodec.NearEndPresets; + + return currentPresets; + } } } \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs index fd36389a..8a67ba14 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs @@ -25,6 +25,8 @@ namespace PepperDash.Essentials public AudioCodecBaseMessenger ACMessenger { get; private set; } + public Dictionary DeviceMessengers { get; private set; } + /// /// @@ -67,7 +69,15 @@ namespace PepperDash.Essentials var routeRoom = Room as IRunRouteAction; if(routeRoom != null) Parent.AddAction(string.Format(@"/room/{0}/source", Room.Key), new Action(c => - routeRoom.RunRouteAction(c.SourceListItem))); + { + if(string.IsNullOrEmpty(c.SourceListKey)) + routeRoom.RunRouteAction(c.SourceListItem, Room.SourceListKey); + else + { + routeRoom.RunRouteAction(c.SourceListItem, c.SourceListKey); + } + })); + var defaultRoom = Room as IRunDefaultPresentRoute; if(defaultRoom != null) @@ -115,6 +125,8 @@ namespace PepperDash.Essentials ACMessenger.RegisterWithAppServer(Parent); } + SetupDeviceMessengers(); + var defCallRm = Room as IRunDefaultCallRoute; if (defCallRm != null) { @@ -134,6 +146,36 @@ namespace PepperDash.Essentials Room.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; } + /// + /// Set up the messengers for each device type + /// + void SetupDeviceMessengers() + { + DeviceMessengers = new Dictionary(); + + foreach (var device in DeviceManager.AllDevices) + { + Debug.Console(2, this, "Attempting to set up device messenger for device: {0}", device.Key); + + if (device is Essentials.Devices.Common.Cameras.CameraBase) + { + var camDevice = device as Essentials.Devices.Common.Cameras.CameraBase; + Debug.Console(2, this, "Adding CameraBaseMessenger for device: {0}", device.Key); + var cameraMessenger = new CameraBaseMessenger(device.Key + "-" + Parent.Key, camDevice, "/device/" + device.Key); + DeviceMessengers.Add(device.Key, cameraMessenger); + cameraMessenger.RegisterWithAppServer(Parent); + } + if (device is Essentials.Devices.Common.SoftCodec.BlueJeansPc) + { + var softCodecDevice = device as Essentials.Devices.Common.SoftCodec.BlueJeansPc; + Debug.Console(2, this, "Adding IRunRouteActionMessnger for device: {0}", device.Key); + var routeMessenger = new IRunRouteActionMessenger(device.Key + "-" + Parent.Key, softCodecDevice, "/device/" + device.Key); + DeviceMessengers.Add(device.Key, routeMessenger); + routeMessenger.RegisterWithAppServer(Parent); + } + } + } + /// /// /// @@ -430,6 +472,7 @@ namespace PepperDash.Essentials public class SourceSelectMessageContent { public string SourceListItem { get; set; } + public string SourceListKey { get; set; } } /// diff --git a/PepperDashEssentials/AppServer/RoomBridges/MobileControlDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/MobileControlSIMPLRoomBridge.cs similarity index 60% rename from PepperDashEssentials/AppServer/RoomBridges/MobileControlDdvc01RoomBridge.cs rename to PepperDashEssentials/AppServer/RoomBridges/MobileControlSIMPLRoomBridge.cs index eefd8fbc..a8589b92 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/MobileControlDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/MobileControlSIMPLRoomBridge.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; +using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; @@ -18,204 +19,8 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Room.MobileControl { - public class MobileControlDdvc01RoomBridge : MobileControlBridgeBase, IDelayedConfiguration + public class MobileControlSIMPLRoomBridge : MobileControlBridgeBase, IDelayedConfiguration { - public class BoolJoin - { - /// - /// 301 - /// - public const uint RoomIsOn = 301; - - /// - /// 12 - /// - public const uint PrivacyMute = 12; - - /// - /// 41 - /// - public const uint PromptForCode = 41; - /// - /// 42 - /// - public const uint ClientJoined = 42; - /// - /// 51 - /// - public const uint ActivityShare = 51; - /// - /// 52 - /// - public const uint ActivityPhoneCall = 52; - /// - /// 53 - /// - public const uint ActivityVideoCall = 53; - - /// - /// 1 - /// - public const uint MasterVolumeIsMuted = 1; - /// - /// 1 - /// - public const uint MasterVolumeMuteToggle = 1; - /// - /// 1 - /// - public const uint VolumeMutesJoinStart = 1; - /// - /// 61 - /// - public const uint ShutdownCancel = 61; - /// - /// 62 - /// - public const uint ShutdownEnd = 62; - /// - /// 63 - /// - public const uint ShutdownStart = 63; - /// - /// 72 - /// - public const uint SourceHasChanged = 71; - - /// - /// 261 - The start of the range of speed dial visibles - /// - public const uint SpeedDialVisibleStartJoin = 261; - /// - /// 501 - /// - public const uint ConfigIsReady = 501; - /// - /// 502 - /// - public const uint HideVideoConfRecents = 502; - /// - /// 503 - /// - public const uint ShowCameraWhenNotInCall = 503; - /// - /// 504 - /// - public const uint UseSourceEnabled = 504; - /// - /// 601 - /// - public const uint SourceShareDisableJoinStart = 601; - /// - /// 621 - /// - public const uint SourceIsEnabledJoinStart = 621; - - } - - public class UshortJoin - { - /// - /// 1 - /// - public const uint MasterVolumeLevel = 1; - /// - /// 1 - /// - public const uint VolumeSlidersJoinStart = 1; - /// - /// 61 - /// - public const uint ShutdownPromptDuration = 61; - /// - /// 101 - /// - public const uint NumberOfAuxFaders = 101; - } - - public class StringJoin - { - /// - /// 1 - /// - public const uint VolumeSliderNamesJoinStart = 1; - /// - /// 71 - /// - public const uint SelectedSourceKey = 71; - - /// - /// 241 - /// - public const uint SpeedDialNameStartJoin = 241; - - /// - /// 251 - /// - public const uint SpeedDialNumberStartJoin = 251; - - /// - /// 501 - /// - public const uint ConfigRoomName = 501; - /// - /// 502 - /// - public const uint ConfigHelpMessage = 502; - /// - /// 503 - /// - public const uint ConfigHelpNumber = 503; - /// - /// 504 - /// - public const uint ConfigRoomPhoneNumber = 504; - /// - /// 505 - /// - public const uint ConfigRoomURI = 505; - /// - /// 401 - /// - public const uint UserCodeToSystem = 401; - /// - /// 402 - /// - public const uint ServerUrl = 402; - /// - /// 512 - /// - public const uint RoomSpeedDialNamesJoinStart = 512; - /// - /// 516 - /// - public const uint RoomSpeedDialNumberssJoinStart = 516; - /// - /// 601 - /// - public const uint SourceNameJoinStart = 601; - /// - /// 621 - /// - public const uint SourceIconJoinStart = 621; - /// - /// 641 - /// - public const uint SourceKeyJoinStart = 641; - /// - /// 661 - /// - public const uint SourceTypeJoinStart = 661; - /// - /// 761 - /// - public const uint CameraNearNameStart = 761; - /// - /// 770 - presence of this name on the input will cause the camera to be added - /// - public const uint CameraFarName = 770; - } - /// /// Fires when config is ready to go /// @@ -223,6 +28,8 @@ namespace PepperDash.Essentials.Room.MobileControl public ThreeSeriesTcpIpEthernetIntersystemCommunications EISC { get; private set; } + public MobileControlSIMPLRoomJoinMap JoinMap { get; private set; } + /// /// /// @@ -231,15 +38,15 @@ namespace PepperDash.Essentials.Room.MobileControl public override string RoomName { get { - var name = EISC.StringOutput[StringJoin.ConfigRoomName].StringValue; + var name = EISC.StringOutput[JoinMap.ConfigRoomName.JoinNumber].StringValue; return string.IsNullOrEmpty(name) ? "Not Loaded" : name; } } MobileControlDdvc01DeviceBridge SourceBridge; - Ddvc01AtcMessenger AtcMessenger; - Ddvc01VtcMessenger VtcMessenger; + SIMPLAtcMessenger AtcMessenger; + SIMPLVtcMessenger VtcMessenger; /// @@ -248,7 +55,7 @@ namespace PepperDash.Essentials.Room.MobileControl /// /// /// - public MobileControlDdvc01RoomBridge(string key, string name, uint ipId) + public MobileControlSIMPLRoomBridge(string key, string name, uint ipId) : base(key, name) { try @@ -258,8 +65,13 @@ namespace PepperDash.Essentials.Room.MobileControl if (reg != Crestron.SimplSharpPro.eDeviceRegistrationUnRegistrationResponse.Success) Debug.Console(0, this, "Cannot connect EISC at IPID {0}: \r{1}", ipId, reg); + JoinMap = new MobileControlSIMPLRoomJoinMap(1); + SourceBridge = new MobileControlDdvc01DeviceBridge(key + "-sourceBridge", "DDVC01 source bridge", EISC); DeviceManager.AddDevice(SourceBridge); + + + } catch (Exception) { @@ -279,24 +91,33 @@ namespace PepperDash.Essentials.Room.MobileControl SetupFeedbacks(); var atcKey = string.Format("atc-{0}-{1}", this.Key, Parent.Key); - AtcMessenger = new Ddvc01AtcMessenger(atcKey, EISC, "/device/audioCodec"); + AtcMessenger = new SIMPLAtcMessenger(atcKey, EISC, "/device/audioCodec"); AtcMessenger.RegisterWithAppServer(Parent); var vtcKey = string.Format("atc-{0}-{1}", this.Key, Parent.Key); - VtcMessenger = new Ddvc01VtcMessenger(vtcKey, EISC, "/device/videoCodec"); + VtcMessenger = new SIMPLVtcMessenger(vtcKey, EISC, "/device/videoCodec"); VtcMessenger.RegisterWithAppServer(Parent); EISC.SigChange += EISC_SigChange; EISC.OnlineStatusChange += (o, a) => { - Debug.Console(1, this, "DDVC EISC online={0}. Config is ready={1}", a.DeviceOnLine, EISC.BooleanOutput[BoolJoin.ConfigIsReady].BoolValue); - if (a.DeviceOnLine && EISC.BooleanOutput[BoolJoin.ConfigIsReady].BoolValue) + Debug.Console(1, this, "DDVC EISC online={0}. Config is ready={1}. Use Essentials Config={2}", + a.DeviceOnLine, EISC.BooleanOutput[JoinMap.ConfigIsReady.JoinNumber].BoolValue, EISC.BooleanOutput[JoinMap.ConfigIsLocal.JoinNumber].BoolValue); + + if (a.DeviceOnLine && EISC.BooleanOutput[JoinMap.ConfigIsReady.JoinNumber].BoolValue) LoadConfigValues(); + + if (a.DeviceOnLine && EISC.BooleanOutput[JoinMap.ConfigIsLocal.JoinNumber].BoolValue) + UseEssentialsConfig(); }; // load config if it's already there - if (EISC.IsOnline && EISC.BooleanOutput[BoolJoin.ConfigIsReady].BoolValue) // || EISC.BooleanInput[BoolJoin.ConfigIsReady].BoolValue) + if (EISC.IsOnline && EISC.BooleanOutput[JoinMap.ConfigIsReady.JoinNumber].BoolValue) // || EISC.BooleanInput[JoinMap.ConfigIsReady].BoolValue) LoadConfigValues(); + if (EISC.IsOnline && EISC.BooleanOutput[JoinMap.ConfigIsLocal.JoinNumber].BoolValue) + { + UseEssentialsConfig(); + } CrestronConsole.AddNewConsoleCommand(s => { @@ -323,41 +144,60 @@ namespace PepperDash.Essentials.Room.MobileControl return base.CustomActivate(); } + void UseEssentialsConfig() + { + ConfigIsLoaded = false; + + SetupDeviceMessengers(); + + Debug.Console(0, this, "******* ESSENTIALS CONFIG: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); + + var handler = ConfigurationIsReady; + if (handler != null) + { + handler(this, new EventArgs()); + } + + ConfigIsLoaded = true; + } /// /// Setup the actions to take place on various incoming API calls /// void SetupFunctions() { - Parent.AddAction(@"/room/room1/promptForCode", new Action(() => EISC.PulseBool(BoolJoin.PromptForCode))); - Parent.AddAction(@"/room/room1/clientJoined", new Action(() => EISC.PulseBool(BoolJoin.ClientJoined))); + Parent.AddAction(@"/room/room1/promptForCode", new Action(() => EISC.PulseBool(JoinMap.PromptForCode.JoinNumber))); + Parent.AddAction(@"/room/room1/clientJoined", new Action(() => EISC.PulseBool(JoinMap.ClientJoined.JoinNumber))); Parent.AddAction(@"/room/room1/status", new Action(SendFullStatus)); Parent.AddAction(@"/room/room1/source", new Action(c => { - EISC.SetString(StringJoin.SelectedSourceKey, c.SourceListItem); - EISC.PulseBool(BoolJoin.SourceHasChanged); + EISC.SetString(JoinMap.CurrentSourceKey.JoinNumber, c.SourceListItem); + EISC.PulseBool(JoinMap.SourceHasChanged.JoinNumber); })); Parent.AddAction(@"/room/room1/defaultsource", new Action(() => - EISC.PulseBool(BoolJoin.ActivityShare))); + EISC.PulseBool(JoinMap.ActivityShare.JoinNumber))); Parent.AddAction(@"/room/room1/activityPhone", new Action(() => - EISC.PulseBool(BoolJoin.ActivityPhoneCall))); + EISC.PulseBool(JoinMap.ActivityPhoneCall.JoinNumber))); Parent.AddAction(@"/room/room1/activityVideo", new Action(() => - EISC.PulseBool(BoolJoin.ActivityVideoCall))); + EISC.PulseBool(JoinMap.ActivityVideoCall.JoinNumber))); Parent.AddAction(@"/room/room1/volumes/master/level", new Action(u => - EISC.SetUshort(UshortJoin.MasterVolumeLevel, u))); + EISC.SetUshort(JoinMap.MasterVolume.JoinNumber, u))); Parent.AddAction(@"/room/room1/volumes/master/muteToggle", new Action(() => - EISC.PulseBool(BoolJoin.MasterVolumeIsMuted))); + EISC.PulseBool(JoinMap.MasterVolume.JoinNumber))); Parent.AddAction(@"/room/room1/volumes/master/privacyMuteToggle", new Action(() => - EISC.PulseBool(BoolJoin.PrivacyMute))); + EISC.PulseBool(JoinMap.PrivacyMute.JoinNumber))); // /xyzxyz/volumes/master/muteToggle ---> BoolInput[1] - for (uint i = 2; i <= 7; i++) + var volumeStart = JoinMap.VolumeJoinStart.JoinNumber; + var volumeEnd = JoinMap.VolumeJoinStart.JoinNumber + JoinMap.VolumeJoinStart.JoinSpan; + + for (uint i = volumeStart; i <= volumeEnd; i++) { var index = i; Parent.AddAction(string.Format(@"/room/room1/volumes/level-{0}/level", index), new Action(u => @@ -367,13 +207,16 @@ namespace PepperDash.Essentials.Room.MobileControl } Parent.AddAction(@"/room/room1/shutdownStart", new Action(() => - EISC.PulseBool(BoolJoin.ShutdownStart))); + EISC.PulseBool(JoinMap.ShutdownStart.JoinNumber))); Parent.AddAction(@"/room/room1/shutdownEnd", new Action(() => - EISC.PulseBool(BoolJoin.ShutdownEnd))); + EISC.PulseBool(JoinMap.ShutdownEnd.JoinNumber))); Parent.AddAction(@"/room/room1/shutdownCancel", new Action(() => - EISC.PulseBool(BoolJoin.ShutdownCancel))); + EISC.PulseBool(JoinMap.ShutdownCancel.JoinNumber))); } + + + /// /// /// @@ -398,21 +241,21 @@ namespace PepperDash.Essentials.Room.MobileControl void SetupFeedbacks() { // Power - EISC.SetBoolSigAction(BoolJoin.RoomIsOn, b => + EISC.SetBoolSigAction(JoinMap.RoomIsOn.JoinNumber, b => PostStatusMessage(new { isOn = b })); // Source change things - EISC.SetSigTrueAction(BoolJoin.SourceHasChanged, () => + EISC.SetSigTrueAction(JoinMap.SourceHasChanged.JoinNumber, () => PostStatusMessage(new { - selectedSourceKey = EISC.StringOutput[StringJoin.SelectedSourceKey].StringValue + selectedSourceKey = EISC.StringOutput[JoinMap.CurrentSourceKey.JoinNumber].StringValue })); // Volume things - EISC.SetUShortSigAction(UshortJoin.MasterVolumeLevel, u => + EISC.SetUShortSigAction(JoinMap.MasterVolume.JoinNumber, u => PostStatusMessage(new { volumes = new @@ -427,7 +270,7 @@ namespace PepperDash.Essentials.Room.MobileControl // map MasterVolumeIsMuted join -> status/volumes/master/muted // - EISC.SetBoolSigAction(BoolJoin.MasterVolumeIsMuted, b => + EISC.SetBoolSigAction(JoinMap.MasterVolume.JoinNumber, b => PostStatusMessage(new { volumes = new @@ -438,7 +281,7 @@ namespace PepperDash.Essentials.Room.MobileControl } } })); - EISC.SetBoolSigAction(BoolJoin.PrivacyMute, b => + EISC.SetBoolSigAction(JoinMap.PrivacyMute.JoinNumber, b => PostStatusMessage(new { volumes = new @@ -450,7 +293,10 @@ namespace PepperDash.Essentials.Room.MobileControl } })); - for (uint i = 2; i <= 7; i++) + var volumeStart = JoinMap.VolumeJoinStart.JoinNumber; + var volumeEnd = JoinMap.VolumeJoinStart.JoinNumber + JoinMap.VolumeJoinStart.JoinSpan; + + for (uint i = volumeStart; i <= volumeEnd; i++) { var index = i; // local scope for lambdas EISC.SetUShortSigAction(index, u => // start at join 2 @@ -481,7 +327,7 @@ namespace PepperDash.Essentials.Room.MobileControl }); } - EISC.SetUShortSigAction(UshortJoin.NumberOfAuxFaders, u => + EISC.SetUShortSigAction(JoinMap.NumberOfAuxFaders.JoinNumber, u => PostStatusMessage(new { volumes = new { numberOfAuxFaders = u, @@ -489,30 +335,30 @@ namespace PepperDash.Essentials.Room.MobileControl })); // shutdown things - EISC.SetSigTrueAction(BoolJoin.ShutdownCancel, new Action(() => + EISC.SetSigTrueAction(JoinMap.ShutdownCancel.JoinNumber, new Action(() => PostMessage("/room/shutdown/", new { state = "wasCancelled" }))); - EISC.SetSigTrueAction(BoolJoin.ShutdownEnd, new Action(() => + EISC.SetSigTrueAction(JoinMap.ShutdownEnd.JoinNumber, new Action(() => PostMessage("/room/shutdown/", new { state = "hasFinished" }))); - EISC.SetSigTrueAction(BoolJoin.ShutdownStart, new Action(() => + EISC.SetSigTrueAction(JoinMap.ShutdownStart.JoinNumber, new Action(() => PostMessage("/room/shutdown/", new { state = "hasStarted", - duration = EISC.UShortOutput[UshortJoin.ShutdownPromptDuration].UShortValue + duration = EISC.UShortOutput[JoinMap.ShutdownPromptDuration.JoinNumber].UShortValue }))); // Config things - EISC.SetSigTrueAction(BoolJoin.ConfigIsReady, LoadConfigValues); + EISC.SetSigTrueAction(JoinMap.ConfigIsReady.JoinNumber, LoadConfigValues); // Activity modes - EISC.SetSigTrueAction(BoolJoin.ActivityShare, () => UpdateActivity(1)); - EISC.SetSigTrueAction(BoolJoin.ActivityPhoneCall, () => UpdateActivity(2)); - EISC.SetSigTrueAction(BoolJoin.ActivityVideoCall, () => UpdateActivity(3)); + EISC.SetSigTrueAction(JoinMap.ActivityShare.JoinNumber, () => UpdateActivity(1)); + EISC.SetSigTrueAction(JoinMap.ActivityPhoneCall.JoinNumber, () => UpdateActivity(2)); + EISC.SetSigTrueAction(JoinMap.ActivityVideoCall.JoinNumber, () => UpdateActivity(3)); } @@ -556,7 +402,7 @@ namespace PepperDash.Essentials.Room.MobileControl Debug.Console(0, this, "Replacing Room[0] in config"); co.Rooms[0] = rm; } - rm.Name = EISC.StringOutput[StringJoin.ConfigRoomName].StringValue; + rm.Name = EISC.StringOutput[JoinMap.ConfigRoomName.JoinNumber].StringValue; rm.Key = "room1"; rm.Type = "ddvc01"; @@ -567,13 +413,13 @@ namespace PepperDash.Essentials.Room.MobileControl rmProps = JsonConvert.DeserializeObject(rm.Properties.ToString()); rmProps.Help = new EssentialsHelpPropertiesConfig(); - rmProps.Help.CallButtonText = EISC.StringOutput[StringJoin.ConfigHelpNumber].StringValue; - rmProps.Help.Message = EISC.StringOutput[StringJoin.ConfigHelpMessage].StringValue; + rmProps.Help.CallButtonText = EISC.StringOutput[JoinMap.ConfigHelpNumber.JoinNumber].StringValue; + rmProps.Help.Message = EISC.StringOutput[JoinMap.ConfigHelpMessage.JoinNumber].StringValue; rmProps.Environment = new EssentialsEnvironmentPropertiesConfig(); // enabled defaults to false - rmProps.RoomPhoneNumber = EISC.StringOutput[StringJoin.ConfigRoomPhoneNumber].StringValue; - rmProps.RoomURI = EISC.StringOutput[StringJoin.ConfigRoomURI].StringValue; + rmProps.RoomPhoneNumber = EISC.StringOutput[JoinMap.ConfigRoomPhoneNumber.JoinNumber].StringValue; + rmProps.RoomURI = EISC.StringOutput[JoinMap.ConfigRoomURI.JoinNumber].StringValue; rmProps.SpeedDials = new List(); // This MAY need a check @@ -581,7 +427,7 @@ namespace PepperDash.Essentials.Room.MobileControl rmProps.VideoCodecKey = "videoCodec"; // volume control names - var volCount = EISC.UShortOutput[UshortJoin.NumberOfAuxFaders].UShortValue; + var volCount = EISC.UShortOutput[JoinMap.NumberOfAuxFaders.JoinNumber].UShortValue; //// use Volumes object or? //rmProps.VolumeSliderNames = new List(); @@ -626,18 +472,18 @@ namespace PepperDash.Essentials.Room.MobileControl // add sources... for (uint i = 0; i <= 19; i++) { - var name = EISC.StringOutput[StringJoin.SourceNameJoinStart + i].StringValue; - if (EISC.BooleanOutput[BoolJoin.UseSourceEnabled].BoolValue - && !EISC.BooleanOutput[BoolJoin.SourceIsEnabledJoinStart + i].BoolValue) + var name = EISC.StringOutput[JoinMap.SourceNameJoinStart.JoinNumber + i].StringValue; + if (EISC.BooleanOutput[JoinMap.UseSourceEnabled.JoinNumber].BoolValue + && !EISC.BooleanOutput[JoinMap.SourceIsEnabledJoinStart.JoinNumber + i].BoolValue) { continue; } - else if(!EISC.BooleanOutput[BoolJoin.UseSourceEnabled].BoolValue && string.IsNullOrEmpty(name)) + else if(!EISC.BooleanOutput[JoinMap.UseSourceEnabled.JoinNumber].BoolValue && string.IsNullOrEmpty(name)) break; - var icon = EISC.StringOutput[StringJoin.SourceIconJoinStart + i].StringValue; - var key = EISC.StringOutput[StringJoin.SourceKeyJoinStart + i].StringValue; - var type = EISC.StringOutput[StringJoin.SourceTypeJoinStart + i].StringValue; - var disableShare = EISC.BooleanOutput[BoolJoin.SourceShareDisableJoinStart + i].BoolValue; + var icon = EISC.StringOutput[JoinMap.SourceIconJoinStart.JoinNumber + i].StringValue; + var key = EISC.StringOutput[JoinMap.SourceKeyJoinStart.JoinNumber + i].StringValue; + var type = EISC.StringOutput[JoinMap.SourceTypeJoinStart.JoinNumber + i].StringValue; + var disableShare = EISC.BooleanOutput[JoinMap.SourceShareDisableJoinStart.JoinNumber + i].BoolValue; Debug.Console(0, this, "Adding source {0} '{1}'", key, name); var newSLI = new SourceListItem{ @@ -679,14 +525,14 @@ namespace PepperDash.Essentials.Room.MobileControl var acFavs = new List(); for (uint i = 0; i < 4; i++) { - if (!EISC.GetBool(BoolJoin.SpeedDialVisibleStartJoin + i)) + if (!EISC.GetBool(JoinMap.SpeedDialVisibleStartJoin.JoinNumber + i)) { break; } acFavs.Add(new PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem() { - Name = EISC.GetString(StringJoin.SpeedDialNameStartJoin + i), - Number = EISC.GetString(StringJoin.SpeedDialNumberStartJoin + i), + Name = EISC.GetString(JoinMap.SpeedDialNameStartJoin.JoinNumber + i), + Number = EISC.GetString(JoinMap.SpeedDialNumberStartJoin.JoinNumber + i), Type = PepperDash.Essentials.Devices.Common.Codec.eCodecCallType.Audio }); } @@ -718,7 +564,7 @@ namespace PepperDash.Essentials.Room.MobileControl var camsProps = new List(); for (uint i = 0; i < 9; i++) { - var name = EISC.GetString(i + StringJoin.CameraNearNameStart); + var name = EISC.GetString(i + JoinMap.CameraNearNameStart.JoinNumber); if (!string.IsNullOrEmpty(name)) { camsProps.Add(new @@ -728,7 +574,7 @@ namespace PepperDash.Essentials.Room.MobileControl }); } } - var farName = EISC.GetString(StringJoin.CameraFarName); + var farName = EISC.GetString(JoinMap.CameraFarName.JoinNumber); if (!string.IsNullOrEmpty(farName)) { camsProps.Add(new @@ -755,6 +601,8 @@ namespace PepperDash.Essentials.Room.MobileControl co.Devices.Add(conf); } + SetupDeviceMessengers(); + Debug.Console(0, this, "******* CONFIG FROM DDVC: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); var handler = ConfigurationIsReady; @@ -766,6 +614,67 @@ namespace PepperDash.Essentials.Room.MobileControl ConfigIsLoaded = true; } + /// + /// Iterates device config and adds messengers as neede for each device type + /// + void SetupDeviceMessengers() + { + try + { + foreach (var device in ConfigReader.ConfigObject.Devices) + { + if (device.Group.Equals("simplmessenger")) + { + var props = JsonConvert.DeserializeObject(device.Properties.ToString()); + + var messengerKey = string.Format("device-{0}-{1}", this.Key, Parent.Key); + + if (DeviceManager.GetDeviceForKey(messengerKey) != null) + { + Debug.Console(2, this, "Messenger with key: {0} already exists. Skipping...", messengerKey); + continue; + } + + var dev = ConfigReader.ConfigObject.GetDeviceForKey(props.DeviceKey); + + if (dev == null) + { + Debug.Console(1, this, "Unable to find device config for key: '{0}'", props.DeviceKey); + continue; + } + + var type = device.Type.ToLower(); + MessengerBase messenger = null; + + if (type.Equals("simplcameramessenger")) + { + Debug.Console(2, this, "Adding SIMPLCameraMessenger for: '{0}'", props.DeviceKey); + messenger = new SIMPLCameraMessenger(messengerKey, EISC, "/device/" + props.DeviceKey, props.JoinStart); + } + else if (type.Equals("simplroutemessenger")) + { + Debug.Console(2, this, "Adding SIMPLRouteMessenger for: '{0}'", props.DeviceKey); + messenger = new SIMPLRouteMessenger(messengerKey, EISC, "/device/" + props.DeviceKey, props.JoinStart); + } + + if (messenger != null) + { + DeviceManager.AddDevice(messenger); + messenger.RegisterWithAppServer(Parent); + } + else + { + Debug.Console(2, this, "Unable to add messenger for device: '{0}' of type: '{1}'", props.DeviceKey, type); + } + } + } + } + catch (Exception e) + { + Debug.Console(2, this, "Error Setting up Device Managers: {0}", e); + } + } + /// /// /// @@ -773,7 +682,7 @@ namespace PepperDash.Essentials.Room.MobileControl { if (ConfigIsLoaded) { - var count = EISC.UShortOutput[UshortJoin.NumberOfAuxFaders].UShortValue; + var count = EISC.UShortOutput[JoinMap.NumberOfAuxFaders.JoinNumber].UShortValue; Debug.Console(1, this, "The Fader Count is : {0}", count); @@ -781,7 +690,11 @@ namespace PepperDash.Essentials.Room.MobileControl // Create auxFaders var auxFaderDict = new Dictionary(); - for (uint i = 2; i <= count; i++) + + var volumeStart = JoinMap.VolumeJoinStart.JoinNumber; + var volumeEnd = JoinMap.VolumeJoinStart.JoinNumber + JoinMap.VolumeJoinStart.JoinSpan; + + for (uint i = volumeStart; i <= count; i++) { auxFaderDict.Add("level-" + i, new Volume("level-" + i, @@ -795,22 +708,22 @@ namespace PepperDash.Essentials.Room.MobileControl var volumes = new Volumes(); volumes.Master = new Volume("master", - EISC.UShortOutput[UshortJoin.MasterVolumeLevel].UShortValue, - EISC.BooleanOutput[BoolJoin.MasterVolumeIsMuted].BoolValue, - EISC.StringOutput[1].StringValue, + EISC.UShortOutput[JoinMap.MasterVolume.JoinNumber].UShortValue, + EISC.BooleanOutput[JoinMap.MasterVolume.JoinNumber].BoolValue, + EISC.StringOutput[JoinMap.MasterVolume.JoinNumber].StringValue, true, "something.png"); volumes.Master.HasPrivacyMute = true; - volumes.Master.PrivacyMuted = EISC.BooleanOutput[BoolJoin.PrivacyMute].BoolValue; + volumes.Master.PrivacyMuted = EISC.BooleanOutput[JoinMap.PrivacyMute.JoinNumber].BoolValue; volumes.AuxFaders = auxFaderDict; - volumes.NumberOfAuxFaders = EISC.UShortInput[UshortJoin.NumberOfAuxFaders].UShortValue; + volumes.NumberOfAuxFaders = EISC.UShortInput[JoinMap.NumberOfAuxFaders.JoinNumber].UShortValue; PostStatusMessage(new { activityMode = GetActivityMode(), - isOn = EISC.BooleanOutput[BoolJoin.RoomIsOn].BoolValue, - selectedSourceKey = EISC.StringOutput[StringJoin.SelectedSourceKey].StringValue, + isOn = EISC.BooleanOutput[JoinMap.RoomIsOn.JoinNumber].BoolValue, + selectedSourceKey = EISC.StringOutput[JoinMap.CurrentSourceKey.JoinNumber].StringValue, volumes = volumes }); } @@ -829,9 +742,9 @@ namespace PepperDash.Essentials.Room.MobileControl /// int GetActivityMode() { - if (EISC.BooleanOutput[BoolJoin.ActivityPhoneCall].BoolValue) return 2; - else if (EISC.BooleanOutput[BoolJoin.ActivityShare].BoolValue) return 1; - else if (EISC.BooleanOutput[BoolJoin.ActivityVideoCall].BoolValue) return 3; + if (EISC.BooleanOutput[JoinMap.ActivityPhoneCall.JoinNumber].BoolValue) return 2; + else if (EISC.BooleanOutput[JoinMap.ActivityShare.JoinNumber].BoolValue) return 1; + else if (EISC.BooleanOutput[JoinMap.ActivityVideoCall.JoinNumber].BoolValue) return 3; return 0; } @@ -873,12 +786,15 @@ namespace PepperDash.Essentials.Room.MobileControl if (Debug.Level >= 1) Debug.Console(1, this, "DDVC EISC change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); var uo = args.Sig.UserObject; - if (uo is Action) - (uo as Action)(args.Sig.BoolValue); - else if (uo is Action) - (uo as Action)(args.Sig.UShortValue); - else if (uo is Action) - (uo as Action)(args.Sig.StringValue); + if (uo != null) + { + if (uo is Action) + (uo as Action)(args.Sig.BoolValue); + else if (uo is Action) + (uo as Action)(args.Sig.UShortValue); + else if (uo is Action) + (uo as Action)(args.Sig.StringValue); + } } /// @@ -905,8 +821,8 @@ namespace PepperDash.Essentials.Room.MobileControl protected override void UserCodeChange() { Debug.Console(1, this, "Server user code changed: {0}", UserCode); - EISC.StringInput[StringJoin.UserCodeToSystem].StringValue = UserCode; - EISC.StringInput[StringJoin.ServerUrl].StringValue = Parent.Config.ClientAppUrl; + EISC.StringInput[JoinMap.UserCodeToSystem.JoinNumber].StringValue = UserCode; + EISC.StringInput[JoinMap.ServerUrl.JoinNumber].StringValue = Parent.Config.ClientAppUrl; } } } \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs b/PepperDashEssentials/AppServer/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs new file mode 100644 index 00000000..286fe28e --- /dev/null +++ b/PepperDashEssentials/AppServer/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.AppServer +{ + public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced + { + [JoinName("MasterVolume")] + public JoinDataComplete MasterVolume = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() {Label = "Master Volume Mute Toggle/FB/Level/Label", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalogSerial }); + [JoinName("VolumeJoinStart")] + public JoinDataComplete VolumeJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata() {Label = "Volume Mute Toggle/FB/Level/Label", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalogSerial }); + + [JoinName("PrivacyMute")] + public JoinDataComplete PrivacyMute = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Label = "Privacy Mute Toggle/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("PromptForCode")] + public JoinDataComplete PromptForCode = new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata() {Label = "Prompt User for Code", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ClientJoined")] + public JoinDataComplete ClientJoined = new JoinDataComplete(new JoinData() { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata() { Label = "Client Joined", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ActivityShare")] + public JoinDataComplete ActivityShare = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() {Label = "Activity Share", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ActivityPhoneCall")] + public JoinDataComplete ActivityPhoneCall = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Label = "Activity Phone Call", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ActivityVideoCall")] + public JoinDataComplete ActivityVideoCall = new JoinDataComplete(new JoinData() { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata() { Label = "Activity Video Call", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("ShutdownPromptDuration")] + public JoinDataComplete ShutdownPromptDuration = new JoinDataComplete(new JoinData() { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata() { Label ="Shutdown Cancel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("ShutdownCancel")] + public JoinDataComplete ShutdownCancel = new JoinDataComplete(new JoinData() { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata() { Label ="Shutdown Cancel", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ShutdownEnd")] + public JoinDataComplete ShutdownEnd = new JoinDataComplete(new JoinData() { JoinNumber = 62, JoinSpan = 1 }, new JoinMetadata() { Label = "Shutdown End", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ShutdownStart")] + public JoinDataComplete ShutdownStart = new JoinDataComplete(new JoinData() { JoinNumber = 63, JoinSpan = 1 }, new JoinMetadata() { Label = "Shutdown Start", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceHasChanged")] + public JoinDataComplete SourceHasChanged = new JoinDataComplete(new JoinData() { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata() { Label = "Source Changed", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CurrentSourceKey")] + public JoinDataComplete CurrentSourceKey = new JoinDataComplete(new JoinData() { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata() { Label = "Key of selected source", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); + + + [JoinName("ConfigIsLocal")] + public JoinDataComplete ConfigIsLocal = new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Label = "Config is local to Essentials", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("NumberOfAuxFaders")] + public JoinDataComplete NumberOfAuxFaders = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Label = "Number of Auxilliary Faders", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("SpeedDialNameStartJoin")] + public JoinDataComplete SpeedDialNameStartJoin = new JoinDataComplete(new JoinData() { JoinNumber = 241, JoinSpan = 10 }, new JoinMetadata() { Label = "Speed Dial names", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("SpeedDialNumberStartJoin")] + public JoinDataComplete SpeedDialNumberStartJoin = new JoinDataComplete(new JoinData() { JoinNumber = 251, JoinSpan = 10 }, new JoinMetadata() { Label = "Speed Dial numbers", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("SpeedDialVisibleStartJoin")] + public JoinDataComplete SpeedDialVisibleStartJoin = new JoinDataComplete(new JoinData() { JoinNumber = 261, JoinSpan = 10 }, new JoinMetadata() { Label = "Speed Dial Visible", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("RoomIsOn")] + public JoinDataComplete RoomIsOn = new JoinDataComplete(new JoinData() { JoinNumber = 301, JoinSpan = 1 }, new JoinMetadata() { Label = "Room Is On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("UserCodeToSystem")] + public JoinDataComplete UserCodeToSystem = new JoinDataComplete(new JoinData() { JoinNumber = 401, JoinSpan = 1 }, new JoinMetadata() { Label = "User Ccde", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ServerUrl")] + public JoinDataComplete ServerUrl = new JoinDataComplete(new JoinData() { JoinNumber = 402, JoinSpan = 1 }, new JoinMetadata() { Label ="Server URL", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("ConfigRoomName")] + public JoinDataComplete ConfigRoomName = new JoinDataComplete(new JoinData() { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata() {Label = "Room Nnme", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ConfigHelpMessage")] + public JoinDataComplete ConfigHelpMessage = new JoinDataComplete(new JoinData() { JoinNumber = 502, JoinSpan = 1 }, new JoinMetadata() { Label = "Room help message", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ConfigHelpNumber")] + public JoinDataComplete ConfigHelpNumber = new JoinDataComplete(new JoinData() { JoinNumber = 503, JoinSpan = 1 }, new JoinMetadata() { Label = "Room help number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ConfigRoomPhoneNumber")] + public JoinDataComplete ConfigRoomPhoneNumber = new JoinDataComplete(new JoinData() { JoinNumber = 504, JoinSpan = 1 }, new JoinMetadata() { Label = "Room phone number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("ConfigRoomURI")] + public JoinDataComplete ConfigRoomURI = new JoinDataComplete(new JoinData() { JoinNumber = 505, JoinSpan = 1 }, new JoinMetadata() { Label = "Room URI", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("ConfigIsReady")] + public JoinDataComplete ConfigIsReady = new JoinDataComplete(new JoinData() { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata() { Label = "Config info from SIMPL is ready", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("HideVideoConfRecents")] + public JoinDataComplete HideVideoConfRecents = new JoinDataComplete(new JoinData() { JoinNumber = 502, JoinSpan = 1 }, new JoinMetadata() { Label = "Hide Video Conference Recents", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ShowCameraWhenNotInCall")] + public JoinDataComplete ShowCameraWhenNotInCall = new JoinDataComplete(new JoinData() { JoinNumber = 503, JoinSpan = 1 }, new JoinMetadata() { Label = "Show camera when not in call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("UseSourceEnabled")] + public JoinDataComplete UseSourceEnabled = new JoinDataComplete(new JoinData() { JoinNumber = 504, JoinSpan = 1 }, new JoinMetadata() { Label = "Use Source Enabled Joins", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + + [JoinName("SourceShareDisableJoinStart")] + public JoinDataComplete SourceShareDisableJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 601, JoinSpan = 20 }, new JoinMetadata() { Label = "Source is not sharable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SourceIsEnabledJoinStart")] + public JoinDataComplete SourceIsEnabledJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 621, JoinSpan = 20 }, new JoinMetadata() { Label = "Source is enabled", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SourceNameJoinStart")] + public JoinDataComplete SourceNameJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 601, JoinSpan = 20 }, new JoinMetadata() { Label = "Source Names", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("SourceIconJoinStart")] + public JoinDataComplete SourceIconJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 621, JoinSpan = 20 }, new JoinMetadata() { Label = "Source Icons", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("SourceKeyJoinStart")] + public JoinDataComplete SourceKeyJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 641, JoinSpan = 20 }, new JoinMetadata() { Label = "Source Keys", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("SourceTypeJoinStart")] + public JoinDataComplete SourceTypeJoinStart = new JoinDataComplete(new JoinData() { JoinNumber = 661, JoinSpan = 20 }, new JoinMetadata() { Label = "Source Types", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("CameraNearNameStart")] + public JoinDataComplete CameraNearNameStart = new JoinDataComplete(new JoinData() { JoinNumber = 761, JoinSpan = 10 }, new JoinMetadata() { Label = "Near End Camera Names", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CameraFarName")] + public JoinDataComplete CameraFarName = new JoinDataComplete(new JoinData() { JoinNumber = 770, JoinSpan = 1 }, new JoinMetadata() { Label = "Far End Camera Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + public MobileControlSIMPLRoomJoinMap(uint joinStart) + :base(joinStart) + { + + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/SIMPLJoinMaps/SIMPLAtcJoinMap.cs b/PepperDashEssentials/AppServer/SIMPLJoinMaps/SIMPLAtcJoinMap.cs new file mode 100644 index 00000000..20abb31e --- /dev/null +++ b/PepperDashEssentials/AppServer/SIMPLJoinMaps/SIMPLAtcJoinMap.cs @@ -0,0 +1,69 @@ +using System.Linq; +using Crestron.SimplSharp.Reflection; + +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.AppServer +{ + public class SIMPLAtcJoinMap : JoinMapBaseAdvanced + { + [JoinName("EndCall")] + public JoinDataComplete EndCall = new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata() { Label = "Hang Up", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("IncomingAnswer")] + public JoinDataComplete IncomingAnswer = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Label = "Answer Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("IncomingReject")] + public JoinDataComplete IncomingReject = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Label = "Reject Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SpeedDialStart")] + public JoinDataComplete SpeedDialStart = new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata() { Label = "Speed Dial", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CurrentDialString")] + public JoinDataComplete CurrentDialString = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Dial String", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentCallNumber")] + public JoinDataComplete CurrentCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentCallName")] + public JoinDataComplete CurrentCallName = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("HookState")] + public JoinDataComplete HookState = new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Hook State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CallDirection")] + public JoinDataComplete CallDirection = new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Call Direction", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("IncomingCallName")] + public JoinDataComplete IncomingCallName = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Label = "Incoming Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("IncomingCallNumber")] + public JoinDataComplete IncomingCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Label = "Incoming Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("0")] + public JoinDataComplete Dtmf0 = new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("1")] + public JoinDataComplete Dtmf1 = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("2")] + public JoinDataComplete Dtmf2 = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("3")] + public JoinDataComplete Dtmf3 = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("4")] + public JoinDataComplete Dtmf4 = new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("5")] + public JoinDataComplete Dtmf5 = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("6")] + public JoinDataComplete Dtmf6 = new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("7")] + public JoinDataComplete Dtmf7 = new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("8")] + public JoinDataComplete Dtmf8 = new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("9")] + public JoinDataComplete Dtmf9 = new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("*")] + public JoinDataComplete DtmfStar = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF *", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("#")] + public JoinDataComplete DtmfPound = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF #", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + /// + /// Constructor that passes the joinStart to the base class + /// + /// + public SIMPLAtcJoinMap(uint joinStart) + : base(joinStart) + { + + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/SIMPLJoinMaps/SIMPLVtcJoinMap.cs b/PepperDashEssentials/AppServer/SIMPLJoinMaps/SIMPLVtcJoinMap.cs new file mode 100644 index 00000000..1ce3c5aa --- /dev/null +++ b/PepperDashEssentials/AppServer/SIMPLJoinMaps/SIMPLVtcJoinMap.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.AppServer +{ + public class SIMPLVtcJoinMap : JoinMapBaseAdvanced + { + [JoinName("EndCall")] + public JoinDataComplete EndCall = new JoinDataComplete(new JoinData() { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata() { Label = "Hang Up", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("IncomingCall")] + public JoinDataComplete IncomingCall = new JoinDataComplete(new JoinData() { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata() { Label = "Incoming Call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("IncomingAnswer")] + public JoinDataComplete IncomingAnswer = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Label = "Answer Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("IncomingReject")] + public JoinDataComplete IncomingReject = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Label = "Reject Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SpeedDialStart")] + public JoinDataComplete SpeedDialStart = new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata() { Label = "Speed Dial", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("DirectorySearchBusy")] + public JoinDataComplete DirectorySearchBusy = new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory Search Busy FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryLineSelected")] + public JoinDataComplete DirectoryLineSelected = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory Line Selected FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryEntryIsContact")] + public JoinDataComplete DirectoryEntryIsContact = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory Selected Entry Is Contact FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryIsRoot")] + public JoinDataComplete DirectoryIsRoot = new JoinDataComplete(new JoinData() { JoinNumber = 102, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory is on Root FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DDirectoryHasChanged")] + public JoinDataComplete DDirectoryHasChanged = new JoinDataComplete(new JoinData() { JoinNumber = 103, JoinSpan = 1 }, new JoinMetadata() {Label = "Directory has changed FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryRoot")] + public JoinDataComplete DirectoryRoot = new JoinDataComplete(new JoinData() { JoinNumber = 104, JoinSpan = 1 }, new JoinMetadata() { Label = "Go to Directory Root", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryFolderBack")] + public JoinDataComplete DirectoryFolderBack = new JoinDataComplete(new JoinData() { JoinNumber = 105, JoinSpan = 1 }, new JoinMetadata() { Label = "Go back one directory level", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryDialSelectedLine")] + public JoinDataComplete DirectoryDialSelectedLine = new JoinDataComplete(new JoinData() { JoinNumber = 106, JoinSpan = 1 }, new JoinMetadata() { Label = "Dial selected directory line", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraTiltUp")] + public JoinDataComplete CameraTiltUp = new JoinDataComplete(new JoinData() { JoinNumber = 111, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Tilt Up", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraTiltDown")] + public JoinDataComplete CameraTiltDown = new JoinDataComplete(new JoinData() { JoinNumber = 112, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Tilt Down", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraPanLeft")] + public JoinDataComplete CameraPanLeft = new JoinDataComplete(new JoinData() { JoinNumber = 113, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Pan Left", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraPanRight")] + public JoinDataComplete CameraPanRight = new JoinDataComplete(new JoinData() { JoinNumber = 114, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Pan Right", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraZoomIn")] + public JoinDataComplete CameraZoomIn = new JoinDataComplete(new JoinData() { JoinNumber = 115, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Zoom In", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraZoomOut")] + public JoinDataComplete CameraZoomOut = new JoinDataComplete(new JoinData() { JoinNumber = 116, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Zoom Out", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraPresetStart")] + public JoinDataComplete CameraPresetStart = new JoinDataComplete(new JoinData() { JoinNumber = 121, JoinSpan = 5 }, new JoinMetadata() { Label = "Camera Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraModeAuto")] + public JoinDataComplete CameraModeAuto = new JoinDataComplete(new JoinData() { JoinNumber = 131, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Mode Auto", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraModeManual")] + public JoinDataComplete CameraModeManual = new JoinDataComplete(new JoinData() { JoinNumber = 132, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Mode Manual", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraModeOff")] + public JoinDataComplete CameraModeOff = new JoinDataComplete(new JoinData() { JoinNumber = 133, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Mode Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraSelfView")] + public JoinDataComplete CameraSelfView = new JoinDataComplete(new JoinData() { JoinNumber = 141, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Self View Toggle/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraLayout")] + public JoinDataComplete CameraLayout = new JoinDataComplete(new JoinData() { JoinNumber = 142, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Layout Toggle", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraSupportsAutoMode")] + public JoinDataComplete CameraSupportsAutoMode = new JoinDataComplete(new JoinData() { JoinNumber = 143, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Supports Auto Mode FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraSupportsOffMode")] + public JoinDataComplete CameraSupportsOffMode = new JoinDataComplete(new JoinData() { JoinNumber = 144, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Supports Off Mode FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraNumberSelect")] + public JoinDataComplete CameraNumberSelect = new JoinDataComplete(new JoinData() { JoinNumber = 60, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Number Select/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectorySelectRow")] + public JoinDataComplete DirectorySelectRow = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory Select Row", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("DirectoryRowCount")] + public JoinDataComplete DirectoryRowCount = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory Row Count FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CurrentDialString")] + public JoinDataComplete CurrentDialString = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Dial String", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentCallName")] + public JoinDataComplete CurrentCallName = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CurrentCallNumber")] + public JoinDataComplete CurrentCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("HookState")] + public JoinDataComplete HookState = new JoinDataComplete(new JoinData() { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Hook State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("CallDirection")] + public JoinDataComplete CallDirection = new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata() { Label = "Current Call Direction", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("IncomingCallName")] + public JoinDataComplete IncomingCallName = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Label = "Incoming Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("IncomingCallNumber")] + public JoinDataComplete IncomingCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Label = "Incoming Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("DirectorySearchString")] + public JoinDataComplete DirectorySearchString = new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Label = "Directory Search String", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); + [JoinName("DirectoryEntriesStart")] + public JoinDataComplete DirectoryEntriesStart = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 255 }, new JoinMetadata() { Label = "Directory Entries", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("DirectoryEntrySelectedName")] + public JoinDataComplete DirectoryEntrySelectedName = new JoinDataComplete(new JoinData() { JoinNumber = 356, JoinSpan = 1 }, new JoinMetadata() { Label = "Selected Directory Entry Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("DirectoryEntrySelectedNumber")] + public JoinDataComplete DirectoryEntrySelectedNumber = new JoinDataComplete(new JoinData() { JoinNumber = 357, JoinSpan = 1 }, new JoinMetadata() { Label = "Selected Directory Entry Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("DirectorySelectedFolderName")] + public JoinDataComplete DirectorySelectedFolderName = new JoinDataComplete(new JoinData() { JoinNumber = 358, JoinSpan = 1 }, new JoinMetadata() { Label = "Selected Directory Folder Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + + [JoinName("1")] + public JoinDataComplete Dtmf1 = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("2")] + public JoinDataComplete Dtmf2 = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("3")] + public JoinDataComplete Dtmf3 = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("4")] + public JoinDataComplete Dtmf4 = new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("5")] + public JoinDataComplete Dtmf5 = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("6")] + public JoinDataComplete Dtmf6 = new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("7")] + public JoinDataComplete Dtmf7 = new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("8")] + public JoinDataComplete Dtmf8 = new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("9")] + public JoinDataComplete Dtmf9 = new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("0")] + public JoinDataComplete Dtmf0 = new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF 0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("*")] + public JoinDataComplete DtmfStar = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF *", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("#")] + public JoinDataComplete DtmfPound = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Label = "DTMF #", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + + public SIMPLVtcJoinMap(uint joinStart) + :base(joinStart) + { + } + + } +} \ No newline at end of file diff --git a/PepperDashEssentials/Bridges/AirMediaControllerBridge.cs b/PepperDashEssentials/Bridges/AirMediaControllerBridge.cs index 1f1b64dc..6d819c7b 100644 --- a/PepperDashEssentials/Bridges/AirMediaControllerBridge.cs +++ b/PepperDashEssentials/Bridges/AirMediaControllerBridge.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Bridges { AirMediaControllerJoinMap joinMap = new AirMediaControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/AppleTvBridge.cs b/PepperDashEssentials/Bridges/AppleTvBridge.cs index 6169a712..99501baa 100644 --- a/PepperDashEssentials/Bridges/AppleTvBridge.cs +++ b/PepperDashEssentials/Bridges/AppleTvBridge.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Bridges { AppleTvJoinMap joinMap = new AppleTvJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if(!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/BridgeBase.cs b/PepperDashEssentials/Bridges/BridgeBase.cs index 73ede03c..0c4e388b 100644 --- a/PepperDashEssentials/Bridges/BridgeBase.cs +++ b/PepperDashEssentials/Bridges/BridgeBase.cs @@ -45,7 +45,6 @@ namespace PepperDash.Essentials.Bridges { } - } /// @@ -55,6 +54,8 @@ namespace PepperDash.Essentials.Bridges { public EiscApiPropertiesConfig PropertiesConfig { get; private set; } + protected Dictionary JoinMaps { get; private set; } + public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc { get; private set; } public EiscApi(DeviceConfig dc) : @@ -95,7 +96,7 @@ namespace PepperDash.Essentials.Bridges } else if (device is CameraBase) { - (device as CameraBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey); + (device as CameraBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); continue; } else if (device is PepperDash.Essentials.Core.DisplayBase) @@ -188,6 +189,23 @@ namespace PepperDash.Essentials.Bridges }); } + /// + /// Adds a join map + /// + /// + /// + public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap) + { + if (!JoinMaps.ContainsKey(deviceKey)) + { + JoinMaps.Add(deviceKey, joinMap); + } + else + { + Debug.Console(2, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey); + } + } + /// /// Used for debugging to trigger an action based on a join number and type /// @@ -284,10 +302,10 @@ namespace PepperDash.Essentials.Bridges public EssentialsControlPropertiesConfig Control { get; set; } [JsonProperty("devices")] - public List Devices { get; set; } + public List Devices { get; set; } - public class ApiDevice + public class ApiDevicePropertiesConfig { [JsonProperty("deviceKey")] public string DeviceKey { get; set; } diff --git a/PepperDashEssentials/Bridges/C2nRthsControllerBridge.cs b/PepperDashEssentials/Bridges/C2nRthsControllerBridge.cs index 58f4600d..13b78bae 100644 --- a/PepperDashEssentials/Bridges/C2nRthsControllerBridge.cs +++ b/PepperDashEssentials/Bridges/C2nRthsControllerBridge.cs @@ -13,7 +13,7 @@ namespace PepperDash.Essentials.Bridges { var joinMap = new C2nRthsControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/CameraControllerBridge.cs b/PepperDashEssentials/Bridges/CameraControllerBridge.cs index badf9ea0..8e25300a 100644 --- a/PepperDashEssentials/Bridges/CameraControllerBridge.cs +++ b/PepperDashEssentials/Bridges/CameraControllerBridge.cs @@ -15,29 +15,31 @@ namespace PepperDash.Essentials.Bridges { public static class CameraControllerApiExtensions { - - public static void LinkToApi(this PepperDash.Essentials.Devices.Common.Cameras.CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey) + public static void LinkToApi(this PepperDash.Essentials.Devices.Common.Cameras.CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApi bridge) { - CameraControllerJoinMap joinMap = new CameraControllerJoinMap(); + CameraControllerJoinMap joinMap = new CameraControllerJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + // Adds the join map to the bridge + bridge.AddJoinMap(cameraDevice.Key, joinMap); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); - joinMap.OffsetJoinNumbers(joinStart); + if (customJoins != null) + { + joinMap.SetCustomJoinData(customJoins); + } Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.Console(0, "Linking to Bridge Type {0}", cameraDevice.GetType().Name.ToString()); var commMonitor = cameraDevice as ICommunicationMonitor; - commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]); + commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); var ptzCamera = cameraDevice as IHasCameraPtzControl; if (ptzCamera != null) { - trilist.SetBoolSigAction(joinMap.Left, (b) => + trilist.SetBoolSigAction(joinMap.PanLeft.JoinNumber, (b) => { if (b) { @@ -48,7 +50,7 @@ namespace PepperDash.Essentials.Bridges ptzCamera.PanStop(); } }); - trilist.SetBoolSigAction(joinMap.Right, (b) => + trilist.SetBoolSigAction(joinMap.PanRight.JoinNumber, (b) => { if (b) { @@ -60,7 +62,7 @@ namespace PepperDash.Essentials.Bridges } }); - trilist.SetBoolSigAction(joinMap.Up, (b) => + trilist.SetBoolSigAction(joinMap.TiltUp.JoinNumber, (b) => { if (b) { @@ -71,7 +73,7 @@ namespace PepperDash.Essentials.Bridges ptzCamera.TiltStop(); } }); - trilist.SetBoolSigAction(joinMap.Down, (b) => + trilist.SetBoolSigAction(joinMap.TiltDown.JoinNumber, (b) => { if (b) { @@ -83,7 +85,7 @@ namespace PepperDash.Essentials.Bridges } }); - trilist.SetBoolSigAction(joinMap.ZoomIn, (b) => + trilist.SetBoolSigAction(joinMap.ZoomIn.JoinNumber, (b) => { if (b) { @@ -95,7 +97,7 @@ namespace PepperDash.Essentials.Bridges } }); - trilist.SetBoolSigAction(joinMap.ZoomOut, (b) => + trilist.SetBoolSigAction(joinMap.ZoomOut.JoinNumber, (b) => { if (b) { @@ -108,27 +110,57 @@ namespace PepperDash.Essentials.Bridges }); } - if (cameraDevice.GetType().Name.ToString().ToLower() == "cameravisca") + if (cameraDevice is IPower) { - var viscaCamera = cameraDevice as PepperDash.Essentials.Devices.Common.Cameras.CameraVisca; - trilist.SetSigTrueAction(joinMap.PowerOn, () => viscaCamera.PowerOn()); - trilist.SetSigTrueAction(joinMap.PowerOff, () => viscaCamera.PowerOff()); + var powerCamera = cameraDevice as IPower; + trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => powerCamera.PowerOn()); + trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => powerCamera.PowerOff()); + + powerCamera.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); + powerCamera.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); + } - viscaCamera.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn]); - viscaCamera.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff]); + if (cameraDevice is ICommunicationMonitor) + { + var monitoredCamera = cameraDevice as ICommunicationMonitor; + monitoredCamera.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); + } - viscaCamera.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]); - for (int i = 0; i < joinMap.NumberOfPresets; i++) + if (cameraDevice is IHasCameraPresets) + { + // Set the preset lables when they change + var presetsCamera = cameraDevice as IHasCameraPresets; + presetsCamera.PresetsListHasChanged += new EventHandler((o, a) => + { + for (int i = 1; i <= joinMap.NumberOfPresets.JoinNumber; i++) + { + int tempNum = i - 1; + + string label = "" ; + + var preset = presetsCamera.Presets.FirstOrDefault(p => p.ID.Equals(i)); + + if (preset != null) + label = preset.Description; + + trilist.SetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum), label); + } + }); + + for (int i = 0; i < joinMap.NumberOfPresets.JoinNumber; i++) { int tempNum = i; - trilist.SetSigTrueAction((ushort)(joinMap.PresetRecallOffset + tempNum), () => + + trilist.SetSigTrueAction((ushort)(joinMap.PresetRecallStart.JoinNumber + tempNum), () => { - viscaCamera.RecallPreset(tempNum); + presetsCamera.PresetSelect(tempNum); + }); + trilist.SetSigTrueAction((ushort)(joinMap.PresetSaveStart.JoinNumber + tempNum), () => + { + var label = trilist.GetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum)); + + presetsCamera.PresetStore(tempNum, label); }); - trilist.SetSigTrueAction((ushort)(joinMap.PresetSaveOffset + tempNum), () => - { - viscaCamera.SavePreset(tempNum); - }); } } } diff --git a/PepperDashEssentials/Bridges/DigitalLoggerBridge.cs b/PepperDashEssentials/Bridges/DigitalLoggerBridge.cs index 2c857da2..7d3fab3d 100644 --- a/PepperDashEssentials/Bridges/DigitalLoggerBridge.cs +++ b/PepperDashEssentials/Bridges/DigitalLoggerBridge.cs @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Bridges { DigitalLoggerJoinMap joinMap = new DigitalLoggerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DisplayControllerBridge.cs b/PepperDashEssentials/Bridges/DisplayControllerBridge.cs index 25791796..c94b3691 100644 --- a/PepperDashEssentials/Bridges/DisplayControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DisplayControllerBridge.cs @@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Bridges DisplayControllerJoinMap joinMap = new DisplayControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if(!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DmBladeChassisControllerBridge.cs b/PepperDashEssentials/Bridges/DmBladeChassisControllerBridge.cs index 6daddbb0..221745e8 100644 --- a/PepperDashEssentials/Bridges/DmBladeChassisControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DmBladeChassisControllerBridge.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Bridges { public static void LinkToApi(this DmBladeChassisController dmChassis, BasicTriList trilist, uint joinStart, string joinMapKey) { DmBladeChassisControllerJoinMap joinMap = new DmBladeChassisControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DmChassisControllerBridge.cs b/PepperDashEssentials/Bridges/DmChassisControllerBridge.cs index e193cc2c..9c8c8551 100644 --- a/PepperDashEssentials/Bridges/DmChassisControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DmChassisControllerBridge.cs @@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Bridges { DmChassisControllerJoinMap joinMap = new DmChassisControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DmRmcControllerBridge.cs b/PepperDashEssentials/Bridges/DmRmcControllerBridge.cs index ca7bdeca..1e99b734 100644 --- a/PepperDashEssentials/Bridges/DmRmcControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DmRmcControllerBridge.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Bridges { DmRmcControllerJoinMap joinMap = new DmRmcControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DmTxControllerBridge.cs b/PepperDashEssentials/Bridges/DmTxControllerBridge.cs index 91f8c6d7..9b28611e 100644 --- a/PepperDashEssentials/Bridges/DmTxControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DmTxControllerBridge.cs @@ -22,7 +22,7 @@ namespace PepperDash.Essentials.Bridges { DmTxControllerJoinMap joinMap = new DmTxControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DmpsAudioOutputControllerBridge.cs b/PepperDashEssentials/Bridges/DmpsAudioOutputControllerBridge.cs index 406550a4..f721b44f 100644 --- a/PepperDashEssentials/Bridges/DmpsAudioOutputControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DmpsAudioOutputControllerBridge.cs @@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Bridges { DmpsAudioOutputControllerJoinMap joinMap = new DmpsAudioOutputControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/DmpsRoutingControllerBridge.cs b/PepperDashEssentials/Bridges/DmpsRoutingControllerBridge.cs index cc95e07b..eb359dd9 100644 --- a/PepperDashEssentials/Bridges/DmpsRoutingControllerBridge.cs +++ b/PepperDashEssentials/Bridges/DmpsRoutingControllerBridge.cs @@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Bridges { DmpsRoutingControllerJoinMap joinMap = new DmpsRoutingControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/GenericLightingBridge.cs b/PepperDashEssentials/Bridges/GenericLightingBridge.cs index 543e124e..d76bbebb 100644 --- a/PepperDashEssentials/Bridges/GenericLightingBridge.cs +++ b/PepperDashEssentials/Bridges/GenericLightingBridge.cs @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Bridges { GenericLightingJoinMap joinMap = new GenericLightingJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/GenericRelayDeviceBridge.cs b/PepperDashEssentials/Bridges/GenericRelayDeviceBridge.cs index 95566712..684a5550 100644 --- a/PepperDashEssentials/Bridges/GenericRelayDeviceBridge.cs +++ b/PepperDashEssentials/Bridges/GenericRelayDeviceBridge.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Bridges { GenericRelayControllerJoinMap joinMap = new GenericRelayControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/GlsOccupancySensorBaseControllerBridge.cs b/PepperDashEssentials/Bridges/GlsOccupancySensorBaseControllerBridge.cs index d905beef..a49061b7 100644 --- a/PepperDashEssentials/Bridges/GlsOccupancySensorBaseControllerBridge.cs +++ b/PepperDashEssentials/Bridges/GlsOccupancySensorBaseControllerBridge.cs @@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Bridges { GlsOccupancySensorBaseJoinMap joinMap = new GlsOccupancySensorBaseJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/HdMdxxxCEControllerBridge.cs b/PepperDashEssentials/Bridges/HdMdxxxCEControllerBridge.cs index 0ec23c55..52bacfec 100644 --- a/PepperDashEssentials/Bridges/HdMdxxxCEControllerBridge.cs +++ b/PepperDashEssentials/Bridges/HdMdxxxCEControllerBridge.cs @@ -22,7 +22,7 @@ namespace PepperDash.Essentials.Bridges { HdMdxxxCEControllerJoinMap joinMap = new HdMdxxxCEControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/IBasicCommunicationBridge.cs b/PepperDashEssentials/Bridges/IBasicCommunicationBridge.cs index 86fbf78b..6ae9334c 100644 --- a/PepperDashEssentials/Bridges/IBasicCommunicationBridge.cs +++ b/PepperDashEssentials/Bridges/IBasicCommunicationBridge.cs @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Bridges { IBasicCommunicationJoinMap joinMap = new IBasicCommunicationJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/IDigitalInputBridge.cs b/PepperDashEssentials/Bridges/IDigitalInputBridge.cs index 4d42cbdc..54c48e1a 100644 --- a/PepperDashEssentials/Bridges/IDigitalInputBridge.cs +++ b/PepperDashEssentials/Bridges/IDigitalInputBridge.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Bridges { IDigitalInputJoinMap joinMap = new IDigitalInputJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/IRSetTopBoxBaseBridge.cs b/PepperDashEssentials/Bridges/IRSetTopBoxBaseBridge.cs index 68d765bc..0f7b5786 100644 --- a/PepperDashEssentials/Bridges/IRSetTopBoxBaseBridge.cs +++ b/PepperDashEssentials/Bridges/IRSetTopBoxBaseBridge.cs @@ -17,7 +17,7 @@ namespace PepperDash.Essentials.Bridges public static void LinkToApi(this PepperDash.Essentials.Devices.Common.IRSetTopBoxBase stbDevice, BasicTriList trilist, uint joinStart, string joinMapKey) { SetTopBoxControllerJoinMap joinMap = new SetTopBoxControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/JoinMaps/CameraControllerJoinMap.cs b/PepperDashEssentials/Bridges/JoinMaps/CameraControllerJoinMap.cs index cf087e5f..44666a4e 100644 --- a/PepperDashEssentials/Bridges/JoinMaps/CameraControllerJoinMap.cs +++ b/PepperDashEssentials/Bridges/JoinMaps/CameraControllerJoinMap.cs @@ -8,54 +8,57 @@ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Bridges { - public class CameraControllerJoinMap : JoinMapBase + /// + /// Join map for CameraBase devices + /// + public class CameraControllerJoinMap : JoinMapBaseAdvanced { - public uint IsOnline { get; set; } - public uint PowerOff { get; set; } - public uint PowerOn { get; set; } - public uint Up { get; set; } - public uint Down { get; set; } - public uint Left { get; set; } - public uint Right { get; set; } - public uint ZoomIn { get; set; } - public uint ZoomOut { get; set; } - public uint PresetRecallOffset { get; set; } - public uint PresetSaveOffset { get; set; } - public uint NumberOfPresets { get; set; } + [JoinName("TiltUp")] + public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("TiltDown")] + public JoinDataComplete TiltDown = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "Tilt Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PanLeft")] + public JoinDataComplete PanLeft = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Label = "Pan Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PanRight")] + public JoinDataComplete PanRight = new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Label = "Pan Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ZoomIn")] + public JoinDataComplete ZoomIn = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Label = "Zoom In", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("ZoomOut")] + public JoinDataComplete ZoomOut = new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Label = "Zoom Out", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); - public CameraControllerJoinMap() + [JoinName("IsOnline")] + public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Label = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PowerOn")] + public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Label = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PowerOff")] + public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Label = "Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("NumberOfPresets")] + public JoinDataComplete NumberOfPresets = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Label = "Tells Essentials the number of defined presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("PresetRecallStart")] + public JoinDataComplete PresetRecallStart = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata() { Label = "Preset Recall Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("PresetLabelStart")] + public JoinDataComplete PresetLabelStart = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata() { Label = "Preset Label Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); + [JoinName("PresetSaveStart")] + public JoinDataComplete PresetSaveStart = new JoinDataComplete(new JoinData() { JoinNumber = 31, JoinSpan = 20 }, new JoinMetadata() { Label = "Preset Save Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("CameraModeAuto")] + public JoinDataComplete CameraModeAuto = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Mode Auto", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraModeManual")] + public JoinDataComplete CameraModeManual = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Mode Manual", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("CameraModeOff")] + public JoinDataComplete CameraModeOff = new JoinDataComplete(new JoinData() { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata() { Label = "Camera Mode Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); + + [JoinName("SupportsCameraModeAuto")] + public JoinDataComplete SupportsCameraModeAuto = new JoinDataComplete(new JoinData() { JoinNumber = 55, JoinSpan = 1 }, new JoinMetadata() { Label = "Supports Camera Mode Auto", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SupportsCameraModeOff")] + public JoinDataComplete SupportsCameraModeOff = new JoinDataComplete(new JoinData() { JoinNumber = 56, JoinSpan = 1 }, new JoinMetadata() { Label = "Supports Camera Mode Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + [JoinName("SupportsPresets")] + public JoinDataComplete SupportsPresets = new JoinDataComplete(new JoinData() { JoinNumber = 57, JoinSpan = 1 }, new JoinMetadata() { Label = "Supports Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); + + public CameraControllerJoinMap(uint joinStart) + :base(joinStart) { - // Digital - IsOnline = 9; - PowerOff = 8; - PowerOn = 7; - Up = 1; - Down = 2; - Left = 3; - Right = 4; - ZoomIn = 5; - ZoomOut = 6; - PresetRecallOffset = 10; - PresetSaveOffset = 30; - NumberOfPresets = 5; - // Analog - } - - public override void OffsetJoinNumbers(uint joinStart) - { - var joinOffset = joinStart - 1; - - IsOnline = IsOnline + joinOffset; - PowerOff = PowerOff + joinOffset; - PowerOn = PowerOn + joinOffset; - Up = Up + joinOffset; - Down = Down + joinOffset; - Left = Left + joinOffset; - Right = Right + joinOffset; - ZoomIn = ZoomIn + joinOffset; - ZoomOut = ZoomOut + joinOffset; - PresetRecallOffset = PresetRecallOffset + joinOffset; - PresetSaveOffset = PresetSaveOffset + joinOffset; } } } \ No newline at end of file diff --git a/PepperDashEssentials/Bridges/StatusSignControllerBridge.cs b/PepperDashEssentials/Bridges/StatusSignControllerBridge.cs index df38ba26..860f070d 100644 --- a/PepperDashEssentials/Bridges/StatusSignControllerBridge.cs +++ b/PepperDashEssentials/Bridges/StatusSignControllerBridge.cs @@ -13,7 +13,7 @@ namespace PepperDash.Essentials.Bridges { var joinMap = new StatusSignControllerJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Bridges/SystemMonitorBridge.cs b/PepperDashEssentials/Bridges/SystemMonitorBridge.cs index 6e41a43f..d048b493 100644 --- a/PepperDashEssentials/Bridges/SystemMonitorBridge.cs +++ b/PepperDashEssentials/Bridges/SystemMonitorBridge.cs @@ -14,7 +14,7 @@ namespace PepperDash.Essentials.Bridges { var joinMap = new SystemMonitorJoinMap(); - var joinMapSerialized = JoinMapHelper.GetJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if(!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); diff --git a/PepperDashEssentials/Factory/DeviceFactory.cs b/PepperDashEssentials/Factory/DeviceFactory.cs index 24c4bfe1..1e0e8ffb 100644 --- a/PepperDashEssentials/Factory/DeviceFactory.cs +++ b/PepperDashEssentials/Factory/DeviceFactory.cs @@ -69,7 +69,7 @@ namespace PepperDash.Essentials { var comm = CommFactory.GetControlPropertiesConfig(dc); - var bridge = new PepperDash.Essentials.Room.MobileControl.MobileControlDdvc01RoomBridge(key, name, comm.IpIdInt); + var bridge = new PepperDash.Essentials.Room.MobileControl.MobileControlSIMPLRoomBridge(key, name, comm.IpIdInt); bridge.AddPreActivationAction(() => { var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as MobileControlSystemController; diff --git a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs index 8ec55881..c6c85d1a 100644 --- a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -186,7 +186,7 @@ namespace PepperDash.Essentials.Fusion FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff")); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey)); // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); @@ -342,7 +342,7 @@ namespace PepperDash.Essentials.Fusion // Current Source var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); - defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff"); }); ; + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ; } } } diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 0bd07ecf..3c4fd6b5 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -108,13 +108,21 @@ + - + - + + + + + + + + @@ -166,7 +174,6 @@ - @@ -179,7 +186,7 @@ - + diff --git a/PepperDashEssentials/PluginLoading/PluginLoading.cs b/PepperDashEssentials/PluginLoading/PluginLoading.cs index 11a4ee32..405241a3 100644 --- a/PepperDashEssentials/PluginLoading/PluginLoading.cs +++ b/PepperDashEssentials/PluginLoading/PluginLoading.cs @@ -8,6 +8,7 @@ using Crestron.SimplSharp.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Plugins; namespace PepperDash.Essentials { @@ -39,7 +40,6 @@ namespace PepperDash.Essentials // The temp directory where .cplz archives will be unzipped to static string _tempDirectory = _pluginDirectory + Global.DirectorySeparator + "temp"; - static PluginLoader() { LoadedAssemblies = new List(); @@ -69,6 +69,11 @@ namespace PepperDash.Essentials { version = Global.AssemblyVersion; assembly = Assembly.GetExecutingAssembly(); + break; + } + case ("PepperDashEssentialsBase.dll"): + { + break; } case ("PepperDash_Core.dll"): @@ -338,49 +343,21 @@ namespace PepperDash.Essentials { try { - var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static); - var loadPlugin = methods.FirstOrDefault(m => m.Name.Equals("LoadPlugin")); - if (loadPlugin != null) + if (typeof(IPluginDeviceFactory).IsAssignableFrom(type)) { - Debug.Console(2, "LoadPlugin method found in {0}", type.Name); - - var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); - - var minimumVersion = fields.FirstOrDefault(p => p.Name.Equals("MinimumEssentialsFrameworkVersion")); - if (minimumVersion != null) - { - Debug.Console(2, "MinimumEssentialsFrameworkVersion found"); - - var minimumVersionString = minimumVersion.GetValue(null) as string; - - if (!string.IsNullOrEmpty(minimumVersionString)) - { - var passed = Global.IsRunningMinimumVersionOrHigher(minimumVersionString); - - if (!passed) - { - Debug.Console(0, Debug.ErrorLogLevel.Error, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", minimumVersionString); - continue; - } - else - { - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Passed plugin passed dependency check (required version {0})", minimumVersionString); - } - } - else - { - Debug.Console(0, Debug.ErrorLogLevel.Warning, "MinimumEssentialsFrameworkVersion found but not set. Loading plugin, but your mileage may vary."); - } - } - else - { - Debug.Console(0, Debug.ErrorLogLevel.Warning, "MinimumEssentialsFrameworkVersion not found. Loading plugin, but your mileage may vary."); - } - - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Adding plugin: {0}", loadedAssembly.Name); - loadPlugin.Invoke(null, null); + var plugin = (IPluginDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(type); + LoadCustomPlugin(plugin, loadedAssembly); } - } + else + { + var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static); + var loadPlugin = methods.FirstOrDefault(m => m.Name.Equals("LoadPlugin")); + if (loadPlugin != null) + { + LoadCustomLegacyPlugin(type, loadPlugin, loadedAssembly); + } + } + } catch (Exception e) { Debug.Console(2, "Load Plugin not found. {0} is not a plugin assembly. Exception: {1}", loadedAssembly.Name, e); @@ -400,6 +377,75 @@ namespace PepperDash.Essentials Debug.Console(0, "Done Loading Custom Plugin Types."); } + /// + /// Loads a + /// + /// + static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly) + { + var passed = Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion); + + if (!passed) + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", plugin.MinimumEssentialsFrameworkVersion); + return; + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Passed plugin passed dependency check (required version {0})", plugin.MinimumEssentialsFrameworkVersion); + } + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading plugin: {0}", loadedAssembly.Name); + plugin.LoadTypeFactories(); + } + + /// + /// Loads a a custom plugin via the legacy method + /// + /// + /// + static void LoadCustomLegacyPlugin(CType type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly) + { + Debug.Console(2, "LoadPlugin method found in {0}", type.Name); + + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); + + var minimumVersion = fields.FirstOrDefault(p => p.Name.Equals("MinimumEssentialsFrameworkVersion")); + if (minimumVersion != null) + { + Debug.Console(2, "MinimumEssentialsFrameworkVersion found"); + + var minimumVersionString = minimumVersion.GetValue(null) as string; + + if (!string.IsNullOrEmpty(minimumVersionString)) + { + var passed = Global.IsRunningMinimumVersionOrHigher(minimumVersionString); + + if (!passed) + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", minimumVersionString); + return; + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Passed plugin passed dependency check (required version {0})", minimumVersionString); + } + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Warning, "MinimumEssentialsFrameworkVersion found but not set. Loading plugin, but your mileage may vary."); + } + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Warning, "MinimumEssentialsFrameworkVersion not found. Loading plugin, but your mileage may vary."); + } + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading legacy plugin: {0}", loadedAssembly.Name); + loadPlugin.Invoke(null, null); + + } + /// /// Loads plugins /// diff --git a/PepperDashEssentials/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs b/PepperDashEssentials/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs index 2044484d..528436d6 100644 --- a/PepperDashEssentials/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs @@ -4,6 +4,10 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; + namespace PepperDash.Essentials.Room.Config { /// @@ -11,9 +15,28 @@ namespace PepperDash.Essentials.Room.Config /// public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig { + /// + /// The key of the default display device + /// + [JsonProperty("defaultDisplayKey")] public string DefaultDisplayKey { get; set; } + + /// + /// The key of the default audio device + /// + [JsonProperty("defaultAudioKey")] public string DefaultAudioKey { get; set; } + + /// + /// The key of the source list for the room + /// + [JsonProperty("sourceListKey")] public string SourceListKey { get; set; } + + /// + /// The key of the default source item from the source list + /// + [JsonProperty("defaultSourceItem")] public string DefaultSourceItem { get; set; } } } \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs index 44c88724..27539ebd 100644 --- a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs @@ -348,7 +348,7 @@ namespace PepperDash.Essentials CrestronEnvironment.Sleep(1000); - RunRouteAction("roomOff"); + RunRouteAction("roomOff", SourceListKey); } /// @@ -357,7 +357,7 @@ namespace PepperDash.Essentials public override bool RunDefaultPresentRoute() { if (DefaultSourceItem != null) - RunRouteAction(DefaultSourceItem); + RunRouteAction(DefaultSourceItem, SourceListKey); return DefaultSourceItem != null; } @@ -368,7 +368,7 @@ namespace PepperDash.Essentials /// public bool RunDefaultCallRoute() { - RunRouteAction(DefaultCodecRouteString); + RunRouteAction(DefaultCodecRouteString, SourceListKey); return true; } @@ -376,9 +376,9 @@ namespace PepperDash.Essentials /// /// /// - public void RunRouteAction(string routeKey) + public void RunRouteAction(string routeKey, string sourceListKey) { - RunRouteAction(routeKey, null); + RunRouteAction(routeKey, sourceListKey, null); } /// @@ -386,7 +386,7 @@ namespace PepperDash.Essentials /// route or commands /// /// - public void RunRouteAction(string routeKey, Action successCallback) + public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback) { // Run this on a separate thread new CTimer(o => @@ -398,10 +398,10 @@ namespace PepperDash.Essentials { Debug.Console(1, this, "Run route action '{0}'", routeKey); - var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey); + var dict = ConfigReader.ConfigObject.GetSourceListForKey(sourceListKey); if (dict == null) { - Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey); + Debug.Console(1, this, "WARNING: Config source list '{0}' not found", sourceListKey); return; } @@ -619,7 +619,7 @@ namespace PepperDash.Essentials { if (!EnablePowerOnToLastSource || LastSourceKey == null) return; - RunRouteAction(LastSourceKey); + RunRouteAction(LastSourceKey, SourceListKey); } /// @@ -630,7 +630,7 @@ namespace PepperDash.Essentials var allRooms = DeviceManager.AllDevices.Where(d => d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions); foreach (var room in allRooms) - (room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff"); + (room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff", (room as EssentialsHuddleSpaceRoom).SourceListKey); } #region IPrivacy Members diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index 9bec05b8..b14e563d 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -264,8 +264,30 @@ namespace PepperDash.Essentials /// public void RunRouteAction(string routeKey) { - RunRouteAction(routeKey, null); - } + RunRouteAction(routeKey, new Action(() => { })); + } + + /// + /// + /// + /// + /// + /// + public void RunRouteAction(string routeKey, string souceListKey) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public void RunRouteAction(string routeKey, string souceListKey, Action successCallback) + { + throw new NotImplementedException(); + } /// /// Gets a source from config list SourceListKey and dynamically build and executes the diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index b2db56ae..c5021526 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -394,8 +394,30 @@ namespace PepperDash.Essentials /// public void RunRouteAction(string routeKey) { - RunRouteAction(routeKey, null); - } + RunRouteAction(routeKey, new Action(() => { })); + } + + /// + /// + /// + /// + /// + /// + public void RunRouteAction(string routeKey, string souceListKey) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + public void RunRouteAction(string routeKey, string souceListKey, Action successCallback) + { + throw new NotImplementedException(); + } /// /// Gets a source from config list SourceListKey and dynamically build and executes the diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs index 144fafb4..232a99da 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs @@ -564,7 +564,7 @@ namespace PepperDash.Essentials void UiSelectSource(string key) { // Run the route and when it calls back, show the source - CurrentRoom.RunRouteAction(key, null); + CurrentRoom.RunRouteAction(key, new Action(() => { })); } /// diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs index 57e68010..9248e50a 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs @@ -726,7 +726,7 @@ namespace PepperDash.Essentials void UiSelectSource(string key) { // Run the route and when it calls back, show the source - CurrentRoom.RunRouteAction(key, null); + CurrentRoom.RunRouteAction(key, new Action(() => { })); } /// @@ -941,7 +941,7 @@ namespace PepperDash.Essentials if (_CurrentRoom != null) _CurrentRoom.CurrentSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange); - TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, () => _CurrentRoom.RunRouteAction("codecOsd")); + TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, () => _CurrentRoom.RunRouteAction("codecOsd", _CurrentRoom.SourceListKey)); (Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom); } @@ -987,7 +987,7 @@ namespace PepperDash.Essentials if (CurrentRoom.CurrentSourceInfo != null && CurrentRoom.CurrentSourceInfo.DisableCodecSharing) { Debug.Console(1, CurrentRoom, "Transitioning to in-call, cancelling non-sharable source"); - CurrentRoom.RunRouteAction("codecOsd"); + CurrentRoom.RunRouteAction("codecOsd", CurrentRoom.SourceListKey); } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/BasicConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/BasicConfig.cs index 3673a384..904bfc74 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/BasicConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/BasicConfig.cs @@ -39,5 +39,25 @@ namespace PepperDash.Essentials.Core.Config return SourceLists[key]; } + + /// + /// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null + /// + /// Key of desired device + /// + public DeviceConfig GetDeviceForKey(string key) + { + if (string.IsNullOrEmpty(key)) + return null; + + var deviceConfig = Devices.FirstOrDefault(d => d.Key.Equals(key)); + + if (deviceConfig != null) + return deviceConfig; + else + { + return null; + } + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Comm and IR/GenericComm.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Comm and IR/GenericComm.cs index 1998f62e..0b0e4d82 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Comm and IR/GenericComm.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Comm and IR/GenericComm.cs @@ -13,12 +13,14 @@ using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { + + /// /// Serves as a generic wrapper class for all styles of IBasicCommuncation ports /// - public class - GenericComm : ReconfigurableDevice + public class GenericComm : ReconfigurableDevice { + EssentialsControlPropertiesConfig PropertiesConfig; public IBasicCommunication CommPort { get; private set; } @@ -29,6 +31,14 @@ namespace PepperDash.Essentials.Core PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); CommPort = CommFactory.CreateCommForDevice(config); + + + } + + public static IKeyed BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new Generic Comm Device"); + return new GenericComm(dc); } public void SetPortConfig(string portConfig) @@ -51,6 +61,22 @@ namespace PepperDash.Essentials.Core ConfigWriter.UpdateDeviceConfig(config); } - + + public class Factory : Essentials.Core.Factory + { + #region IDeviceFactory Members + + List TypeNames = new List() { "genericComm" }; + + #endregion + + public override IKeyed BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new Generic Comm Device"); + return new GenericComm(dc); + } + } } + + } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs new file mode 100644 index 00000000..88c62f48 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class + /// + public abstract class EssentialsDevice : Device + { + protected EssentialsDevice(string key) + : base(key) + { + + } + } + + public abstract class Factory : IDeviceFactory + { + #region IDeviceFactory Members + + public List TypeNames { get; protected set; } + + public virtual void LoadTypeFactories() + { + foreach (var typeName in TypeNames) + { + DeviceFactory.AddFactoryForType(typeName, BuildDevice); + } + } + + #endregion + + public abstract IKeyed BuildDevice(DeviceConfig dc); + + protected Factory() + { + TypeNames = new List(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs index 3acfcac0..b19b40b5 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs @@ -12,7 +12,7 @@ namespace PepperDash.Essentials.Core.Devices /// /// /// - public abstract class ReconfigurableDevice : Device + public abstract class ReconfigurableDevice : EssentialsDevice { public event EventHandler ConfigChanged; diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/SourceListItem.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/SourceListItem.cs index efa2b2ad..601d75a7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/SourceListItem.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/SourceListItem.cs @@ -67,36 +67,68 @@ namespace PepperDash.Essentials.Core [JsonProperty("name")] public string Name { get; set; } + /// + /// Specifies and icon for the source list item + /// [JsonProperty("icon")] public string Icon { get; set; } + /// + /// Alternate icon + /// [JsonProperty("altIcon")] public string AltIcon { get; set; } + /// + /// Indicates if the item should be included in the source list + /// [JsonProperty("includeInSourceList")] public bool IncludeInSourceList { get; set; } + /// + /// Used to specify the order of the items in the source list when displayed + /// [JsonProperty("order")] public int Order { get; set; } + /// + /// The key of the device for volume control + /// [JsonProperty("volumeControlKey")] public string VolumeControlKey { get; set; } + /// + /// The type of source list item + /// [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public eSourceListItemType Type { get; set; } + /// + /// The list of routes to execute for this source list item + /// [JsonProperty("routeList")] public List RouteList { get; set; } + /// + /// Indicates if this source should be disabled for sharing to the far end call participants via codec content + /// [JsonProperty("disableCodecSharing")] public bool DisableCodecSharing { get; set; } + /// + /// Indicates if this source should be disabled for routing to a shared output + /// [JsonProperty("disableRoutedSharing")] public bool DisableRoutedSharing { get; set; } [JsonProperty("destinations")] public List Destinations { get; set; } + /// + /// A means to reference a source list for this source item, in the event that this source has an input that can have sources routed to it + /// + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } public SourceListItem() { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs index c07bc010..47947691 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs @@ -87,4 +87,17 @@ namespace PepperDash.Essentials.Core return null; } } + + + /// + /// Responsible for loading all of the device types + /// + public class CoreDeviceFactory + { + public CoreDeviceFactory() + { + var genComm = new GenericComm.Factory() as IDeviceFactory; + genComm.LoadTypeFactories(); + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/IDeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/IDeviceFactory.cs new file mode 100644 index 00000000..0781d647 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/IDeviceFactory.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines a class that is capable of loading device types + /// + public interface IDeviceFactory + { + /// + /// Will be called when the plugin is loaded by Essentials. Must add any new types to the DeviceFactory using DeviceFactory.AddFactoryForType() for each new type + /// + void LoadTypeFactories(); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 00edd9bd..1134f3e2 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -332,7 +332,7 @@ namespace PepperDash.Essentials.Core.Fusion FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsRoomBase).PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction("roomOff")); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction("roomOff", Room.SourceListKey)); // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); FusionRoom.ErrorMessage.InputSig.StringValue = "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; @@ -1086,7 +1086,7 @@ namespace PepperDash.Essentials.Core.Fusion SourceToFeedbackSigs.Add(pSrc, sigD.InputSig); // And respond to selection in Fusion - sigD.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction(routeKey)); + sigD.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction(routeKey, Room.SourceListKey)); } catch (Exception) { @@ -1288,7 +1288,7 @@ namespace PepperDash.Essentials.Core.Fusion // Current Source var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); - defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as IRunRouteAction).RunRouteAction("roomOff"); }); ; + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as IRunRouteAction).RunRouteAction("roomOff", Room.SourceListKey); }); ; } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs index 2d7bfc51..8ea1cf7f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs @@ -3,9 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; +using Crestron.SimplSharp.Reflection; +using PepperDash.Core; using PepperDash.Essentials.Core.Config; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Core { public static class JoinMapHelper @@ -15,7 +19,7 @@ namespace PepperDash.Essentials.Core /// /// /// - public static string GetJoinMapForDevice(string joinMapKey) + public static string GetSerializedJoinMapForDevice(string joinMapKey) { if (string.IsNullOrEmpty(joinMapKey)) return null; @@ -29,11 +33,37 @@ namespace PepperDash.Essentials.Core else return null; } + + /// + /// Attempts to find a custom join map by key and returns it deserialized if found + /// + /// + /// + public static Dictionary TryGetJoinMapAdvancedForDevice(string joinMapKey) + { + if (string.IsNullOrEmpty(joinMapKey)) + return null; + + var joinMapSerialzed = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; + + if (joinMapSerialzed != null) + { + var joinMap = JsonConvert.DeserializeObject>(joinMapSerialzed); + + if (joinMap != null) + return joinMap; + else + return null; + } + else + return null; + } } /// /// Base class for join maps /// + [Obsolete("This is being deprecated in favor of JoinMapBaseAdvanced")] public abstract class JoinMapBase { /// @@ -42,8 +72,361 @@ namespace PepperDash.Essentials.Core /// public abstract void OffsetJoinNumbers(uint joinStart); + /// + /// The collection of joins and associated metadata + /// + public Dictionary Joins = new Dictionary(); + + /// + /// Prints the join information to console + /// + public void PrintJoinMapInfo() + { + Debug.Console(0, "{0}:\n", this.GetType().Name); + + // Get the joins of each type and print them + Debug.Console(0, "Digitals:"); + var digitals = Joins.Where(j => (j.Value.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value); + PrintJoinList(GetSortedJoins(digitals)); + + Debug.Console(0, "Analogs:"); + var analogs = Joins.Where(j => (j.Value.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value); + PrintJoinList(GetSortedJoins(analogs)); + + Debug.Console(0, "Serials:"); + var serials = Joins.Where(j => (j.Value.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value); + PrintJoinList(GetSortedJoins(serials)); + + } + + /// + /// Returns a sorted list by JoinNumber + /// + /// + /// + List> GetSortedJoins(Dictionary joins) + { + var sortedJoins = joins.ToList(); + + sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber)); + + return sortedJoins; + } + + void PrintJoinList(List> joins) + { + foreach (var join in joins) + { + Debug.Console(0, + @"Join Number: {0} | Label: '{1}' | JoinSpan: '{2}' | Type: '{3}' | Capabilities: '{4}'", + join.Value.JoinNumber, + join.Value.Label, + join.Value.JoinSpan, + join.Value.JoinType.ToString(), + join.Value.JoinCapabilities.ToString()); + } + } + + /// + /// Returns the join number for the join with the specified key + /// + /// + /// + public uint GetJoinForKey(string key) + { + if (Joins.ContainsKey(key)) + return Joins[key].JoinNumber; + + else return 0; + } + + /// + /// Returns the join span for the join with the specified key + /// + /// + /// + public uint GetJoinSpanForKey(string key) + { + if (Joins.ContainsKey(key)) + return Joins[key].JoinSpan; + + else return 0; + } } + /// + /// Base class for join maps + /// + public abstract class JoinMapBaseAdvanced + { + protected uint _joinOffset; + /// + /// The collection of joins and associated metadata + /// + public Dictionary Joins = new Dictionary(); + + protected JoinMapBaseAdvanced(uint joinStart) + { + _joinOffset = joinStart - 1; + + // Add all the JoinDataComplete properties to the Joins Dictionary and pass in the offset + Joins = GetType() + .GetCType() + .GetProperties() + .Where(prop => prop.IsDefined(typeof(JoinNameAttribute), false)) + .Select(prop => (JoinDataComplete)prop.GetValue(this, null)) + .ToDictionary(join => join.GetNameAttribute(), join => + { + join.SetJoinOffset(_joinOffset); + return join; + }); + + PrintJoinMapInfo(); + } + + /// + /// Prints the join information to console + /// + public void PrintJoinMapInfo() + { + Debug.Console(0, "{0}:\n", this.GetType().Name); + + // Get the joins of each type and print them + Debug.Console(0, "Digitals:"); + var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value); + PrintJoinList(GetSortedJoins(digitals)); + + Debug.Console(0, "Analogs:"); + var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value); + PrintJoinList(GetSortedJoins(analogs)); + + Debug.Console(0, "Serials:"); + var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value); + PrintJoinList(GetSortedJoins(serials)); + + } + + /// + /// Returns a sorted list by JoinNumber + /// + /// + /// + List> GetSortedJoins(Dictionary joins) + { + var sortedJoins = joins.ToList(); + + sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber)); + + return sortedJoins; + } + + void PrintJoinList(List> joins) + { + foreach (var join in joins) + { + Debug.Console(0, + @"Join Number: {0} | JoinSpan: '{1}' | Label: '{2}' | Type: '{3}' | Capabilities: '{4}'", + join.Value.JoinNumber, + join.Value.JoinSpan, + join.Value.Metadata.Label, + join.Value.Metadata.JoinType.ToString(), + join.Value.Metadata.JoinCapabilities.ToString()); + } + } + + /// + /// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom + /// + /// + public void SetCustomJoinData(Dictionary joinData) + { + foreach (var customJoinData in joinData) + { + var join = Joins[customJoinData.Key]; + + if (join != null) + { + join.SetCustomJoinData(customJoinData.Value); + } + else + { + Debug.Console(2, "No mathcing key found in join map for: '{0}'", customJoinData.Key); + } + } + } + + ///// + ///// Returns the join number for the join with the specified key + ///// + ///// + ///// + //public uint GetJoinForKey(string key) + //{ + // return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0; + //} + + + ///// + ///// Returns the join span for the join with the specified key + ///// + ///// + ///// + //public uint GetJoinSpanForKey(string key) + //{ + // return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0; + //} + } + + /// + /// Read = Provides feedback to SIMPL + /// Write = Responds to sig values from SIMPL + /// + [Flags] + public enum eJoinCapabilities + { + None = 0, + ToSIMPL = 1, + FromSIMPL = 2, + ToFromSIMPL = ToSIMPL | FromSIMPL + } + + [Flags] + public enum eJoinType + { + None = 0, + Digital = 1, + Analog = 2, + Serial = 4, + DigitalAnalog = Digital | Analog, + DigitalSerial = Digital | Serial, + AnalogSerial = Analog | Serial, + DigitalAnalogSerial = Digital | Analog | Serial + } + + /// + /// Metadata describing the join + /// + public class JoinMetadata + { + /// + /// Join number (based on join offset value) + /// + [JsonProperty("joinNumber")] + [Obsolete] + public uint JoinNumber { get; set; } + /// + /// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range + /// + [Obsolete] + [JsonProperty("joinSpan")] + public uint JoinSpan { get; set; } + + /// + /// A label for the join to better describe it's usage + /// + [JsonProperty("label")] + public string Label { get; set; } + /// + /// Signal type(s) + /// + [JsonProperty("joinType")] + public eJoinType JoinType { get; set; } + /// + /// Indicates whether the join is read and/or write + /// + [JsonProperty("joinCapabilities")] + public eJoinCapabilities JoinCapabilities { get; set; } + /// + /// Indicates a set of valid values (particularly if this translates to an enum + /// + [JsonProperty("validValues")] + public string[] ValidValues { get; set; } + + } + + /// + /// Data describing the join. Can be + /// + public class JoinData + { + /// + /// Join number (based on join offset value) + /// + [JsonProperty("joinNumber")] + public uint JoinNumber { get; set; } + /// + /// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range + /// + [JsonProperty("joinSpan")] + public uint JoinSpan { get; set; } + } + + /// + /// A class to aggregate the JoinData and JoinMetadata for a join + /// + public class JoinDataComplete + { + private uint _joinOffset; + + private JoinData _data; + public JoinMetadata Metadata { get; set; } + + public JoinDataComplete(JoinData data, JoinMetadata metadata) + { + _data = data; + Metadata = metadata; + } + + /// + /// Sets the join offset value + /// + /// + public void SetJoinOffset(uint joinOffset) + { + _joinOffset = joinOffset; + } + + /// + /// The join number (including the offset) + /// + public uint JoinNumber + { + get { return _data.JoinNumber+ _joinOffset; } + set { _data.JoinNumber = value; } + } + + public uint JoinSpan + { + get { return _data.JoinSpan; } + } + + public void SetCustomJoinData(JoinData customJoinData) + { + _data = customJoinData; + } + + public string GetNameAttribute() + { + string name = string.Empty; + JoinNameAttribute attribute = (JoinNameAttribute)Attribute.GetCustomAttribute(typeof(JoinDataComplete), typeof(JoinNameAttribute)); + if (attribute != null) + { + name = attribute.Name; + } + return name; + } + } + + [AttributeUsage(AttributeTargets.Field)] + public class JoinNameAttribute : Attribute + { + public string Name { get; set; } + + public JoinNameAttribute(string name) + { + Name = name; + } + } } \ 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 61d1ffce..c3ea8202 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -132,11 +132,13 @@ + + @@ -156,6 +158,10 @@ + + + + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/IPluginDeviceConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/IPluginDeviceConfig.cs deleted file mode 100644 index 7ac894c6..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/IPluginDeviceConfig.cs +++ /dev/null @@ -1,11 +0,0 @@ -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; - -namespace PepperDash.Essentials.Core.Plugins -{ - public interface IPluginDeviceConfig - { - string MinimumEssentialsFrameworkVersion { get; } - IKeyed BuildDevice(DeviceConfig dc); - } -} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/IPluginDeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/IPluginDeviceFactory.cs new file mode 100644 index 00000000..ff979599 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/IPluginDeviceFactory.cs @@ -0,0 +1,19 @@ +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines a class that is capable of loading custom plugin device types + /// + public interface IPluginDeviceFactory : IDeviceFactory + { + /// + /// Required to define the minimum version for Essentials in the format xx.yy.zz + /// + string MinimumEssentialsFrameworkVersion { get; } + + } + + +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs new file mode 100644 index 00000000..3870159d --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharp.Reflection; + +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials +{ + /// + /// Deals with loading plugins at runtime + /// + public static class PluginLoader + { + /// + /// The complete list of loaded assemblies. Includes Essentials Framework assemblies and plugins + /// + public static List LoadedAssemblies { get; private set; } + + /// + /// The list of assemblies loaded from the plugins folder + /// + static List LoadedPluginFolderAssemblies; + + /// + /// The directory to look in for .cplz plugin packages + /// + static string _pluginDirectory = Global.FilePathPrefix + "plugins"; + + /// + /// The directory where plugins will be moved to and loaded from + /// + static string _loadedPluginsDirectoryPath = _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies"; + + // The temp directory where .cplz archives will be unzipped to + static string _tempDirectory = _pluginDirectory + Global.DirectorySeparator + "temp"; + + + static PluginLoader() + { + LoadedAssemblies = new List(); + LoadedPluginFolderAssemblies = new List(); + } + + /// + /// Retrieves all the loaded assemblies from the program directory + /// + public static void AddProgramAssemblies() + { + Debug.Console(2, "Getting Assemblies loaded with Essentials"); + // Get the loaded assembly filenames + var appDi = new DirectoryInfo(Global.ApplicationDirectoryPathPrefix); + var assemblyFiles = appDi.GetFiles("*.dll"); + + Debug.Console(2, "Found {0} Assemblies", assemblyFiles.Length); + + foreach (var fi in assemblyFiles) + { + string version = string.Empty; + Assembly assembly = null; + + switch (fi.Name) + { + case ("PepperDashEssentials.dll"): + { + version = Global.AssemblyVersion; + assembly = Assembly.GetExecutingAssembly(); + break; + } + case ("PepperDash_Core.dll"): + { + version = PepperDash.Core.Debug.PepperDashCoreVersion; + break; + } + } + + LoadedAssemblies.Add(new LoadedAssembly(fi.Name, version, assembly)); + } + + if (Debug.Level > 1) + { + Debug.Console(2, "Loaded Assemblies:"); + + foreach (var assembly in LoadedAssemblies) + { + Debug.Console(2, "Assembly: {0}", assembly.Name); + } + } + } + + /// + /// Loads an assembly via Reflection and adds it to the list of loaded assemblies + /// + /// + static LoadedAssembly LoadAssembly(string filePath) + { + Debug.Console(2, "Attempting to load {0}", filePath); + var assembly = Assembly.LoadFrom(filePath); + if (assembly != null) + { + var assyVersion = GetAssemblyVersion(assembly); + + var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly); + LoadedAssemblies.Add(loadedAssembly); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version); + return loadedAssembly; + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to load assembly: '{0}'", filePath); + } + + return null; + + } + + /// + /// Attempts to get the assembly informational version and if not possible gets the version + /// + /// + /// + static string GetAssemblyVersion(Assembly assembly) + { + var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); + if (ver != null && ver.Length > 0) + { + // Get the AssemblyInformationalVersion + AssemblyInformationalVersionAttribute verAttribute = ver[0] as AssemblyInformationalVersionAttribute; + return verAttribute.InformationalVersion; + } + else + { + // Get the AssemblyVersion + var version = assembly.GetName().Version; + var verStr = string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision); + return verStr; + } + } + + /// + /// Checks if the filename matches an already loaded assembly file's name + /// + /// + /// True if file already matches loaded assembly file. + public static bool CheckIfAssemblyLoaded(string name) + { + Debug.Console(2, "Checking if assembly: {0} is loaded...", name); + var loadedAssembly = LoadedAssemblies.FirstOrDefault(s => s.Name.Equals(name)); + + if (loadedAssembly != null) + { + Debug.Console(2, "Assembly already loaded."); + return true; + } + else + { + Debug.Console(2, "Assembly not loaded."); + return false; + } + } + + /// + /// Used by console command to report the currently loaded assemblies and versions + /// + /// + public static void ReportAssemblyVersions(string command) + { + Debug.Console(0, "Loaded Assemblies:"); + foreach (var assembly in LoadedAssemblies) + { + Debug.Console(0, "{0} Version: {1}", assembly.Name, assembly.Version); + } + } + + /// + /// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder + /// + static void MoveDllAssemblies() + { + Debug.Console(0, "Looking for .dll assemblies from plugins folder..."); + + var pluginDi = new DirectoryInfo(_pluginDirectory); + var pluginFiles = pluginDi.GetFiles("*.dll"); + + if (pluginFiles.Length > 0) + { + if (!Directory.Exists(_loadedPluginsDirectoryPath)) + { + Directory.CreateDirectory(_loadedPluginsDirectoryPath); + } + } + + foreach (var pluginFile in pluginFiles) + { + try + { + Debug.Console(0, "Found .dll: {0}", pluginFile.Name); + + if (!CheckIfAssemblyLoaded(pluginFile.Name)) + { + string filePath = string.Empty; + + filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + pluginFile.Name; + + // Check if there is a previous file in the loadedPlugins directory and delete + if (File.Exists(filePath)) + { + Debug.Console(0, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath); + File.Delete(filePath); + } + + // Move the file + File.Move(pluginFile.FullName, filePath); + Debug.Console(2, "Moved {0} to {1}", pluginFile.FullName, filePath); + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Skipping assembly: {0}. There is already an assembly with that name loaded.", pluginFile.FullName); + } + } + catch (Exception e) + { + Debug.Console(2, "Error with plugin file {0} . Exception: {1}", pluginFile.FullName, e); + continue; //catching any load issues and continuing. There will be exceptions loading Crestron .dlls from the cplz Probably should do something different here + } + } + + Debug.Console(0, "Done with .dll assemblies"); + } + + /// + /// Unzips each .cplz archive into the temp directory and moves any unloaded files into loadedPlugins + /// + static void UnzipAndMoveCplzArchives() + { + Debug.Console(0, "Looking for .cplz archives from plugins folder..."); + var di = new DirectoryInfo(_pluginDirectory); + var zFiles = di.GetFiles("*.cplz"); + + if (zFiles.Length > 0) + { + if (!Directory.Exists(_loadedPluginsDirectoryPath)) + { + Directory.CreateDirectory(_loadedPluginsDirectoryPath); + } + } + + foreach (var zfi in zFiles) + { + Directory.CreateDirectory(_tempDirectory); + var tempDi = new DirectoryInfo(_tempDirectory); + + Debug.Console(0, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.Name); + var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName); + Debug.Console(0, "UnZip Result: {0}", result.ToString()); + + var tempFiles = tempDi.GetFiles("*.dll"); + foreach (var tempFile in tempFiles) + { + try + { + if (!CheckIfAssemblyLoaded(tempFile.Name)) + { + string filePath = string.Empty; + + filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + tempFile.Name; + + // Check if there is a previous file in the loadedPlugins directory and delete + if (File.Exists(filePath)) + { + Debug.Console(0, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath); + File.Delete(filePath); + } + + // Move the file + File.Move(tempFile.FullName, filePath); + Debug.Console(2, "Moved {0} to {1}", tempFile.FullName, filePath); + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Skipping assembly: {0}. There is already an assembly with that name loaded.", tempFile.FullName); + } + } + catch (Exception e) + { + Debug.Console(2, "Assembly {0} is not a custom assembly. Exception: {1}", tempFile.FullName, e); + continue; //catching any load issues and continuing. There will be exceptions loading Crestron .dlls from the cplz Probably should do something different here + } + } + + // Delete the .cplz and the temp directory + Directory.Delete(_tempDirectory, true); + zfi.Delete(); + } + + Debug.Console(0, "Done with .cplz archives"); + } + + /// + /// Attempts to load the assemblies from the loadedPlugins folder + /// + static void LoadPluginAssemblies() + { + Debug.Console(0, "Loading assemblies from loadedPlugins folder..."); + var pluginDi = new DirectoryInfo(_loadedPluginsDirectoryPath); + var pluginFiles = pluginDi.GetFiles("*.dll"); + + Debug.Console(2, "Found {0} plugin assemblies to load", pluginFiles.Length); + + foreach (var pluginFile in pluginFiles) + { + var loadedAssembly = LoadAssembly(pluginFile.FullName); + + LoadedPluginFolderAssemblies.Add(loadedAssembly); + } + + Debug.Console(0, "All Plugins Loaded."); + } + + /// + /// Iterate the loaded assemblies and try to call the LoadPlugin method + /// + static void LoadCustomPluginTypes() + { + Debug.Console(0, "Loading Custom Plugin Types..."); + foreach (var loadedAssembly in LoadedPluginFolderAssemblies) + { + // iteratate this assembly's classes, looking for "LoadPlugin()" methods + try + { + var assy = loadedAssembly.Assembly; + var types = assy.GetTypes(); + foreach (var type in types) + { + try + { + var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static); + var loadPlugin = methods.FirstOrDefault(m => m.Name.Equals("LoadPlugin")); + if (loadPlugin != null) + { + Debug.Console(2, "LoadPlugin method found in {0}", type.Name); + + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); + + var minimumVersion = fields.FirstOrDefault(p => p.Name.Equals("MinimumEssentialsFrameworkVersion")); + if (minimumVersion != null) + { + Debug.Console(2, "MinimumEssentialsFrameworkVersion found"); + + var minimumVersionString = minimumVersion.GetValue(null) as string; + + if (!string.IsNullOrEmpty(minimumVersionString)) + { + var passed = Global.IsRunningMinimumVersionOrHigher(minimumVersionString); + + if (!passed) + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", minimumVersionString); + continue; + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Passed plugin passed dependency check (required version {0})", minimumVersionString); + } + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Warning, "MinimumEssentialsFrameworkVersion found but not set. Loading plugin, but your mileage may vary."); + } + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Warning, "MinimumEssentialsFrameworkVersion not found. Loading plugin, but your mileage may vary."); + } + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Adding plugin: {0}", loadedAssembly.Name); + loadPlugin.Invoke(null, null); + } + } + catch (Exception e) + { + Debug.Console(2, "Load Plugin not found. {0} is not a plugin assembly. Exception: {1}", loadedAssembly.Name, e); + continue; + } + + } + } + catch (Exception e) + { + Debug.Console(2, "Error Loading Assembly: {0} Exception: (1) ", loadedAssembly.Name, e); + continue; + } + } + // plugin dll will be loaded. Any classes in plugin should have a static constructor + // that registers that class with the Core.DeviceFactory + Debug.Console(0, "Done Loading Custom Plugin Types."); + } + + /// + /// Loads plugins + /// + public static void LoadPlugins() + { + if (Directory.Exists(_pluginDirectory)) + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Plugins directory found, checking for plugins"); + + // Deal with any .dll files + MoveDllAssemblies(); + + // Deal with any .cplz files + UnzipAndMoveCplzArchives(); + + if(Directory.Exists(_loadedPluginsDirectoryPath)) { + // Load the assemblies from the loadedPlugins folder into the AppDomain + LoadPluginAssemblies(); + + // Load the types from any custom plugin assemblies + LoadCustomPluginTypes(); + } + } + } + } + + /// + /// Represents an assembly loaded at runtime and it's associated metadata + /// + public class LoadedAssembly + { + public string Name { get; private set; } + public string Version { get; private set; } + public Assembly Assembly { get; private set; } + + public LoadedAssembly(string name, string version, Assembly assembly) + { + Name = name; + Version = version; + Assembly = assembly; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetBase.cs new file mode 100644 index 00000000..76ffbbc3 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetBase.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core.Presets +{ + public class PresetBase + { + [JsonProperty("id")] + public int ID { get; set; } + /// + /// Used to store the name of the preset + /// + [JsonProperty("description")] + public string Description { get; set; } + /// + /// Indicates if the preset is defined(stored) in the codec + /// + [JsonProperty("defined")] + public bool Defined { get; set; } + /// + /// Indicates if the preset has the capability to be defined + /// + [JsonProperty("isDefinable")] + public bool IsDefinable { get; set; } + + public PresetBase(int id, string description, bool def, bool isDef) + { + ID = id; + Description = description; + Defined = def; + IsDefinable = isDef; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs index 7781f468..bb57941e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs @@ -173,6 +173,8 @@ namespace PepperDash.Essentials.Core RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; else if (mode == eVacancyMode.InInitialVacancy) RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; + else if (mode == eVacancyMode.InShutdownWarning) + RoomVacancyShutdownTimer.SecondsToCount = 60; VacancyMode = mode; RoomVacancyShutdownTimer.Start(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs index 36f390c3..1743bdaa 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs @@ -35,9 +35,10 @@ namespace PepperDash.Essentials.Core /// public interface IRunRouteAction { - void RunRouteAction(string routeKey); + void RunRouteAction(string routeKey, string sourceListKey); + + void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); - void RunRouteAction(string routeKey, Action successCallback); } /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/IRoutingInputsExtensions.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/IRoutingInputsExtensions.cs deleted file mode 100644 index ad4a3458..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/IRoutingInputsExtensions.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - /// - /// - /// - public static class IRoutingInputsExtensions - { - /// - /// Gets any existing route for a destination, clears it, and then - /// - public static void ReleaseAndMakeRoute(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType) - { - var sw = new Stopwatch(); - sw.Start(); - - destination.ReleaseRoute(); - - if (source == null) return; - var newRoute = destination.GetRouteToSource(source, signalType); - if (newRoute == null) return; - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute); - Debug.Console(2, destination, "Executing new route"); - newRoute.ExecuteRoutes(); - sw.Stop(); - Debug.Console(2, destination, "Route took {0} ms", sw.ElapsedMilliseconds); - } - - /// - /// Will release the existing route on the destination - /// - /// - /// - public static void ReleaseRoute(this IRoutingInputs destination) - { - var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination); - if (current != null) - { - Debug.Console(2, destination, "Releasing current route: {0}", current.Source.Key); - current.ReleaseRoutes(); - } - } - - - /// - /// - /// - /// - /// - /// - /// - public static RouteDescriptor GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType) - { - var routeTable = new RouteDescriptor (source, destination, signalType); - - Debug.Console(0, destination, "Attempting to build source route from {0}***", source.Key); - if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeTable)) - routeTable = null; - - Debug.Console(0, destination, "Route{0} discovered ***", routeTable == null ? " NOT" : ""); - return routeTable; - } - - /// - /// The recursive part of this. Will stop on each device, search its inputs for the - /// desired source and if not found, invoke this function for the each input port - /// hoping to find the source. - /// - /// - /// - /// - /// - /// - /// - /// - /// true if source is hit - static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, - RoutingOutputPort onSuccessOutputPort, List alreadyCheckedDevices, - eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable) - { - cycle++; - Debug.Console(0, destination, "SelectInput-cycle {1}. Finding {2} route back to {0}", source.Key, cycle, signalType); - var destDevInputTies = TieLineCollection.Default.Where(t => - t.DestinationPort.ParentDevice == destination && (t.Type == signalType || t.Type == eRoutingSignalType.AudioVideo)); - - // find a direct tie - var directTie = destDevInputTies.FirstOrDefault( - t => !(t.SourcePort.ParentDevice is IRoutingInputsOutputs) - && t.DestinationPort.ParentDevice == destination - && t.SourcePort.ParentDevice == source); - RoutingInputPort inputPort = null; - if (directTie != null) // Found a tie directly to the source - { - Debug.Console(0, destination, "Found direct tie to {0}**", source.Key); - inputPort = directTie.DestinationPort; - } - else // no direct-connect. Walk back devices. - { - Debug.Console(0, destination, "is not directly connected to {0}. Walking down tie lines", source.Key); - - // No direct tie? Run back out on the inputs' attached devices... - // Only the ones that are routing devices - var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); - foreach (var inputTieToTry in attachedMidpoints) - { - Debug.Console(0, destination, "Trying to find route on {0}", inputTieToTry.SourcePort.ParentDevice.Key); - var upstreamDeviceOutputPort = inputTieToTry.SourcePort; - var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs; - // Check if this previous device has already been walked - if (!(alreadyCheckedDevices != null && alreadyCheckedDevices.Contains(upstreamRoutingDevice))) - { - // haven't seen this device yet. Do it. Pass the output port to the next - // level to enable switching on success - var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort, - alreadyCheckedDevices, signalType, cycle, routeTable); - if (upstreamRoutingSuccess) - { - Debug.Console(0, destination, "Upstream device route found"); - inputPort = inputTieToTry.DestinationPort; - break; // Stop looping the inputs in this cycle - } - } - } - } - - // we have a route on corresponding inputPort. *** Do the route *** - if (inputPort != null) - { - Debug.Console(0, destination, "adding route:"); - if (onSuccessOutputPort == null) - { - // it's a sink device - routeTable.Routes.Add(new RouteSwitchDescriptor(inputPort)); - } - else if (destination is IRouting) - { - routeTable.Routes.Add(new RouteSwitchDescriptor (onSuccessOutputPort, inputPort)); - } - else // device is merely IRoutingInputOutputs - Debug.Console(0, destination, " No routing. Passthrough device"); - Debug.Console(0, destination, "Exiting cycle {0}", cycle); - return true; - } - - if(alreadyCheckedDevices == null) - alreadyCheckedDevices = new List(); - alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); - - Debug.Console(0, destination, "No route found to {0}", source.Key); - return false; - } - } - - - - - - // MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE - - - /// - /// A collection of routes - typically the global DefaultCollection is used - /// - public class RouteDescriptorCollection - { - public static RouteDescriptorCollection DefaultCollection - { - get - { - if (_DefaultCollection == null) - _DefaultCollection = new RouteDescriptorCollection(); - return _DefaultCollection; - } - } - static RouteDescriptorCollection _DefaultCollection; - - List RouteDescriptors = new List(); - - public void AddRouteDescriptor(RouteDescriptor descriptor) - { - if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)) - { - Debug.Console(1, descriptor.Destination, - "Route to [{0}] already exists in global routes table", descriptor.Source.Key); - return; - } - RouteDescriptors.Add(descriptor); - } - - public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) - { - return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); - } - - /// - /// Returns the RouteDescriptor for a given destination and removes it from collection. - /// Returns null if no route with the provided destination exists. - /// - public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination) - { - var descr = GetRouteDescriptorForDestination(destination); - if (descr != null) - RouteDescriptors.Remove(descr); - return descr; - } - } - - /// - /// Represents an collection of individual route steps between Source and Destination - /// - public class RouteDescriptor - { - public IRoutingInputs Destination { get; private set; } - public IRoutingOutputs Source { get; private set; } - public eRoutingSignalType SignalType { get; private set; } - public List Routes { get; private set; } - - - public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) - { - Destination = destination; - Source = source; - SignalType = signalType; - Routes = new List(); - } - - public void ExecuteRoutes() - { - foreach (var route in Routes) - { - Debug.Console(2, route.ToString()); - if (route.SwitchingDevice is IRoutingSinkWithSwitching) - (route.SwitchingDevice as IRoutingSinkWithSwitching).ExecuteSwitch(route.InputPort.Selector); - else if (route.SwitchingDevice is IRouting) - { - (route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); - route.OutputPort.InUseTracker.AddUser(Destination, "destination"); - } - } - } - - public void ReleaseRoutes() - { - foreach (var route in Routes) - { - if (route.SwitchingDevice is IRouting) - { - // Pull the route from the port. Whatever is watching the output's in use tracker is - // responsible for responding appropriately. - route.OutputPort.InUseTracker.RemoveUser(Destination, "destination"); - } - } - } - - public override string ToString() - { - var routesText = Routes.Select(r => r.ToString()).ToArray(); - return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText)); - } - } - - /// - /// Represents an individual link for a route - /// - public class RouteSwitchDescriptor - { - public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } } - public RoutingOutputPort OutputPort { get; set; } - public RoutingInputPort InputPort { get; set; } - - public RouteSwitchDescriptor(RoutingInputPort inputPort) - { - InputPort = inputPort; - } - - public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) - { - InputPort = inputPort; - OutputPort = outputPort; - } - - public override string ToString() - { - if(OutputPort == null) // IRoutingSink - return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector); - - return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector); - } - } -} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingInterfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingInterfaces.cs deleted file mode 100644 index 352a35dc..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingInterfaces.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - //******************************************************************************************* - // Interfaces - - public interface IRoutingInputs : IKeyed - { - RoutingPortCollection InputPorts { get; } - } - - public interface IRoutingOutputs : IKeyed - { - RoutingPortCollection OutputPorts { get; } - } - - /// - /// For fixed-source endpoint devices - /// - public interface IRoutingSinkNoSwitching : IRoutingInputs - { - - } - - public interface IRoutingSinkWithSwitching : IRoutingSinkNoSwitching - { - //void ClearRoute(); - void ExecuteSwitch(object inputSelector); - } - - /// - /// For devices like RMCs, baluns, other devices with no switching. - /// - public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs - { - } - - public interface IRouting : IRoutingInputsOutputs - { - //void ClearRoute(object outputSelector); - void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType); - } - - public interface IRoutingSource : IRoutingOutputs - { - } -} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingPort.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingPort.cs deleted file mode 100644 index e2a026ab..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingPort.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Collections.Generic; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - /// - /// Base class for RoutingInput and Output ports - /// - public abstract class RoutingPort : IKeyed - { - public string Key { get; private set; } - public eRoutingSignalType Type { get; private set; } - public eRoutingPortConnectionType ConnectionType { get; private set; } - public readonly object Selector; - public bool IsInternal { get; private set; } - - public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, bool isInternal) - { - Key = key; - Type = type; - ConnectionType = connType; - Selector = selector; - IsInternal = IsInternal; - } - } - - public enum eRoutingSignalType - { - Audio, - Video, - AudioVideo - } - - public enum eRoutingPortConnectionType - { - None, BackplaneOnly, Hdmi, Rgb, Vga, LineAudio, DigitalAudio, Sdi, Composite, Component, DmCat, DmMmFiber, DmSmFiber - } - - /// - /// Basic RoutingInput with no statuses. - /// - public class RoutingInputPort : RoutingPort - { - /// - /// The IRoutingInputs object this lives on - /// - public IRoutingInputs ParentDevice { get; private set; } - - /// - /// Constructor for a basic RoutingInputPort - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingInputs object this lives on - public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingInputs parent) - : this (key, type, connType, selector, parent, false) - { - } - - /// - /// Constructor for a virtual routing input port that lives inside a device. For example - /// the ports that link a DM card to a DM matrix bus - /// - /// true for internal ports - public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingInputs parent, bool isInternal) - : base(key, type, connType, selector, isInternal) - { - if (parent == null) - throw new ArgumentNullException("parent"); - ParentDevice = parent; - } - - } - - /// - /// A RoutingInputPort for devices like DM-TX and DM input cards. - /// Will provide video statistics on connected signals - /// - public class RoutingInputPortWithVideoStatuses : RoutingInputPort - { - /// - /// Video statuses attached to this port - /// - public VideoStatusOutputs VideoStatus { get; private set; } - - /// - /// Constructor - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingInputs object this lives on - /// A VideoStatusFuncsWrapper used to assign the callback funcs that will get - /// the values for the various stats - public RoutingInputPortWithVideoStatuses(string key, - eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, - IRoutingInputs parent, VideoStatusFuncsWrapper funcs) : - base(key, type, connType, selector, parent) - { - VideoStatus = new VideoStatusOutputs(funcs); - } - } - - public class RoutingOutputPort : RoutingPort - { - /// - /// The IRoutingOutputs object this port lives on - /// - public IRoutingOutputs ParentDevice { get; private set; } - - public InUseTracking InUseTracker { get; private set; } - - - /// - /// - /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. - /// May be string, number, whatever - /// The IRoutingOutputs object this port lives on - public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingOutputs parent) - : this(key, type, connType, selector, parent, false) - { - } - - public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, - object selector, IRoutingOutputs parent, bool isInternal) - : base(key, type, connType, selector, isInternal) - { - if (parent == null) - throw new ArgumentNullException("parent"); - ParentDevice = parent; - InUseTracker = new InUseTracking(); - } - - public override string ToString() - { - return ParentDevice.Key + ":" + Key; - } - } -} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingPortCollection.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingPortCollection.cs deleted file mode 100644 index ba972ab7..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/RoutingPortCollection.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - /// - /// Basically a List , with an indexer to find ports by key name - /// - public class RoutingPortCollection : List where T: RoutingPort - { - /// - /// Case-insensitive port lookup linked to ports' keys - /// - public T this[string key] - { - get - { - return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); - } - } - } -} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/TieLine.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/TieLine.cs deleted file mode 100644 index 6a89d2de..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing-CHECK REMOVE/TieLine.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; - -using PepperDash.Core; - -namespace PepperDash.Essentials.Core -{ - public class TieLine - { - public RoutingOutputPort SourcePort { get; private set; } - public RoutingInputPort DestinationPort { get; private set; } - public int InUseCount { get { return DestinationUsingThis.Count; } } - - /// - /// Gets the type of this tie line. Will either be the type of the desination port - /// or the type of OverrideType when it is set. - /// - public eRoutingSignalType Type - { - get - { - if (OverrideType.HasValue) return OverrideType.Value; - return DestinationPort.Type; - } - } - - /// - /// Use this to override the Type property for the destination port. For example, - /// when the tie line is type AudioVideo, and the signal flow should be limited to - /// Audio-only or Video only, changing this type will alter the signal paths - /// available to the routing algorithm without affecting the actual Type - /// of the destination port. - /// - public eRoutingSignalType? OverrideType { get; set; } - - List DestinationUsingThis = new List(); - - /// - /// For tie lines that represent internal links, like from cards to the matrix in a DM. - /// This property is true if SourcePort and DestinationPort IsInternal - /// property are both true - /// - public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } } - public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } } - public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } } - public string TypeMismatchNote { get; set; } - - /// - /// - /// - /// - /// - public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort) - { - if (sourcePort == null || destinationPort == null) - throw new ArgumentNullException("source or destination port"); - SourcePort = sourcePort; - DestinationPort = destinationPort; - } - - /// - /// Creates a tie line with an overriding Type. See help for OverrideType property for info - /// - /// The signal type to limit the link to. Overrides DestinationPort.Type - public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) : - this(sourcePort, destinationPort) - { - OverrideType = overrideType; - } - - public static TieLine TieLineFromStrings(string sourceKey, string sourcePortKey, string destinationKey, string destinationPortKey) - { - var sourceDev = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs; - if (sourceDev == null) - { - Debug.Console(1, "WARNING: Cannot create tie line, routable source '{0}' not found", sourceKey); - return null; - } - var destDev = DeviceManager.GetDeviceForKey(destinationKey) as IRoutingInputs; - if (destDev == null) - { - Debug.Console(1, "WARNING: Cannot create tie line, routable destination '{0}' not found", destinationKey); - return null; - } - var sourcePort = sourceDev.OutputPorts[sourcePortKey]; - if (sourcePort == null) - { - Debug.Console(1, "WARNING: Cannot create tie line. Source '{0}' does not contain port '{1}'", sourceKey, sourcePortKey); - return null; - } - var destPort = destDev.InputPorts[destinationPortKey]; - if (destPort == null) - { - Debug.Console(1, "WARNING: Cannot create tie line. Destination '{0}' does not contain port '{1}'", destinationKey, destinationPortKey); - return null; - } - - return new TieLine(sourcePort, destPort); - } - - /// - /// Will link up video status from supporting inputs to connected outputs - /// - public void Activate() - { - // Now does nothing - } - - public void Deactivate() - { - // Now does nothing - } - - public override string ToString() - { - return string.Format("Tie line: [{0}]{1} --> [{2}]{3}", SourcePort.ParentDevice.Key, SourcePort.Key, - DestinationPort.ParentDevice.Key, DestinationPort.Key); - } - } - - - //******************************************************************************** - - public class TieLineCollection : List - { - public static TieLineCollection Default - { - get - { - if (_Default == null) - _Default = new TieLineCollection(); - return _Default; - } - } - static TieLineCollection _Default; - } -} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs index 8a7dcf03..8e2af6cb 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs @@ -2,13 +2,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Crestron.SimplSharp; -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.Codec; using System.Text.RegularExpressions; +using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Presets; +using PepperDash.Essentials.Devices.Common.Codec; + +using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Cameras { @@ -21,8 +24,16 @@ namespace PepperDash.Essentials.Devices.Common.Cameras Focus = 8 } - public abstract class CameraBase : Device + public abstract class CameraBase : Device, IRoutingOutputs { + public eCameraControlMode ControlMode { get; protected set; } + + #region IRoutingOutputs Members + + public RoutingPortCollection OutputPorts { get; protected set; } + + #endregion + public bool CanPan { get @@ -59,14 +70,37 @@ namespace PepperDash.Essentials.Devices.Common.Cameras protected eCameraCapabilities Capabilities { get; set; } public CameraBase(string key, string name) : - base(key, name) { } + base(key, name) + { + OutputPorts = new RoutingPortCollection(); + + ControlMode = eCameraControlMode.Manual; + } } + public class CameraPreset : PresetBase + { + public CameraPreset(int id, string description, bool isDefined, bool isDefinable) + : base(id, description, isDefined, isDefinable) + { + + } + } + + public class CameraPropertiesConfig { public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } public ControlPropertiesConfig Control { get; set; } + [JsonProperty("supportsAutoMode")] + public bool SupportsAutoMode { get; set; } + + [JsonProperty("supportsOffMode")] + public bool SupportsOffMode { get; set; } + + [JsonProperty("presets")] + public List Presets { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs index b17bd325..36142bdd 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraControl.cs @@ -9,9 +9,9 @@ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Cameras { public enum eCameraControlMode - { - Off = 0, - Manual, + { + Manual = 0, + Off, Auto } @@ -88,6 +88,8 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public interface IHasCameraPanControl { + // void PanLeft(bool pressRelease); + // void PanRight(bool pressRelease); void PanLeft(); void PanRight(); void PanStop(); @@ -98,6 +100,8 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public interface IHasCameraTiltControl { + // void TiltDown(bool pressRelease); + // void TildUp(bool pressRelease); void TiltDown(); void TiltUp(); void TiltStop(); @@ -108,6 +112,8 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public interface IHasCameraZoomControl { + // void ZoomIn(bool pressRelease); + // void ZoomOut(bool pressRelease); void ZoomIn(); void ZoomOut(); void ZoomStop(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs index 182b560c..3d50079b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs @@ -11,7 +11,7 @@ using Crestron.SimplSharp.Reflection; namespace PepperDash.Essentials.Devices.Common.Cameras { - public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor + public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IPower { public IBasicCommunication Communication { get; private set; } public CommunicationGather PortGather { get; private set; } @@ -25,11 +25,14 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public bool PowerIsOn { get; private set; } byte[] IncomingBuffer = new byte[] { }; - public BoolFeedback PowerIsOnFeedback { get; private set; } + public BoolFeedback PowerIsOnFeedback { get; private set; } public CameraVisca(string key, string name, IBasicCommunication comm, CameraPropertiesConfig props) : base(key, name) { + Presets = props.Presets; + + OutputPorts.Add(new RoutingOutputPort("videoOut", eRoutingSignalType.Video, eRoutingPortConnectionType.None, null, this, true)); // Default to all capabilties Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; @@ -132,6 +135,15 @@ namespace PepperDash.Essentials.Devices.Common.Cameras { SendBytes(new Byte[] {0x81, 0x01, 0x04, 0x00, 0x03, 0xFF}); } + + public void PowerToggle() + { + if (PowerIsOnFeedback.BoolValue) + PowerOff(); + else + PowerOn(); + } + public void PanLeft() { SendPanTiltCommand(new byte[] {0x01, 0x03}); @@ -206,5 +218,22 @@ namespace PepperDash.Essentials.Devices.Common.Cameras SendBytes(new byte[] { 0x81, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF }); } - } + #region IHasCameraPresets Members + + public event EventHandler PresetsListHasChanged; + + public List Presets { get; private set; } + + public void PresetSelect(int preset) + { + RecallPreset(preset); + } + + public void PresetStore(int preset, string description) + { + SavePreset(preset); + } + + #endregion + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/IHasCameraPresets.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/IHasCameraPresets.cs new file mode 100644 index 00000000..a8e8983d --- /dev/null +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/IHasCameraPresets.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Describes a camera with preset functionality + /// + public interface IHasCameraPresets + { + event EventHandler PresetsListHasChanged; + + List Presets { get; } + + void PresetSelect(int preset); + + void PresetStore(int preset, string description); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/BiampTesira/BiampTesiraForteDspLevel.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/BiampTesira/BiampTesiraForteDspLevel.cs index d0f83115..15d424a2 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/BiampTesira/BiampTesiraForteDspLevel.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/BiampTesira/BiampTesiraForteDspLevel.cs @@ -10,6 +10,19 @@ using System.Text.RegularExpressions; namespace PepperDash.Essentials.Devices.Common.DSP { + public interface IBiampTesiraDspLevelControl : IBasicVolumeWithFeedback + { + /// + /// In BiAmp: Instance Tag, QSC: Named Control, Polycom: + /// + string ControlPointTag { get; } + int Index1 { get; } + int Index2 { get; } + bool HasMute { get; } + bool HasLevel { get; } + bool AutomaticUnmuteOnVolumeUp { get; } + } + public class TesiraForteLevelControl : TesiraForteControlPoint, IBiampTesiraDspLevelControl, IKeyed { bool _IsMuted; diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/DspBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/DspBase.cs index 318268f1..0f572642 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/DspBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/DSP/DspBase.cs @@ -56,19 +56,4 @@ namespace PepperDash.Essentials.Devices.Common.DSP // ATC // Mics, unusual - public interface IBiampTesiraDspLevelControl : IBasicVolumeWithFeedback - { - /// - /// In BiAmp: Instance Tag, QSC: Named Control, Polycom: - /// - string ControlPointTag { get; } - int Index1 { get; } - int Index2 { get; } - bool HasMute { get; } - bool HasLevel { get; } - bool AutomaticUnmuteOnVolumeUp { get; } - } - - - } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index 6b57d1ca..6585b074 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -102,6 +102,7 @@ + @@ -114,6 +115,7 @@ + diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs index 48179ff1..58f97b03 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs @@ -129,22 +129,27 @@ namespace PepperDash.Essentials.Devices.Common return new Core.Devices.Laptop(key, name); } - else if (typeName == "mockvc") - { - return new VideoCodec.MockVC(dc); - } + else if (typeName == "bluejeanspc") + { + return new SoftCodec.BlueJeansPc(key, name); + } - else if (typeName == "mockac") - { - var props = JsonConvert.DeserializeObject(properties.ToString()); - return new AudioCodec.MockAC(key, name, props); - } + else if (typeName == "mockvc") + { + return new VideoCodec.MockVC(dc); + } - else if (typeName.StartsWith("ciscospark")) - { - var comm = CommFactory.CreateCommForDevice(dc); - return new VideoCodec.Cisco.CiscoSparkCodec(dc, comm); - } + else if (typeName == "mockac") + { + var props = JsonConvert.DeserializeObject(properties.ToString()); + return new AudioCodec.MockAC(key, name, props); + } + + else if (typeName.StartsWith("ciscospark")) + { + var comm = CommFactory.CreateCommForDevice(dc); + return new VideoCodec.Cisco.CiscoSparkCodec(dc, comm); + } else if (typeName == "zoomroom") { diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/SoftCodec/BlueJeansPc.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/SoftCodec/BlueJeansPc.cs new file mode 100644 index 00000000..462ae5cb --- /dev/null +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/SoftCodec/BlueJeansPc.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Core.Devices; +using PepperDash.Essentials.Core.Config; + + +namespace PepperDash.Essentials.Devices.Common.SoftCodec +{ + public class BlueJeansPc : InRoomPc, IRoutingInputs, IRunRouteAction, IRoutingSinkNoSwitching + { + + public RoutingInputPort AnyVideoIn { get; private set; } + + #region IRoutingInputs Members + + public RoutingPortCollection InputPorts { get; private set; } + + #endregion + + public BlueJeansPc(string key, string name) + : base(key, name) + { + InputPorts = new RoutingPortCollection(); + InputPorts.Add(AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)); + } + + #region IRunRouteAction Members + + public void RunRouteAction(string routeKey, string sourceListKey) + { + RunRouteAction(routeKey, sourceListKey, null); + } + + public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback) + { + CrestronInvoke.BeginInvoke(o => + { + Debug.Console(1, this, "Run route action '{0}' on SourceList: {1}", routeKey, sourceListKey); + + var dict = ConfigReader.ConfigObject.GetSourceListForKey(sourceListKey); + if (dict == null) + { + Debug.Console(1, this, "WARNING: Config source list '{0}' not found", sourceListKey); + return; + } + + // Try to get the list item by it's string key + if (!dict.ContainsKey(routeKey)) + { + Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'", + routeKey, sourceListKey); + return; + } + + var item = dict[routeKey]; + + foreach (var route in item.RouteList) + { + DoRoute(route); + } + + // store the name and UI info for routes + if (item.SourceKey == "none") + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = null; + } + else if (item.SourceKey != null) + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = item; + } + + // report back when done + if (successCallback != null) + successCallback(); + }); + } + + #endregion + + /// + /// + /// + /// + /// + bool DoRoute(SourceRouteListItem route) + { + IRoutingSinkNoSwitching dest = null; + + dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching; + + if (dest == null) + { + Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey); + return false; + } + + if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase)) + { + dest.ReleaseRoute(); + if (dest is IPower) + (dest as IPower).PowerOff(); + } + else + { + var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs; + if (source == null) + { + Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey); + return false; + } + dest.ReleaseAndMakeRoute(source, route.Type); + } + return true; + } + + + + #region IHasCurrentSourceInfoChange Members + + public string CurrentSourceInfoKey { get; set; } + + /// + /// The SourceListItem last run - containing names and icons + /// + public SourceListItem CurrentSourceInfo + { + get { return _CurrentSourceInfo; } + set + { + if (value == _CurrentSourceInfo) return; + + var handler = CurrentSourceChange; + // remove from in-use tracker, if so equipped + if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) + (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); + + _CurrentSourceInfo = value; + + // add to in-use tracking + if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) + (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); + } + } + SourceListItem _CurrentSourceInfo; + + public event SourceInfoChangeHandler CurrentSourceChange; + + #endregion + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs index 2846674a..1b456774 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/RoomPresets.cs @@ -7,6 +7,7 @@ using Crestron.SimplSharp; using Newtonsoft.Json; using PepperDash.Core; +using PepperDash.Essentials.Core.Presets; using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; namespace PepperDash.Essentials.Devices.Common.VideoCodec @@ -67,34 +68,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } /// - /// Represents a room preset on a video coded. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled. + /// Represents a room preset on a video codec. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled. /// - public class CodecRoomPreset + public class CodecRoomPreset : PresetBase { - [JsonProperty("id")] - public int ID { get; set; } - /// - /// Used to store the name of the preset - /// - [JsonProperty("description")] - public string Description { get; set; } - /// - /// Indicates if the preset is defined(stored) in the codec - /// - [JsonProperty("defined")] - public bool Defined { get; set; } - /// - /// Indicates if the preset has the capability to be defined - /// - [JsonProperty("isDefinable")] - public bool IsDefinable { get; set; } - public CodecRoomPreset(int id, string description, bool def, bool isDef) + : base(id, description, def, isDef) { - ID = id; - Description = description; - Defined = def; - IsDefinable = isDef; + } } } \ No newline at end of file