Compare commits

..

4 Commits

Author SHA1 Message Date
Nick Genovese
fdae50a972 Adds a generic queue and string/byte implementations. Also adds a class that processes string responses from a IBasicCommunication or Gather 2020-08-31 15:38:06 -04:00
Andrew Welker
6194948259 Merge pull request #391 from PepperDash/hotfix/fix-joinedsiginterlock-nullref
Hotfix/fix joinedsiginterlock nullref
2020-08-27 20:51:18 -04:00
Andrew Welker
2373d0ace7 Merge pull request #390 from PepperDash/hotfix/fix-hdcp-issues-on-specific-inputcard-types
Hotfix/fix hdcp issues on specific inputcard types
2020-08-27 19:16:21 -04:00
Andrew Welker
726f2083db Merge pull request #385 from PepperDash/release/1.6.2
Release/1.6.2
2020-08-26 18:48:39 -04:00
16 changed files with 553 additions and 689 deletions

View File

@@ -120,22 +120,14 @@ namespace PepperDash.Essentials
/// 1206
/// </summary>
public const uint VCRecentsVisible = 1206;
/// <summary>
/// 1207
/// </summary>
public const uint VCCameraVisible = 1207;
/// <summary>
/// 1208
/// </summary>
public const uint VCCameraAutoVisible = 1208;
/// <summary>
/// 1209
/// </summary>
public const uint VCCameraManualVisible = 1209;
/// <summary>
/// 1210
/// </summary>
public const uint VCCameraOffVisible = 1210;
public const uint VCSelfViewLayoutVisible = 1208;
/// <summary>
/// 1211 - 1215
/// </summary>
@@ -233,59 +225,6 @@ namespace PepperDash.Essentials
/// </summary>
public const uint VCMinMaxEnable = 1256;
/// <summary>
/// 1260
/// </summary>
public const uint VCCameraModeBarVisible = 1260;
/// <summary>
/// 1261
/// </summary>
public const uint VCCameraSelectBarWithoutModeVisible = 1261;
/// <summary>
/// 1271
/// </summary>
public const uint VCCameraZoomIn = 1271;
/// <summary>
/// 1272
/// </summary>
public const uint VCCameraZoomOut = 1272;
/// <summary>
/// 1280
/// </summary>
public const uint VCCameraPresetSavedLabelVisible = 1280;
/// <summary>
/// 1281
/// </summary>
public const uint VCCameraPreset1 = 1281;
/// <summary>
/// 1282
/// </summary>
public const uint VCCameraPreset2 = 1282;
/// <summary>
/// 1283
/// </summary>
public const uint VCCameraPreset3 = 1283;
/// <summary>
/// 1291
/// </summary>
public const uint VCCameraPreset1Visible = 1291;
/// <summary>
/// 1292
/// </summary>
public const uint VCCameraPreset2Visible = 1292;
/// <summary>
/// 1293
/// </summary>
public const uint VCCameraPreset3Visible = 1293;
// Letter joins start at 2921;
//******************************************************

View File

@@ -33,21 +33,6 @@
/// </summary>
public const uint VCLayoutsList = 1205;
/// <summary>
/// 1206 VC Camera Mode horizontal list
/// </summary>
public const uint VCCameraMode = 1206;
/// <summary>
/// 1207 VC Camera Mode Dpad
/// </summary>
public const uint VCCameraDpad = 1207;
/// <summary>
/// 1208 VC Camera Select
/// </summary>
public const uint VCCameraSelect = 1208;
//******************************************************
// General

View File

@@ -41,21 +41,6 @@ namespace PepperDash.Essentials
public const uint VCRecentListTimeTextStart = 1231;
// RANGE IN USE
public const uint VCRecentListTimeTextEnd = 1260;
/// <summary>
/// 1281
/// </summary>
public const uint VCCameraPresetLabel1 = 1281;
/// <summary>
/// 1282
/// </summary>
public const uint VCCameraPresetLabel2 = 1282;
/// <summary>
/// 1283
/// </summary>
public const uint VCCameraPresetLabel3 = 1283;
/// <summary>
/// 1291 - the current layout mode
/// </summary>

View File

@@ -1,81 +1,80 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.UI;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.SmartObjects;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase, IHasScreenSaverController
{
CTimer InactivityTimer;
/// <summary>
/// Assign the appropriate A/V driver.
/// Want to keep the AvDriver alive, because it may hold states
/// </summary>
public IAVDriver AvDriver { get; set;}
public EssentialsHeaderDriver HeaderDriver { get; set; }
public EssentialsEnvironmentDriver EnvironmentDriver { get; set; }
public PanelDriverBase CurrentChildDriver { get; private set; }
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.UI;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.SmartObjects;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase
{
CTimer InactivityTimer;
/// <summary>
/// Assign the appropriate A/V driver.
/// Want to keep the AvDriver alive, because it may hold states
/// </summary>
public IAVDriver AvDriver { get; set; }
public EssentialsHeaderDriver HeaderDriver { get; set; }
public EssentialsEnvironmentDriver EnvironmentDriver { get; set; }
public PanelDriverBase CurrentChildDriver { get; private set; }
public ScreenSaverController ScreenSaverController { get; set; }
private readonly long _timeoutMs;
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
/// The main interlock for popups
/// </summary>
//public JoinedSigInterlock PopupInterlock { get; private set; }
public EssentialsPanelMainInterfaceDriver(BasicTriListWithSmartObject trilist,
CrestronTouchpanelPropertiesConfig config)
: base(trilist)
{
Config = config;
_timeoutMs = Config.ScreenSaverTimeoutMin * 60 * 1000;
var tsx52or60 = trilist as Tswx52ButtonVoiceControl;
private readonly long _timeoutMs;
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
/// The main interlock for popups
/// </summary>
//public JoinedSigInterlock PopupInterlock { get; private set; }
public EssentialsPanelMainInterfaceDriver(BasicTriListWithSmartObject trilist,
CrestronTouchpanelPropertiesConfig config)
: base(trilist)
{
Config = config;
_timeoutMs = Config.ScreenSaverTimeoutMin * 60 * 1000;
var tsx52or60 = trilist as Tswx52ButtonVoiceControl;
if (tsx52or60 != null)
{
tsx52or60.ExtenderTouchDetectionReservedSigs.Use();
tsx52or60.ExtenderTouchDetectionReservedSigs.DeviceExtenderSigChange += ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange;
tsx52or60.ExtenderTouchDetectionReservedSigs.Time.UShortValue = 1;
ManageInactivityTimer();
}
else
{
var tswx70 = trilist as TswX70Base;
if (tswx70 != null)
}
else
{
var tswx70 = trilist as TswX70Base;
if (tswx70 != null)
{
tswx70.ExtenderTouchDetectionReservedSigs.Use();
tswx70.ExtenderTouchDetectionReservedSigs.DeviceExtenderSigChange += ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange;
tswx70.ExtenderTouchDetectionReservedSigs.Time.UShortValue = 1;
ManageInactivityTimer();
}
}
}
void ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange(Crestron.SimplSharpPro.DeviceExtender currentDeviceExtender, Crestron.SimplSharpPro.SigEventArgs args)
{
ManageInactivityTimer();
}
}
}
void ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange(Crestron.SimplSharpPro.DeviceExtender currentDeviceExtender, Crestron.SimplSharpPro.SigEventArgs args)
{
if (args.Sig.BoolValue)
{
ManageInactivityTimer();
}
}
}
private void ManageInactivityTimer()
@@ -88,52 +87,46 @@ namespace PepperDash.Essentials
{
InactivityTimer = new CTimer((o) => InactivityTimerExpired(), _timeoutMs);
}
}
void InactivityTimerExpired()
{
InactivityTimer.Stop();
InactivityTimer.Dispose();
InactivityTimer = null;
ScreenSaverController.Show();
}
public override void Show()
{
CurrentChildDriver = null;
ShowSubDriver(AvDriver as PanelDriverBase);
base.Show();
}
public override void Hide()
{
TriList.BooleanInput[AvDriver.StartPageVisibleJoin].BoolValue = false;
base.Hide();
}
void ShowSubDriver(PanelDriverBase driver)
{
CurrentChildDriver = driver;
if (driver == null)
return;
this.Hide();
driver.Show();
}
/// <summary>
///
/// </summary>
public override void BackButtonPressed()
{
if(CurrentChildDriver != null)
CurrentChildDriver.BackButtonPressed();
}
}
public interface IHasScreenSaverController
{
ScreenSaverController ScreenSaverController { get; }
}
}
void InactivityTimerExpired()
{
InactivityTimer.Stop();
InactivityTimer.Dispose();
InactivityTimer = null;
ScreenSaverController.Show();
}
public override void Show()
{
CurrentChildDriver = null;
ShowSubDriver(AvDriver as PanelDriverBase);
base.Show();
}
public override void Hide()
{
TriList.BooleanInput[AvDriver.StartPageVisibleJoin].BoolValue = false;
base.Hide();
}
void ShowSubDriver(PanelDriverBase driver)
{
CurrentChildDriver = driver;
if (driver == null)
return;
this.Hide();
driver.Show();
}
/// <summary>
///
/// </summary>
public override void BackButtonPressed()
{
if(CurrentChildDriver != null)
CurrentChildDriver.BackButtonPressed();
}
}
}

View File

@@ -114,7 +114,7 @@ namespace PepperDash.Essentials
/// <summary>
/// The parent driver for this
/// </summary>
public PanelDriverBase Parent { get; private set; }
PanelDriverBase Parent;
/// <summary>
/// All children attached to this driver. For hiding and showing as a group.

View File

@@ -72,7 +72,7 @@ namespace PepperDash.Essentials
/// <summary>
/// The parent driver for this
/// </summary>
public PanelDriverBase Parent { get; private set; }
PanelDriverBase Parent;
/// <summary>
/// All children attached to this driver. For hiding and showing as a group.
@@ -1430,7 +1430,6 @@ namespace PepperDash.Essentials
/// </summary>
public interface IAVDriver
{
PanelDriverBase Parent { get; }
JoinedSigInterlock PopupInterlock { get; }
void ShowNotificationRibbon(string message, int timeout);
void HideNotificationRibbon();

View File

@@ -21,8 +21,6 @@ namespace PepperDash.Essentials
private readonly EssentialsPanelMainInterfaceDriver _parent;
private JoinedSigInterlock PositionInterlock;
CTimer PositionTimer;
uint PositionTimeoutMs;
@@ -40,9 +38,7 @@ namespace PepperDash.Essentials
PositionJoins = new List<uint>() { UIBoolJoin.MCScreenSaverPosition1Visible, UIBoolJoin.MCScreenSaverPosition2Visible, UIBoolJoin.MCScreenSaverPosition3Visible, UIBoolJoin.MCScreenSaverPosition4Visible };
PositionInterlock = new JoinedSigInterlock(parent.TriList);
var cmdName = String.Format("shwscrsvr-{0}", parent.TriList.ID);
var cmdName = String.Format("shwscrsvr-{0}", config.IpId);
CrestronConsole.AddNewConsoleCommand((o) => Show(), cmdName, "Shows Panel Screensaver", ConsoleAccessLevelEnum.AccessOperator);
@@ -51,13 +47,10 @@ namespace PepperDash.Essentials
public override void Show()
{
if (_parent.AvDriver != null)
{
_parent.AvDriver.PopupInterlock.ShowInterlocked(UIBoolJoin.MCScreenSaverVisible);
}
_parent.AvDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.MCScreenSaverVisible);
CurrentPositionIndex = 0;
ShowCurrentPosition();
SetCurrentPosition();
StartPositionTimer();
base.Show();
@@ -65,8 +58,6 @@ namespace PepperDash.Essentials
public override void Hide()
{
Debug.Console(1, "Hiding ScreenSaverController");
if (PositionTimer != null)
{
PositionTimer.Stop();
@@ -76,10 +67,7 @@ namespace PepperDash.Essentials
ClearAllPositions();
if (_parent.AvDriver != null)
{
_parent.AvDriver.PopupInterlock.HideAndClear();
}
_parent.AvDriver.PopupInterlock.HideAndClear();
base.Hide();
}
@@ -101,7 +89,7 @@ namespace PepperDash.Essentials
{
IncrementPositionIndex();
ShowCurrentPosition();
SetCurrentPosition();
StartPositionTimer();
}
@@ -121,16 +109,20 @@ namespace PepperDash.Essentials
}
//
void ShowCurrentPosition()
void SetCurrentPosition()
{
ClearAllPositions();
// Set based on current index
PositionInterlock.ShowInterlocked(PositionJoins[CurrentPositionIndex]);
TriList.SetBool(PositionJoins[CurrentPositionIndex], true);
}
void ClearAllPositions()
{
Debug.Console(1, "Hiding all screensaver positions");
PositionInterlock.HideAndClear();
foreach (var join in PositionJoins)
{
TriList.SetBool(join, false);
}
}
}

View File

@@ -4,7 +4,6 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
@@ -14,7 +13,6 @@ using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.Touchpanels.Keyboards;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.UIDrivers.VC
{
@@ -43,11 +41,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary>
JoinedSigInterlock VCControlsInterlock;
/// <summary>
/// For the camera control mode (auto/manual/off)
/// </summary>
JoinedSigInterlock VCCameraControlModeInterlock;
/// <summary>
/// For the different staging bars: Active, inactive
/// </summary>
@@ -65,12 +58,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
SmartObjectDynamicList RecentCallsList;
SmartObjectDynamicList DirectoryList;
SmartObjectDPad CameraPtzPad;
SmartObjectDynamicList CameraModeList;
SmartObjectDynamicList CameraSelectList;
BoolFeedback DirectoryBackButtonVisibleFeedback;
@@ -89,8 +76,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
bool CodecHasFavorites;
bool ShowCameraModeControls;
CTimer BackspaceTimer;
@@ -133,9 +118,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
LocalPrivacyIsMuted = new BoolFeedback(() => false);
VCControlsInterlock = new JoinedSigInterlock(triList);
VCCameraControlModeInterlock = new JoinedSigInterlock(triList);
if (CodecHasFavorites)
VCControlsInterlock.SetButDontShow(UIBoolJoin.VCKeypadWithFavoritesVisible);
else
@@ -179,7 +161,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
SetupDirectoryList();
SearchStringBackspaceVisibleFeedback = new BoolFeedback(() => SearchStringBuilder.Length > 0);
SearchStringBackspaceVisibleFeedback.LinkInputSig(triList.BooleanInput[UIBoolJoin.VCDirectoryBackspaceVisible]);
@@ -215,8 +196,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
if(HeaderDriver.HeaderButtonsAreSetUp)
HeaderDriver.ComputeHeaderCallStatus(Codec);
SetupCameraControls();
}
void SetupAddresses()
@@ -398,8 +377,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary>
void ShowIncomingModal(CodecActiveCallItem call)
{
Debug.Console(1, "Showing Incoming Call Modal");
(Parent as IAVWithVCDriver).PrepareForCodecIncomingCall();
IncomingCallModal = new ModalDialog(TriList);
string msg;
@@ -415,19 +392,13 @@ namespace PepperDash.Essentials.UIDrivers.VC
msg = string.Format("Incoming video call from: {0}", call.Name);
}
// Hide screensaver
var screenSaverParent = Parent.Parent as IHasScreenSaverController;
if (screenSaverParent != null)
if (Parent.PopupInterlock.IsShown)
{
screenSaverParent.ScreenSaverController.Hide();
if (Parent.PopupInterlock.CurrentJoin == UIBoolJoin.MCScreenSaverVisible)
{
Parent.PopupInterlock.HideAndClear();
}
}
else
{
Debug.Console(1, "Parent.Parent is null or does not implement IHasScreenSaverController");
}
IncomingCallModal.PresentModalDialog(2, "Incoming Call", icon, msg,
"Ignore", "Accept", false, false, b =>
@@ -479,7 +450,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
TriList.SetSigFalseAction(UIBoolJoin.VCStagingDirectoryPress, ShowDirectory);
TriList.SetSigFalseAction(UIBoolJoin.VCStagingKeypadPress, ShowKeypad);
TriList.SetSigFalseAction(UIBoolJoin.VCStagingRecentsPress, ShowRecents);
TriList.SetSigFalseAction(UIBoolJoin.VCStagingCameraPress, ShowCameraControls);
TriList.SetSigFalseAction(UIBoolJoin.VCStagingConnectPress, ConnectPress);
TriList.SetSigFalseAction(UIBoolJoin.CallEndPress, () =>
{
@@ -497,393 +467,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
});
}
void SetupCameraControls()
{
CameraPtzPad = new SmartObjectDPad(TriList.SmartObjects[UISmartObjectJoin.VCCameraDpad], true);
// If the codec supports camera auto or off, we need to show the mode selector subpage
ShowCameraModeControls = Codec is IHasCameraAutoMode || Codec is IHasCameraOff;
if (ShowCameraModeControls)
{
CameraModeList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCCameraMode], true, 0);
VCControlsInterlock.StatusChanged += new EventHandler<StatusChangedEventArgs>(VCControlsInterlock_StatusChanged);
var codecOffCameras = Codec as IHasCameraOff;
var codecAutoCameras = Codec as IHasCameraAutoMode;
if (codecAutoCameras != null)
{
CameraModeList.SetItemButtonAction(1,(b) => codecAutoCameras.CameraAutoModeOn());
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 1 Visible"].BoolValue = true;
codecAutoCameras.CameraAutoModeIsOnFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 1 Selected"]);
//TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanOutput["Item 1 Pressed"].SetSigFalseAction(
//() => codecAutoCameras.CameraAutoModeOn());
codecAutoCameras.CameraAutoModeIsOnFeedback.OutputChange += (o, a) =>
{
if (a.BoolValue)
{
SetCameraManualModeButtonFeedback(false);
if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCCameraModeBarVisible)
{
VCCameraControlModeInterlock.ShowInterlocked(UIBoolJoin.VCCameraAutoVisible);
}
else
{
VCCameraControlModeInterlock.SetButDontShow(UIBoolJoin.VCCameraAutoVisible);
}
}
else
{
ShowCameraManualMode();
}
};
}
// Manual button always visible
CameraModeList.SetItemButtonAction(2, (b) => ShowCameraManualMode());
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 2 Visible"].BoolValue = true;
//TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanOutput["Item 2 Pressed"].SetSigFalseAction(
// () => ShowCameraManualMode());
if (codecOffCameras != null)
{
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 3 Visible"].BoolValue = true;
codecOffCameras.CameraIsOffFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 3 Selected"]);
CameraModeList.SetItemButtonAction(3, (b) => codecOffCameras.CameraOff());
//TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanOutput["Item 3 Pressed"].SetSigFalseAction(
// () => codecOffCameras.CameraOff());
codecOffCameras.CameraIsOffFeedback.OutputChange += (o, a) =>
{
if (a.BoolValue)
{
SetCameraManualModeButtonFeedback(false);
if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCCameraModeBarVisible)
{
VCCameraControlModeInterlock.ShowInterlocked(UIBoolJoin.VCCameraOffVisible);
}
else
{
VCCameraControlModeInterlock.SetButDontShow(UIBoolJoin.VCCameraOffVisible);
}
}
else
{
ShowCameraManualMode();
}
};
}
}
var camerasCodec = Codec as IHasCameras;
if(camerasCodec != null)
{
//CameraSelectList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect], true, 0);
var so = TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect];
so.SigChange += SmartObject_SigChange;
for (uint i = 1; i <= camerasCodec.Cameras.Count; i++)
{
var cameraKey = camerasCodec.Cameras[(int)i - 1].Key;
Debug.Console(1, "Setting up action for Camera {0} with Key: {1} for button Item {0} Pressed", i, cameraKey);
//TODO: Fix camera selection action. For some reson this action doesn't execute when the buttons are pressed
var sig = so.BooleanOutput[String.Format("Item {0} Pressed", i)];
so.BooleanOutput[string.Format("Item {0} Pressed", i)].SetSigFalseAction(
() => camerasCodec.SelectCamera(cameraKey));
}
so.UShortInput["Set Number of Items"].UShortValue = (ushort)camerasCodec.Cameras.Count;
//TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect].UShortOutput["Item Clicked"].SetUShortSigAction(
// (u) =>
// {
// var cameraKey = camerasCodec.Cameras[u - 1].Key;
// Debug.Console(1, "Selecting Camera {0} with Key: {1}", u, cameraKey);
// camerasCodec.SelectCamera(cameraKey);
// });
// Set the names for the cameras
for (int i = 1; i <= camerasCodec.Cameras.Count; i++)
{
so.StringInput[string.Format("Set Item {0} Text", i)].StringValue = camerasCodec.Cameras[i - 1].Name;
}
SetCameraSelectedFeedback();
camerasCodec.CameraSelected += camerasCodec_CameraSelected;
MapCameraActions();
}
SetupPresets();
}
void SmartObject_SigChange(GenericBase currentDevice, SmartObjectEventArgs args)
{
var uo = args.Sig.UserObject;
if (uo is Action<bool>)
(uo as Action<bool>)(args.Sig.BoolValue);
else if (uo is Action<ushort>)
(uo as Action<ushort>)(args.Sig.UShortValue);
else if (uo is Action<string>)
(uo as Action<string>)(args.Sig.StringValue);
}
void VCControlsInterlock_StatusChanged(object sender, StatusChangedEventArgs e)
{
// Need to hide the camera mode interlock if the mode bar gets hidden
if (e.PreviousJoin == UIBoolJoin.VCCameraModeBarVisible)
VCCameraControlModeInterlock.Hide();
// These deal with hiding/showing the camera select bar if no mode controls are visible (tied to manual controls being visible)
if(!ShowCameraModeControls)
{
if(e.PreviousJoin == UIBoolJoin.VCCameraManualVisible)
TriList.SetBool(UIBoolJoin.VCCameraSelectBarWithoutModeVisible, false);
if (e.NewJoin == UIBoolJoin.VCCameraManualVisible)
TriList.SetBool(UIBoolJoin.VCCameraSelectBarWithoutModeVisible, true);
}
}
/// <summary>
/// Shows the preset saved label for 2 seconds
/// </summary>
void ShowPresetStoreFeedback()
{
TriList.BooleanInput[UIBoolJoin.VCCameraPresetSavedLabelVisible].BoolValue = true;
var timer = new CTimer((o) => TriList.BooleanInput[UIBoolJoin.VCCameraPresetSavedLabelVisible].BoolValue = false, 2000);
}
void presetsCodec_CodecRoomPresetsListHasChanged(object sender, EventArgs e)
{
SetupPresets();
}
void camerasCodec_CameraSelected(object sender, CameraSelectedEventArgs e)
{
MapCameraActions();
SetCameraSelectedFeedback();
}
/// <summary>
/// Set the feedback for the button of the selected camera
/// </summary>
void SetCameraSelectedFeedback()
{
var camerasCodec = Codec as IHasCameras;
for (int i = 1; i <= camerasCodec.Cameras.Count; i++)
{
var cameraSelected = camerasCodec.SelectedCameraFeedback.StringValue;
var state = false;
if (cameraSelected == camerasCodec.Cameras[i - 1].Key)
{
state = true;
}
TriList.SmartObjects[UISmartObjectJoin.VCCameraSelect].BooleanInput[string.Format("Item {0} Selected", i)].BoolValue = state;
}
}
void SetupPresets()
{
var presetsCodec = Codec as IHasCodecRoomPresets;
if (presetsCodec != null)
{
uint holdTime = 5000;
presetsCodec.CodecRoomPresetsListHasChanged += new EventHandler<EventArgs>(presetsCodec_CodecRoomPresetsListHasChanged);
var preset = 1;
if (presetsCodec.NearEndPresets[preset - 1] != null && presetsCodec.NearEndPresets[preset - 1].Defined)
{
TriList.SetBool(UIBoolJoin.VCCameraPreset1Visible, true);
TriList.BooleanOutput[UIBoolJoin.VCCameraPreset1].SetSigHeldAction(
holdTime, ShowPresetStoreFeedback,() => presetsCodec.CodecRoomPresetStore(preset, presetsCodec.NearEndPresets[preset - 1].Description),
() => presetsCodec.CodecRoomPresetSelect(preset));
TriList.StringInput[UIStringJoin.VCCameraPresetLabel1].StringValue = presetsCodec.NearEndPresets[preset - 1].Description;
}
else
{
TriList.SetBool(UIBoolJoin.VCCameraPreset1Visible, false);
}
if (presetsCodec.NearEndPresets[1] != null && presetsCodec.NearEndPresets[1].Defined)
{
TriList.SetBool(UIBoolJoin.VCCameraPreset2Visible, true);
TriList.BooleanOutput[UIBoolJoin.VCCameraPreset2].SetSigHeldAction(
holdTime, ShowPresetStoreFeedback, () => presetsCodec.CodecRoomPresetStore(preset, presetsCodec.NearEndPresets[preset - 1].Description),
() => presetsCodec.CodecRoomPresetSelect(preset));
TriList.StringInput[UIStringJoin.VCCameraPresetLabel2].StringValue = presetsCodec.NearEndPresets[1].Description;
}
else
{
TriList.SetBool(UIBoolJoin.VCCameraPreset2Visible, false);
}
if (presetsCodec.NearEndPresets[2] != null && presetsCodec.NearEndPresets[2].Defined)
{
TriList.SetBool(UIBoolJoin.VCCameraPreset3Visible, true);
TriList.BooleanOutput[UIBoolJoin.VCCameraPreset3].SetSigHeldAction(
holdTime, ShowPresetStoreFeedback, () => presetsCodec.CodecRoomPresetStore(preset, presetsCodec.NearEndPresets[preset - 1].Description),
() => presetsCodec.CodecRoomPresetSelect(preset));
TriList.StringInput[UIStringJoin.VCCameraPresetLabel3].StringValue = presetsCodec.NearEndPresets[2].Description;
}
else
{
TriList.SetBool(UIBoolJoin.VCCameraPreset3Visible, false);
}
}
}
/// <summary>
/// Maps button actions to the selected camera
/// </summary>
void MapCameraActions()
{
// Now we setup the button actions for the manual controls
var camerasCodec = Codec as IHasCameras;
if (camerasCodec != null && camerasCodec.SelectedCamera != null)
{
var dpad = CameraPtzPad;
var camera = camerasCodec.SelectedCamera as IHasCameraPtzControl;
if (camera != null)
{
if (camerasCodec.SelectedCamera.CanTilt)
{
dpad.SigUp.SetBoolSigAction((b) =>
{
if (b)
camera.TiltUp();
else
camera.TiltStop();
});
dpad.SigDown.SetBoolSigAction((b) =>
{
if (b)
camera.TiltDown();
else
camera.TiltStop();
});
}
if (camerasCodec.SelectedCamera.CanPan)
{
dpad.SigLeft.SetBoolSigAction((b) =>
{
if (b)
camera.PanLeft();
else
camera.PanStop();
});
dpad.SigRight.SetBoolSigAction((b) =>
{
if (b)
camera.PanRight();
else
camera.PanStop();
});
}
//dpad.SigCenter.SetSigFalseAction(() => camera.PositionHome());
//var homeButton = dpad.BooleanOutput["Home"];
//if (homeButton != null)
//{
// homeButton.SetSigFalseAction(() => camera.PositionHome());
//}
if (camerasCodec.SelectedCamera.CanZoom)
{
TriList.BooleanOutput[UIBoolJoin.VCCameraZoomIn].SetBoolSigAction((b) =>
{
if (b)
camera.ZoomIn();
else
camera.ZoomStop();
});
TriList.BooleanOutput[UIBoolJoin.VCCameraZoomOut].SetBoolSigAction((b) =>
{
if (b)
camera.ZoomOut();
else
camera.ZoomStop();
});
}
}
}
}
// Determines if codec is in manual camera control mode and shows feedback
void ShowCameraManualMode()
{
var inManualMode = true;
var codecOffCameras = Codec as IHasCameraOff;
var codecAutoCameras = Codec as IHasCameraAutoMode;
if (codecOffCameras != null && codecOffCameras.CameraIsOffFeedback.BoolValue)
{
inManualMode = false;
}
// Clear auto mode
if (codecAutoCameras != null )
{
if (codecAutoCameras.CameraAutoModeIsOnFeedback.BoolValue)
{
codecAutoCameras.CameraAutoModeOff();
inManualMode = true;
}
}
if (inManualMode)
{
VCCameraControlModeInterlock.SetButDontShow(UIBoolJoin.VCCameraManualVisible);
if (VCControlsInterlock.CurrentJoin == UIBoolJoin.VCCameraModeBarVisible)
VCCameraControlModeInterlock.Show();
}
SetCameraManualModeButtonFeedback(inManualMode);
}
void SetCameraManualModeButtonFeedback(bool state)
{
// Set button feedback for manual mode
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 2 Selected"].BoolValue = state;
}
/// <summary>
///
/// </summary>
@@ -1344,32 +927,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary>
void ShowCameraControls()
{
if (ShowCameraModeControls)
{
VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraModeBarVisible);
if (VCCameraControlModeInterlock.CurrentJoin != 0)
{
VCCameraControlModeInterlock.Show();
}
else
{
var codecAutoCamera = Codec as IHasCameraAutoMode;
if (codecAutoCamera != null)
{
ShowCameraManualMode();
VCCameraControlModeInterlock.Show();
}
}
}
else
{
// Just show the manual camera control page
VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraManualVisible);
}
VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraVisible);
StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingCameraPress);
}
@@ -1402,7 +960,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// </summary>
void ShowSelfViewLayout()
{
VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCCameraAutoVisible);
VCControlsInterlock.ShowInterlocked(UIBoolJoin.VCSelfViewLayoutVisible);
StagingButtonsFeedbackInterlock.ShowInterlocked(UIBoolJoin.VCStagingSelfViewLayoutPress);
}

View File

@@ -98,12 +98,12 @@
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
@@ -113,7 +113,7 @@
</Reference>
<Reference Include="SimplSharpPro, Version=1.5.3.17, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
@@ -158,6 +158,7 @@
<Compile Include="Bridges\JoinMaps\SetTopBoxControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\StatusSignControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\SystemMonitorJoinMap.cs" />
<Compile Include="Queues\BytesQueue.cs" />
<Compile Include="Comm and IR\CecPortController.cs" />
<Compile Include="Comm and IR\CommFactory.cs" />
<Compile Include="Comm and IR\CommunicationExtras.cs" />
@@ -222,8 +223,10 @@
<Compile Include="Fusion\FusionRviDataClasses.cs" />
<Compile Include="Gateways\CenRfgwController.cs" />
<Compile Include="Gateways\EssentialsRfGatewayConfig.cs" />
<Compile Include="Queues\GenericQueue.cs" />
<Compile Include="Global\JobTimer.cs" />
<Compile Include="Global\Scheduler.cs" />
<Compile Include="Queues\IQueue.cs" />
<Compile Include="JoinMaps\JoinMapBase.cs" />
<Compile Include="Lighting\Lighting Interfaces.cs" />
<Compile Include="Lighting\LightingBase.cs" />
@@ -313,6 +316,8 @@
<Compile Include="SmartObjects\SmartObjectDPad.cs" />
<Compile Include="SmartObjects\SmartObjectHelperBase.cs" />
<Compile Include="Routing\TieLine.cs" />
<Compile Include="Queues\StringQueue.cs" />
<Compile Include="Queues\StringResponseProcessor.cs" />
<Compile Include="Timers\CountdownTimer.cs" />
<Compile Include="Touchpanels\CrestronTouchpanelPropertiesConfig.cs" />
<Compile Include="Touchpanels\Interfaces.cs" />

View File

@@ -0,0 +1,67 @@
using System;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
{
/// <summary>
/// Byte implementation of Action queue
/// </summary>
public class BytesQueue : IQueue<byte[]>
{
private readonly IQueue<byte[]> _queue;
/// <summary>
/// Constructor for BytesQueue
/// </summary>
/// <param name="key">Key</param>
/// <param name="processBytesAction">Action to process queued bytes</param>
public BytesQueue(string key, Action<byte[]> processBytesAction)
{
_queue = new GenericQueue<byte[]>(key, processBytesAction);
}
/// <summary>
/// Constructor for BytesQueue
/// </summary>
/// <param name="key">Key</param>
/// <param name="processBytesAction">Action to process queued bytes</param>
/// <param name="pacing">Delay in ms between actions being invoked</param>
public BytesQueue(string key, Action<byte[]> processBytesAction, int pacing)
{
_queue = new GenericQueue<byte[]>(key, processBytesAction, pacing);
}
/// <summary>
/// Enqueue a byte array to be processed
/// </summary>
/// <param name="item">Byte array to be processed</param>
public void Enqueue(byte[] item)
{
_queue.Enqueue(item);
}
/// <summary>
/// If the instance has been disposed
/// </summary>
public bool Disposed
{
get { return _queue.Disposed; }
}
/// <summary>
/// Key
/// </summary>
public string Key
{
get { return _queue.Key; }
}
/// <summary>
/// Disposes of resources
/// </summary>
public void Dispose()
{
_queue.Dispose();
}
}
}

View File

@@ -0,0 +1,156 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.CrestronThread;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
{
/// <summary>
/// Threadsafe processing of queued items with pacing if required
/// </summary>
/// <typeparam name="T">Type of item to be processed</typeparam>
public class GenericQueue<T> : IQueue<T> where T : class
{
private readonly string _key;
protected readonly CrestronQueue<T> _queue;
protected readonly Thread _worker;
protected readonly CEvent _waitHandle = new CEvent();
private readonly bool _delayEnabled;
private readonly int _delayTime;
/// <summary>
/// If the instance has been disposed.
/// </summary>
public bool Disposed { get; private set; }
/// <summary>
/// Constructor for generic queue with no pacing
/// </summary>
/// <param name="key">Key</param>
/// <param name="processQueueAction">Action to process items in the queue</param>
public GenericQueue(string key, Action<T> processQueueAction)
{
_key = key;
_queue = new CrestronQueue<T>();
_worker = new Thread(ProcessQueue, processQueueAction, Thread.eThreadStartOptions.Running);
CrestronEnvironment.ProgramStatusEventHandler += programEvent =>
{
if (programEvent != eProgramStatusEventType.Stopping)
return;
Dispose();
};
}
/// <summary>
/// Constructor for generic queue with no pacing
/// </summary>
/// <param name="key">Key</param>
/// <param name="processQueueAction">Action to process items in the queue</param>
/// <param name="pacing">Pacing in ms between actions</param>
public GenericQueue(string key, Action<T> processQueueAction, int pacing)
: this(key, processQueueAction)
{
_delayEnabled = pacing > 0;
_delayTime = pacing;
}
/// <summary>
/// Thread callback
/// </summary>
/// <param name="obj">The action used to process dequeued items</param>
/// <returns>Null when the thread is exited</returns>
private object ProcessQueue(object obj)
{
var action = obj as Action<T>;
if (action == null)
throw new ArgumentNullException("obj");
while (true)
{
T item = null;
if (_queue.Count > 0)
{
item = _queue.Dequeue();
if (item == null)
break;
}
if (item != null)
{
try
{
Debug.Console(2, this, "Processing queue item: '{0}'", item.ToString());
action(item);
if (_delayEnabled)
Thread.Sleep(_delayTime);
}
catch (Exception ex)
{
Debug.ConsoleWithLog(0, this, "Caught an exception in the ComsQueue {0}\r{1}\r{2}", ex.Message, ex.InnerException, ex.StackTrace);
}
}
else _waitHandle.Wait();
}
return null;
}
/// <summary>
/// Enqueues an item and processes the queue. If 'null' is enqueued the thread will close and
/// the class must be reinstantiated.
/// </summary>
/// <param name="item">Item to be processed</param>
public virtual void Enqueue(T item)
{
_queue.Enqueue(item);
_waitHandle.Set();
}
/// <summary>
/// Disposes the thread and cleans up resources. Thread cannot be restarted once
/// disposed.
/// </summary>
public void Dispose()
{
Dispose(true);
CrestronEnvironment.GC.SuppressFinalize(this);
}
/// <summary>
/// Actually does the disposing. If you override this method, be sure to either call the base implementation
/// or clean up all the resources yourself.
/// </summary>
/// <param name="disposing">set to true unless called from finalizer</param>
protected void Dispose(bool disposing)
{
if (Disposed)
return;
if (disposing)
{
Enqueue(null);
_worker.Join();
_waitHandle.Close();
}
Disposed = true;
}
~GenericQueue()
{
Dispose(false);
}
/// <summary>
/// Key
/// </summary>
public string Key
{
get { return _key; }
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
{
public interface IQueue<T> : IKeyed, IDisposable where T : class
{
void Enqueue(T item);
bool Disposed { get; }
}
}

View File

@@ -0,0 +1,66 @@
using System;
namespace PepperDash_Essentials_Core.Queues
{
/// <summary>
/// String implementation of Action Queue
/// </summary>
public class StringQueue : IQueue<string>
{
private readonly IQueue<string> _queue;
/// <summary>
/// Constructor for BytesQueue
/// </summary>
/// <param name="key">Key</param>
/// <param name="processStringAction">Action to process queued strings</param>
public StringQueue(string key, Action<string> processStringAction)
{
_queue = new GenericQueue<string>(key, processStringAction);
}
/// <summary>
/// Constructor for StringQueue
/// </summary>
/// <param name="key">Key</param>
/// <param name="processStringAction">Action to process queued strings</param>
/// <param name="pacing">Delay in ms between actions being invoked</param>
public StringQueue(string key, Action<string> processStringAction, int pacing)
{
_queue = new GenericQueue<string>(key, processStringAction, pacing);
}
/// <summary>
/// Enqueue a byte array to be processed
/// </summary>
/// <param name="item">Byte array to be processed</param>
public void Enqueue(string item)
{
_queue.Enqueue(item);
}
/// <summary>
/// Key
/// </summary>
public string Key
{
get { return _queue.Key; }
}
/// <summary>
/// Disposes of resources
/// </summary>
public void Dispose()
{
_queue.Dispose();
}
/// <summary>
/// If the instance has been disposed
/// </summary>
public bool Disposed
{
get { return _queue.Disposed; }
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash_Essentials_Core.Queues
{
public sealed class StringResponseProcessor : IKeyed, IDisposable
{
private readonly IQueue<string> _queue;
private readonly IBasicCommunication _coms;
private readonly CommunicationGather _gather;
private StringResponseProcessor(string key, Action<string> processStringAction)
{
_queue = new StringQueue(key, processStringAction);
CrestronEnvironment.ProgramStatusEventHandler += programEvent =>
{
if (programEvent != eProgramStatusEventType.Stopping)
return;
Dispose();
};
}
/// <summary>
/// Constructor that builds an instance and subscribes to coms TextReceived for processing
/// </summary>
/// <param name="coms">Com port to process strings from</param>
/// <param name="processStringAction">Action to process the incoming strings</param>
public StringResponseProcessor(IBasicCommunication coms, Action<string> processStringAction)
: this(coms.Key, processStringAction)
{
_coms = coms;
coms.TextReceived += OnResponseReceived;
}
/// <summary>
/// Constructor that builds an instance and subscribes to gather Line Received for processing
/// </summary>
/// <param name="gather">Gather to process strings from</param>
/// <param name="processStringAction">Action to process the incoming strings</param>
public StringResponseProcessor(CommunicationGather gather, Action<string> processStringAction)
: this(gather.Port.Key, processStringAction)
{
_gather = gather;
gather.LineReceived += OnResponseReceived;
}
private void OnResponseReceived(object sender, GenericCommMethodReceiveTextArgs args)
{
_queue.Enqueue(args.Text);
}
/// <summary>
/// Key
/// </summary>
public string Key
{
get { return _queue.Key; }
}
/// <summary>
/// Disposes the instance and cleans up resources.
/// </summary>
public void Dispose()
{
Dispose(true);
CrestronEnvironment.GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (Disposed)
return;
if (disposing)
{
if (_coms != null)
_coms.TextReceived -= OnResponseReceived;
if (_gather != null)
{
_gather.LineReceived -= OnResponseReceived;
_gather.Stop();
}
_queue.Dispose();
}
Disposed = true;
}
/// <summary>
/// If the instance has been disposed or not. If it has, you can not use it anymore
/// </summary>
public bool Disposed { get; private set; }
~StringResponseProcessor()
{
Dispose(false);
}
}
}

View File

@@ -68,12 +68,12 @@
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
@@ -83,7 +83,7 @@
</Reference>
<Reference Include="SimplSharpPro, Version=1.5.3.17, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">

View File

@@ -77,12 +77,12 @@
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
@@ -92,7 +92,7 @@
</Reference>
<Reference Include="SimplSharpPro, Version=1.5.3.17, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">