Removes essentials-framework as a submodule and brings the files back into the main repo

This commit is contained in:
Neil Dorin
2019-07-09 17:21:53 -06:00
parent 2cd68d40dc
commit 48c6bb78bc
362 changed files with 54624 additions and 5 deletions

View File

@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials Devices Common", "Essentials Devices Common\Essentials Devices Common.csproj", "{892B761C-E479-44CE-BD74-243E9214AF13}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,75 @@
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;
namespace PepperDash.Essentials.Devices.Common
{
/// <summary>
/// Represents and audio endpoint
/// </summary>
public class GenericAudioOut : Device, IRoutingSinkNoSwitching
{
public RoutingInputPort AnyAudioIn { get; private set; }
public GenericAudioOut(string key, string name)
: base(key, name)
{
AnyAudioIn = new RoutingInputPort(RoutingPortNames.AnyAudioIn, eRoutingSignalType.Audio,
eRoutingPortConnectionType.LineAudio, null, this);
}
#region IRoutingInputs Members
public RoutingPortCollection<RoutingInputPort> InputPorts
{
get { return new RoutingPortCollection<RoutingInputPort> { AnyAudioIn }; }
}
#endregion
}
/// <summary>
/// Allows a zone-device's audio control to be attached to the endpoint, for easy routing and
/// control switching. Will also set the zone name on attached devices, like SWAMP or other
/// hardware with names built in.
/// </summary>
public class GenericAudioOutWithVolume : GenericAudioOut, IHasVolumeDevice
{
public string VolumeDeviceKey { get; private set; }
public uint VolumeZone { get; private set; }
public IBasicVolumeControls VolumeDevice
{
get
{
var dev = DeviceManager.GetDeviceForKey(VolumeDeviceKey);
if (dev is IAudioZones)
return (dev as IAudioZones).Zone[VolumeZone];
else return dev as IBasicVolumeControls;
}
}
/// <summary>
/// Constructor - adds the name to the attached audio device, if appropriate.
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
/// <param name="audioDevice"></param>
/// <param name="zone"></param>
public GenericAudioOutWithVolume(string key, string name, string audioDevice, uint zone)
: base(key, name)
{
VolumeDeviceKey = audioDevice;
VolumeZone = zone;
}
}
}

View File

@@ -0,0 +1,104 @@
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.Devices.Common.Codec;
namespace PepperDash.Essentials.Devices.Common.AudioCodec
{
public abstract class AudioCodecBase : Device, IHasDialer, IUsageTracking, IAudioCodecInfo
{
public event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
public AudioCodecInfo CodecInfo { get; protected set; }
#region IUsageTracking Members
/// <summary>
/// This object can be added by outside users of this class to provide usage tracking
/// for various services
/// </summary>
public UsageTracking UsageTracker { get; set; }
#endregion
/// <summary>
/// Returns true when any call is not in state Unknown, Disconnecting, Disconnected
/// </summary>
public bool IsInCall
{
get
{
bool value;
if (ActiveCalls != null)
value = ActiveCalls.Any(c => c.IsActiveCall);
else
value = false;
return value;
}
}
// In most cases only a single call can be active
public List<CodecActiveCallItem> ActiveCalls { get; set; }
public AudioCodecBase(string key, string name)
: base(key, name)
{
ActiveCalls = new List<CodecActiveCallItem>();
}
/// <summary>
/// Helper method to fire CallStatusChange event with old and new status
/// </summary>
protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call)
{
call.Status = newStatus;
OnCallStatusChange(call);
}
/// <summary>
///
/// </summary>
/// <param name="previousStatus"></param>
/// <param name="newStatus"></param>
/// <param name="item"></param>
protected void OnCallStatusChange(CodecActiveCallItem item)
{
var handler = CallStatusChange;
if (handler != null)
handler(this, new CodecCallStatusItemChangeEventArgs(item));
if (UsageTracker != null)
{
if (IsInCall && !UsageTracker.UsageTrackingStarted)
UsageTracker.StartDeviceUsage();
else if (UsageTracker.UsageTrackingStarted && !IsInCall)
UsageTracker.EndDeviceUsage();
}
}
#region IHasDialer Members
public abstract void Dial(string number);
public abstract void EndCall(CodecActiveCallItem activeCall);
public abstract void EndAllCalls();
public abstract void AcceptCall(CodecActiveCallItem item);
public abstract void RejectCall(CodecActiveCallItem item);
public abstract void SendDtmf(string digit);
#endregion
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.AudioCodec
{
/// <summary>
/// Implements a common set of data about a codec
/// </summary>
public interface IAudioCodecInfo
{
AudioCodecInfo CodecInfo { get; }
}
/// <summary>
/// Stores general information about a codec
/// </summary>
public abstract class AudioCodecInfo
{
public abstract string PhoneNumber { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.AudioCodec
{
/// <summary>
/// For rooms that have audio codec
/// </summary>
public interface IHasAudioCodec
{
AudioCodecBase AudioCodec { get; }
BoolFeedback InCallFeedback { get; }
///// <summary>
///// Make this more specific
///// </summary>
//List<PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem> ActiveCalls { get; }
}
}

View File

@@ -0,0 +1,114 @@
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.Devices.Common.Codec;
namespace PepperDash.Essentials.Devices.Common.AudioCodec
{
public class MockAC : AudioCodecBase
{
public MockAC(string key, string name, MockAcPropertiesConfig props)
: base(key, name)
{
CodecInfo = new MockAudioCodecInfo();
CodecInfo.PhoneNumber = props.PhoneNumber;
}
public override void Dial(string number)
{
if (!IsInCall)
{
Debug.Console(1, this, "Dial: {0}", number);
var call = new CodecActiveCallItem()
{
Name = "Mock Outgoing Call",
Number = number,
Type = eCodecCallType.Audio,
Status = eCodecCallStatus.Connected,
Direction = eCodecCallDirection.Outgoing,
Id = "mockAudioCall-1"
};
ActiveCalls.Add(call);
OnCallStatusChange(call);
}
else
{
Debug.Console(1, this, "Already in call. Cannot dial new call.");
}
}
public override void EndCall(CodecActiveCallItem call)
{
Debug.Console(1, this, "EndCall");
ActiveCalls.Remove(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call);
}
public override void EndAllCalls()
{
Debug.Console(1, this, "EndAllCalls");
for (int i = ActiveCalls.Count - 1; i >= 0; i--)
{
var call = ActiveCalls[i];
ActiveCalls.Remove(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call);
}
}
public override void AcceptCall(CodecActiveCallItem call)
{
Debug.Console(1, this, "AcceptCall");
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call);
}
public override void RejectCall(CodecActiveCallItem call)
{
Debug.Console(1, this, "RejectCall");
ActiveCalls.Remove(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call);
}
public override void SendDtmf(string s)
{
Debug.Console(1, this, "BEEP BOOP SendDTMF: {0}", s);
}
/// <summary>
///
/// </summary>
/// <param name="url"></param>
public void TestIncomingAudioCall(string number)
{
Debug.Console(1, this, "TestIncomingAudioCall from {0}", number);
var call = new CodecActiveCallItem() { Name = number, Id = number, Number = number, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming };
ActiveCalls.Add(call);
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call);
}
}
public class MockAudioCodecInfo : AudioCodecInfo
{
string _phoneNumber;
public override string PhoneNumber
{
get
{
return _phoneNumber;
}
set
{
_phoneNumber = value;
}
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.AudioCodec
{
public class MockAcPropertiesConfig
{
[JsonProperty("phoneNumber")]
public string PhoneNumber { get; set; }
}
}

View File

@@ -0,0 +1,72 @@
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.Devices.Common.Codec;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Reflection;
namespace PepperDash.Essentials.Devices.Common.Cameras
{
public enum eCameraCapabilities
{
None = 0,
Pan = 1,
Tilt = 2,
Zoom = 4,
Focus = 8
}
public abstract class CameraBase : Device
{
public bool CanPan
{
get
{
return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan;
}
}
public bool CanTilt
{
get
{
return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt;
}
}
public bool CanZoom
{
get
{
return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom;
}
}
public bool CanFocus
{
get
{
return (Capabilities & eCameraCapabilities.Focus) == eCameraCapabilities.Focus;
}
}
// A bitmasked value to indicate the movement capabilites of this camera
protected eCameraCapabilities Capabilities { get; set; }
public CameraBase(string key, string name) :
base(key, name) { }
}
public class CameraPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
}
}

View File

@@ -0,0 +1,210 @@
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.Devices.Common.Codec;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Reflection;
namespace PepperDash.Essentials.Devices.Common.Cameras
{
public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public byte PanSpeed = 0x10;
public byte TiltSpeed = 0x10;
private bool IsMoving;
private bool IsZooming;
public bool PowerIsOn { get; private set; }
byte[] IncomingBuffer = new byte[] { };
public BoolFeedback PowerIsOnFeedback { get; private set; }
public CameraVisca(string key, string name, IBasicCommunication comm, CameraPropertiesConfig props) :
base(key, name)
{
// Default to all capabilties
Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus;
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\xFF");
Communication.BytesReceived += new EventHandler<GenericCommMethodReceiveBytesArgs>(Communication_BytesReceived);
PowerIsOnFeedback = new BoolFeedback(() => { return PowerIsOn; });
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "\x81\x09\x04\x00\xFF");
}
DeviceManager.AddDevice(CommunicationMonitor);
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
}
else
{
}
}
void SendBytes(byte[] b)
{
if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
Debug.Console(2, this, "Sending:{0}", ComTextHelper.GetEscapedText(b));
Communication.SendBytes(b);
}
void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e)
{
// This is probably not thread-safe buffering
// Append the incoming bytes with whatever is in the buffer
var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length];
IncomingBuffer.CopyTo(newBytes, 0);
e.Bytes.CopyTo(newBytes, IncomingBuffer.Length);
if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
Debug.Console(2, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes));
}
private void SendPanTiltCommand (byte[] cmd)
{
var temp = new Byte[] { 0x81, 0x01, 0x06, 0x01, PanSpeed, TiltSpeed };
int length = temp.Length + cmd.Length + 1;
byte[] sum = new byte[length];
temp.CopyTo(sum, 0);
cmd.CopyTo(sum, temp.Length);
sum[length - 1] = 0xFF;
SendBytes(sum);
}
public void PowerOn()
{
SendBytes(new Byte[] { 0x81, 0x01, 0x04, 0x00, 0x02, 0xFF });
}
public void PowerOff()
{
SendBytes(new Byte[] {0x81, 0x01, 0x04, 0x00, 0x03, 0xFF});
}
public void PanLeft()
{
SendPanTiltCommand(new byte[] {0x01, 0x03});
IsMoving = true;
}
public void PanRight()
{
SendPanTiltCommand(new byte[] { 0x02, 0x03 });
IsMoving = true;
}
public void PanStop()
{
Stop();
}
public void TiltDown()
{
SendPanTiltCommand(new byte[] { 0x03, 0x02 });
IsMoving = true;
}
public void TiltUp()
{
SendPanTiltCommand(new byte[] { 0x03, 0x01 });
IsMoving = true;
}
public void TiltStop()
{
Stop();
}
private void SendZoomCommand (byte cmd)
{
SendBytes(new byte[] {0x81, 0x01, 0x04, 0x07, cmd, 0xFF} );
}
public void ZoomIn()
{
SendZoomCommand(0x02);
IsZooming = true;
}
public void ZoomOut()
{
SendZoomCommand(0x03);
IsZooming = true;
}
public void ZoomStop()
{
Stop();
}
public void Stop()
{
if (IsZooming)
{
SendZoomCommand(0x00);
IsZooming = false;
}
else
{
SendPanTiltCommand(new byte[] {0x03, 0x03});
IsMoving = false;
}
}
public void PositionHome()
{
throw new NotImplementedException();
}
public void RecallPreset(int presetNumber)
{
SendBytes(new byte[] {0x81, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF} );
}
public void SavePreset(int presetNumber)
{
SendBytes(new byte[] { 0x81, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF });
}
}
}

View File

@@ -0,0 +1,740 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="PepperDash.Essentials.Devices.Common.GenericAudioOut" Collapsed="true">
<Position X="0.5" Y="7.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAA=</HashCode>
<FileName>Audio\GenericAudioOut.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.GenericAudioOutWithVolume" Collapsed="true">
<Position X="0.5" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAgAAAAQA=</HashCode>
<FileName>Audio\GenericAudioOut.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.CenRfgwController" Collapsed="true">
<Position X="19" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAIIAAAAAAACABAAAAAAAAAAAA=</HashCode>
<FileName>Crestron\Gateways\CenRfgwController.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.IRBlurayBase" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="17.25" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>gUyjAAoIAAAAxgYAABAAgAECABAoAEAQqcCAQHIABAI=</HashCode>
<FileName>DiscPlayer\IRDiscPlayerBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DeviceFactory" Collapsed="true">
<Position X="15.5" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAA=</HashCode>
<FileName>Factory\DeviceFactory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.GenericSource" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="12" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAgAAAAAAAACAAAAAAAAAAAAAAAgAAAAAAAAAAIAAAA=</HashCode>
<FileName>Generic\GenericSource.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.InRoomPc" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="15.5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAwAAAAAAAACAAAAAAACAAAAAQAgAAAAAAAAAAIAAAA=</HashCode>
<FileName>PC\InRoomPc.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Laptop" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="22.5" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAwAAAAAAAACAAAAAAACAAAAAQAgAAAAAAAAAAIAAAA=</HashCode>
<FileName>PC\Laptop.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.IRSetTopBoxBase" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="19" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AUgjCAqAEAASwgYAACAAoAECABAoAEAwrcCAQHKABAI=</HashCode>
<FileName>SetTopBox\IRSetTopBoxBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.SetTopBoxPropertiesConfig" Collapsed="true">
<Position X="13.75" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAEEAAQAAAAAAAAIAAAAAAAAAAAAAAAAACAAAA=</HashCode>
<FileName>SetTopBox\SetTopBoxPropertiesConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.AppleTV" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="10.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAggAAIAAAAARAAAAAAAgAACABAoAEAQqACAQAAABAI=</HashCode>
<FileName>Streaming\AppleTV.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Roku2" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="10.25" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAggAAIAAAAABAAAAAAAgAACABAoAEAQqACAQAAABAI=</HashCode>
<FileName>Streaming\Roku.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem" Collapsed="true">
<Position X="19" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAACAAAEAAAAAAAAAOAAAAQAAAAAAAAAAQAAAAAAAAA=</HashCode>
<FileName>Codec\CodecActiveCallItem.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs" Collapsed="true">
<Position X="15.5" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\CodecActiveCallItem.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallDirection" Collapsed="true">
<Position X="20.75" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAA=</HashCode>
<FileName>Codec\eCodecCallDirection.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallStatus" Collapsed="true">
<Position X="13.75" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAA=</HashCode>
<FileName>Codec\eCodecCallStatus.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallType" Collapsed="true">
<Position X="17.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAA=</HashCode>
<FileName>Codec\eCodecCallType.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallPrivacy" Collapsed="true">
<Position X="12" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAA=</HashCode>
<FileName>Codec\eMeetingPrivacy.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.VideoCodecInfo" Collapsed="true">
<Position X="5.5" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>gIAAAAAAAAAAAACCAACAAAAAAAAAAAACAAAAAABAAAA=</HashCode>
<FileName>Codec\iCodecInfo.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallFavorites" Collapsed="true">
<Position X="22.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAA=</HashCode>
<FileName>Codec\iHasCallFavorites.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecCallHistory" Collapsed="true">
<Position X="10.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAQAAAAAgAAAAAAAAAAAAAAGAAAABAAAAAAACQ=</HashCode>
<FileName>Codec\iHasCallHistory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.DirectoryEventArgs" Collapsed="true">
<Position X="17.25" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecDirectory" Collapsed="true">
<Position X="20.75" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAIAAAAAAAAAAAABAAAAAIAAIAAQAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.DirectoryItem" Collapsed="true">
<Position X="6.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.DirectoryFolder" Collapsed="true">
<Position X="5.5" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAIAAAAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.DirectoryContact" Collapsed="true">
<Position X="7.75" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAgAAAAAAAEAAAAAAAAAAAAAAAAEIAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.ContactMethod" Collapsed="true">
<Position X="13.75" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAIAAAAAAAgAAAEAAAAAAAAAIAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.DirectorySearchResultEventArgs" Collapsed="true">
<Position X="19" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CodecScheduleAwareness" Collapsed="true">
<Position X="10.25" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAABAAAAAEAAAAAAAgAAEAAAABAAAAAAAIQAAAAA=</HashCode>
<FileName>Codec\iHasScheduleAwareness.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.Meeting" Collapsed="true">
<Position X="13.75" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAACAAAAAAACEEgAAAAAAAgQIAAoAQABAAQAAEgAAAA=</HashCode>
<FileName>Codec\iHasScheduleAwareness.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.Call" Collapsed="true">
<Position X="17.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAEAAAABAAAAIAAAAAAAAAAgAAAA=</HashCode>
<FileName>Codec\iHasScheduleAwareness.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.MeetingEventArgs" Collapsed="true">
<Position X="15.5" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAQAAAAA=</HashCode>
<FileName>Codec\iHasScheduleAwareness.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.CiscoSparkCodecPropertiesConfig" Collapsed="true">
<Position X="17.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAQAAAAAAAAAAAAAAAAAIQAAACAABAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\CiscoSparkCodecPropertiesConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Codec.SharingProperties" Collapsed="true">
<Position X="15.5" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\CiscoSparkCodecPropertiesConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Displays.AvocorDisplay" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="12" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>hC4gIEAIUAABoQAEgBACAAAdBC1gmsGRICKGdQNBACw=</HashCode>
<FileName>Display\AvocorVTFDisplay.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Displays.ComTcpDisplayBase" Collapsed="true">
<Position X="6.5" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAEQAAAAA=</HashCode>
<FileName>Display\ComTcpDisplayBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Displays.DisplayDeviceFactory" Collapsed="true">
<Position X="20.75" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAA=</HashCode>
<FileName>Display\DeviceFactory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Displays.NecPaSeriesProjector" Collapsed="true">
<Position X="6.5" Y="8" Width="1.5" />
<TypeIdentifier>
<HashCode>ogSIAAKIAAALCAAEABAQEAgABAAAAMIAAAAAEABAACA=</HashCode>
<FileName>Display\NecPaSeriesProjector.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Displays.NecPSXMDisplay" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="22.5" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>hLQgIShIAABFQQRUAvICDRMQESwSEQKRKACCZQNAESY=</HashCode>
<FileName>Display\NECPSXMDisplay.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Displays.SamsungMDC" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="12" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>hKwwIEAIQAABoUAGgBACAAAEBGxAmYORKCCGZQJAACw=</HashCode>
<FileName>Display\SamsungMDCDisplay.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.BiampTesiraForteDsp" Collapsed="true">
<Position X="3.5" Y="8" Width="1.5" />
<TypeIdentifier>
<HashCode>gACAAIAAAAEAQYCigAAAAAAQAACgCAAAAAAAAAMAAAI=</HashCode>
<FileName>DSP\BiampTesira\BiampTesiraForteDsp.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.TesiraForteLevelControl" Collapsed="true">
<Position X="0.5" Y="6.25" Width="1.5" />
<TypeIdentifier>
<HashCode>RAAgJACAAAAAAYAAAkIAAAAAIAQCEACJABACRAAAAUQ=</HashCode>
<FileName>DSP\BiampTesira\BiampTesiraForteDspLevel.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.BiampTesiraFortePropertiesConfig" Collapsed="true">
<Position X="15.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>BAAAAAAEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAA=</HashCode>
<FileName>DSP\BiampTesira\BiampTesiraFortePropertiesConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.BiampTesiraForteLevelControlBlockConfig" Collapsed="true">
<Position X="13.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAEAAAAIAAAAAAAAAAAAAAAAAIAAEAAAAAAEQ=</HashCode>
<FileName>DSP\BiampTesira\BiampTesiraFortePropertiesConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.TesiraForteControlPoint" Collapsed="true">
<Position X="0.5" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAIAAAAACAAQQAAAAAQAAAAAAAIAAAABEAAAAAAEA=</HashCode>
<FileName>DSP\BiampTesira\TesiraForteControlPoint.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.DspBase" Collapsed="true">
<Position X="3.5" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAEAIAgAAAAAAIAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DSP\DspBase.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.DspControlPoint" Collapsed="true">
<Position X="1.75" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DSP\DspBase.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.DspMuteControl" Collapsed="true">
<Position X="2.75" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>BAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAQAAAAAQ=</HashCode>
<FileName>DSP\DspBase.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.DSP.SoundStructureBasics" Collapsed="true">
<Position X="17.25" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAA=</HashCode>
<FileName>DSP\PolycomSoundStructure\SoundStructureBasics.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Environment.Lutron.LutronQuantumArea" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="10.25" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>gACAEBAAAoAABQBAASAAAAAAAAEgAAACAAACAAMAQAI=</HashCode>
<FileName>Environment\Lutron\LutronQuantum.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Environment.Lutron.LutronQuantumPropertiesConfig" Collapsed="true">
<Position X="12" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAEAAAAAAAAgQAAAAAAAAAAAAQCAAACAAAAAAA=</HashCode>
<FileName>Environment\Lutron\LutronQuantum.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController" Collapsed="true">
<Position X="17.25" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>gQAABAAAAxAAIACAgAgAgCBAUQAAQAgCIAEQAACBAAA=</HashCode>
<FileName>Microphone\MicrophonePrivacyController.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyControllerConfig" Collapsed="true">
<Position X="19" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAEAAAAAgAIAAAAAAAAAA=</HashCode>
<FileName>Microphone\MicrophonePrivacyControllerConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Microphones.KeyedDevice" Collapsed="true">
<Position X="20.75" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Microphone\MicrophonePrivacyControllerConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Occupancy.EssentialsGlsOccupancySensorBaseController" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="22.5" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIAAAAAAAABAABgAAAAAASEABAAAAAAAAA=</HashCode>
<FileName>Occupancy\EssentialsGlsOccupancySensorBaseController.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.Occupancy.EssentialsOccupancyAggregator" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="10.25" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAACBAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Occupancy\EssentialsOccupancyAggregator.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodecBookings" Collapsed="true">
<Position X="22.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg=</HashCode>
<FileName>VideoCodec\CiscoCodec\BookingsDataClasses.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCallHistory" Collapsed="true">
<Position X="20.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\CallHistoryDataClasses.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodecPhonebook" Collapsed="true">
<Position X="13.75" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>EAAAABAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\PhonebookDataClasses.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.MockVC" Collapsed="true">
<Position X="0.5" Y="2" Width="1.5" />
<TypeIdentifier>
<HashCode>BgYAIAACAQaKBACAAwAAUSQAAWYCEACDAAiAQBBCgQU=</HashCode>
<FileName>VideoCodec\MockVC\MockVC.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.MockCodecInfo" Collapsed="true">
<Position X="5.5" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>gKAAAAAAAAAAAACCAACAAAAAAAAAAAACAAAAAABBAAA=</HashCode>
<FileName>VideoCodec\MockVC\MockVC.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.MockVcPropertiesConfig" Collapsed="true">
<Position X="20.75" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAA=</HashCode>
<FileName>VideoCodec\MockVC\MockVcPropertiesConfig.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase" Collapsed="true">
<Position X="1.75" Y="2" Width="1.5" />
<TypeIdentifier>
<HashCode>BiwgAAECAASAAECAgQEDIABAAAYiEBCpCEigQBZCAQU=</HashCode>
<FileName>VideoCodec\VideoCodecBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.CodecPhonebookSyncState" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="22.5" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>EAiCAAQAAgEAAQQAEAAAAAAAAAEAAAAAAACAAAAAAAM=</HashCode>
<FileName>VideoCodec\VideoCodecBase.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoSparkCodec" Collapsed="true">
<Position X="2.75" Y="2" Width="1.5" />
<TypeIdentifier>
<HashCode>jhQEtAJaASb7kSCwAwtxECSABsf2n1GBJEmAVJFKWTc=</HashCode>
<FileName>VideoCodec\CiscoCodec\CiscoSparkCodec.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CodecCommandWithLabel" Collapsed="true">
<Position X="19" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAEAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\CiscoSparkCodec.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CodecSyncState" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="12" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AIAAAAQACAEAAAQAEAAAAAAAAAAgAAAAAAAACAACACE=</HashCode>
<FileName>VideoCodec\CiscoCodec\CiscoSparkCodec.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" Collapsed="true" />
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.HttpApiServer" Collapsed="true">
<Position X="13.75" Y="4.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAQAAAACAAAAABAAAAAAAIAIAAAAAAAQAAgAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\HttpApiServer.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoCodecConfiguration" Collapsed="true">
<Position X="10.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\xConfiguration.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoCodecEvents" Collapsed="true">
<Position X="12" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\xEvent.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoCodecStatus" Collapsed="true">
<Position X="15.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\xStatus.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodec.xStatusSparkPlus" Collapsed="true">
<Position X="19" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\xStatusSparkPlus.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.ICodecAudio" Collapsed="true">
<Position X="10.25" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iCodecAudio.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.iCodecInfo" Collapsed="true">
<Position X="12" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iCodecInfo.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.IHasCallFavorites" Collapsed="true">
<Position X="15.5" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasCallFavorites.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.IHasCallHistory" Collapsed="true">
<Position X="17.25" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAQAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasCallHistory.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.IHasContentSharing" Collapsed="true">
<Position X="22.5" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAACAAAAAAAAAAAAAAAAAAAAAAAIAEAgABAAAAA=</HashCode>
<FileName>Codec\iHasContentSharing.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.IHasDialer" Collapsed="true">
<Position X="10.25" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAgAAAACAAAAAACAAAAAAAAAAAICAAAAAAAAAAQCAAA=</HashCode>
<FileName>Codec\iHasDialer.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.IHasDirectory" Collapsed="true">
<Position X="12" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAgAAAAAAAAAAAAgCAAAAABAAAEAAAAAA=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Codec.IHasScheduleAwareness" Collapsed="true">
<Position X="13.75" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Codec\iHasScheduleAwareness.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputHdmi1" Collapsed="true">
<Position X="19" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputHdmi2" Collapsed="true">
<Position X="20.75" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputHdmi3" Collapsed="true">
<Position X="22.5" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputHdmi4" Collapsed="true">
<Position X="10.25" Y="9.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputDisplayPort1" Collapsed="true">
<Position X="15.5" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputDisplayPort2" Collapsed="true">
<Position X="17.25" Y="8.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Displays.IInputVga1" Collapsed="true">
<Position X="12" Y="9.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Display\InputInterfaces.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.DSP.IDspLevelControl" Collapsed="true">
<Position X="13.75" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>QAAAAACAAAAAAAAAAAAAAAAAAAAAAAAIAAEAAAAAAAQ=</HashCode>
<FileName>DSP\DspBase.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider" Collapsed="true">
<Position X="13.75" Y="9.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Occupancy\iOccupancyStatusProvider.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.VideoCodec.IHasCodecLayouts" Collapsed="true">
<Position X="19" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAgAAAAAAAAAAAAAAAEEgAAAAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\Interfaces\IHasCodecLayouts.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="PepperDash.Essentials.Devices.Common.VideoCodec.IHasCodecSelfview" Collapsed="true">
<Position X="20.75" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>ABAAEAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAABAAAAI=</HashCode>
<FileName>VideoCodec\Interfaces\IHasCodecSelfview.cs</FileName>
</TypeIdentifier>
</Interface>
<Enum Name="PepperDash.Essentials.Devices.Common.eExGatewayType" Collapsed="true">
<Position X="10.25" Y="11" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAgAAAAAAAAAAAAAIAAAEAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Crestron\Gateways\CenRfgwController.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eCodecCallDirection" Collapsed="true">
<Position X="12" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAABA=</HashCode>
<FileName>Codec\eCodecCallDirection.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eCodecCallStatus" Collapsed="true">
<Position X="13.75" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>CAgAAABAAAAAQAACAAABAAAAAAAAAAABCAAAAiAAQBA=</HashCode>
<FileName>Codec\eCodecCallStatus.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eCodecCallType" Collapsed="true">
<Position X="15.5" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAoBg=</HashCode>
<FileName>Codec\eCodecCallType.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eMeetingPrivacy" Collapsed="true">
<Position X="13.75" Y="11" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAQBA=</HashCode>
<FileName>Codec\eMeetingPrivacy.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eCodecOccurrenceType" Collapsed="true">
<Position X="17.25" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAABAAAAAIAAAAAAAAAAAAAAAAAAAEAAAAAAABA=</HashCode>
<FileName>Codec\iHasCallHistory.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eContactMethodDevice" Collapsed="true">
<Position X="22.5" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>BAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAAAAAABg=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eContactMethodCallType" Collapsed="true">
<Position X="20.75" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAABg=</HashCode>
<FileName>Codec\iHasDirectory.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Codec.eMeetingEventChangeType" Collapsed="true">
<Position X="12" Y="11" Width="1.5" />
<TypeIdentifier>
<HashCode>BAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAIACg=</HashCode>
<FileName>Codec\iHasScheduleAwareness.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.Environment.Lutron.eAction" Collapsed="true">
<Position X="10.25" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AACAACAAABAAgIAAgAAQAAAAAAAAIAAAIAAAACAEAAg=</HashCode>
<FileName>Environment\Lutron\LutronQuantum.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eCommandType" Collapsed="true">
<Position X="19" Y="10.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAACAQAAAAABAAEAAAAAAAAgAAAAAAAAAA=</HashCode>
<FileName>VideoCodec\CiscoCodec\CiscoSparkCodec.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public class CodecActiveCallItem
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
[JsonProperty("type")]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallType Type { get; set; }
[JsonProperty("status")]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallStatus Status { get; set; }
[JsonProperty("direction")]
[JsonConverter(typeof(StringEnumConverter))]
public eCodecCallDirection Direction { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
//public object CallMetaData { get; set; }
/// <summary>
/// Returns true when this call is any status other than
/// Unknown, Disconnected, Disconnecting
/// </summary>
[JsonProperty("isActiveCall")]
public bool IsActiveCall
{
get
{
return !(Status == eCodecCallStatus.Disconnected
|| Status == eCodecCallStatus.Disconnecting
|| Status == eCodecCallStatus.Idle
|| Status == eCodecCallStatus.Unknown);
}
}
}
/// <summary>
///
/// </summary>
public class CodecCallStatusItemChangeEventArgs : EventArgs
{
public CodecActiveCallItem CallItem { get; private set; }
public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item)
{
CallItem = item;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public class CodecActiveCallItem
{
public string Name { get; set; }
public string Number { get; set; }
<<<<<<< HEAD:Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs
public eCodecCallType Type { get; set; }
public eCodecCallStatus Status { get; set; }
public string Id { get; set; }
=======
public eCodecCallType Type { get; set; }
public eCodecCallStatus Status { get; set; }
public string Id { get; set; }
public object CallMetaData { get; set; }
>>>>>>> origin/feature/cisco-spark-2:Essentials Devices Common/Essentials Devices Common/VideoCodec/CodecActiveCallItem.cs
}
public enum eCodecCallType
{
Unknown = 0, Audio, Video
<<<<<<< HEAD:Essentials Devices Common/Essentials Devices Common/Codec/CodecActiveCallItem.cs
}
public enum eCodecCallStatus
{
Unknown = 0, Dialing, Connected, Incoming, OnHold, Disconnected
=======
}
public enum eCodecCallStatus
{
Unknown = 0, Dialing, Connected, Incoming, OnHold, Disconnected
>>>>>>> origin/feature/cisco-spark-2:Essentials Devices Common/Essentials Devices Common/VideoCodec/CodecActiveCallItem.cs
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eCodecCallDirection
{
Unknown = 0, Incoming, Outgoing
}
public class CodecCallDirection
{
/// <summary>
/// Takes the Cisco call type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eCodecCallDirection ConvertToDirectionEnum(string s)
{
switch (s.ToLower())
{
case "incoming":
{
return eCodecCallDirection.Incoming;
}
case "outgoing":
{
return eCodecCallDirection.Outgoing;
}
default:
return eCodecCallDirection.Unknown;
}
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eCodecCallStatus
{
Unknown = 0,
Connected,
Connecting,
Dialing,
Disconnected,
Disconnecting,
EarlyMedia,
Idle,
OnHold,
Ringing,
Preserved,
RemotePreserved,
}
public class CodecCallStatus
{
/// <summary>
/// Takes the Cisco call type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eCodecCallStatus ConvertToStatusEnum(string s)
{
switch (s)
{
case "Connected":
{
return eCodecCallStatus.Connected;
}
case "Connecting":
{
return eCodecCallStatus.Connecting;
}
case "Dialling":
{
return eCodecCallStatus.Dialing;
}
case "Disconnected":
{
return eCodecCallStatus.Disconnected;
}
case "Disconnecting":
{
return eCodecCallStatus.Disconnecting;
}
case "EarlyMedia":
{
return eCodecCallStatus.EarlyMedia;
}
case "Idle":
{
return eCodecCallStatus.Idle;
}
case "OnHold":
{
return eCodecCallStatus.OnHold;
}
case "Ringing":
{
return eCodecCallStatus.Ringing;
}
case "Preserved":
{
return eCodecCallStatus.Preserved;
}
case "RemotePreserved":
{
return eCodecCallStatus.RemotePreserved;
}
default:
return eCodecCallStatus.Unknown;
}
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eCodecCallType
{
Unknown = 0,
Audio,
Video,
AudioCanEscalate,
ForwardAllCall
}
public class CodecCallType
{
/// <summary>
/// Takes the Cisco call type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eCodecCallType ConvertToTypeEnum(string s)
{
switch (s)
{
case "Audio":
{
return eCodecCallType.Audio;
}
case "Video":
{
return eCodecCallType.Video;
}
case "AudioCanEscalate":
{
return eCodecCallType.AudioCanEscalate;
}
case "ForwardAllCall":
{
return eCodecCallType.ForwardAllCall;
}
default:
return eCodecCallType.Unknown;
}
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eMeetingPrivacy
{
Unknown = 0,
Public,
Private
}
public class CodecCallPrivacy
{
/// <summary>
/// Takes the Cisco privacy type and converts to the matching enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static eMeetingPrivacy ConvertToDirectionEnum(string s)
{
switch (s.ToLower())
{
case "public":
{
return eMeetingPrivacy.Public;
}
case "private":
{
return eMeetingPrivacy.Private;
}
default:
return eMeetingPrivacy.Unknown;
}
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Defines minimum volume controls for a codec device with dialing capabilities
/// </summary>
public interface ICodecAudio : IBasicVolumeWithFeedback, IPrivacy
{
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public interface IHasCallFavorites
{
CodecCallFavorites CallFavorites { get; }
}
/// <summary>
/// Represents favorites entries for a codec device
/// </summary>
public class CodecCallFavorites
{
public List<CodecActiveCallItem> Favorites { get; set; }
public CodecCallFavorites()
{
Favorites = new List<CodecActiveCallItem>();
}
}
}

View File

@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public interface IHasCallHistory
{
CodecCallHistory CallHistory { get; }
void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry);
}
public enum eCodecOccurrenceType
{
Unknown = 0,
Placed,
Received,
NoAnswer
}
/// <summary>
/// Represents the recent call history for a codec device
/// </summary>
public class CodecCallHistory
{
public event EventHandler<EventArgs> RecentCallsListHasChanged;
public List<CallHistoryEntry> RecentCalls { get; private set; }
/// <summary>
/// Item that gets added to the list when there are no recent calls in history
/// </summary>
CallHistoryEntry ListEmptyEntry;
public CodecCallHistory()
{
ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" };
RecentCalls = new List<CallHistoryEntry>();
RecentCalls.Add(ListEmptyEntry);
}
void OnRecentCallsListChange()
{
var handler = RecentCallsListHasChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
public void RemoveEntry(CallHistoryEntry entry)
{
RecentCalls.Remove(entry);
OnRecentCallsListChange();
}
/// <summary>
/// Generic call history entry, not device specific
/// </summary>
public class CallHistoryEntry : CodecActiveCallItem
{
[JsonConverter(typeof(IsoDateTimeConverter))]
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty("occurrenceType")]
public eCodecOccurrenceType OccurrenceType { get; set; }
[JsonProperty("occurrenceHistoryId")]
public string OccurrenceHistoryId { get; set; }
}
/// <summary>
/// Converts a list of call history entries returned by a Cisco codec to the generic list type
/// </summary>
/// <param name="entries"></param>
/// <returns></returns>
public void ConvertCiscoCallHistoryToGeneric(List<CiscoCallHistory.Entry> entries)
{
var genericEntries = new List<CallHistoryEntry>();
foreach (CiscoCallHistory.Entry entry in entries)
{
genericEntries.Add(new CallHistoryEntry()
{
Name = entry.DisplayName.Value,
Number = entry.CallbackNumber.Value,
StartTime = entry.LastOccurrenceStartTime.Value,
OccurrenceHistoryId = entry.LastOccurrenceHistoryId.Value,
OccurrenceType = ConvertToOccurenceTypeEnum(entry.OccurrenceType.Value)
});
}
// Check if list is empty and if so, add an item to display No Recent Calls
if(genericEntries.Count == 0)
genericEntries.Add(ListEmptyEntry);
RecentCalls = genericEntries;
OnRecentCallsListChange();
}
/// <summary>
/// Takes the Cisco occurence type and converts it to the matching enum
/// </summary>
/// <param name="s"></para
public eCodecOccurrenceType ConvertToOccurenceTypeEnum(string s)
{
switch (s)
{
case "Placed":
{
return eCodecOccurrenceType.Placed;
}
case "Received":
{
return eCodecOccurrenceType.Received;
}
case "NoAnswer":
{
return eCodecOccurrenceType.NoAnswer;
}
default:
return eCodecOccurrenceType.Unknown;
}
}
}
}

View File

@@ -0,0 +1,24 @@
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.Devices.Common.Codec
{
public interface IHasContentSharing
{
BoolFeedback SharingContentIsOnFeedback { get; }
StringFeedback SharingSourceFeedback { get; }
bool AutoShareContentWhileInCall { get; }
void StartSharing();
void StopSharing();
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Requirements for a device that has dialing capabilities
/// </summary>
public interface IHasDialer
{
// Add requirements for Dialer functionality
event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
void Dial(string number);
void EndCall(CodecActiveCallItem activeCall);
void EndAllCalls();
void AcceptCall(CodecActiveCallItem item);
void RejectCall(CodecActiveCallItem item);
void SendDtmf(string digit);
bool IsInCall { get; }
}
}

View File

@@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Devices.Common.Codec
{
/// <summary>
/// Defines the API for codecs with a directory
/// </summary>
public interface IHasDirectory
{
event EventHandler<DirectoryEventArgs> DirectoryResultReturned;
CodecDirectory DirectoryRoot { get; }
CodecDirectory CurrentDirectoryResult { get; }
CodecPhonebookSyncState PhonebookSyncState { get; }
void SearchDirectory(string searchString);
void GetDirectoryFolderContents(string folderId);
void SetCurrentDirectoryToRoot();
void GetDirectoryParentFolderContents();
BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; }
/// <summary>
/// Tracks the directory browse history when browsing beyond the root directory
/// </summary>
List<CodecDirectory> DirectoryBrowseHistory { get; }
}
/// <summary>
///
/// </summary>
public class DirectoryEventArgs : EventArgs
{
public CodecDirectory Directory { get; set; }
public bool DirectoryIsOnRoot { get; set; }
}
/// <summary>
/// Represents a codec directory
/// </summary>
public class CodecDirectory
{
/// <summary>
/// Represents the contents of the directory
/// </summary>
[JsonProperty("directoryResults")]
public List<DirectoryItem> CurrentDirectoryResults { get; private set; }
/// <summary>
/// Used to store the ID of the current folder for CurrentDirectoryResults
/// </summary>
[JsonProperty("resultsFolderId")]
public string ResultsFolderId { get; set; }
public CodecDirectory()
{
CurrentDirectoryResults = new List<DirectoryItem>();
}
/// <summary>
/// Adds folders to the directory
/// </summary>
/// <param name="folders"></param>
public void AddFoldersToDirectory(List<DirectoryItem> folders)
{
if(folders != null)
CurrentDirectoryResults.AddRange(folders);
SortDirectory();
}
/// <summary>
/// Adds contacts to the directory
/// </summary>
/// <param name="contacts"></param>
public void AddContactsToDirectory(List<DirectoryItem> contacts)
{
if(contacts != null)
CurrentDirectoryResults.AddRange(contacts);
SortDirectory();
}
/// <summary>
/// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically
/// </summary>
private void SortDirectory()
{
var sortedFolders = new List<DirectoryItem>();
sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder));
sortedFolders.OrderBy(f => f.Name);
var sortedContacts = new List<DirectoryItem>();
sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact));
sortedFolders.OrderBy(c => c.Name);
CurrentDirectoryResults.Clear();
CurrentDirectoryResults.AddRange(sortedFolders);
CurrentDirectoryResults.AddRange(sortedContacts);
}
}
/// <summary>
/// Used to decorate a contact to indicate it can be invided to a meeting
/// </summary>
public interface IInvitableContact
{
}
/// <summary>
/// Represents an item in the directory
/// </summary>
public class DirectoryItem : ICloneable
{
public object Clone()
{
return this.MemberwiseClone();
}
[JsonProperty("folderId")]
public string FolderId { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
/// <summary>
/// Represents a folder type DirectoryItem
/// </summary>
public class DirectoryFolder : DirectoryItem
{
[JsonProperty("contacts")]
public List<DirectoryContact> Contacts { get; set; }
[JsonProperty("parentFolderId")]
public string ParentFolderId { get; set; }
public DirectoryFolder()
{
Contacts = new List<DirectoryContact>();
}
}
/// <summary>
/// Represents a contact type DirectoryItem
/// </summary>
public class DirectoryContact : DirectoryItem
{
[JsonProperty("contactId")]
public string ContactId { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("contactMethods")]
public List<ContactMethod> ContactMethods { get; set; }
public DirectoryContact()
{
ContactMethods = new List<ContactMethod>();
}
}
/// <summary>
/// Represents a method of contact for a contact
/// </summary>
public class ContactMethod
{
[JsonProperty("contactMethodId")]
public string ContactMethodId { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
[JsonProperty("device")]
[JsonConverter(typeof(StringEnumConverter))]
public eContactMethodDevice Device { get; set; }
[JsonProperty("callType")]
[JsonConverter(typeof(StringEnumConverter))]
public eContactMethodCallType CallType { get; set; }
}
/// <summary>
///
/// </summary>
public enum eContactMethodDevice
{
Unknown = 0,
Mobile,
Other,
Telephone,
Video
}
/// <summary>
///
/// </summary>
public enum eContactMethodCallType
{
Unknown = 0,
Audio,
Video
}
}

View File

@@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public enum eMeetingEventChangeType
{
Unkown = 0,
MeetingStartWarning,
MeetingStart,
MeetingEndWarning,
MeetingEnd
}
public interface IHasScheduleAwareness
{
CodecScheduleAwareness CodecSchedule { get; }
void GetSchedule();
}
public class CodecScheduleAwareness
{
List<Meeting> _Meetings;
public event EventHandler<MeetingEventArgs> MeetingEventChange;
public event EventHandler<EventArgs> MeetingsListHasChanged;
/// <summary>
/// Setter triggers MeetingsListHasChanged event
/// </summary>
public List<Meeting> Meetings
{
get
{
return _Meetings;
}
set
{
_Meetings = value;
var handler = MeetingsListHasChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
}
private CTimer ScheduleChecker;
public CodecScheduleAwareness()
{
Meetings = new List<Meeting>();
ScheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000);
}
private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting)
{
var handler = MeetingEventChange;
if (handler != null)
{
handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting });
}
}
private void CheckSchedule(object o)
{
// Iterate the meeting list and check if any meeting need to do anythingk
foreach (Meeting m in Meetings)
{
eMeetingEventChangeType changeType = eMeetingEventChangeType.Unkown;
if (m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start
changeType = eMeetingEventChangeType.MeetingStartWarning;
else if (m.TimeToMeetingStart.TotalMinutes == 0) // Meeting Start
changeType = eMeetingEventChangeType.MeetingStart;
else if (m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end
changeType = eMeetingEventChangeType.MeetingEndWarning;
else if (m.TimeToMeetingEnd.TotalMinutes == 0) // Meeting has ended
changeType = eMeetingEventChangeType.MeetingEnd;
if (changeType != eMeetingEventChangeType.Unkown)
OnMeetingChange(changeType, m);
}
}
}
/// <summary>
/// Generic class to represent a meeting (Cisco or Polycom OBTP or Fusion)
/// </summary>
public class Meeting
{
public TimeSpan MeetingWarningMinutes = TimeSpan.FromMinutes(5);
public string Id { get; set; }
public string Organizer { get; set; }
public string Title { get; set; }
public string Agenda { get; set; }
public TimeSpan TimeToMeetingStart
{
get
{
return StartTime - DateTime.Now;
}
}
public TimeSpan TimeToMeetingEnd
{
get
{
return EndTime - DateTime.Now;
}
}
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration
{
get
{
return EndTime - StartTime;
}
}
public eMeetingPrivacy Privacy { get; set; }
public bool Joinable
{
get
{
return StartTime.AddMinutes(-5) <= DateTime.Now
&& DateTime.Now <= EndTime; //.AddMinutes(-5);
}
}
//public string ConferenceNumberToDial { get; set; }
public string ConferencePassword { get; set; }
public bool IsOneButtonToPushMeeting { get; set; }
public List<Call> Calls { get; private set; }
public Meeting()
{
Calls = new List<Call>();
}
}
public class Call
{
public string Number { get; set; }
public string Protocol { get; set; }
public string CallRate { get; set; }
public string CallType { get; set; }
}
public class MeetingEventArgs : EventArgs
{
public eMeetingEventChangeType ChangeType { get; set; }
public Meeting Meeting { get; set; }
}
}

View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.Gateways;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common
{
public class CenRfgwController : CrestronGenericBaseDevice
{
public GatewayBase Gateway { get { return Hardware as GatewayBase; } }
/// <summary>
/// Constructor for the on-board gateway
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public CenRfgwController(string key, string name, GatewayBase gateway) :
base(key, name, gateway)
{
}
public static CenRfgwController GetNewExGatewayController(string key, string name, string id, string gatewayType)
{
uint uid;
eExGatewayType type;
try
{
uid = Convert.ToUInt32(id, 16);
type = (eExGatewayType)Enum.Parse(typeof(eExGatewayType), gatewayType, true);
var cs = Global.ControlSystem;
GatewayBase gw = null;
switch (type)
{
case eExGatewayType.Ethernet:
gw = new CenRfgwEx(uid, cs);
break;
case eExGatewayType.EthernetShared:
gw = new CenRfgwExEthernetSharable(uid, cs);
break;
case eExGatewayType.Cresnet:
gw = new CenRfgwExCresnet(uid, cs);
break;
}
return new CenRfgwController(key, name, gw);
}
catch (Exception)
{
Debug.Console(0, "ERROR: Cannot create EX Gateway, id {0}, type {1}", id, gatewayType);
return null;
}
}
public static CenRfgwController GetNewErGatewayController(string key, string name, string id, string gatewayType)
{
uint uid;
eExGatewayType type;
try
{
uid = Convert.ToUInt32(id, 16);
type = (eExGatewayType)Enum.Parse(typeof(eExGatewayType), gatewayType, true);
var cs = Global.ControlSystem;
GatewayBase gw = null;
switch (type)
{
case eExGatewayType.Ethernet:
gw = new CenErfgwPoe(uid, cs);
break;
case eExGatewayType.EthernetShared:
gw = new CenErfgwPoeEthernetSharable(uid, cs);
break;
case eExGatewayType.Cresnet:
gw = new CenErfgwPoeCresnet(uid, cs);
break;
}
return new CenRfgwController(key, name, gw);
}
catch (Exception)
{
Debug.Console(0, "ERROR: Cannot create EX Gateway, id {0}, type {1}", id, gatewayType);
return null;
}
}
/// <summary>
/// Gets the actual Crestron EX gateway for a given key. "processor" or the key of
/// a CenRfgwExController in DeviceManager
/// </summary>
/// <param name="key"></param>
/// <returns>Either processor GW or Gateway property of CenRfgwExController</returns>
public static GatewayBase GetExGatewayBaseForKey(string key)
{
key = key.ToLower();
if (key == "processor" && Global.ControlSystem.SupportsInternalRFGateway)
return Global.ControlSystem.ControllerRFGatewayDevice;
var gwCont = DeviceManager.GetDeviceForKey(key) as CenRfgwController;
if (gwCont != null)
return gwCont.Gateway;
return null;
}
}
public enum eExGatewayType
{
Ethernet, EthernetShared, Cresnet
}
}

View File

@@ -0,0 +1,376 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class BiampTesiraForteDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
new public Dictionary<string, TesiraForteLevelControl> LevelControlPoints { get; private set; }
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public BiampTesiraForteDsp(string key, string name, IBasicCommunication comm, BiampTesiraFortePropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0d\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "SESSION get aliases\x0d\x0a");
}
LevelControlPoints = new Dictionary<string, TesiraForteLevelControl>();
foreach (KeyValuePair<string, BiampTesiraForteLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new TesiraForteLevelControl(block.Key, block.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
// Tasks on connect
}
else
{
// Cleanup items from this session
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
void SubscribeToAttributes()
{
SendLine("SESSION set verbose true");
foreach (KeyValuePair<string, TesiraForteLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
if (!CommandQueueInProgress)
SendNextQueuedCommand();
ResetSubscriptionTimer();
}
/// <summary>
/// Resets or Sets the subscription timer
/// </summary>
void ResetSubscriptionTimer()
{
isSubscribed = true;
if (SubscriptionTimer != null)
{
SubscriptionTimer = new CTimer(o => SubscribeToAttributes(), 30000);
SubscriptionTimer.Reset();
}
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "RX: '{0}'",
ShowHexResponse ? ComTextHelper.GetEscapedText(args.Text) : args.Text);
Debug.Console(1, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("Welcome to the Tesira Text Protocol Server...") > -1)
{
// Indicates a new TTP session
SubscribeToAttributes();
}
else if (args.Text.IndexOf("publishToken") > -1)
{
// response is from a subscribed attribute
string pattern = "! \"publishToken\":[\"](.*)[\"] \"value\":(.*)";
Match match = Regex.Match(args.Text, pattern);
if (match.Success)
{
string key;
string customName;
string value;
customName = match.Groups[1].Value;
// Finds the key (everything before the '~' character
key = customName.Substring(0, customName.IndexOf("~", 0) - 1);
value = match.Groups[2].Value;
foreach (KeyValuePair<string, TesiraForteLevelControl> controlPoint in LevelControlPoints)
{
if (customName == controlPoint.Value.LevelCustomName || customName == controlPoint.Value.MuteCustomName)
{
controlPoint.Value.ParseSubscriptionMessage(customName, value);
return;
}
}
}
/// same for dialers
/// same for switchers
}
else if (args.Text.IndexOf("+OK") > -1)
{
if (args.Text == "+OK" || args.Text.IndexOf("list\":") > -1 ) // Check for a simple "+OK" only 'ack' repsonse or a list response and ignore
return;
// response is not from a subscribed attribute. From a get/set/toggle/increment/decrement command
if (!CommandQueue.IsEmpty)
{
if (CommandQueue.Peek() is QueuedCommand)
{
// Expected response belongs to a child class
QueuedCommand tempCommand = (QueuedCommand)CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
tempCommand.ControlPoint.ParseGetMessage(tempCommand.AttributeCode, args.Text);
}
else
{
// Expected response belongs to this class
string temp = (string)CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
}
if (CommandQueue.IsEmpty)
CommandQueueInProgress = false;
else
SendNextQueuedCommand();
}
}
else if (args.Text.IndexOf("-ERR") > -1)
{
// Error response
switch (args.Text)
{
case "-ERR ALREADY_SUBSCRIBED":
{
ResetSubscriptionTimer();
break;
}
default:
{
Debug.Console(0, this, "Error From DSP: '{0}'", args.Text);
break;
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
//Debug.Console(2, this, "Attempting to send next queued command. CommandQueueInProgress: {0} Communication isConnected: {1}", CommandQueueInProgress, Communication.IsConnected);
//if (CommandQueue.IsEmpty)
// CommandQueueInProgress = false;
//Debug.Console(1, this, "CommandQueue has {0} Elements:\n", CommandQueue.Count);
//foreach (object o in CommandQueue)
//{
// if (o is string)
// Debug.Console(1, this, "{0}", o);
// else if(o is QueuedCommand)
// {
// var item = (QueuedCommand)o;
// Debug.Console(1, this, "{0}", item.Command);
// }
//}
//Debug.Console(1, this, "End of CommandQueue");
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public override void RunPreset(string name)
{
SendLine(string.Format("DEVICE recallPreset {0}", name));
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public TesiraForteControlPoint ControlPoint { get; set; }
}
}
}

View File

@@ -0,0 +1,366 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public class TesiraForteLevelControl : TesiraForteControlPoint, IBiampTesiraDspLevelControl, IKeyed
{
bool _IsMuted;
ushort _VolumeLevel;
public BoolFeedback MuteFeedback { get; private set; }
public IntFeedback VolumeLevelFeedback { get; private set; }
public bool Enabled { get; set; }
public string ControlPointTag { get { return base.InstanceTag; } }
/// <summary>
/// Used for to identify level subscription values
/// </summary>
public string LevelCustomName { get; private set; }
/// <summary>
/// Used for to identify mute subscription values
/// </summary>
public string MuteCustomName { get; private set; }
/// <summary>
/// Minimum fader level
/// </summary>
double MinLevel;
/// <summary>
/// Maximum fader level
/// </summary>
double MaxLevel;
/// <summary>
/// Checks if a valid subscription string has been recieved for all subscriptions
/// </summary>
public bool IsSubsribed
{
get
{
bool isSubscribed = false;
if (HasMute && MuteIsSubscribed)
isSubscribed = true;
if (HasLevel && LevelIsSubscribed)
isSubscribed = true;
return isSubscribed;
}
}
public bool AutomaticUnmuteOnVolumeUp { get; private set; }
public bool HasMute { get; private set; }
public bool HasLevel { get; private set; }
bool MuteIsSubscribed;
bool LevelIsSubscribed;
//public TesiraForteLevelControl(string label, string id, int index1, int index2, bool hasMute, bool hasLevel, BiampTesiraForteDsp parent)
// : base(id, index1, index2, parent)
//{
// Initialize(label, hasMute, hasLevel);
//}
public TesiraForteLevelControl(string key, BiampTesiraForteLevelControlBlockConfig config, BiampTesiraForteDsp parent)
: base(config.InstanceTag, config.Index1, config.Index2, parent)
{
Initialize(key, config.Label, config.HasMute, config.HasLevel);
}
/// <summary>
/// Initializes this attribute based on config values and generates subscriptions commands and adds commands to the parent's queue.
/// </summary>
public void Initialize(string key, string label, bool hasMute, bool hasLevel)
{
Key = string.Format("{0}--{1}", Parent.Key, key);
DeviceManager.AddDevice(this);
Debug.Console(2, this, "Adding LevelControl '{0}'", Key);
this.IsSubscribed = false;
MuteFeedback = new BoolFeedback(() => _IsMuted);
VolumeLevelFeedback = new IntFeedback(() => _VolumeLevel);
HasMute = hasMute;
HasLevel = hasLevel;
}
public void Subscribe()
{
// Do subscriptions and blah blah
// Subscribe to mute
if (this.HasMute)
{
MuteCustomName = string.Format("{0}~mute{1}", this.InstanceTag, this.Index1);
SendSubscriptionCommand(MuteCustomName, "mute", 500);
}
// Subscribe to level
if (this.HasLevel)
{
LevelCustomName = string.Format("{0}~level{1}", this.InstanceTag, this.Index1);
SendSubscriptionCommand(LevelCustomName, "level", 250);
SendFullCommand("get", "minLevel", null);
SendFullCommand("get", "maxLevel", null);
}
}
/// <summary>
/// Parses the response from the DspBase
/// </summary>
/// <param name="customName"></param>
/// <param name="value"></param>
public void ParseSubscriptionMessage(string customName, string value)
{
// Check for valid subscription response
if (this.HasMute && customName == MuteCustomName)
{
//if (value.IndexOf("+OK") > -1)
//{
// int pointer = value.IndexOf(" +OK");
// MuteIsSubscribed = true;
// // Removes the +OK
// value = value.Substring(0, value.Length - (value.Length - (pointer - 1)));
//}
if (value.IndexOf("true") > -1)
{
_IsMuted = true;
MuteIsSubscribed = true;
}
else if (value.IndexOf("false") > -1)
{
_IsMuted = false;
MuteIsSubscribed = true;
}
MuteFeedback.FireUpdate();
}
else if (this.HasLevel && customName == LevelCustomName)
{
//if (value.IndexOf("+OK") > -1)
//{
// int pointer = value.IndexOf(" +OK");
// LevelIsSubscribed = true;
//}
var _value = Double.Parse(value);
_VolumeLevel = (ushort)Scale(_value, MinLevel, MaxLevel, 0, 65535);
LevelIsSubscribed = true;
VolumeLevelFeedback.FireUpdate();
}
}
/// <summary>
/// Parses a non subscription response
/// </summary>
/// <param name="attributeCode">The attribute code of the command</param>
/// <param name="message">The message to parse</param>
public override void ParseGetMessage(string attributeCode, string message)
{
try
{
// Parse an "+OK" message
string pattern = @"\+OK ""value"":(.*)";
Match match = Regex.Match(message, pattern);
if (match.Success)
{
string value = match.Groups[1].Value;
Debug.Console(1, this, "Response: '{0}' Value: '{1}'", attributeCode, value);
if (message.IndexOf("\"value\":") > -1)
{
switch (attributeCode)
{
case "minLevel":
{
MinLevel = Double.Parse(value);
Debug.Console(1, this, "MinLevel is '{0}'", MinLevel);
break;
}
case "maxLevel":
{
MaxLevel = Double.Parse(value);
Debug.Console(1, this, "MaxLevel is '{0}'", MaxLevel);
break;
}
default:
{
Debug.Console(2, "Response does not match expected attribute codes: '{0}'", message);
break;
}
}
}
}
}
catch (Exception e)
{
Debug.Console(2, "Unable to parse message: '{0}'\n{1}", message, e);
}
}
/// <summary>
/// Turns the mute off
/// </summary>
public void MuteOff()
{
SendFullCommand("set", "mute", "false");
}
/// <summary>
/// Turns the mute on
/// </summary>
public void MuteOn()
{
SendFullCommand("set", "mute", "true");
}
/// <summary>
/// Sets the volume to a specified level
/// </summary>
/// <param name="level"></param>
public void SetVolume(ushort level)
{
Debug.Console(1, this, "volume: {0}", level);
// Unmute volume if new level is higher than existing
if (level > _VolumeLevel && AutomaticUnmuteOnVolumeUp)
if(_IsMuted)
MuteOff();
double volumeLevel = Scale(level, 0, 65535, MinLevel, MaxLevel);
SendFullCommand("set", "level", string.Format("{0:0.000000}", volumeLevel));
}
/// <summary>
/// Toggles mute status
/// </summary>
public void MuteToggle()
{
SendFullCommand("toggle", "mute", "");
}
/// <summary>
/// Decrements volume level
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeDown(bool pressRelease)
{
SendFullCommand("decrement", "level", "");
}
/// <summary>
/// Increments volume level
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeUp(bool pressRelease)
{
SendFullCommand("increment", "level", "");
if (AutomaticUnmuteOnVolumeUp)
if (!_IsMuted)
MuteOff();
}
///// <summary>
///// Scales the input from the input range to the output range
///// </summary>
///// <param name="input"></param>
///// <param name="inMin"></param>
///// <param name="inMax"></param>
///// <param name="outMin"></param>
///// <param name="outMax"></param>
///// <returns></returns>
//int Scale(int input, int inMin, int inMax, int outMin, int outMax)
//{
// Debug.Console(1, this, "Scaling (int) input '{0}' with min '{1}'/max '{2}' to output range min '{3}'/max '{4}'", input, inMin, inMax, outMin, outMax);
// int inputRange = inMax - inMin;
// int outputRange = outMax - outMin;
// var output = (((input-inMin) * outputRange) / inputRange ) - outMin;
// Debug.Console(1, this, "Scaled output '{0}'", output);
// return output;
//}
/// <summary>
/// Scales the input from the input range to the output range
/// </summary>
/// <param name="input"></param>
/// <param name="inMin"></param>
/// <param name="inMax"></param>
/// <param name="outMin"></param>
/// <param name="outMax"></param>
/// <returns></returns>
double Scale(double input, double inMin, double inMax, double outMin, double outMax)
{
Debug.Console(1, this, "Scaling (double) input '{0}' with min '{1}'/max '{2}' to output range min '{3}'/max '{4}'",input ,inMin ,inMax ,outMin, outMax);
double inputRange = inMax - inMin;
if (inputRange <= 0)
{
throw new ArithmeticException(string.Format("Invalid Input Range '{0}' for Scaling. Min '{1}' Max '{2}'.", inputRange, inMin, inMax));
}
double outputRange = outMax - outMin;
var output = (((input - inMin) * outputRange) / inputRange) + outMin;
Debug.Console(1, this, "Scaled output '{0}'", output);
return output;
}
}
}

View File

@@ -0,0 +1,40 @@
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.Devices.Common.DSP
{
/// <summary>
///
/// </summary>
public class BiampTesiraFortePropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
/// <summary>
/// These are key-value pairs, string id, string type.
/// Valid types are level and mute.
/// Need to include the index values somehow
/// </summary>
public Dictionary<string, BiampTesiraForteLevelControlBlockConfig> LevelControlBlocks { get; set; }
// public Dictionary<string, BiampTesiraForteDialerControlBlockConfig> DialerControlBlocks {get; set;}
}
public class BiampTesiraForteLevelControlBlockConfig
{
public bool Enabled { get; set; }
public string Label { get; set; }
public string InstanceTag { get; set; }
public int Index1 { get; set; }
public int Index2 { get; set; }
public bool HasMute { get; set; }
public bool HasLevel { get; set; }
}
}

View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public abstract class TesiraForteControlPoint : DspControlPoint
{
public string Key { get; protected set; }
public string InstanceTag { get; set; }
public int Index1 { get; private set; }
public int Index2 { get; private set; }
public BiampTesiraForteDsp Parent { get; private set; }
public bool IsSubscribed { get; protected set; }
protected TesiraForteControlPoint(string id, int index1, int index2, BiampTesiraForteDsp parent)
{
InstanceTag = id;
Index1 = index1;
Index2 = index2;
Parent = parent;
}
virtual public void Initialize()
{
}
/// <summary>
/// Sends a command to the DSP
/// </summary>
/// <param name="command">command</param>
/// <param name="attribute">attribute code</param>
/// <param name="value">value (use "" if not applicable)</param>
public virtual void SendFullCommand(string command, string attributeCode, string value)
{
// Command Format: InstanceTag get/set/toggle/increment/decrement/subscribe/unsubscribe attributeCode [index] [value]
// Ex: "RoomLevel set level 1.00"
string cmd;
if (attributeCode == "level" || attributeCode == "mute" || attributeCode == "minLevel" || attributeCode == "maxLevel" || attributeCode == "label" || attributeCode == "rampInterval" || attributeCode == "rampStep")
{
//Command requires Index
if (String.IsNullOrEmpty(value))
{
// format command without value
cmd = string.Format("{0} {1} {2} {3}", InstanceTag, command, attributeCode, Index1);
}
else
{
// format commadn with value
cmd = string.Format("{0} {1} {2} {3} {4}", InstanceTag, command, attributeCode, Index1, value);
}
}
else
{
//Command does not require Index
if (String.IsNullOrEmpty(value))
{
cmd = string.Format("{0} {1} {2} {3}", InstanceTag, command, attributeCode, value);
}
else
{
cmd = string.Format("{0} {1} {2}", InstanceTag, command, attributeCode);
}
}
if (command == "get")
{
// This command will generate a return value response so it needs to be queued
Parent.EnqueueCommand(new BiampTesiraForteDsp.QueuedCommand{ Command = cmd, AttributeCode = attributeCode, ControlPoint = this });
}
else
{
// This command will generate a simple "+OK" response and doesn't need to be queued
Parent.SendLine(cmd);
}
}
virtual public void ParseGetMessage(string attributeCode, string message)
{
}
public virtual void SendSubscriptionCommand(string customName, string attributeCode, int responseRate)
{
// Subscription string format: InstanceTag subscribe attributeCode Index1 customName responseRate
// Ex: "RoomLevel subscribe level 1 MyRoomLevel 500"
string cmd;
if (responseRate > 0)
{
cmd = string.Format("{0} subscribe {1} {2} {3} {4}", InstanceTag, attributeCode, Index1, customName, responseRate);
}
else
{
cmd = string.Format("{0} subscribe {1} {2} {3}", InstanceTag, attributeCode, Index1, customName);
}
Parent.SendLine(cmd);
}
}
}

View File

@@ -0,0 +1,79 @@
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.Devices.Common.DSP
{
//QUESTIONS:
//When subscribing, just use the Instance ID for Custom Name?
//Verbose on subscriptions?
//! "publishToken":"name" "value":-77.0
//! "myLevelName" -77
//public class TesiraForteMuteControl : IDspLevelControl
//{
// BiampTesiraForteDsp Parent;
// bool _IsMuted;
// ushort _VolumeLevel;
// public TesiraForteMuteControl(string id, BiampTesiraForteDsp parent)
// : base(id)
// {
// Parent = parent;
// }
// public void Initialize()
// {
// }
// protected override Func<bool> MuteFeedbackFunc
// {
// get { return () => _IsMuted; }
// }
// protected override Func<int> VolumeLevelFeedbackFunc
// {
// get { return () => _VolumeLevel; }
// }
// public override void MuteOff()
// {
// throw new NotImplementedException();
// }
// public override void MuteOn()
// {
// throw new NotImplementedException();
// }
// public override void SetVolume(ushort level)
// {
// throw new NotImplementedException();
// }
// public override void MuteToggle()
// {
// }
// public override void VolumeDown(bool pressRelease)
// {
// throw new NotImplementedException();
// }
// public override void VolumeUp(bool pressRelease)
// {
// throw new NotImplementedException();
// }
//}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public abstract class DspBase : Device
{
public Dictionary<string, DspControlPoint> LevelControlPoints { get; private set; }
public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
public abstract void RunPreset(string name);
public DspBase(string key, string name) :
base(key, name) { }
// in audio call feedback
// VOIP
// Phone dialer
}
// Fusion
// Privacy state
// Online state
// level/mutes ?
// AC Log call stats
// Typical presets:
// call default preset to restore levels and mutes
public abstract class DspControlPoint
{
string Key { get; set; }
}
public class DspDialerBase
{
}
// Main program
// VTC
// ATC
// Mics, unusual
public interface IBiampTesiraDspLevelControl : IBasicVolumeWithFeedback
{
/// <summary>
/// In BiAmp: Instance Tag, QSC: Named Control, Polycom:
/// </summary>
string ControlPointTag { get; }
#warning I dont think index1 and index2 should be a part of the interface. JTA 2018-07-17
int Index1 { get; }
int Index2 { get; }
bool HasMute { get; }
bool HasLevel { get; }
bool AutomaticUnmuteOnVolumeUp { get; }
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public class SoundStructureBasics
{
// public Dictionary<string, IBiampTesiraDspLevelControl> Levels { get; private set; }
}
}

View File

@@ -0,0 +1,328 @@
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.Devices.Common.Codec;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Reflection;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class QscDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public GenericCommunicationMonitor CommunicationMonitor { get; private set; }
new public Dictionary<string, QscDspLevelControl> LevelControlPoints { get; private set; }
new public Dictionary<string, QscDspDialer> Dialers { get; set; }
public List<QscDspPresets> PresetList = new List<QscDspPresets>();
public bool isSubscribed;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
public bool ShowHexResponse { get; set; }
public QscDsp(string key, string name, IBasicCommunication comm, QscDspPropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0a");
PortGather.LineReceived += this.Port_LineReceived;
LevelControlPoints = new Dictionary<string, QscDspLevelControl>();
Dialers = new Dictionary<string, QscDspDialer>();
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "cgp 1\x0D\x0A");
}
foreach (KeyValuePair<string, QscDspLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new QscDspLevelControl(block.Key, block.Value, this));
Debug.Console(2, this, "Added LevelControlPoint {0}", block.Key);
}
foreach (KeyValuePair<string, QscDspPresets> preset in props.presets)
{
this.addPreset(preset.Value);
Debug.Console(2, this, "Added Preset {0} {1}", preset.Value.label, preset.Value.preset);
}
foreach (KeyValuePair<string, QscDialerConfig> dialerConfig in props.dialerControlBlocks)
{
Debug.Console(2, this, "Added Dialer {0}\n {1}", dialerConfig.Key, dialerConfig.Value);
this.Dialers.Add(dialerConfig.Key, new QscDspDialer(dialerConfig.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
SubscribeToAttributes();
}
else
{
// Cleanup items from this session
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
void SubscribeToAttributes()
{
SendLine("cgd 1");
SendLine("cgc 1");
foreach (KeyValuePair<string, QscDspLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
foreach (var dialer in Dialers)
{
dialer.Value.Subscribe();
}
if (CommunicationMonitor != null)
{
CommunicationMonitor.Start();
//CommunicationMonitor = null;
}
else
{
}
//CommunicationMonitor.Message = "cgp 1\x0D\x0A";
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
//CommunicationMonitor.Start();
if (!CommandQueueInProgress)
SendNextQueuedCommand();
// ResetSubscriptionTimer();
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("sr ") > -1)
{
}
else if (args.Text.IndexOf("cv") > -1)
{
var changeMessage = args.Text.Split(null);
string changedInstance = changeMessage[1].Replace("\"", "");
Debug.Console(1, this, "cv parse Instance: {0}", changedInstance);
bool foundItFlag = false;
foreach (KeyValuePair<string, QscDspLevelControl> controlPoint in LevelControlPoints)
{
if (changedInstance == controlPoint.Value.LevelInstanceTag)
{
controlPoint.Value.ParseSubscriptionMessage(changedInstance, changeMessage[4]);
foundItFlag = true;
return;
}
else if (changedInstance == controlPoint.Value.MuteInstanceTag)
{
controlPoint.Value.ParseSubscriptionMessage(changedInstance, changeMessage[2].Replace("\"", ""));
foundItFlag = true;
return;
}
}
if (!foundItFlag)
{
foreach (var dialer in Dialers)
{
PropertyInfo[] properties = dialer.Value.Tags.GetType().GetCType().GetProperties();
//GetPropertyValues(Tags);
foreach (var prop in properties)
{
var propValue = prop.GetValue(dialer.Value.Tags, null) as string;
if (changedInstance == propValue)
{
dialer.Value.ParseSubscriptionMessage(changedInstance, changeMessage[2].Replace("\"", ""));
foundItFlag = true;
return;
}
}
if (foundItFlag)
{
return;
}
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
public void RunPresetNumber(ushort n)
{
RunPreset(PresetList[n].preset);
}
public void addPreset(QscDspPresets s)
{
PresetList.Add(s);
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public override void RunPreset(string name)
{
SendLine(string.Format("ssl {0}", name));
SendLine("cgp 1");
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public QscDspControlPoint ControlPoint { get; set; }
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public abstract class QscDspControlPoint : DspControlPoint
{
public string Key { get; protected set; }
public string LevelInstanceTag { get; set; }
public string MuteInstanceTag { get; set; }
public QscDsp Parent { get; private set; }
public bool IsSubscribed { get; protected set; }
protected QscDspControlPoint(string levelInstanceTag, string muteInstanceTag, QscDsp parent)
{
LevelInstanceTag = levelInstanceTag;
MuteInstanceTag = muteInstanceTag;
Parent = parent;
}
virtual public void Initialize()
{
}
/// <summary>
/// Sends a command to the DSP
/// </summary>
/// <param name="command">command</param>
/// <param name="attribute">attribute code</param>
/// <param name="value">value (use "" if not applicable)</param>
public virtual void SendFullCommand(string cmd, string instance, string value)
{
var cmdToSemd = string.Format("{0} {1} {2}", cmd, instance, value);
Parent.SendLine(cmdToSemd);
}
virtual public void ParseGetMessage(string attributeCode, string message)
{
}
public virtual void SendSubscriptionCommand(string instanceTag, string changeGroup)
{
// Subscription string format: InstanceTag subscribe attributeCode Index1 customName responseRate
// Ex: "RoomLevel subscribe level 1 MyRoomLevel 500"
string cmd;
cmd = string.Format("cga {0} {1}", changeGroup, instanceTag);
Parent.SendLine(cmd);
}
}
}

View File

@@ -0,0 +1,270 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharp;
using PepperDash.Essentials.Devices.Common.Codec;
using Crestron.SimplSharpPro.CrestronThread;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public class QscDspDialer : DspDialerBase, IHasDialer
{
public QscDialerConfig Tags;
public bool IsInCall { get; private set; }
public QscDsp Parent { get; private set; }
public string DialString { get; private set; }
public bool OffHook { get; private set; }
public bool AutoAnswerState { get; private set; }
public bool DoNotDisturbState { get; private set; }
public BoolFeedback OffHookFeedback;
public BoolFeedback AutoAnswerFeedback;
public BoolFeedback DoNotDisturbFeedback;
public StringFeedback DialStringFeedback;
// Add requirements for Dialer functionality
public QscDspDialer(QscDialerConfig Config, QscDsp parent)
{
Tags = Config;
Parent = parent;
DialStringFeedback = new StringFeedback(() => { return DialString; });
OffHookFeedback = new BoolFeedback(() => { return OffHook; });
AutoAnswerFeedback = new BoolFeedback(() => { return AutoAnswerState; });
DoNotDisturbFeedback = new BoolFeedback(() => { return DoNotDisturbState; });
}
public event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
public void Subscribe()
{
try
{
// Do subscriptions and blah blah
// This would be better using reflection JTA 2018-08-28
PropertyInfo[] properties = Tags.GetType().GetCType().GetProperties();
//GetPropertyValues(Tags);
Debug.Console(2, "QscDspDialer Subscribe");
foreach (var prop in properties)
{
//var val = prop.GetValue(obj, null);
Debug.Console(2, "Property {0}, {1}, {2}\n", prop.GetType().Name, prop.Name, prop.PropertyType.FullName);
if (prop.Name.Contains("Tag") && !prop.Name.Contains("keypad"))
{
var propValue = prop.GetValue(Tags, null) as string;
Debug.Console(2, "Property {0}, {1}, {2}\n", prop.GetType().Name, prop.Name, propValue);
SendSubscriptionCommand(propValue, "1");
}
}
}
catch (Exception e)
{
Debug.Console(2, "QscDspDialer Subscription Error: '{0}'\n", e);
}
// SendSubscriptionCommand(, "1");
// SendSubscriptionCommand(config. , "mute", 500);
}
public void ParseSubscriptionMessage(string customName, string value)
{
// Check for valid subscription response
Debug.Console(1, "QscDialerTag {0} Response: '{1}'", customName, value);
if (customName == Tags.dialStringTag)
{
Debug.Console(2, "QscDialerTag DialStringChanged ", value);
this.DialString = value;
this.DialStringFeedback.FireUpdate();
}
else if (customName == Tags.doNotDisturbTag)
{
if (value == "on")
{
this.DoNotDisturbState = true;
}
else if (value == "off")
{
this.DoNotDisturbState = false;
}
DoNotDisturbFeedback.FireUpdate();
}
else if (customName == Tags.callStatusTag)
{
if (value == "Dialing")
{
this.OffHook = true;
}
else if (value == "Disconnected")
{
this.OffHook = false;
if (Tags.ClearOnHangup)
{
this.SendKeypad(eKeypadKeys.Clear);
}
}
this.OffHookFeedback.FireUpdate();
}
else if (customName == Tags.autoAnswerTag)
{
if (value == "on")
{
this.AutoAnswerState = true;
}
else if (value == "off")
{
this.AutoAnswerState = false;
}
AutoAnswerFeedback.FireUpdate();
}
else if (customName == Tags.hookStatusTag)
{
if (value == "true")
{
this.OffHook = true;
}
else if (value == "false")
{
this.OffHook = false;
}
this.OffHookFeedback.FireUpdate();
}
}
public void DoNotDisturbToggle()
{
int dndStateInt = !DoNotDisturbState ? 1 : 0;
Parent.SendLine(string.Format("csv {0} {1}", Tags.doNotDisturbTag, dndStateInt));
}
public void DoNotDisturbOn()
{
Parent.SendLine(string.Format("csv {0} 1", Tags.doNotDisturbTag));
}
public void DoNotDisturbOff()
{
Parent.SendLine(string.Format("csv {0} 0", Tags.doNotDisturbTag));
}
public void AutoAnswerToggle()
{
int autoAnswerStateInt = !AutoAnswerState ? 1 : 0;
Parent.SendLine(string.Format("csv {0} {1}", Tags.autoAnswerTag, autoAnswerStateInt));
}
public void AutoAnswerOn()
{
Parent.SendLine(string.Format("csv {0} 1", Tags.autoAnswerTag));
}
public void AutoAnswerOff()
{
Parent.SendLine(string.Format("csv {0} 0", Tags.autoAnswerTag));
}
private void PollKeypad()
{
Thread.Sleep(50);
Parent.SendLine(string.Format("cg {0}", Tags.dialStringTag));
}
public void SendKeypad(eKeypadKeys button)
{
string keypadTag = null;
switch (button)
{
case eKeypadKeys.Num0: keypadTag = Tags.keypad0Tag; break;
case eKeypadKeys.Num1: keypadTag = Tags.keypad1Tag; break;
case eKeypadKeys.Num2: keypadTag = Tags.keypad2Tag; break;
case eKeypadKeys.Num3: keypadTag = Tags.keypad3Tag; break;
case eKeypadKeys.Num4: keypadTag = Tags.keypad4Tag; break;
case eKeypadKeys.Num5: keypadTag = Tags.keypad5Tag; break;
case eKeypadKeys.Num6: keypadTag = Tags.keypad6Tag; break;
case eKeypadKeys.Num7: keypadTag = Tags.keypad7Tag; break;
case eKeypadKeys.Num8: keypadTag = Tags.keypad8Tag; break;
case eKeypadKeys.Num9: keypadTag = Tags.keypad9Tag; break;
case eKeypadKeys.Pound: keypadTag = Tags.keypadPoundTag; break;
case eKeypadKeys.Star: keypadTag = Tags.keypadStarTag; break;
case eKeypadKeys.Backspace: keypadTag = Tags.keypadBackspaceTag; break;
case eKeypadKeys.Clear: keypadTag = Tags.keypadClearTag; break;
}
if (keypadTag != null)
{
var cmdToSend = string.Format("ct {0}", keypadTag);
Parent.SendLine(cmdToSend);
PollKeypad();
}
}
public void SendSubscriptionCommand(string instanceTag, string changeGroup)
{
// Subscription string format: InstanceTag subscribe attributeCode Index1 customName responseRate
// Ex: "RoomLevel subscribe level 1 MyRoomLevel 500"
var cmd = string.Format("cga {0} {1}", changeGroup, instanceTag);
Parent.SendLine(cmd);
}
public void Dial()
{
if (!this.OffHook)
{
Parent.SendLine(string.Format("ct {0}", Tags.connectTag));
}
else
{
Parent.SendLine(string.Format("ct {0}", Tags.disconnectTag));
}
Thread.Sleep(50);
Parent.SendLine(string.Format("cg {0}", Tags.callStatusTag));
}
public void Dial(string number)
{
}
public void EndCall(CodecActiveCallItem activeCall)
{
}
public void EndAllCalls()
{
}
public void AcceptCall(CodecActiveCallItem item)
{
}
public void RejectCall(CodecActiveCallItem item)
{
}
public void SendDtmf(string digit)
{
}
public enum eKeypadKeys
{
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
Num0,
Star,
Pound,
Clear,
Backspace
}
}
}

View File

@@ -0,0 +1,307 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public class QscDspLevelControl : QscDspControlPoint, IBasicVolumeWithFeedback, IKeyed
{
bool _IsMuted;
ushort _VolumeLevel;
public BoolFeedback MuteFeedback { get; private set; }
public IntFeedback VolumeLevelFeedback { get; private set; }
public bool Enabled { get; set; }
public ePdtLevelTypes Type;
CTimer VolumeUpRepeatTimer;
CTimer VolumeDownRepeatTimer;
/// <summary>
/// Used for to identify level subscription values
/// </summary>
public string LevelCustomName { get; private set; }
/// <summary>
/// Used for to identify mute subscription values
/// </summary>
public string MuteCustomName { get; private set; }
/// <summary>
/// Minimum fader level
/// </summary>
double MinLevel;
/// <summary>
/// Maximum fader level
/// </summary>
double MaxLevel;
/// <summary>
/// Checks if a valid subscription string has been recieved for all subscriptions
/// </summary>
public bool IsSubsribed
{
get
{
bool isSubscribed = false;
if (HasMute && MuteIsSubscribed)
isSubscribed = true;
if (HasLevel && LevelIsSubscribed)
isSubscribed = true;
return isSubscribed;
}
}
public bool AutomaticUnmuteOnVolumeUp { get; private set; }
public bool HasMute { get; private set; }
public bool HasLevel { get; private set; }
bool MuteIsSubscribed;
bool LevelIsSubscribed;
//public TesiraForteLevelControl(string label, string id, int index1, int index2, bool hasMute, bool hasLevel, BiampTesiraForteDsp parent)
// : base(id, index1, index2, parent)
//{
// Initialize(label, hasMute, hasLevel);
//}
public QscDspLevelControl(string key, QscDspLevelControlBlockConfig config, QscDsp parent)
: base(config.LevelInstanceTag, config.MuteInstanceTag, parent)
{
if (!config.Disabled)
{
Initialize(key, config);
}
}
/// <summary>
/// Initializes this attribute based on config values and generates subscriptions commands and adds commands to the parent's queue.
/// </summary>
public void Initialize(string key, QscDspLevelControlBlockConfig config)
{
Key = string.Format("{0}--{1}", Parent.Key, key);
Enabled = true;
DeviceManager.AddDevice(this);
if (config.IsMic)
{
Type = ePdtLevelTypes.microphone;
}
else
{
Type = ePdtLevelTypes.speaker;
}
Debug.Console(2, this, "Adding LevelControl '{0}'", Key);
this.IsSubscribed = false;
MuteFeedback = new BoolFeedback(() => _IsMuted);
VolumeLevelFeedback = new IntFeedback(() => _VolumeLevel);
VolumeUpRepeatTimer = new CTimer(VolumeUpRepeat, Timeout.Infinite);
VolumeDownRepeatTimer = new CTimer(VolumeDownRepeat, Timeout.Infinite);
LevelCustomName = config.Label;
HasMute = config.HasMute;
HasLevel = config.HasLevel;
}
public void Subscribe()
{
// Do subscriptions and blah blah
// Subscribe to mute
if (this.HasMute)
{
SendSubscriptionCommand(this.MuteInstanceTag, "1");
// SendSubscriptionCommand(config. , "mute", 500);
}
// Subscribe to level
if (this.HasLevel)
{
SendSubscriptionCommand(this.LevelInstanceTag, "1");
// SendSubscriptionCommand(this.con, "level", 250);
//SendFullCommand("get", "minLevel", null);
//SendFullCommand("get", "maxLevel", null);
}
}
/// <summary>
/// Parses the response from the DspBase
/// </summary>
/// <param name="customName"></param>
/// <param name="value"></param>
public void ParseSubscriptionMessage(string customName, string value)
{
// Check for valid subscription response
Debug.Console(1, this, "Level {0} Response: '{1}'", customName, value);
if (customName == MuteInstanceTag)
{
if (value == "muted")
{
_IsMuted = true;
MuteIsSubscribed = true;
}
else if (value == "unmuted")
{
_IsMuted = false;
MuteIsSubscribed = true;
}
MuteFeedback.FireUpdate();
}
else if (customName == LevelInstanceTag)
{
var _value = Double.Parse(value);
_VolumeLevel = (ushort)(_value * 65535);
Debug.Console(1, this, "Level {0} VolumeLevel: '{1}'", customName, _VolumeLevel);
LevelIsSubscribed = true;
VolumeLevelFeedback.FireUpdate();
}
}
/// <summary>
/// Turns the mute off
/// </summary>
public void MuteOff()
{
SendFullCommand("csv", this.MuteInstanceTag, "0");
}
/// <summary>
/// Turns the mute on
/// </summary>
public void MuteOn()
{
SendFullCommand("csv", this.MuteInstanceTag, "1");
}
/// <summary>
/// Sets the volume to a specified level
/// </summary>
/// <param name="level"></param>
public void SetVolume(ushort level)
{
Debug.Console(1, this, "volume: {0}", level);
// Unmute volume if new level is higher than existing
if (AutomaticUnmuteOnVolumeUp && _IsMuted)
{
MuteOff();
}
double newLevel = Scale(level);
Debug.Console(1, this, "newVolume: {0}", newLevel);
SendFullCommand("csp", this.LevelInstanceTag, string.Format("{0}", newLevel));
}
/// <summary>
/// Toggles mute status
/// </summary>
public void MuteToggle()
{
if (_IsMuted)
{
SendFullCommand("csv", this.MuteInstanceTag, "0");
}
else
{
SendFullCommand("csv", this.MuteInstanceTag, "1");
}
}
public void VolumeUpRepeat(object callbackObject)
{
this.VolumeUp(true);
}
public void VolumeDownRepeat(object callbackObject)
{
this.VolumeDown(true);
}
public void VolumeDown(bool press)
{
if (press)
{
VolumeDownRepeatTimer.Reset(100);
SendFullCommand("css ", this.LevelInstanceTag, "--");
}
else
{
VolumeDownRepeatTimer.Stop();
// VolumeDownRepeatTimer.Dispose();
}
}
/// <summary>
/// Increments volume level
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeUp(bool press)
{
if (press)
{
VolumeUpRepeatTimer.Reset(100);
SendFullCommand("css ", this.LevelInstanceTag, "++");
if (AutomaticUnmuteOnVolumeUp)
if (!_IsMuted)
MuteOff();
}
else
{
VolumeUpRepeatTimer.Stop();
}
}
/// <returns></returns>
double Scale(double input)
{
Debug.Console(1, this, "Scaling (double) input '{0}'",input );
var output = (input / 65535);
Debug.Console(1, this, "Scaled output '{0}'", output);
return output;
}
}
public enum ePdtLevelTypes
{
speaker = 0,
microphone = 1
}
}

View File

@@ -0,0 +1,88 @@
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.Devices.Common.DSP
{
/// <summary>
///
/// </summary>
public class QscDspPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
/// <summary>
/// These are key-value pairs, string id, string type.
/// Valid types are level and mute.
/// Need to include the index values somehow
/// </summary>
public Dictionary<string, QscDspLevelControlBlockConfig> LevelControlBlocks { get; set; }
public Dictionary<string, QscDialerConfig> dialerControlBlocks { get; set; }
public Dictionary<string, QscDspPresets> presets { get; set; }
// public Dictionary<string, BiampTesiraForteDialerControlBlockConfig> DialerControlBlocks {get; set;}
}
public interface IQscDspBasicLevel : IBasicVolumeWithFeedback
{
/// <summary>
/// In BiAmp: Instance Tag, QSC: Named Control, Polycom:
/// </summary>
string LevelInstanceTag { get; set; }
string MuteInstanceTag { get; set; }
bool HasMute { get; }
bool HasLevel { get; }
bool AutomaticUnmuteOnVolumeUp { get; }
}
public class QscDspLevelControlBlockConfig
{
public bool Disabled { get; set; }
public string Label { get; set; }
public string LevelInstanceTag { get; set; }
public string MuteInstanceTag { get; set; }
public bool HasMute { get; set; }
public bool HasLevel { get; set; }
public bool IsMic { get; set; }
}
public class QscDialerConfig
{
public string incomingCallRingerTag {get; set;}
public string dialStringTag {get; set;}
public string disconnectTag {get; set;}
public string connectTag {get; set;}
public string callStatusTag {get; set;}
public string hookStatusTag {get; set;}
public string doNotDisturbTag { get; set; }
public string autoAnswerTag { get; set; }
public string keypadBackspaceTag {get; set;}
public string keypadClearTag {get; set;}
public string keypad1Tag {get; set;}
public string keypad2Tag {get; set;}
public string keypad3Tag {get; set;}
public string keypad4Tag {get; set;}
public string keypad5Tag {get; set;}
public string keypad6Tag {get; set;}
public string keypad7Tag {get; set;}
public string keypad8Tag {get; set;}
public string keypad9Tag {get; set;}
public string keypad0Tag {get; set;}
public string keypadPoundTag {get; set;}
public string keypadStarTag {get; set;}
public bool ClearOnHangup { get; set; }
}
public class QscDspPresets
{
public string label { get; set; }
public string preset { get; set; }
}
}

View File

@@ -0,0 +1,328 @@
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.Devices.Common.Codec;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Reflection;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class QscDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public GenericCommunicationMonitor CommunicationMonitor { get; private set; }
new public Dictionary<string, QscDspLevelControl> LevelControlPoints { get; private set; }
new public Dictionary<string, QscDspDialer> Dialers { get; set; }
public List<QscDspPresets> PresetList = new List<QscDspPresets>();
public bool isSubscribed;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
public bool ShowHexResponse { get; set; }
public QscDsp(string key, string name, IBasicCommunication comm, QscDspPropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0a");
PortGather.LineReceived += this.Port_LineReceived;
LevelControlPoints = new Dictionary<string, QscDspLevelControl>();
Dialers = new Dictionary<string, QscDspDialer>();
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "cgp 1\x0D\x0A");
}
foreach (KeyValuePair<string, QscDspLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new QscDspLevelControl(block.Key, block.Value, this));
Debug.Console(2, this, "Added LevelControlPoint {0}", block.Key);
}
foreach (KeyValuePair<string, QscDspPresets> preset in props.presets)
{
this.addPreset(preset.Value);
Debug.Console(2, this, "Added Preset {0} {1}", preset.Value.label, preset.Value.preset);
}
foreach (KeyValuePair<string, QscDialerConfig> dialerConfig in props.dialerControlBlocks)
{
Debug.Console(2, this, "Added Dialer {0}\n {1}", dialerConfig.Key, dialerConfig.Value);
this.Dialers.Add(dialerConfig.Key, new QscDspDialer(dialerConfig.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
SubscribeToAttributes();
}
else
{
// Cleanup items from this session
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
void SubscribeToAttributes()
{
SendLine("cgd 1");
SendLine("cgc 1");
foreach (KeyValuePair<string, QscDspLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
foreach (var dialer in Dialers)
{
dialer.Value.Subscribe();
}
if (CommunicationMonitor != null)
{
CommunicationMonitor.Start();
//CommunicationMonitor = null;
}
else
{
}
//CommunicationMonitor.Message = "cgp 1\x0D\x0A";
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
//CommunicationMonitor.Start();
if (!CommandQueueInProgress)
SendNextQueuedCommand();
// ResetSubscriptionTimer();
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("sr ") > -1)
{
}
else if (args.Text.IndexOf("cv") > -1)
{
var changeMessage = args.Text.Split(null);
string changedInstance = changeMessage[1].Replace("\"", "");
Debug.Console(1, this, "cv parse Instance: {0}", changedInstance);
bool foundItFlag = false;
foreach (KeyValuePair<string, QscDspLevelControl> controlPoint in LevelControlPoints)
{
if (changedInstance == controlPoint.Value.LevelInstanceTag)
{
controlPoint.Value.ParseSubscriptionMessage(changedInstance, changeMessage[4]);
foundItFlag = true;
return;
}
else if (changedInstance == controlPoint.Value.MuteInstanceTag)
{
controlPoint.Value.ParseSubscriptionMessage(changedInstance, changeMessage[2].Replace("\"", ""));
foundItFlag = true;
return;
}
}
if (!foundItFlag)
{
foreach (var dialer in Dialers)
{
PropertyInfo[] properties = dialer.Value.Tags.GetType().GetCType().GetProperties();
//GetPropertyValues(Tags);
foreach (var prop in properties)
{
var propValue = prop.GetValue(dialer.Value.Tags, null) as string;
if (changedInstance == propValue)
{
dialer.Value.ParseSubscriptionMessage(changedInstance, changeMessage[2].Replace("\"", ""));
foundItFlag = true;
return;
}
}
if (foundItFlag)
{
return;
}
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
public void RunPresetNumber(ushort n)
{
RunPreset(PresetList[n].preset);
}
public void addPreset(QscDspPresets s)
{
PresetList.Add(s);
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public override void RunPreset(string name)
{
SendLine(string.Format("ssl {0}", name));
SendLine("cgp 1");
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public QscDspControlPoint ControlPoint { get; set; }
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public abstract class QscDspControlPoint : DspControlPoint
{
public string Key { get; protected set; }
public string LevelInstanceTag { get; set; }
public string MuteInstanceTag { get; set; }
public QscDsp Parent { get; private set; }
public bool IsSubscribed { get; protected set; }
protected QscDspControlPoint(string levelInstanceTag, string muteInstanceTag, QscDsp parent)
{
LevelInstanceTag = levelInstanceTag;
MuteInstanceTag = muteInstanceTag;
Parent = parent;
}
virtual public void Initialize()
{
}
/// <summary>
/// Sends a command to the DSP
/// </summary>
/// <param name="command">command</param>
/// <param name="attribute">attribute code</param>
/// <param name="value">value (use "" if not applicable)</param>
public virtual void SendFullCommand(string cmd, string instance, string value)
{
var cmdToSemd = string.Format("{0} {1} {2}", cmd, instance, value);
Parent.SendLine(cmdToSemd);
}
virtual public void ParseGetMessage(string attributeCode, string message)
{
}
public virtual void SendSubscriptionCommand(string instanceTag, string changeGroup)
{
// Subscription string format: InstanceTag subscribe attributeCode Index1 customName responseRate
// Ex: "RoomLevel subscribe level 1 MyRoomLevel 500"
string cmd;
cmd = string.Format("cga {0} {1}", changeGroup, instanceTag);
Parent.SendLine(cmd);
}
}
}

View File

@@ -0,0 +1,270 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharp;
using PepperDash.Essentials.Devices.Common.Codec;
using Crestron.SimplSharpPro.CrestronThread;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public class QscDspDialer : DspDialerBase, IHasDialer
{
public QscDialerConfig Tags;
public bool IsInCall { get; private set; }
public QscDsp Parent { get; private set; }
public string DialString { get; private set; }
public bool OffHook { get; private set; }
public bool AutoAnswerState { get; private set; }
public bool DoNotDisturbState { get; private set; }
public BoolFeedback OffHookFeedback;
public BoolFeedback AutoAnswerFeedback;
public BoolFeedback DoNotDisturbFeedback;
public StringFeedback DialStringFeedback;
// Add requirements for Dialer functionality
public QscDspDialer(QscDialerConfig Config, QscDsp parent)
{
Tags = Config;
Parent = parent;
DialStringFeedback = new StringFeedback(() => { return DialString; });
OffHookFeedback = new BoolFeedback(() => { return OffHook; });
AutoAnswerFeedback = new BoolFeedback(() => { return AutoAnswerState; });
DoNotDisturbFeedback = new BoolFeedback(() => { return DoNotDisturbState; });
}
public event EventHandler<CodecCallStatusItemChangeEventArgs> CallStatusChange;
public void Subscribe()
{
try
{
// Do subscriptions and blah blah
// This would be better using reflection JTA 2018-08-28
PropertyInfo[] properties = Tags.GetType().GetCType().GetProperties();
//GetPropertyValues(Tags);
Debug.Console(2, "QscDspDialer Subscribe");
foreach (var prop in properties)
{
//var val = prop.GetValue(obj, null);
Debug.Console(2, "Property {0}, {1}, {2}\n", prop.GetType().Name, prop.Name, prop.PropertyType.FullName);
if (prop.Name.Contains("Tag") && !prop.Name.Contains("keypad"))
{
var propValue = prop.GetValue(Tags, null) as string;
Debug.Console(2, "Property {0}, {1}, {2}\n", prop.GetType().Name, prop.Name, propValue);
SendSubscriptionCommand(propValue, "1");
}
}
}
catch (Exception e)
{
Debug.Console(2, "QscDspDialer Subscription Error: '{0}'\n", e);
}
// SendSubscriptionCommand(, "1");
// SendSubscriptionCommand(config. , "mute", 500);
}
public void ParseSubscriptionMessage(string customName, string value)
{
// Check for valid subscription response
Debug.Console(1, "QscDialerTag {0} Response: '{1}'", customName, value);
if (customName == Tags.dialStringTag)
{
Debug.Console(2, "QscDialerTag DialStringChanged ", value);
this.DialString = value;
this.DialStringFeedback.FireUpdate();
}
else if (customName == Tags.doNotDisturbTag)
{
if (value == "on")
{
this.DoNotDisturbState = true;
}
else if (value == "off")
{
this.DoNotDisturbState = false;
}
DoNotDisturbFeedback.FireUpdate();
}
else if (customName == Tags.callStatusTag)
{
if (value == "Dialing")
{
this.OffHook = true;
}
else if (value == "Disconnected")
{
this.OffHook = false;
if (Tags.ClearOnHangup)
{
this.SendKeypad(eKeypadKeys.Clear);
}
}
this.OffHookFeedback.FireUpdate();
}
else if (customName == Tags.autoAnswerTag)
{
if (value == "on")
{
this.AutoAnswerState = true;
}
else if (value == "off")
{
this.AutoAnswerState = false;
}
AutoAnswerFeedback.FireUpdate();
}
else if (customName == Tags.hookStatusTag)
{
if (value == "true")
{
this.OffHook = true;
}
else if (value == "false")
{
this.OffHook = false;
}
this.OffHookFeedback.FireUpdate();
}
}
public void DoNotDisturbToggle()
{
int dndStateInt = !DoNotDisturbState ? 1 : 0;
Parent.SendLine(string.Format("csv {0} {1}", Tags.doNotDisturbTag, dndStateInt));
}
public void DoNotDisturbOn()
{
Parent.SendLine(string.Format("csv {0} 1", Tags.doNotDisturbTag));
}
public void DoNotDisturbOff()
{
Parent.SendLine(string.Format("csv {0} 0", Tags.doNotDisturbTag));
}
public void AutoAnswerToggle()
{
int autoAnswerStateInt = !AutoAnswerState ? 1 : 0;
Parent.SendLine(string.Format("csv {0} {1}", Tags.autoAnswerTag, autoAnswerStateInt));
}
public void AutoAnswerOn()
{
Parent.SendLine(string.Format("csv {0} 1", Tags.autoAnswerTag));
}
public void AutoAnswerOff()
{
Parent.SendLine(string.Format("csv {0} 0", Tags.autoAnswerTag));
}
private void PollKeypad()
{
Thread.Sleep(50);
Parent.SendLine(string.Format("cg {0}", Tags.dialStringTag));
}
public void SendKeypad(eKeypadKeys button)
{
string keypadTag = null;
switch (button)
{
case eKeypadKeys.Num0: keypadTag = Tags.keypad0Tag; break;
case eKeypadKeys.Num1: keypadTag = Tags.keypad1Tag; break;
case eKeypadKeys.Num2: keypadTag = Tags.keypad2Tag; break;
case eKeypadKeys.Num3: keypadTag = Tags.keypad3Tag; break;
case eKeypadKeys.Num4: keypadTag = Tags.keypad4Tag; break;
case eKeypadKeys.Num5: keypadTag = Tags.keypad5Tag; break;
case eKeypadKeys.Num6: keypadTag = Tags.keypad6Tag; break;
case eKeypadKeys.Num7: keypadTag = Tags.keypad7Tag; break;
case eKeypadKeys.Num8: keypadTag = Tags.keypad8Tag; break;
case eKeypadKeys.Num9: keypadTag = Tags.keypad9Tag; break;
case eKeypadKeys.Pound: keypadTag = Tags.keypadPoundTag; break;
case eKeypadKeys.Star: keypadTag = Tags.keypadStarTag; break;
case eKeypadKeys.Backspace: keypadTag = Tags.keypadBackspaceTag; break;
case eKeypadKeys.Clear: keypadTag = Tags.keypadClearTag; break;
}
if (keypadTag != null)
{
var cmdToSend = string.Format("ct {0}", keypadTag);
Parent.SendLine(cmdToSend);
PollKeypad();
}
}
public void SendSubscriptionCommand(string instanceTag, string changeGroup)
{
// Subscription string format: InstanceTag subscribe attributeCode Index1 customName responseRate
// Ex: "RoomLevel subscribe level 1 MyRoomLevel 500"
var cmd = string.Format("cga {0} {1}", changeGroup, instanceTag);
Parent.SendLine(cmd);
}
public void Dial()
{
if (!this.OffHook)
{
Parent.SendLine(string.Format("ct {0}", Tags.connectTag));
}
else
{
Parent.SendLine(string.Format("ct {0}", Tags.disconnectTag));
}
Thread.Sleep(50);
Parent.SendLine(string.Format("cg {0}", Tags.callStatusTag));
}
public void Dial(string number)
{
}
public void EndCall(CodecActiveCallItem activeCall)
{
}
public void EndAllCalls()
{
}
public void AcceptCall(CodecActiveCallItem item)
{
}
public void RejectCall(CodecActiveCallItem item)
{
}
public void SendDtmf(string digit)
{
}
public enum eKeypadKeys
{
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
Num0,
Star,
Pound,
Clear,
Backspace
}
}
}

View File

@@ -0,0 +1,307 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
public class QscDspLevelControl : QscDspControlPoint, IBasicVolumeWithFeedback, IKeyed
{
bool _IsMuted;
ushort _VolumeLevel;
public BoolFeedback MuteFeedback { get; private set; }
public IntFeedback VolumeLevelFeedback { get; private set; }
public bool Enabled { get; set; }
public ePdtLevelTypes Type;
CTimer VolumeUpRepeatTimer;
CTimer VolumeDownRepeatTimer;
/// <summary>
/// Used for to identify level subscription values
/// </summary>
public string LevelCustomName { get; private set; }
/// <summary>
/// Used for to identify mute subscription values
/// </summary>
public string MuteCustomName { get; private set; }
/// <summary>
/// Minimum fader level
/// </summary>
double MinLevel;
/// <summary>
/// Maximum fader level
/// </summary>
double MaxLevel;
/// <summary>
/// Checks if a valid subscription string has been recieved for all subscriptions
/// </summary>
public bool IsSubsribed
{
get
{
bool isSubscribed = false;
if (HasMute && MuteIsSubscribed)
isSubscribed = true;
if (HasLevel && LevelIsSubscribed)
isSubscribed = true;
return isSubscribed;
}
}
public bool AutomaticUnmuteOnVolumeUp { get; private set; }
public bool HasMute { get; private set; }
public bool HasLevel { get; private set; }
bool MuteIsSubscribed;
bool LevelIsSubscribed;
//public TesiraForteLevelControl(string label, string id, int index1, int index2, bool hasMute, bool hasLevel, BiampTesiraForteDsp parent)
// : base(id, index1, index2, parent)
//{
// Initialize(label, hasMute, hasLevel);
//}
public QscDspLevelControl(string key, QscDspLevelControlBlockConfig config, QscDsp parent)
: base(config.LevelInstanceTag, config.MuteInstanceTag, parent)
{
if (!config.Disabled)
{
Initialize(key, config);
}
}
/// <summary>
/// Initializes this attribute based on config values and generates subscriptions commands and adds commands to the parent's queue.
/// </summary>
public void Initialize(string key, QscDspLevelControlBlockConfig config)
{
Key = string.Format("{0}--{1}", Parent.Key, key);
Enabled = true;
DeviceManager.AddDevice(this);
if (config.IsMic)
{
Type = ePdtLevelTypes.microphone;
}
else
{
Type = ePdtLevelTypes.speaker;
}
Debug.Console(2, this, "Adding LevelControl '{0}'", Key);
this.IsSubscribed = false;
MuteFeedback = new BoolFeedback(() => _IsMuted);
VolumeLevelFeedback = new IntFeedback(() => _VolumeLevel);
VolumeUpRepeatTimer = new CTimer(VolumeUpRepeat, Timeout.Infinite);
VolumeDownRepeatTimer = new CTimer(VolumeDownRepeat, Timeout.Infinite);
LevelCustomName = config.Label;
HasMute = config.HasMute;
HasLevel = config.HasLevel;
}
public void Subscribe()
{
// Do subscriptions and blah blah
// Subscribe to mute
if (this.HasMute)
{
SendSubscriptionCommand(this.MuteInstanceTag, "1");
// SendSubscriptionCommand(config. , "mute", 500);
}
// Subscribe to level
if (this.HasLevel)
{
SendSubscriptionCommand(this.LevelInstanceTag, "1");
// SendSubscriptionCommand(this.con, "level", 250);
//SendFullCommand("get", "minLevel", null);
//SendFullCommand("get", "maxLevel", null);
}
}
/// <summary>
/// Parses the response from the DspBase
/// </summary>
/// <param name="customName"></param>
/// <param name="value"></param>
public void ParseSubscriptionMessage(string customName, string value)
{
// Check for valid subscription response
Debug.Console(1, this, "Level {0} Response: '{1}'", customName, value);
if (customName == MuteInstanceTag)
{
if (value == "muted")
{
_IsMuted = true;
MuteIsSubscribed = true;
}
else if (value == "unmuted")
{
_IsMuted = false;
MuteIsSubscribed = true;
}
MuteFeedback.FireUpdate();
}
else if (customName == LevelInstanceTag)
{
var _value = Double.Parse(value);
_VolumeLevel = (ushort)(_value * 65535);
Debug.Console(1, this, "Level {0} VolumeLevel: '{1}'", customName, _VolumeLevel);
LevelIsSubscribed = true;
VolumeLevelFeedback.FireUpdate();
}
}
/// <summary>
/// Turns the mute off
/// </summary>
public void MuteOff()
{
SendFullCommand("csv", this.MuteInstanceTag, "0");
}
/// <summary>
/// Turns the mute on
/// </summary>
public void MuteOn()
{
SendFullCommand("csv", this.MuteInstanceTag, "1");
}
/// <summary>
/// Sets the volume to a specified level
/// </summary>
/// <param name="level"></param>
public void SetVolume(ushort level)
{
Debug.Console(1, this, "volume: {0}", level);
// Unmute volume if new level is higher than existing
if (AutomaticUnmuteOnVolumeUp && _IsMuted)
{
MuteOff();
}
double newLevel = Scale(level);
Debug.Console(1, this, "newVolume: {0}", newLevel);
SendFullCommand("csp", this.LevelInstanceTag, string.Format("{0}", newLevel));
}
/// <summary>
/// Toggles mute status
/// </summary>
public void MuteToggle()
{
if (_IsMuted)
{
SendFullCommand("csv", this.MuteInstanceTag, "0");
}
else
{
SendFullCommand("csv", this.MuteInstanceTag, "1");
}
}
public void VolumeUpRepeat(object callbackObject)
{
this.VolumeUp(true);
}
public void VolumeDownRepeat(object callbackObject)
{
this.VolumeDown(true);
}
public void VolumeDown(bool press)
{
if (press)
{
VolumeDownRepeatTimer.Reset(100);
SendFullCommand("css ", this.LevelInstanceTag, "--");
}
else
{
VolumeDownRepeatTimer.Stop();
// VolumeDownRepeatTimer.Dispose();
}
}
/// <summary>
/// Increments volume level
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeUp(bool press)
{
if (press)
{
VolumeUpRepeatTimer.Reset(100);
SendFullCommand("css ", this.LevelInstanceTag, "++");
if (AutomaticUnmuteOnVolumeUp)
if (!_IsMuted)
MuteOff();
}
else
{
VolumeUpRepeatTimer.Stop();
}
}
/// <returns></returns>
double Scale(double input)
{
Debug.Console(1, this, "Scaling (double) input '{0}'",input );
var output = (input / 65535);
Debug.Console(1, this, "Scaled output '{0}'", output);
return output;
}
}
public enum ePdtLevelTypes
{
speaker = 0,
microphone = 1
}
}

View File

@@ -0,0 +1,88 @@
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.Devices.Common.DSP
{
/// <summary>
///
/// </summary>
public class QscDspPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
/// <summary>
/// These are key-value pairs, string id, string type.
/// Valid types are level and mute.
/// Need to include the index values somehow
/// </summary>
public Dictionary<string, QscDspLevelControlBlockConfig> LevelControlBlocks { get; set; }
public Dictionary<string, QscDialerConfig> dialerControlBlocks { get; set; }
public Dictionary<string, QscDspPresets> presets { get; set; }
// public Dictionary<string, BiampTesiraForteDialerControlBlockConfig> DialerControlBlocks {get; set;}
}
public interface IQscDspBasicLevel : IBasicVolumeWithFeedback
{
/// <summary>
/// In BiAmp: Instance Tag, QSC: Named Control, Polycom:
/// </summary>
string LevelInstanceTag { get; set; }
string MuteInstanceTag { get; set; }
bool HasMute { get; }
bool HasLevel { get; }
bool AutomaticUnmuteOnVolumeUp { get; }
}
public class QscDspLevelControlBlockConfig
{
public bool Disabled { get; set; }
public string Label { get; set; }
public string LevelInstanceTag { get; set; }
public string MuteInstanceTag { get; set; }
public bool HasMute { get; set; }
public bool HasLevel { get; set; }
public bool IsMic { get; set; }
}
public class QscDialerConfig
{
public string incomingCallRingerTag {get; set;}
public string dialStringTag {get; set;}
public string disconnectTag {get; set;}
public string connectTag {get; set;}
public string callStatusTag {get; set;}
public string hookStatusTag {get; set;}
public string doNotDisturbTag { get; set; }
public string autoAnswerTag { get; set; }
public string keypadBackspaceTag {get; set;}
public string keypadClearTag {get; set;}
public string keypad1Tag {get; set;}
public string keypad2Tag {get; set;}
public string keypad3Tag {get; set;}
public string keypad4Tag {get; set;}
public string keypad5Tag {get; set;}
public string keypad6Tag {get; set;}
public string keypad7Tag {get; set;}
public string keypad8Tag {get; set;}
public string keypad9Tag {get; set;}
public string keypad0Tag {get; set;}
public string keypadPoundTag {get; set;}
public string keypadStarTag {get; set;}
public bool ClearOnHangup { get; set; }
}
public class QscDspPresets
{
public string label { get; set; }
public string preset { get; set; }
}
}

View File

@@ -0,0 +1,314 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Common
{
public class IRBlurayBase : Device, IDiscPlayerControls, IUiDisplayInfo, IRoutingOutputs, IUsageTracking
{
public IrOutputPortController IrPort { get; private set; }
public uint DisplayUiType { get { return DisplayUiConstants.TypeBluray; } }
public IRBlurayBase(string key, string name, IrOutputPortController portCont)
: base(key, name)
{
IrPort = portCont;
DeviceManager.AddDevice(portCont);
HasKeypadAccessoryButton1 = true;
KeypadAccessoryButton1Command = "Clear";
KeypadAccessoryButton1Label = "Clear";
HasKeypadAccessoryButton2 = true;
KeypadAccessoryButton2Command = "NumericEnter";
KeypadAccessoryButton2Label = "Enter";
PowerIsOnFeedback = new BoolFeedback(() => _PowerIsOn);
HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this);
AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio,
eRoutingPortConnectionType.DigitalAudio, null, this);
OutputPorts = new RoutingPortCollection<RoutingOutputPort> { HdmiOut, AnyAudioOut };
}
#region IDPad Members
public void Up(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease);
}
public void Down(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease);
}
public void Left(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease);
}
public void Right(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease);
}
public void Select(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease);
}
public void Menu(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease);
}
public void Exit(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease);
}
#endregion
#region INumericKeypad Members
public void Digit0(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_0, pressRelease);
}
public void Digit1(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_1, pressRelease);
}
public void Digit2(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_2, pressRelease);
}
public void Digit3(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_3, pressRelease);
}
public void Digit4(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_4, pressRelease);
}
public void Digit5(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_5, pressRelease);
}
public void Digit6(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_6, pressRelease);
}
public void Digit7(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_7, pressRelease);
}
public void Digit8(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_8, pressRelease);
}
public void Digit9(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_9, pressRelease);
}
/// <summary>
/// Defaults to true
/// </summary>
public bool HasKeypadAccessoryButton1 { get; set; }
/// <summary>
/// Defaults to "-"
/// </summary>
public string KeypadAccessoryButton1Label { get; set; }
/// <summary>
/// Defaults to "Dash"
/// </summary>
public string KeypadAccessoryButton1Command { get; set; }
public void KeypadAccessoryButton1(bool pressRelease)
{
IrPort.PressRelease(KeypadAccessoryButton1Command, pressRelease);
}
/// <summary>
/// Defaults to true
/// </summary>
public bool HasKeypadAccessoryButton2 { get; set; }
/// <summary>
/// Defaults to "Enter"
/// </summary>
public string KeypadAccessoryButton2Label { get; set; }
/// <summary>
/// Defaults to "Enter"
/// </summary>
public string KeypadAccessoryButton2Command { get; set; }
public void KeypadAccessoryButton2(bool pressRelease)
{
IrPort.PressRelease(KeypadAccessoryButton2Command, pressRelease);
}
#endregion
#region IChannelFunctions Members
public void ChannelUp(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_CH_PLUS, pressRelease);
}
public void ChannelDown(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_CH_MINUS, pressRelease);
}
public void LastChannel(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_LAST, pressRelease);
}
public void Guide(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_GUIDE, pressRelease);
}
public void Info(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_INFO, pressRelease);
}
#endregion
#region IColorFunctions Members
public void Red(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RED, pressRelease);
}
public void Green(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_GREEN, pressRelease);
}
public void Yellow(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_YELLOW, pressRelease);
}
public void Blue(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_BLUE, pressRelease);
}
#endregion
#region IRoutingOutputs Members
public RoutingOutputPort HdmiOut { get; private set; }
public RoutingOutputPort AnyAudioOut { get; private set; }
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
#region IPower Members
public void PowerOn()
{
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, 200);
_PowerIsOn = true;
}
public void PowerOff()
{
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, 200);
_PowerIsOn = false;
}
public void PowerToggle()
{
IrPort.Pulse(IROutputStandardCommands.IROut_POWER, 200);
_PowerIsOn = false;
}
public BoolFeedback PowerIsOnFeedback { get; set; }
bool _PowerIsOn;
#endregion
#region ITransport Members
public void Play(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease);
}
public void Pause(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_PAUSE, pressRelease);
}
public void Rewind(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease);
}
public void FFwd(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease);
}
public void ChapMinus(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_TRACK_MINUS, pressRelease);
}
public void ChapPlus(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_TRACK_PLUS, pressRelease);
}
public void Stop(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_STOP, pressRelease);
}
public void Record(bool pressRelease)
{
}
#endregion
#region IUsageTracking Members
public UsageTracking UsageTracker { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,720 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.CrestronThread;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Displays
{
/// <summary>
///
/// </summary>
public class AvocorDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, ICommunicationMonitor, IInputDisplayPort1,
IInputHdmi1, IInputHdmi2, IInputHdmi3, IInputHdmi4, IInputVga1
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public byte ID { get; private set; }
/// <summary>
/// 0x08
/// </summary>
const byte InputVga1Value = 0x00;
/// <summary>
/// 0x09
/// </summary>
const byte InputHdmi1Value = 0x09;
/// <summary>
/// 0x0a
/// </summary>
const byte InputHdmi2Value = 0x0a;
/// <summary>
/// 0x0b
/// </summary>
const byte InputHdmi3Value = 0x0b;
/// <summary>
/// 0x0c
/// </summary>
const byte InputHdmi4Value = 0x0c;
/// <summary>
/// 0c0d
/// </summary>
const byte InputDisplayPort1Value = 0x0d;
/// <summary>
/// 0x0e
/// </summary>
const byte InputIpcOpsValue = 0x0e;
/// <summary>
/// 0x11
/// </summary>
const byte InputHdmi5Value = 0x11;
/// <summary>
/// 0x12
/// </summary>
const byte InputMediaPlayerValue = 0x12;
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
ushort _VolumeLevelForSig;
int _LastVolumeSent;
ushort _PreMuteVolumeLevel;
bool _IsMuted;
RoutingInputPort _CurrentInputPort;
ActionIncrementer VolumeIncrementer;
bool VolumeIsRamping;
public bool IsInStandby { get; private set; }
protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } }
protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } }
protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } }
protected override Func<string> CurrentInputFeedbackFunc { get { return () => _CurrentInputPort.Key; } }
/// <summary>
/// Constructor for IBasicCommunication
/// </summary>
public AvocorDisplay(string key, string name, IBasicCommunication comm, string id)
: base(key, name)
{
Communication = comm;
//Communication.BytesReceived += new EventHandler<GenericCommMethodReceiveBytesArgs>(Communication_BytesReceived);
PortGather = new CommunicationGather(Communication, '\x08');
PortGather.IncludeDelimiter = true;
PortGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(PortGather_LineReceived);
ID = id == null ? (byte)0x01 : Convert.ToByte(id, 16); // If id is null, set default value of 0x01, otherwise assign value passed in constructor
Init();
}
/// <summary>
/// Constructor for TCP
/// </summary>
public AvocorDisplay(string key, string name, string hostname, int port, string id)
: base(key, name)
{
Communication = new GenericTcpIpClient(key + "-tcp", hostname, port, 5000);
PortGather = new CommunicationGather(Communication, '\x0d');
PortGather.IncludeDelimiter = true;
PortGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(PortGather_LineReceived);
ID = id == null ? (byte)0x01 : Convert.ToByte(id, 16); // If id is null, set default value of 0x01, otherwise assign value passed in constructor
Init();
}
/// <summary>
/// Constructor for COM
/// </summary>
public AvocorDisplay(string key, string name, ComPort port, ComPort.ComPortSpec spec, string id)
: base(key, name)
{
Communication = new ComPortController(key + "-com", port, spec);
PortGather = new CommunicationGather(Communication, '\x0d');
PortGather.IncludeDelimiter = true;
PortGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(PortGather_LineReceived);
ID = id == null ? (byte)0x01 : Convert.ToByte(id, 16); // If id is null, set default value of 0x01, otherwise assign value passed in constructor
Init();
}
void AddRoutingInputPort(RoutingInputPort port, byte fbMatch)
{
port.FeedbackMatchObject = fbMatch;
InputPorts.Add(port);
}
void Init()
{
WarmupTime = 10000;
CooldownTime = 8000;
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, StatusGet);
DeviceManager.AddDevice(CommunicationMonitor);
VolumeIncrementer = new ActionIncrementer(655, 0, 65535, 800, 80,
v => SetVolume((ushort)v),
() => _LastVolumeSent);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi1), this), InputHdmi1Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi2), this), InputHdmi2Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi3), this), InputHdmi3Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi4), this), InputHdmi4Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn5, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi5), this), InputHdmi5Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.DisplayPortIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.DisplayPort, new Action(InputDisplayPort1), this), InputDisplayPort1Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Dvi, new Action(InputVga1), this), InputVga1Value);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.IpcOps, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Composite, new Action(InputIpcOps), this), InputIpcOpsValue);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.MediaPlayer, eRoutingSignalType.Video,
eRoutingPortConnectionType.Vga, new Action(InputMediaPlayer), this), InputMediaPlayerValue);
VolumeLevelFeedback = new IntFeedback(() => { return _VolumeLevelForSig; });
MuteFeedback = new BoolFeedback(() => _IsMuted);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override bool CustomActivate()
{
Communication.Connect();
var socket = Communication as ISocketStatus;
if (socket != null)
{
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
StatusGet();
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
if (e.Client.IsConnected)
StatusGet();
}
public override FeedbackCollection<Feedback> Feedbacks
{
get
{
var list = base.Feedbacks;
list.AddRange(new List<Feedback>
{
VolumeLevelFeedback,
MuteFeedback,
CurrentInputFeedback
});
return list;
}
}
///// <summary>
///// /
///// </summary>
///// <param name="sender"></param>
//void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e)
//{
// // This is probably not thread-safe buffering
// // Append the incoming bytes with whatever is in the buffer
// var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length];
// IncomingBuffer.CopyTo(newBytes, 0);
// e.Bytes.CopyTo(newBytes, IncomingBuffer.Length);
// if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
// Debug.Console(2, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes));
// // Need to find AA FF and have
// for (int i = 0; i < newBytes.Length; i++)
// {
// if (newBytes[i] == 0xAA && newBytes[i + 1] == 0xFF)
// {
// newBytes = newBytes.Skip(i).ToArray(); // Trim off junk if there's "dirt" in the buffer
// // parse it
// // If it's at least got the header, then process it,
// while (newBytes.Length > 4 && newBytes[0] == 0xAA && newBytes[1] == 0xFF)
// {
// var msgLen = newBytes[3];
// // if the buffer is shorter than the header (3) + message (msgLen) + checksum (1),
// // give and save it for next time
// if (newBytes.Length < msgLen + 4)
// break;
// // Good length, grab the message
// var message = newBytes.Skip(4).Take(msgLen).ToArray();
// // At this point, the ack/nak is the first byte
// if (message[0] == 0x41)
// {
// switch (message[1]) // type byte
// {
// case 0x00: // General status
// UpdatePowerFB(message[2], message[5]); // "power" can be misrepresented when the display sleeps
// UpdateInputFb(message[5]);
// UpdateVolumeFB(message[3]);
// UpdateMuteFb(message[4]);
// UpdateInputFb(message[5]);
// break;
// case 0x11:
// UpdatePowerFB(message[2]);
// break;
// case 0x12:
// UpdateVolumeFB(message[2]);
// break;
// case 0x13:
// UpdateMuteFb(message[2]);
// break;
// case 0x14:
// UpdateInputFb(message[2]);
// break;
// default:
// break;
// }
// }
// // Skip over what we've used and save the rest for next time
// newBytes = newBytes.Skip(5 + msgLen).ToArray();
// }
// break; // parsing will mean we can stop looking for header in loop
// }
// }
// // Save whatever partial message is here
// IncomingBuffer = newBytes;
//}
void PortGather_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
{
Debug.Console(1, this, "Receivied: '{0}'", ComTextHelper.GetEscapedText(e.Text));
if (e.Text.IndexOf("\x50\x4F\x57") > -1)
{
// Power Status Response
var value = e.Text.ToCharArray();
switch (value[6])
{
case '\x00':
{
_PowerIsOn = false;
break;
}
case '\x01':
{
_PowerIsOn = true;
break;
}
}
PowerIsOnFeedback.FireUpdate();
Debug.Console(1, this, "PowerIsOn State: {0}", PowerIsOnFeedback.BoolValue);
}
else if (e.Text.IndexOf("\x4D\x49\x4E") > -1)
{
var value = e.Text.ToCharArray();
var b = value[6];
var newInput = InputPorts.FirstOrDefault(i => i.FeedbackMatchObject.Equals(b));
if (newInput != null && newInput != _CurrentInputPort)
{
_CurrentInputPort = newInput;
CurrentInputFeedback.FireUpdate();
Debug.Console(1, this, "Current Input: {0}", CurrentInputFeedback.StringValue);
}
}
else if (e.Text.IndexOf("\x56\x4F\x4C") > -1)
{
// Volume Status Response
var value = e.Text.ToCharArray();
var b = value[6];
var newVol = (ushort)NumericalHelpers.Scale((double)b, 0, 100, 0, 65535);
if (!VolumeIsRamping)
_LastVolumeSent = newVol;
if (newVol != _VolumeLevelForSig)
{
_VolumeLevelForSig = newVol;
VolumeLevelFeedback.FireUpdate();
if (_VolumeLevelForSig > 0)
_IsMuted = false;
else
_IsMuted = true;
MuteFeedback.FireUpdate();
Debug.Console(1, this, "Volume Level: {0}", VolumeLevelFeedback.IntValue);
}
}
}
/// <summary>
///
/// </summary>
void UpdatePowerFB(byte powerByte)
{
var newVal = powerByte == 1;
if (newVal != _PowerIsOn)
{
_PowerIsOn = newVal;
PowerIsOnFeedback.FireUpdate();
}
}
/// <summary>
/// Updates power status from general updates where source is included.
/// Compensates for errant standby / power off hiccups by ignoring
/// power off states with input < 0x10
/// </summary>
void UpdatePowerFB(byte powerByte, byte inputByte)
{
// This should reject errant power feedbacks when switching away from input on standby.
if (powerByte == 0x01 && inputByte < 0x10)
IsInStandby = true;
if (powerByte == 0x00 && IsInStandby) // Ignore power off if coming from standby - glitch
{
IsInStandby = false;
return;
}
UpdatePowerFB(powerByte);
}
/// <summary>
///
/// </summary>
void UpdateVolumeFB(byte b)
{
var newVol = (ushort)NumericalHelpers.Scale((double)b, 0, 100, 0, 65535);
if (!VolumeIsRamping)
_LastVolumeSent = newVol;
if (newVol != _VolumeLevelForSig)
{
_VolumeLevelForSig = newVol;
VolumeLevelFeedback.FireUpdate();
}
}
/// <summary>
///
/// </summary>
void UpdateMuteFb(byte b)
{
var newMute = b == 1;
if (newMute != _IsMuted)
{
_IsMuted = newMute;
MuteFeedback.FireUpdate();
}
}
/// <summary>
///
/// </summary>
void UpdateInputFb(byte b)
{
var newInput = InputPorts.FirstOrDefault(i => i.FeedbackMatchObject.Equals(b));
if (newInput != null && newInput != _CurrentInputPort)
{
_CurrentInputPort = newInput;
CurrentInputFeedback.FireUpdate();
}
}
/// <summary>
/// Formats an outgoing message. Replaces third byte with ID and replaces last byte with checksum
/// </summary>
/// <param name="b"></param>
void SendBytes(byte[] b)
{
b[1] = ID;
var command = b.ToString();
Debug.Console(1, this, "Sending: '{0}'",ComTextHelper.GetEscapedText(b));
Communication.SendBytes(b);
}
/// <summary>
///
/// </summary>
public void StatusGet()
{
PowerGet();
CrestronEnvironment.Sleep(100);
InputGet();
CrestronEnvironment.Sleep(100);
VolumeGet();
}
/// <summary>
///
/// </summary>
public override void PowerOn()
{
//Send(PowerOnCmd);
SendBytes(new byte[] { 0x07, ID, 0x02, 0x50, 0x4F, 0x57, 0x01, 0x08, 0x0d });
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate();
// Fake power-up cycle
WarmupTimer = new CTimer(o =>
{
_IsWarmingUp = false;
_PowerIsOn = true;
IsWarmingUpFeedback.FireUpdate();
PowerIsOnFeedback.FireUpdate();
}, WarmupTime);
}
}
/// <summary>
///
/// </summary>
public override void PowerOff()
{
// If a display has unreliable-power off feedback, just override this and
// remove this check.
if (!_IsWarmingUp && !_IsCoolingDown) // PowerIsOnFeedback.BoolValue &&
{
//Send(PowerOffCmd);
SendBytes(new byte[] { 0x07, ID, 0x02, 0x50, 0x4F, 0x57, 0x00, 0x08, 0x0d });
_IsCoolingDown = true;
_PowerIsOn = false;
PowerIsOnFeedback.FireUpdate();
IsCoolingDownFeedback.FireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
_IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate();
}, CooldownTime);
}
}
public override void PowerToggle()
{
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn();
}
public void PowerGet()
{
SendBytes(new byte[] { 0x07, ID, 0x01, 0x50, 0x4F, 0x57, 0x08, 0x0d });
}
public void InputHdmi1()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputHdmi1Value, 0x08, 0x0d });
}
public void InputHdmi2()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputHdmi2Value, 0x08, 0x0d });
}
public void InputHdmi3()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputHdmi3Value, 0x08, 0x0d });
}
public void InputHdmi4()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputHdmi4Value, 0x08, 0x0d });
}
public void InputHdmi5()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputHdmi5Value, 0x08, 0x0d });
}
public void InputDisplayPort1()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputDisplayPort1Value, 0x08, 0x0d });
}
public void InputVga1()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputVga1Value, 0x08, 0x0d });
}
public void InputIpcOps()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputIpcOpsValue, 0x08, 0x0d });
}
public void InputMediaPlayer()
{
SendBytes(new byte[] { 0x07, ID, 0x02, 0x4D, 0x49, 0x4E, InputMediaPlayerValue, 0x08, 0x0d });
}
public void InputGet()
{
SendBytes(new byte[] { 0x07, ID, 0x01, 0x4D, 0x49, 0x4E, 0x08, 0x0d });
}
public void VolumeGet()
{
SendBytes(new byte[] { 0x07, ID, 0x01, 0x56, 0x4F, 0x4C, 0x08, 0x0d });
}
/// <summary>
/// Executes a switch, turning on display if necessary.
/// </summary>
/// <param name="selector"></param>
public override void ExecuteSwitch(object selector)
{
//if (!(selector is Action))
// Debug.Console(1, this, "WARNING: ExecuteSwitch cannot handle type {0}", selector.GetType());
if (_PowerIsOn)
(selector as Action)();
else // if power is off, wait until we get on FB to send it.
{
// One-time event handler to wait for power on before executing switch
EventHandler<FeedbackEventArgs> handler = null; // necessary to allow reference inside lambda to handler
handler = (o, a) =>
{
if (!_IsWarmingUp) // Done warming
{
IsWarmingUpFeedback.OutputChange -= handler;
(selector as Action)();
}
};
IsWarmingUpFeedback.OutputChange += handler; // attach and wait for on FB
PowerOn();
}
}
/// <summary>
/// Scales the level to the range of the display and sends the command
/// </summary>
/// <param name="level"></param>
public void SetVolume(ushort level)
{
_LastVolumeSent = level;
var scaled = (int)NumericalHelpers.Scale(level, 0, 65535, 0, 100);
// The inputs to Scale ensure that byte won't overflow
SendBytes(new byte[] { 0x07, ID, 0x02, 0x56, 0x4F, 0x4C, Convert.ToByte(scaled), 0x08, 0x0d });
}
#region IBasicVolumeWithFeedback Members
public IntFeedback VolumeLevelFeedback { get; private set; }
public BoolFeedback MuteFeedback { get; private set; }
/// <summary>
///
/// </summary>
public void MuteOff()
{
SetVolume(_PreMuteVolumeLevel);
}
/// <summary>
///
/// </summary>
public void MuteOn()
{
_PreMuteVolumeLevel = _VolumeLevelForSig;
SetVolume(0);
}
///// <summary>
/////
///// </summary>
//public void MuteGet()
//{
// SendBytes(new byte[] { 0x07, ID, 0x01, });
//}
#endregion
#region IBasicVolumeControls Members
/// <summary>
///
/// </summary>
public void MuteToggle()
{
if (_IsMuted)
MuteOff();
else
MuteOn();
}
/// <summary>
///
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeDown(bool pressRelease)
{
if (pressRelease)
{
VolumeIncrementer.StartDown();
VolumeIsRamping = true;
}
else
{
VolumeIsRamping = false;
VolumeIncrementer.Stop();
}
}
/// <summary>
///
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeUp(bool pressRelease)
{
if (pressRelease)
{
VolumeIncrementer.StartUp();
VolumeIsRamping = true;
}
else
{
VolumeIsRamping = false;
VolumeIncrementer.Stop();
}
}
#endregion
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Displays
{
public abstract class ComTcpDisplayBase : DisplayBase, IPower
{
/// <summary>
/// Sets the communication method for this - swaps out event handlers and output handlers
/// </summary>
public IBasicCommunication CommunicationMethod
{
get { return _CommunicationMethod; }
set
{
if (_CommunicationMethod != null)
_CommunicationMethod.BytesReceived -= this.CommunicationMethod_BytesReceived;
// Outputs???
_CommunicationMethod = value;
if (_CommunicationMethod != null)
_CommunicationMethod.BytesReceived += this.CommunicationMethod_BytesReceived;
// Outputs?
}
}
IBasicCommunication _CommunicationMethod;
public ComTcpDisplayBase(string key, string name)
: base(key, name)
{
}
protected abstract void CommunicationMethod_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs args);
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Devices.Displays
{
public class DisplayDeviceFactory
{
public static IKeyed GetDevice(DeviceConfig dc)
{
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var typeName = dc.Type.ToLower();
try
{
if (typeName == "necmpsx")
{
var comm = CommFactory.CreateCommForDevice(dc);
if (comm != null)
return new NecPSXMDisplay(dc.Key, dc.Name, comm);
}
if (typeName == "panasonicthef")
{
var comm = CommFactory.CreateCommForDevice(dc);
if (comm != null)
return new PanasonicThefDisplay(dc.Key, dc.Name, comm);
}
else if(typeName == "samsungmdc")
{
var comm = CommFactory.CreateCommForDevice(dc);
if (comm != null)
return new SamsungMDC(dc.Key, dc.Name, comm, dc.Properties["id"].Value<string>());
}
if (typeName == "avocorvtf")
{
var comm = CommFactory.CreateCommForDevice(dc);
if (comm != null)
return new AvocorDisplay(dc.Key, dc.Name, comm, null);
}
}
catch (Exception e)
{
Debug.Console(0, "Displays factory: Exception creating device type {0}, key {1}: \nCONFIG JSON: {2} \nERROR: {3}\n\n",
dc.Type, dc.Key, JsonConvert.SerializeObject(dc), e);
return null;
}
return null;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Displays
{
public interface IInputHdmi1 { void InputHdmi1(); }
public interface IInputHdmi2 { void InputHdmi2(); }
public interface IInputHdmi3 { void InputHdmi3(); }
public interface IInputHdmi4 { void InputHdmi4(); }
public interface IInputDisplayPort1 { void InputDisplayPort1(); }
public interface IInputDisplayPort2 { void InputDisplayPort2(); }
public interface IInputVga1 { void InputVga1(); }
}

View File

@@ -0,0 +1,356 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Displays
{
/// <summary>
///
/// </summary>
public class NecPSXMDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, ICommunicationMonitor
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
#region Command constants
public const string InputGetCmd = "\x01\x30\x41\x30\x43\x30\x36\x02\x30\x30\x36\x30\x03\x03\x0D";
public const string Hdmi1Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x31\x31\x03\x72\x0d";
public const string Hdmi2Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x31\x32\x03\x71\x0D";
public const string Hdmi3Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x38\x32\x03\x78\x0D";
public const string Hdmi4Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x38\x33\x03\x79\x0D";
public const string Dp1Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x30\x46\x03\x04\x0D";
public const string Dp2Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x31\x30\x03\x73\x0D";
public const string Dvi1Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x30\x33\x03\x71\x0d";
public const string Video1Cmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x30\x35\x03\x77\x0D";
public const string VgaCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x30\x31\x03\x73\x0D";
public const string RgbCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x30\x30\x30\x30\x32\x03\x70\x0D";
public const string PowerOnCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x30\x33\x44\x36\x30\x30\x30\x31\x03\x73\x0D";
public const string PowerOffCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x30\x33\x44\x36\x30\x30\x30\x34\x03\x76\x0D";
public const string PowerToggleIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x30\x33\x30\x33\x03\x02\x0D";
public const string MuteOffCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x38\x44\x30\x30\x30\x30\x03\x08\x0D";
public const string MuteOnCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x38\x44\x30\x30\x30\x31\x03\x09\x0D";
public const string MuteToggleIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x31\x42\x30\x33\x03\x72\x0D";
public const string MuteGetCmd = "\x01\x30\x41\x30\x43\x30\x36\x02\x30\x30\x38\x44\x03\x79\x0D";
public const string VolumeGetCmd = "\x01\x30\x41\x30\x43\x30\x36\x02\x30\x30\x36\x32\x03\x01\x0D";
public const string VolumeLevelPartialCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x30\x30\x36\x32"; //\x46\x46\x46\x46\x03\xNN\x0D
public const string VolumeUpCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x31\x30\x41\x44\x30\x30\x30\x31\x03\x71\x0D";
public const string VolumeDownCmd = "\x01\x30\x41\x30\x45\x30\x41\x02\x31\x30\x41\x44\x30\x30\x30\x32\x03\x72\x0D";
public const string MenuIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x32\x30\x30\x33\x03\x03\x0D";
public const string UpIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x31\x35\x30\x33\x03\x05\x0D";
public const string DownIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x31\x34\x30\x33\x03\x04\x0D";
public const string LeftIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x32\x31\x30\x33\x03\x02\x0D";
public const string RightIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x32\x32\x30\x33\x03\x01\x0D";
public const string SelectIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x32\x33\x30\x33\x03\x00\x0D";
public const string ExitIrCmd = "\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x31\x30\x30\x30\x31\x46\x30\x33\x03\x76\x0D";
#endregion
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
ushort _VolumeLevel;
bool _IsMuted;
protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } }
protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } }
protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } }
protected override Func<string> CurrentInputFeedbackFunc { get { return () => "Not Implemented"; } }
/// <summary>
/// Constructor for IBasicCommunication
/// </summary>
public NecPSXMDisplay(string key, string name, IBasicCommunication comm)
: base(key, name)
{
Communication = comm;
Init();
}
/// <summary>
/// Constructor for TCP
/// </summary>
public NecPSXMDisplay(string key, string name, string hostname, int port)
: base(key, name)
{
Communication = new GenericTcpIpClient(key + "-tcp", hostname, port, 5000);
Init();
}
/// <summary>
/// Constructor for COM
/// </summary>
public NecPSXMDisplay(string key, string name, ComPort port, ComPort.ComPortSpec spec)
: base(key, name)
{
Communication = new ComPortController(key + "-com", port, spec);
Init();
}
void Init()
{
PortGather = new CommunicationGather(Communication, '\x0d');
PortGather.LineReceived += this.Port_LineReceived;
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, "xx\x0d");
InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi2), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi3), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi4), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.DisplayPortIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.DisplayPort, new Action(InputDisplayPort1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.DisplayPortIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.DisplayPort, new Action(InputDisplayPort2), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.DviIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Dvi, new Action(InputDvi1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.CompositeIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Composite, new Action(InputVideo1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video,
eRoutingPortConnectionType.Vga, new Action(InputVga), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.RgbIn, eRoutingSignalType.Video,
eRoutingPortConnectionType.Rgb, new Action(new Action(InputRgb)), this));
VolumeLevelFeedback = new IntFeedback(() => { return _VolumeLevel; });
MuteFeedback = new BoolFeedback(() => _IsMuted);
// new BoolCueActionPair(CommonBoolCue.Menu, b => { if(b) Send(MenuIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Up, b => { if(b) Send(UpIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Down, b => { if(b) Send(DownIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Left, b => { if(b) Send(LeftIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Right, b => { if(b) Send(RightIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Select, b => { if(b) Send(SelectIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Exit, b => { if(b) Send(ExitIrCmd); }),
//};
}
~NecPSXMDisplay()
{
PortGather = null;
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
return true;
}
public override FeedbackCollection<Feedback> Feedbacks
{
get
{
var list = base.Feedbacks;
list.AddRange(new List<Feedback>
{
});
return list;
}
}
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Received: '{0}'", ComTextHelper.GetEscapedText(args.Text));
if (args.Text=="DO SOMETHING HERE EVENTUALLY")
{
_IsMuted = true;
MuteFeedback.FireUpdate();
}
}
void AppendChecksumAndSend(string s)
{
int x = 0;
for (int i = 1; i < s.Length; i++)
x = x ^ s[i];
string send = s + (char)x + '\x0d';
Send(send);
}
void Send(string s)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Send: '{0}'", ComTextHelper.GetEscapedText(s));
Communication.SendText(s);
}
public override void PowerOn()
{
Send(PowerOnCmd);
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate();
// Fake power-up cycle
WarmupTimer = new CTimer(o =>
{
_IsWarmingUp = false;
_PowerIsOn = true;
IsWarmingUpFeedback.FireUpdate();
PowerIsOnFeedback.FireUpdate();
}, WarmupTime);
}
}
public override void PowerOff()
{
// If a display has unreliable-power off feedback, just override this and
// remove this check.
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
Send(PowerOffCmd);
_IsCoolingDown = true;
_PowerIsOn = false;
PowerIsOnFeedback.FireUpdate();
IsCoolingDownFeedback.FireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
Debug.Console(2, this, "Cooldown timer ending");
_IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate();
}, CooldownTime);
}
}
public override void PowerToggle()
{
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn();
}
public void InputHdmi1()
{
Send(Hdmi1Cmd);
}
public void InputHdmi2()
{
Send(Hdmi2Cmd);
}
public void InputHdmi3()
{
Send(Hdmi3Cmd);
}
public void InputHdmi4()
{
Send(Hdmi4Cmd);
}
public void InputDisplayPort1()
{
Send(Dp1Cmd);
}
public void InputDisplayPort2()
{
Send(Dp2Cmd);
}
public void InputDvi1()
{
Send(Dvi1Cmd);
}
public void InputVideo1()
{
Send(Video1Cmd);
}
public void InputVga()
{
Send(VgaCmd);
}
public void InputRgb()
{
Send(RgbCmd);
}
public override void ExecuteSwitch(object selector)
{
if (selector is Action)
(selector as Action).Invoke();
else
Debug.Console(1, this, "WARNING: ExecuteSwitch cannot handle type {0}", selector.GetType());
//Send((string)selector);
}
void SetVolume(ushort level)
{
var levelString = string.Format("{0}{1:X4}\x03", VolumeLevelPartialCmd, level);
AppendChecksumAndSend(levelString);
//Debug.Console(2, this, "Volume:{0}", ComTextHelper.GetEscapedText(levelString));
_VolumeLevel = level;
VolumeLevelFeedback.FireUpdate();
}
#region IBasicVolumeWithFeedback Members
public IntFeedback VolumeLevelFeedback { get; private set; }
public BoolFeedback MuteFeedback { get; private set; }
public void MuteOff()
{
Send(MuteOffCmd);
}
public void MuteOn()
{
Send(MuteOnCmd);
}
void IBasicVolumeWithFeedback.SetVolume(ushort level)
{
SetVolume(level);
}
#endregion
#region IBasicVolumeControls Members
public void MuteToggle()
{
Send(MuteToggleIrCmd);
}
public void VolumeDown(bool pressRelease)
{
//throw new NotImplementedException();
//#warning need incrementer for these
SetVolume(_VolumeLevel++);
}
public void VolumeUp(bool pressRelease)
{
//throw new NotImplementedException();
SetVolume(_VolumeLevel--);
}
#endregion
}
}

View File

@@ -0,0 +1,243 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using PepperDash.Essentials.Core;
using PepperDash.Core;
namespace PepperDash.Essentials.Devices.Displays
{
public class NecPaSeriesProjector : ComTcpDisplayBase
{
public readonly IntFeedback Lamp1RemainingPercent;
int _Lamp1RemainingPercent;
public readonly IntFeedback Lamp2RemainingPercent;
int _Lamp2RemainingPercent;
protected override Func<bool> PowerIsOnFeedbackFunc
{
get { return () => _PowerIsOn; }
}
bool _PowerIsOn;
protected override Func<bool> IsCoolingDownFeedbackFunc
{
get { return () => false; }
}
protected override Func<bool> IsWarmingUpFeedbackFunc
{
get { return () => false; }
}
public override void PowerToggle()
{
throw new NotImplementedException();
}
public override void ExecuteSwitch(object selector)
{
throw new NotImplementedException();
}
Dictionary<string, string> InputMap;
/// <summary>
/// Constructor
/// </summary>
public NecPaSeriesProjector(string key, string name)
: base(key, name)
{
Lamp1RemainingPercent = new IntFeedback("Lamp1RemainingPercent", () => _Lamp1RemainingPercent);
Lamp2RemainingPercent = new IntFeedback("Lamp2RemainingPercent", () => _Lamp2RemainingPercent);
InputMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "computer1", "\x02\x03\x00\x00\x02\x01\x01\x09" },
{ "computer2", "\x02\x03\x00\x00\x02\x01\x02\x0a" },
{ "computer3", "\x02\x03\x00\x00\x02\x01\x03\x0b" },
{ "hdmi", "\x02\x03\x00\x00\x02\x01\x1a\x22" },
{ "dp", "\x02\x03\x00\x00\x02\x01\x1b\x23" },
{ "video", "\x02\x03\x00\x00\x02\x01\x06\x0e" },
{ "viewer", "\x02\x03\x00\x00\x02\x01\x1f\x27" },
{ "network", "\x02\x03\x00\x00\x02\x01\x20\x28" },
};
}
void IsConnected_OutputChange(object sender, EventArgs e)
{
}
public void SetEnable(bool state)
{
var tcp = CommunicationMethod as GenericTcpIpClient;
if (tcp != null)
{
tcp.Connect();
}
}
public override void PowerOn()
{
SendText("\x02\x00\x00\x00\x00\x02");
}
public override void PowerOff()
{
SendText("\x02\x01\x00\x00\x00\x03");
}
public void PictureMuteOn()
{
SendText("\x02\x10\x00\x00\x00\x12");
}
public void PictureMuteOff()
{
SendText("\x02\x11\x00\x00\x00\x13");
}
public void GetRunningStatus()
{
SendText("\x00\x85\x00\x00\x01\x01\x87");
}
public void GetLampRemaining(int lampNum)
{
if (!_PowerIsOn) return;
var bytes = new byte[]{0x03,0x96,0x00,0x00,0x02,0x00,0x04};
if (lampNum == 2)
bytes[5] = 0x01;
SendBytes(AppendChecksum(bytes));
}
public void SelectInput(string inputKey)
{
if (InputMap.ContainsKey(inputKey))
SendText(InputMap[inputKey]);
}
void SendText(string text)
{
if (CommunicationMethod != null)
CommunicationMethod.SendText(text);
}
void SendBytes(byte[] bytes)
{
if (CommunicationMethod != null)
CommunicationMethod.SendBytes(bytes);
}
byte[] AppendChecksum(byte[] bytes)
{
byte sum = unchecked((byte)bytes.Sum(x => (int)x));
var retVal = new byte[bytes.Length + 1];
bytes.CopyTo(retVal, 0);
retVal[retVal.Length - 1] = sum;
return retVal;
}
protected override void CommunicationMethod_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs args)
{
var bytes = args.Bytes;
ParseBytes(args.Bytes);
}
void ParseBytes(byte[] bytes)
{
if (bytes[0] == 0x22)
{
// Power on
if (bytes[1] == 0x00)
{
_PowerIsOn = true;
PowerIsOnFeedback.FireUpdate();
}
// Power off
else if (bytes[1] == 0x01)
{
_PowerIsOn = false;
PowerIsOnFeedback.FireUpdate();
}
}
// Running Status
else if (bytes[0] == 0x20 && bytes[1] == 0x85 && bytes[4] == 0x10)
{
var operationStates = new Dictionary<int, string>
{
{ 0x00, "Standby" },
{ 0x04, "Power On" },
{ 0x05, "Cooling" },
{ 0x06, "Standby (error)" },
{ 0x0f, "Standby (power saving" },
{ 0x10, "Network Standby" },
{ 0xff, "Not supported" }
};
var newPowerIsOn = bytes[7] == 0x01;
if (newPowerIsOn != _PowerIsOn)
{
_PowerIsOn = newPowerIsOn;
PowerIsOnFeedback.FireUpdate();
}
Debug.Console(2, this, "PowerIsOn={0}\rCooling={1}\rPowering on/off={2}\rStatus={3}",
_PowerIsOn,
bytes[8] == 0x01,
bytes[9] == 0x01,
operationStates[bytes[10]]);
}
// Lamp remaining
else if (bytes[0] == 0x23 && bytes[1] == 0x96 && bytes[4] == 0x06 && bytes[6] == 0x04)
{
var newValue = bytes[7];
if (bytes[5] == 0x00)
{
if (newValue != _Lamp1RemainingPercent)
{
_Lamp1RemainingPercent = newValue;
Lamp1RemainingPercent.FireUpdate();
}
}
else
{
if (newValue != _Lamp2RemainingPercent)
{
_Lamp2RemainingPercent = newValue;
Lamp2RemainingPercent.FireUpdate();
}
}
Debug.Console(0, this, "Lamp {0}, {1}% remaining", (bytes[5] + 1), bytes[7]);
}
}
#region INonStandardControls Members
public Dictionary<Cue, Action<object>> GetNonStandardControls()
{
return new Dictionary<Cue, Action<object>>
{
{ CommonBoolCue.PowerOn, o => PowerOn() },
{ CommonBoolCue.PowerOff, o => PowerOff() },
{ Cue.BoolCue("PictureMute", 0), o =>
{
if((bool)o)
PictureMuteOn();
else
PictureMuteOff(); } },
{ Cue.UShortCue("GetLampRemaining", 0), o => GetLampRemaining((int) o) },
{ Cue.StringCue("SelectInput", 0), o => SelectInput((String)o) }
};
}
#endregion
}
}

View File

@@ -0,0 +1,338 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Displays
{
/// <summary>
///
/// </summary>
public class PanasonicThefDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, ICommunicationMonitor
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
#region Command constants
public const string InputGetCmd = "\x02QMI\x03";
public const string Hdmi1Cmd = "\x02IMS:HM1\x03";
public const string Hdmi2Cmd = "\x02IMS:HM2\x03";
public const string Hdmi3Cmd = "";
public const string Hdmi4Cmd = "";
public const string Dp1Cmd = "";
public const string Dp2Cmd = "";
public const string Dvi1Cmd = "\x02IMS:DV1";
public const string Video1Cmd = "";
public const string VgaCmd = "";
public const string RgbCmd = "";
public const string PowerOnCmd = "\x02PON\x03";
public const string PowerOffCmd = "\x02POF\x03";
public const string PowerToggleIrCmd = "";
public const string MuteOffCmd = "\x02AMT:0\x03";
public const string MuteOnCmd = "\x02AMT:1\x03";
public const string MuteToggleIrCmd = "\x02AMT\x03";
public const string MuteGetCmd = "\x02QAM\x03";
public const string VolumeGetCmd = "\x02QAV\x03";
public const string VolumeLevelPartialCmd = "\x02AVL:"; //
public const string VolumeUpCmd = "\x02AUU\x03";
public const string VolumeDownCmd = "\x02AUD\x03";
public const string MenuIrCmd = "";
public const string UpIrCmd = "";
public const string DownIrCmd = "";
public const string LeftIrCmd = "";
public const string RightIrCmd = "";
public const string SelectIrCmd = "";
public const string ExitIrCmd = "";
#endregion
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
ushort _VolumeLevel;
bool _IsMuted;
protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } }
protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } }
protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } }
protected override Func<string> CurrentInputFeedbackFunc { get { return () => "Not Implemented"; } }
/// <summary>
/// Constructor for IBasicCommunication
/// </summary>
public PanasonicThefDisplay(string key, string name, IBasicCommunication comm)
: base(key, name)
{
Communication = comm;
Init();
}
/// <summary>
/// Constructor for TCP
/// </summary>
public PanasonicThefDisplay(string key, string name, string hostname, int port)
: base(key, name)
{
Communication = new GenericTcpIpClient(key + "-tcp", hostname, port, 5000);
Init();
}
/// <summary>
/// Constructor for COM
/// </summary>
public PanasonicThefDisplay(string key, string name, ComPort port, ComPort.ComPortSpec spec)
: base(key, name)
{
Communication = new ComPortController(key + "-com", port, spec);
Init();
}
void Init()
{
PortGather = new CommunicationGather(Communication, '\x0d');
PortGather.LineReceived += this.Port_LineReceived;
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 30000, 120000, 300000, "\x02QPW\x03"); // Query Power
InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi2), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.DviIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Dvi, new Action(InputDvi1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.CompositeIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Composite, new Action(InputVideo1), this));
InputPorts.Add(new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video,
eRoutingPortConnectionType.Vga, new Action(InputVga), this));
VolumeLevelFeedback = new IntFeedback(() => { return _VolumeLevel; });
MuteFeedback = new BoolFeedback(() => _IsMuted);
// new BoolCueActionPair(CommonBoolCue.Menu, b => { if(b) Send(MenuIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Up, b => { if(b) Send(UpIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Down, b => { if(b) Send(DownIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Left, b => { if(b) Send(LeftIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Right, b => { if(b) Send(RightIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Select, b => { if(b) Send(SelectIrCmd); }),
// new BoolCueActionPair(CommonBoolCue.Exit, b => { if(b) Send(ExitIrCmd); }),
//};
}
~PanasonicThefDisplay()
{
PortGather = null;
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
return true;
}
public override FeedbackCollection<Feedback> Feedbacks
{
get
{
var list = base.Feedbacks;
list.AddRange(new List<Feedback>
{
});
return list;
}
}
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Received: '{0}'", ComTextHelper.GetEscapedText(args.Text));
if (args.Text=="DO SOMETHING HERE EVENTUALLY")
{
_IsMuted = true;
MuteFeedback.FireUpdate();
}
}
void Send(string s)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Send: '{0}'", ComTextHelper.GetEscapedText(s));
Communication.SendText(s);
}
public override void PowerOn()
{
Send(PowerOnCmd);
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate();
// Fake power-up cycle
WarmupTimer = new CTimer(o =>
{
_IsWarmingUp = false;
_PowerIsOn = true;
IsWarmingUpFeedback.FireUpdate();
PowerIsOnFeedback.FireUpdate();
}, WarmupTime);
}
}
public override void PowerOff()
{
// If a display has unreliable-power off feedback, just override this and
// remove this check.
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
Send(PowerOffCmd);
_IsCoolingDown = true;
_PowerIsOn = false;
PowerIsOnFeedback.FireUpdate();
IsCoolingDownFeedback.FireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
Debug.Console(2, this, "Cooldown timer ending");
_IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate();
}, CooldownTime);
}
}
public override void PowerToggle()
{
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn();
}
public void InputHdmi1()
{
Send(Hdmi1Cmd);
}
public void InputHdmi2()
{
Send(Hdmi2Cmd);
}
public void InputHdmi3()
{
Send(Hdmi3Cmd);
}
public void InputHdmi4()
{
Send(Hdmi4Cmd);
}
public void InputDisplayPort1()
{
Send(Dp1Cmd);
}
public void InputDisplayPort2()
{
Send(Dp2Cmd);
}
public void InputDvi1()
{
Send(Dvi1Cmd);
}
public void InputVideo1()
{
Send(Video1Cmd);
}
public void InputVga()
{
Send(VgaCmd);
}
public void InputRgb()
{
Send(RgbCmd);
}
public override void ExecuteSwitch(object selector)
{
if (selector is Action)
(selector as Action).Invoke();
else
Debug.Console(1, this, "WARNING: ExecuteSwitch cannot handle type {0}", selector.GetType());
//Send((string)selector);
}
void SetVolume(ushort level)
{
var levelString = string.Format("{0}{1:X3}\x03", VolumeLevelPartialCmd, level);
//Debug.Console(2, this, "Volume:{0}", ComTextHelper.GetEscapedText(levelString));
_VolumeLevel = level;
VolumeLevelFeedback.FireUpdate();
}
#region IBasicVolumeWithFeedback Members
public IntFeedback VolumeLevelFeedback { get; private set; }
public BoolFeedback MuteFeedback { get; private set; }
public void MuteOff()
{
Send(MuteOffCmd);
}
public void MuteOn()
{
Send(MuteOnCmd);
}
void IBasicVolumeWithFeedback.SetVolume(ushort level)
{
SetVolume(level);
}
#endregion
#region IBasicVolumeControls Members
public void MuteToggle()
{
Send(MuteToggleIrCmd);
}
public void VolumeDown(bool pressRelease)
{
//throw new NotImplementedException();
//#warning need incrementer for these
SetVolume(_VolumeLevel++);
}
public void VolumeUp(bool pressRelease)
{
//throw new NotImplementedException();
SetVolume(_VolumeLevel--);
}
#endregion
}
}

View File

@@ -0,0 +1,620 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.CrestronThread;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Displays
{
/// <summary>
///
/// </summary>
public class SamsungMDC : TwoWayDisplayBase, IBasicVolumeWithFeedback, ICommunicationMonitor, IInputDisplayPort1, IInputDisplayPort2,
IInputHdmi1, IInputHdmi2, IInputHdmi3, IInputHdmi4
{
public IBasicCommunication Communication { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public byte ID { get; private set; }
bool LastCommandSentWasVolume;
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
ushort _VolumeLevelForSig;
int _LastVolumeSent;
bool _IsMuted;
RoutingInputPort _CurrentInputPort;
byte[] IncomingBuffer = new byte[]{};
ActionIncrementer VolumeIncrementer;
bool VolumeIsRamping;
public bool IsInStandby { get; private set; }
bool IsPoweringOnIgnorePowerFb;
protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } }
protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } }
protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } }
protected override Func<string> CurrentInputFeedbackFunc { get { return () => _CurrentInputPort.Key; } }
/// <summary>
/// Constructor for IBasicCommunication
/// </summary>
public SamsungMDC(string key, string name, IBasicCommunication comm, string id)
: base(key, name)
{
Communication = comm;
Communication.BytesReceived += new EventHandler<GenericCommMethodReceiveBytesArgs>(Communication_BytesReceived);
ID = id == null ? (byte)0x01 : Convert.ToByte(id, 16); // If id is null, set default value of 0x01, otherwise assign value passed in constructor
Init();
}
/// <summary>
/// Constructor for TCP
/// </summary>
public SamsungMDC(string key, string name, string hostname, int port, string id)
: base(key, name)
{
Communication = new GenericTcpIpClient(key + "-tcp", hostname, port, 5000);
ID = id == null ? (byte)0x01 : Convert.ToByte(id, 16); // If id is null, set default value of 0x01, otherwise assign value passed in constructor
Init();
}
/// <summary>
/// Constructor for COM
/// </summary>
public SamsungMDC(string key, string name, ComPort port, ComPort.ComPortSpec spec, string id)
: base(key, name)
{
Communication = new ComPortController(key + "-com", port, spec);
//Communication.TextReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(Communication_TextReceived);
ID = id == null ? (byte)0x01 : Convert.ToByte(id, 16); // If id is null, set default value of 0x01, otherwise assign value passed in constructor
Init();
}
void AddRoutingInputPort(RoutingInputPort port, byte fbMatch)
{
port.FeedbackMatchObject = fbMatch;
InputPorts.Add(port);
}
void Init()
{
WarmupTime = 10000;
CooldownTime = 8000;
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 2000, 120000, 300000, StatusGet);
DeviceManager.AddDevice(CommunicationMonitor);
VolumeIncrementer = new ActionIncrementer(655, 0, 65535, 800, 80,
v => SetVolume((ushort)v),
() => _LastVolumeSent);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi1), this), 0x21);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn1PC, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi1PC), this), 0x22);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi2), this), 0x23);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn2PC, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi2PC), this), 0x24);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi3), this), 0x32);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.DisplayPortIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.DisplayPort, new Action(InputDisplayPort1), this), 0x25);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.DviIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Dvi, new Action(InputDvi1), this), 0x18);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.CompositeIn, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Composite, new Action(InputVideo1), this), 0x08);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.RgbIn1, eRoutingSignalType.Video,
eRoutingPortConnectionType.Vga, new Action(InputRgb1), this), 0x14);
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.RgbIn2, eRoutingSignalType.Video,
eRoutingPortConnectionType.Rgb, new Action(new Action(InputRgb2)), this), 0x1E);
VolumeLevelFeedback = new IntFeedback(() => { return _VolumeLevelForSig; });
MuteFeedback = new BoolFeedback(() => _IsMuted);
StatusGet();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
return true;
}
public override FeedbackCollection<Feedback> Feedbacks
{
get
{
var list = base.Feedbacks;
list.AddRange(new List<Feedback>
{
VolumeLevelFeedback,
MuteFeedback,
CurrentInputFeedback
});
return list;
}
}
/// <summary>
/// /
/// </summary>
/// <param name="sender"></param>
void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e)
{
// This is probably not thread-safe buffering
// Append the incoming bytes with whatever is in the buffer
var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length];
IncomingBuffer.CopyTo(newBytes, 0);
e.Bytes.CopyTo(newBytes, IncomingBuffer.Length);
if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
Debug.Console(2, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes));
// Need to find AA FF and have
for (int i = 0; i < newBytes.Length; i++)
{
if (newBytes[i] == 0xAA && newBytes[i + 1] == 0xFF)
{
newBytes = newBytes.Skip(i).ToArray(); // Trim off junk if there's "dirt" in the buffer
// parse it
// If it's at least got the header, then process it,
while (newBytes.Length > 4 && newBytes[0] == 0xAA && newBytes[1] == 0xFF)
{
var msgLen = newBytes[3];
// if the buffer is shorter than the header (3) + message (msgLen) + checksum (1),
// give and save it for next time
if (newBytes.Length < msgLen + 4)
break;
// Good length, grab the message
var message = newBytes.Skip(4).Take(msgLen).ToArray();
// At this point, the ack/nak is the first byte
if (message[0] == 0x41)
{
switch (message[1]) // type byte
{
case 0x00: // General status
//UpdatePowerFB(message[2], message[5]); // "power" can be misrepresented when the display sleeps
// Handle the first power on fb when waiting for it.
if (IsPoweringOnIgnorePowerFb && message[2] == 0x01)
IsPoweringOnIgnorePowerFb = false;
// Ignore general-status power off messages when powering up
if (!(IsPoweringOnIgnorePowerFb && message[2] == 0x00))
UpdatePowerFB(message[2]);
UpdateVolumeFB(message[3]);
UpdateMuteFb(message[4]);
UpdateInputFb(message[5]);
break;
case 0x11:
UpdatePowerFB(message[2]);
break;
case 0x12:
UpdateVolumeFB(message[2]);
break;
case 0x13:
UpdateMuteFb(message[2]);
break;
case 0x14:
UpdateInputFb(message[2]);
break;
default:
break;
}
}
// Skip over what we've used and save the rest for next time
newBytes = newBytes.Skip(5 + msgLen).ToArray();
}
break; // parsing will mean we can stop looking for header in loop
}
}
// Save whatever partial message is here
IncomingBuffer = newBytes;
}
/// <summary>
///
/// </summary>
void UpdatePowerFB(byte powerByte)
{
var newVal = powerByte == 1;
if (newVal != _PowerIsOn)
{
_PowerIsOn = newVal;
PowerIsOnFeedback.FireUpdate();
}
}
/// <summary>
/// Updates power status from general updates where source is included.
/// Compensates for errant standby / power off hiccups by ignoring
/// power off states with input < 0x10
/// </summary>
void UpdatePowerFB(byte powerByte, byte inputByte)
{
// This should reject errant power feedbacks when switching away from input on standby.
if (powerByte == 0x01 && inputByte < 0x10)
IsInStandby = true;
if (powerByte == 0x00 && IsInStandby) // Ignore power off if coming from standby - glitch
{
IsInStandby = false;
return;
}
UpdatePowerFB(powerByte);
}
/// <summary>
///
/// </summary>
void UpdateVolumeFB(byte b)
{
var newVol = (ushort)NumericalHelpers.Scale((double)b, 0, 100, 0, 65535);
if (!VolumeIsRamping)
_LastVolumeSent = newVol;
if (newVol != _VolumeLevelForSig)
{
_VolumeLevelForSig = newVol;
VolumeLevelFeedback.FireUpdate();
}
}
/// <summary>
///
/// </summary>
void UpdateMuteFb(byte b)
{
var newMute = b == 1;
if (newMute != _IsMuted)
{
_IsMuted = newMute;
MuteFeedback.FireUpdate();
}
}
/// <summary>
///
/// </summary>
void UpdateInputFb(byte b)
{
var newInput = InputPorts.FirstOrDefault(i => i.FeedbackMatchObject.Equals(b));
if (newInput != null && newInput != _CurrentInputPort)
{
_CurrentInputPort = newInput;
CurrentInputFeedback.FireUpdate();
}
}
/// <summary>
/// Formats an outgoing message. Replaces third byte with ID and replaces last byte with checksum
/// </summary>
/// <param name="b"></param>
void SendBytes(byte[] b)
{
if (LastCommandSentWasVolume) // If the last command sent was volume
if (b[1] != 0x12) // Check if this command is volume, and if not, delay this command
CrestronEnvironment.Sleep(100);
b[2] = ID;
// append checksum by adding all bytes, except last which should be 00
int checksum = 0;
for (var i = 1; i < b.Length - 1; i++) // add 2nd through 2nd-to-last bytes
{
checksum += b[i];
}
checksum = checksum & 0x000000FF; // mask off MSBs
b[b.Length - 1] = (byte)checksum;
if(Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
Debug.Console(2, this, "Sending:{0}", ComTextHelper.GetEscapedText(b));
if (b[1] == 0x12)
LastCommandSentWasVolume = true;
else
LastCommandSentWasVolume = false;
Communication.SendBytes(b);
}
/// <summary>
///
/// </summary>
public void StatusGet()
{
SendBytes(new byte[] { 0xAA, 0x00, 0x00, 0x00, 0x00 });
}
/// <summary>
///
/// </summary>
public override void PowerOn()
{
IsPoweringOnIgnorePowerFb = true;
//Send(PowerOnCmd);
SendBytes(new byte[] { 0xAA, 0x11, 0x00, 0x01, 0x01, 0x00 });
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate();
// Fake power-up cycle
WarmupTimer = new CTimer(o =>
{
_IsWarmingUp = false;
_PowerIsOn = true;
IsWarmingUpFeedback.FireUpdate();
PowerIsOnFeedback.FireUpdate();
}, WarmupTime);
}
}
/// <summary>
///
/// </summary>
public override void PowerOff()
{
IsPoweringOnIgnorePowerFb = false;
// If a display has unreliable-power off feedback, just override this and
// remove this check.
if (!_IsWarmingUp && !_IsCoolingDown) // PowerIsOnFeedback.BoolValue &&
{
//Send(PowerOffCmd);
SendBytes(new byte[] { 0xAA, 0x11, 0x00, 0x01, 0x00, 0x00 });
_IsCoolingDown = true;
_PowerIsOn = false;
PowerIsOnFeedback.FireUpdate();
IsCoolingDownFeedback.FireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
_IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate();
}, CooldownTime);
}
}
public override void PowerToggle()
{
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn();
}
public void PowerGet()
{
SendBytes(new byte[] { 0xAA, 0x11, 0x00, 0x00, 0x00 });
}
public void InputHdmi1()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x21, 0x00 });
}
public void InputHdmi1PC()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x22, 0x00 });
}
public void InputHdmi2()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x23, 0x00 });
}
public void InputHdmi2PC()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x24, 0x00 });
}
public void InputHdmi3()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x32, 0x00 });
}
public void InputHdmi4()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x34, 0x00 });
}
public void InputDisplayPort1()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x25, 0x00 });
}
public void InputDisplayPort2()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x26, 0x00 });
}
public void InputDvi1()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x18, 0x00 });
}
public void InputVideo1()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x08, 0x00 });
}
public void InputRgb1()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x14, 0x00 });
}
public void InputRgb2()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x01, 0x1E, 0x00 });
}
public void InputGet()
{
SendBytes(new byte[] { 0xAA, 0x14, 0x00, 0x00, 0x00 });
}
/// <summary>
/// Executes a switch, turning on display if necessary.
/// </summary>
/// <param name="selector"></param>
public override void ExecuteSwitch(object selector)
{
//if (!(selector is Action))
// Debug.Console(1, this, "WARNING: ExecuteSwitch cannot handle type {0}", selector.GetType());
if (_PowerIsOn)
(selector as Action)();
else // if power is off, wait until we get on FB to send it.
{
// One-time event handler to wait for power on before executing switch
EventHandler<FeedbackEventArgs> handler = null; // necessary to allow reference inside lambda to handler
handler = (o, a) =>
{
if (!_IsWarmingUp) // Done warming
{
IsWarmingUpFeedback.OutputChange -= handler;
(selector as Action)();
}
};
IsWarmingUpFeedback.OutputChange += handler; // attach and wait for on FB
PowerOn();
}
}
/// <summary>
/// Scales the level to the range of the display and sends the command
/// </summary>
/// <param name="level"></param>
public void SetVolume(ushort level)
{
_LastVolumeSent = level;
var scaled = (int)NumericalHelpers.Scale(level, 0, 65535, 0, 100);
// The inputs to Scale ensure that byte won't overflow
SendBytes(new byte[] { 0xAA, 0x12, 0x00, 0x01, Convert.ToByte(scaled), 0x00 });
}
#region IBasicVolumeWithFeedback Members
public IntFeedback VolumeLevelFeedback { get; private set; }
public BoolFeedback MuteFeedback { get; private set; }
/// <summary>
///
/// </summary>
public void MuteOff()
{
SendBytes(new byte[] { 0xAA, 0x13, 0x00, 0x01, 0x00, 0x00 });
}
/// <summary>
///
/// </summary>
public void MuteOn()
{
SendBytes(new byte[] { 0xAA, 0x13, 0x00, 0x01, 0x01, 0x00 });
}
/// <summary>
///
/// </summary>
public void MuteGet()
{
SendBytes(new byte[] { 0xAA, 0x13, 0x00, 0x00, 0x00 });
}
#endregion
#region IBasicVolumeControls Members
/// <summary>
///
/// </summary>
public void MuteToggle()
{
if (_IsMuted)
MuteOff();
else
MuteOn();
}
/// <summary>
///
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeDown(bool pressRelease)
{
if (pressRelease)
{
VolumeIncrementer.StartDown();
VolumeIsRamping = true;
}
else
{
VolumeIsRamping = false;
VolumeIncrementer.Stop();
}
}
/// <summary>
///
/// </summary>
/// <param name="pressRelease"></param>
public void VolumeUp(bool pressRelease)
{
if (pressRelease)
{
VolumeIncrementer.StartUp();
VolumeIsRamping = true;
}
else
{
VolumeIsRamping = false;
VolumeIncrementer.Stop();
}
}
/// <summary>
///
/// </summary>
public void VolumeGet()
{
SendBytes(new byte[] { 0xAA, 0x12, 0x00, 0x00, 0x00 });
}
#endregion
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.Lighting;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.CrestronIO;
namespace PepperDash.Essentials.Devices.Common.Environment.Lighting
{
public class Din8sw8Controller : Device, ISwitchedOutputCollection
{
// Need to figure out some sort of interface to make these switched outputs behave like processor relays so they can be used interchangably
public Din8Sw8 SwitchModule { get; private set; }
/// <summary>
/// Collection of generic switched outputs
/// </summary>
public Dictionary<uint, ISwitchedOutput> SwitchedOutputs { get; private set; }
public Din8sw8Controller(string key, uint cresnetId)
: base(key)
{
SwitchedOutputs = new Dictionary<uint, ISwitchedOutput>();
SwitchModule = new Din8Sw8(cresnetId, Global.ControlSystem);
if (SwitchModule.Register() != eDeviceRegistrationUnRegistrationResponse.Success)
{
Debug.Console(2, this, "Error registering Din8sw8. Reason: {0}", SwitchModule.RegistrationFailureReason);
}
PopulateDictionary();
}
public override bool CustomActivate()
{
return base.CustomActivate();
}
/// <summary>
/// Populates the generic collection with the loads from the Crestron collection
/// </summary>
void PopulateDictionary()
{
foreach (var item in SwitchModule.SwitchedLoads)
{
SwitchedOutputs.Add(item.Number, new Din8sw8Output(item));
}
}
}
/// <summary>
/// Wrapper class to
/// </summary>
public class Din8sw8Output : ISwitchedOutput
{
SwitchedLoadWithOverrideParameter SwitchedOutput;
public BoolFeedback OutputIsOnFeedback { get; protected set; }
public Din8sw8Output(SwitchedLoadWithOverrideParameter switchedOutput)
{
SwitchedOutput = switchedOutput;
OutputIsOnFeedback = new BoolFeedback(new Func<bool>(() => SwitchedOutput.IsOn));
}
public void On()
{
SwitchedOutput.FullOn();
}
public void Off()
{
SwitchedOutput.FullOff();
}
}
}

View File

@@ -0,0 +1,256 @@
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.Lighting;
namespace PepperDash.Essentials.Devices.Common.Environment.Lutron
{
public class LutronQuantumArea : LightingBase, ILightingMasterRaiseLower, ICommunicationMonitor
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
CTimer SubscribeAfterLogin;
public string IntegrationId;
string Username;
string Password;
const string Delimiter = "\x0d\x0a";
const string Set = "#";
const string Get = "?";
public LutronQuantumArea(string key, string name, IBasicCommunication comm, LutronQuantumPropertiesConfig props)
: base(key, name)
{
Communication = comm;
IntegrationId = props.IntegrationId;
if (props.Control.Method != eControlMethod.Com)
{
Username = props.Control.TcpSshProperties.Username;
Password = props.Control.TcpSshProperties.Password;
}
LightingScenes = props.Scenes;
var socket = comm as ISocketStatus;
if (socket != null)
{
// IP Control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// RS-232 Control
}
Communication.TextReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(Communication_TextReceived);
PortGather = new CommunicationGather(Communication, Delimiter);
PortGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(PortGather_LineReceived);
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "?ETHERNET,0\x0d\x0a");
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
// Tasks on connect
}
}
/// <summary>
/// Checks for responses that do not contain the delimiter
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void Communication_TextReceived(object sender, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "Text Received: '{0}'", args.Text);
if (args.Text.Contains("login:"))
{
// Login
SendLine(Username);
}
else if (args.Text.Contains("password:"))
{
// Login
SendLine(Password);
SubscribeAfterLogin = new CTimer(x => SubscribeToFeedback(), null, 5000);
}
else if (args.Text.Contains("Access Granted"))
{
if (SubscribeAfterLogin != null)
{
SubscribeAfterLogin.Stop();
}
SubscribeToFeedback();
}
}
/// <summary>
/// Handles all responses that contain the delimiter
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void PortGather_LineReceived(object sender, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "Line Received: '{0}'", args.Text);
try
{
if (args.Text.Contains("~AREA"))
{
var response = args.Text.Split(',');
var integrationId = response[1];
if (integrationId != IntegrationId)
{
Debug.Console(2, this, "Response is not for correct Integration ID");
return;
}
else
{
var action = Int32.Parse(response[2]);
switch (action)
{
case (int)eAction.Scene:
{
var scene = response[3];
CurrentLightingScene = LightingScenes.FirstOrDefault(s => s.ID.Equals(scene));
OnLightingSceneChange();
break;
}
default:
break;
}
}
}
}
catch (Exception e)
{
Debug.Console(2, this, "Error parsing response:\n{0}", e);
}
}
/// <summary>
/// Subscribes to feedback
/// </summary>
public void SubscribeToFeedback()
{
Debug.Console(1, "Sending Monitoring Subscriptions");
SendLine("#MONITORING,6,1");
SendLine("#MONITORING,8,1");
SendLine("#MONITORING,5,2");
}
/// <summary>
/// Recalls the specified scene
/// </summary>
/// <param name="scene"></param>
///
public override void SelectScene(LightingScene scene)
{
Debug.Console(1, this, "Selecting Scene: '{0}'", scene.Name);
SendLine(string.Format("{0}AREA,{1},{2},{3}", Set, IntegrationId, (int)eAction.Scene, scene.ID));
}
/// <summary>
/// Begins raising the lights in the area
/// </summary>
public void MasterRaise()
{
SendLine(string.Format("{0}AREA,{1},{2}", Set, IntegrationId, (int)eAction.Raise));
}
/// <summary>
/// Begins lowering the lights in the area
/// </summary>
public void MasterLower()
{
SendLine(string.Format("{0}AREA,{1},{2}", Set, IntegrationId, (int)eAction.Lower));
}
/// <summary>
/// Stops the current raise/lower action
/// </summary>
public void MasterRaiseLowerStop()
{
SendLine(string.Format("{0}AREA,{1},{2}", Set, IntegrationId, (int)eAction.Stop));
}
/// <summary>
/// Appends the delimiter and sends the string
/// </summary>
/// <param name="s"></param>
public void SendLine(string s)
{
Debug.Console(2, this, "TX: '{0}'", s);
Communication.SendText(s + Delimiter);
}
}
public enum eAction : int
{
SetLevel = 1,
Raise = 2,
Lower = 3,
Stop = 4,
Scene = 6,
DaylightMode = 7,
OccupancyState = 8,
OccupancyMode = 9,
OccupiedLevelOrScene = 12,
UnoccupiedLevelOrScene = 13,
HyperionShaddowSensorOverrideState = 26,
HyperionBrightnessSensorOverrideStatue = 27
}
public class LutronQuantumPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
public string IntegrationId { get; set; }
public List<LightingScene> Scenes { get; set; }
// Moved to use existing properties in Control object
// public string Username { get; set; }
// public string Password { get; set; }
}
}

View File

@@ -0,0 +1,113 @@
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.CrestronIO;
using PepperDash.Essentials.Core.Shades;
namespace PepperDash.Essentials.Devices.Common.Environment.Somfy
{
/// <summary>
/// Controls a single shade using three relays
/// </summary>
public class RelayControlledShade : ShadeBase, IShadesOpenCloseStop
{
RelayControlledShadeConfigProperties Config;
ISwitchedOutput OpenRelay;
ISwitchedOutput StopOrPresetRelay;
ISwitchedOutput CloseRelay;
int RelayPulseTime;
public string StopOrPresetButtonLabel { get; set; }
public RelayControlledShade(string key, string name, RelayControlledShadeConfigProperties config)
: base(key, name)
{
Config = config;
RelayPulseTime = Config.RelayPulseTime;
StopOrPresetButtonLabel = Config.StopOrPresetLabel;
}
public override bool CustomActivate()
{
//Create ISwitchedOutput objects based on props
OpenRelay = GetSwitchedOutputFromDevice(Config.Relays.Open);
StopOrPresetRelay = GetSwitchedOutputFromDevice(Config.Relays.StopOrPreset);
CloseRelay = GetSwitchedOutputFromDevice(Config.Relays.Close);
return base.CustomActivate();
}
public override void Open()
{
Debug.Console(1, this, "Opening Shade: '{0}'", this.Name);
PulseOutput(OpenRelay, RelayPulseTime);
}
public override void StopOrPreset()
{
Debug.Console(1, this, "Stopping or recalling preset on Shade: '{0}'", this.Name);
PulseOutput(StopOrPresetRelay, RelayPulseTime);
}
public override void Close()
{
Debug.Console(1, this, "Closing Shade: '{0}'", this.Name);
PulseOutput(CloseRelay, RelayPulseTime);
}
void PulseOutput(ISwitchedOutput output, int pulseTime)
{
output.On();
CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime);
}
/// <summary>
/// Attempts to get the port on teh specified device from config
/// </summary>
/// <param name="relayConfig"></param>
/// <returns></returns>
ISwitchedOutput GetSwitchedOutputFromDevice(IOPortConfig relayConfig)
{
var portDevice = DeviceManager.GetDeviceForKey(relayConfig.PortDeviceKey);
if (portDevice != null)
{
return (portDevice as ISwitchedOutputCollection).SwitchedOutputs[relayConfig.PortNumber];
}
else
{
Debug.Console(1, this, "Error: Unable to get relay on port '{0}' from device with key '{1}'", relayConfig.PortNumber, relayConfig.PortDeviceKey);
return null;
}
}
}
public class RelayControlledShadeConfigProperties
{
public int RelayPulseTime { get; set; }
public ShadeRelaysConfig Relays { get; set; }
public string StopOrPresetLabel { get; set; }
public class ShadeRelaysConfig
{
public IOPortConfig Open { get; set; }
public IOPortConfig StopOrPreset { get; set; }
public IOPortConfig Close { get; set; }
}
}
}

View File

@@ -0,0 +1,205 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{892B761C-E479-44CE-BD74-243E9214AF13}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PepperDash.Essentials.Devices.Common</RootNamespace>
<AssemblyName>Essentials Devices Common</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92300};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="Crestron.SimplSharpPro.DeviceSupport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DeviceSupport.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.Gateways, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Gateways.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.GeneralIO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.Lighting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Lighting.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.4.20530, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\references\PepperDash_Core.dll</HintPath>
</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>
<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>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</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>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="AudioCodec\AudioCodecBase.cs" />
<Compile Include="AudioCodec\Interfaces\IAudioCodecInfo.cs" />
<Compile Include="AudioCodec\Interfaces\IHasAudioCodec.cs" />
<Compile Include="AudioCodec\MockAC\MockAC.cs" />
<Compile Include="AudioCodec\MockAC\MockAcPropertiesConfig.cs" />
<Compile Include="Cameras\CameraBase.cs" />
<Compile Include="Cameras\CameraVisca.cs" />
<Compile Include="Codec\eCodecCallDirection.cs" />
<Compile Include="Codec\eCodecCallType.cs" />
<Compile Include="Codec\eCodecCallStatus.cs" />
<Compile Include="Codec\eMeetingPrivacy.cs" />
<Compile Include="Codec\iCodecAudio.cs" />
<Compile Include="ImageProcessors\TVOneCorio.cs" />
<Compile Include="ImageProcessors\TVOneCorioPropertiesConfig.cs" />
<Compile Include="Power Controllers\Digitallogger.cs" />
<Compile Include="Power Controllers\DigitalLoggerPropertiesConfig.cs" />
<Compile Include="Evertz\EvertsEndpointStatusServer.cs" />
<Compile Include="Evertz\EvertzEndpointVarIds.cs" />
<Compile Include="Evertz\EvertzEndpoint.cs" />
<Compile Include="Evertz\EvertzEndpointPropertiesConfig.cs" />
<Compile Include="Evertz\GenericHttpClient.cs" />
<Compile Include="ImageProcessors\AnalogWay\AnalongWayLiveCore.cs" />
<Compile Include="ImageProcessors\AnalogWay\AnalogWayLiveCorePropertiesConfig.cs" />
<Compile Include="VideoCodec\CiscoCodec\CiscoCamera.cs" />
<Compile Include="VideoCodec\CiscoCodec\RoomPresets.cs" />
<Compile Include="VideoCodec\Interfaces\CameraControl.cs" />
<Compile Include="Display\PanasonicThDisplay.cs" />
<Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" />
<Compile Include="Codec\iHasCallFavorites.cs" />
<Compile Include="Codec\iHasCallHistory.cs" />
<Compile Include="Codec\iHasContentSharing.cs" />
<Compile Include="Codec\iHasDialer.cs" />
<Compile Include="Codec\iHasDirectory.cs" />
<Compile Include="Codec\iHasScheduleAwareness.cs" />
<Compile Include="Crestron\Gateways\CenRfgwController.cs" />
<Compile Include="Display\ComTcpDisplayBase.cs" />
<Compile Include="Display\AvocorVTFDisplay.cs" />
<Compile Include="Display\InputInterfaces.cs" />
<Compile Include="Display\SamsungMDCDisplay.cs" />
<Compile Include="Display\DeviceFactory.cs" />
<Compile Include="Display\NecPaSeriesProjector.cs" />
<Compile Include="Display\NECPSXMDisplay.cs" />
<Compile Include="DSP\BiampTesira\BiampTesiraForteDspLevel.cs" />
<Compile Include="DSP\BiampTesira\TesiraForteControlPoint.cs" />
<Compile Include="DSP\BiampTesira\TesiraForteMuteControl.cs" />
<Compile Include="DSP\DspBase.cs" />
<Compile Include="DSP\BiampTesira\BiampTesiraForteDsp.cs" />
<Compile Include="DSP\BiampTesira\BiampTesiraFortePropertiesConfig.cs" />
<Compile Include="DSP\PolycomSoundStructure\SoundStructureBasics.cs" />
<Compile Include="Environment\Crestron Lighting\Din8sw8.cs" />
<Compile Include="Environment\Lutron\LutronQuantum.cs" />
<Compile Include="Environment\Somfy\RelayControlledShade.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Generic\GenericSource.cs" />
<Compile Include="Microphone\MicrophonePrivacyController.cs" />
<Compile Include="Microphone\MicrophonePrivacyControllerConfig.cs" />
<Compile Include="Occupancy\EssentialsGlsOccupancySensorBaseController.cs" />
<Compile Include="Occupancy\EssentialsOccupancyAggregator.cs" />
<Compile Include="Occupancy\iOccupancyStatusProvider.cs" />
<Compile Include="PC\InRoomPc.cs" />
<Compile Include="PC\Laptop.cs" />
<Compile Include="SetTopBox\SetTopBoxPropertiesConfig.cs" />
<Compile Include="Streaming\AppleTV.cs" />
<Compile Include="Audio\GenericAudioOut.cs" />
<Compile Include="DiscPlayer\IRDiscPlayerBase.cs" />
<Compile Include="SetTopBox\IRSetTopBoxBase.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Streaming\Roku.cs" />
<Compile Include="VideoCodec\CiscoCodec\BookingsDataClasses.cs" />
<Compile Include="VideoCodec\CiscoCodec\CallHistoryDataClasses.cs" />
<Compile Include="VideoCodec\CiscoCodec\CiscoSparkCodec.cs" />
<Compile Include="VideoCodec\CiscoCodec\CiscoSparkCodecPropertiesConfig.cs" />
<Compile Include="VideoCodec\CiscoCodec\xStatusSparkPlus.cs" />
<Compile Include="VideoCodec\Interfaces\IHasVideoCodec.cs" />
<Compile Include="VideoCodec\MockVC\MockCodecDirectory.cs" />
<Compile Include="VideoCodec\MockVC\MockVCCamera.cs" />
<Compile Include="VideoCodec\MockVC\MockVcPropertiesConfig.cs" />
<Compile Include="VideoCodec\CiscoCodec\PhonebookDataClasses.cs" />
<Compile Include="VideoCodec\CiscoCodec\xConfiguration.cs" />
<Compile Include="VideoCodec\CiscoCodec\xEvent.cs" />
<Compile Include="VideoCodec\CiscoCodec\HttpApiServer.cs" />
<Compile Include="Codec\CodecActiveCallItem.cs" />
<Compile Include="VideoCodec\Interfaces\IHasCodecLayouts.cs" />
<Compile Include="VideoCodec\Interfaces\IHasCodecSelfview.cs" />
<Compile Include="VideoCodec\MockVC\MockVC.cs" />
<Compile Include="VideoCodec\CiscoCodec\xStatus.cs" />
<Compile Include="VideoCodec\VideoCodecBase.cs" />
<Compile Include="VideoCodec\ZoomRoom\ResponseObjects.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoom.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomCamera.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomPropertiesConfig.cs" />
<None Include="Properties\ControlSystem.cfg" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Essentials Core\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj">
<Project>{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}</Project>
<Name>PepperDash_Essentials_Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>rem S# Pro preparation will execute after these operations</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Crestron.SimplSharp.CrestronSockets;
namespace PepperDash.Essentials.Devices.Common
{
/*****
* TODO JTA: Add Polling
* TODO JTA: Move all the registration commnads to the EvertEndpoint class.
*
*
*
*
*
*/
public class EvertzEndpointStatusServer : Device
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public bool isSubscribed;
public string Address;
public GenericUdpServer Server;
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public Dictionary<string, EvertzEndpoint> Endpoints;
public Dictionary<string, string> ServerIdByEndpointIp;
public EvertzEndpointStatusServer(string key, string name, GenericUdpServer server, EvertzEndpointStatusServerPropertiesConfig props) :
base(key, name)
{
Server = server;
Address = props.serverHostname;
Server.DataRecievedExtra += new EventHandler<GenericUdpReceiveTextExtraArgs>(_Server_DataRecievedExtra);
Server.Connect();
Endpoints = new Dictionary<string,EvertzEndpoint>();
//CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
}
//TODO JTA: Move this method and process over to the endpoint itself. return a bool.
public bool RegisterEvertzEndpoint (EvertzEndpoint device)
{
if (Endpoints.ContainsKey(device.Address) == false)
{
Endpoints.Add(device.Address, device);
}
return true;
}
void _Server_DataRecievedExtra(object sender, GenericUdpReceiveTextExtraArgs e)
{
Debug.Console(2, this, "_Server_DataRecievedExtra:\nIP:{0}\nPort:{1}\nText{2}\nBytes:{3} ", e.IpAddress, e.Port, e.Text, e.Bytes);
}
public override bool CustomActivate()
{
/*
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
*/
return true;
}
}
public class EvertzPortRestResponse
{
public string id;
public string name;
public string type;
public string value;
}
public class EvertsStatusRequesstResponse
{
public EvertzStatusDataResponse data;
public string error;
}
public class EvertzStatusDataResponse
{
public List<EvertzServerStatusResponse> servers;
}
public class EvertzServerStatusResponse
{
public string id;
public string name;
public EvertsServerStausNotificationsResponse notify;
}
public class EvertsServerStausNotificationsResponse
{
public string ip;
public List<string> parameters;
public string port;
public string protocol;
}
public class EvertzEndpointStatusServerPropertiesConfig
{
public ControlPropertiesConfig control { get; set; }
public string serverHostname { get; set; }
}
}

View File

@@ -0,0 +1,337 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Essentials.Devices.Common
{
public class EvertzEndpoint : Device
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public GenericCommunicationMonitor CommunicationMonitor { get; private set; }
private GenericHttpClient Client;
public string userName;
public string password;
public string Address;
private bool OnlineStatus;
public BoolFeedback OnlineFeedback;
public IntFeedback PresetFeedback;
public bool isSubscribed;
CrestronQueue CommandQueue;
public Dictionary<string, EvertzEndpointPort> Ports;
private string _ControllerKey;
private EvertzEndpointStatusServer StatusServer;
private String StatusServerId;
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public EvertzEndpoint(string key, string name, EvertzEndpointPropertiesConfig props, string type) :
base(key, name)
{
this.Address = props.address;
Client = new GenericHttpClient(string.Format("{0}-GenericWebClient", name), string.Format("{0}-GenericWebClient", name), this.Address);
Client.ResponseRecived += new EventHandler<GenericHttpClientEventArgs>(Client_ResponseRecived);
Ports = new Dictionary<string, EvertzEndpointPort>();
if (type.ToLower() == "mma10g-trs4k")
{
//create port hdmi 01
EvertzEndpointPort hdmi1 = new EvertzEndpointPort("HDMI01", "131.0@s", "136.0@s");
EvertzEndpointPort hdmi2 = new EvertzEndpointPort("HDMI02", "131.1@s", "136.1@s");
// add to dictionay with all keys
addPortToDictionary(hdmi1);
addPortToDictionary(hdmi2);
}
_ControllerKey = null;
if (props.controllerKey != null)
{
_ControllerKey = props.controllerKey;
}
AddPostActivationAction( () => {PostActivation();});
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Client, props.CommunicationMonitorProperties);
}
else
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Client, 40000, 120000, 300000, "v.api/apis/EV/SERVERSTATUS");
}
}
/// <summary>
/// Helper method
/// </summary>
/// <param name="port"></param>
private void addPortToDictionary(EvertzEndpointPort port)
{
Ports.Add(port.PortName, port);
Ports.Add(port.ResolutionVarID, port);
Ports.Add(port.SyncVarID, port);
//PollForState(port.SyncVarID);
//PollForState(port.ResolutionVarID);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override bool CustomActivate()
{
// Create Device -> Constructor fires
// PreActivations get called
// CustomActivate Gets Called Anything that is involved with this single class Ex: Connection, Setup Feedback, Etc.
// After this point all devices are ready for interaction
// PostActivation gets called. Use this for interClass activation.
CommunicationMonitor.Start();
OnlineFeedback = new BoolFeedback(() => { return OnlineStatus; });
//CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
/// <summary>
///
/// </summary>
private void PostActivation()
{
Debug.Console(2, this, "EvertzEndpoint Post Activation");
if (_ControllerKey != null)
{
StatusServer = DeviceManager.GetDeviceForKey(_ControllerKey) as EvertzEndpointStatusServer;
StatusServer.RegisterEvertzEndpoint(this);
// RegisterStatusServer();
// SendStatusRequest();
}
// PollAll();
}
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
Debug.Console(1, this, "Program stopping. Disabling EvertzStatusServer");
if (StatusServerId != null)
{
//UnregisterServer();
}
}
}
private void ProcessServerStatusRequest(EvertsStatusRequesstResponse status)
{
// var status = JsonConvert.DeserializeObject<EvertsStatusRequesstResponse>(SendStatusRequest());
if (status.error != null)
{
}
else if (status.data != null)
{
foreach (var server in status.data.servers)
{
if (server.name == string.Format("{0}-{1}", this.Name, StatusServer.Address))
{
StatusServerId = server.id;
Debug.Console(2, this, "EvertzEndpoint {0} StatusServer {1} Registered ID {2}", Name, StatusServer.Name, StatusServerId);
/*
foreach (var port in Ports)
{
// TODO JTA: This needs a better check
// you get a {"status": "success"} or "error": "error to register notification- Variable exists.."
if (!server.notify.parameters.Contains(port.Value.ResolutionVarID))
{
RegisterForNotification(StatusServerId, port.Value.ResolutionVarID);
}
if (!server.notify.parameters.Contains(port.Value.ResolutionVarID))
{
RegisterForNotification(StatusServerId, port.Value.SyncVarID);
}
}
*/
break;
}
}
StatusServerId = null;
}
}
private void RegisterServerWithEndpoint()
{
/*
var registrationResult = RegisterServer(StatusServer.Address, string.Format("{0}-{1}", this.Name, StatusServer.Address), StatusServer.Server.Port.ToString());
Debug.Console(2, this, "EvertzEndpointStatusServer Registration Result with device {0}\n{1}", Address, registrationResult);
if (registrationResult.Contains("success"))
{
RegisterStatusServer();
}
else
{
Debug.Console(0, this, "EvertzEndpointStatusServer RegisterServerWithEndpoint with device {0}\n{1}", Address, registrationResult);
}
* */
}
public void PollAll()
{
string collection = "";
foreach (var parameter in Ports)
{
if (parameter.Key.Contains("@"))
{
collection = collection + parameter.Key + ",";
}
}
collection = collection.Substring(0, collection.Length - 1);
SendGetRequest(collection);
}
public void PollForState(string varId)
{
try
{
SendGetRequest(varId);
//var returnState = JsonConvert.DeserializeObject<EvertzPortRestResponse>(SendGetRequest(varId));
}
catch (Exception e)
{
Debug.Console(0, this, "PollForState {0}", e);
}
}
public void ProcessGetParameterResponse(EvertzPortRestResponse response)
{
var PortObject = Ports[response.id];
if (response.name == "Input Status")
{
if (response.value == "Missing") { PortObject.SyncDetected = false; }
else { PortObject.SyncDetected = true; }
}
}
public void SendGetRequest(string s)
{
Client.SendText("v.api/apis/EV/GET/parameter/{0}", s);
}
public void SendStatusRequest()
{
Client.SendText("/v.api/apis/EV/SERVERSTATUS");
}
public void RegisterServer(string hostname, string servername, string port)
{
Client.SendText("v.api/apis/EV/SERVERADD/server/{0}/{1}/{2}/udp", hostname, servername, port);
}
public void UnregisterServer()
{
if (StatusServerId != null)
{
Client.SendTextNoResponse("v.api/apis/EV/SERVERDEL/server/{0}", StatusServerId);
}
}
// TODO JTA: Craete a UnregisterServerFast using DispatchASync.
public void RegisterForNotification(string varId)
{
Client.SendText("v.api/apis/EV/NOTIFYADD/parameter/{0}/{1}", StatusServerId, varId);
}
void Client_ResponseRecived(object sender, GenericHttpClientEventArgs e)
{
if (e.Error == HTTP_CALLBACK_ERROR.COMPLETED)
{
if (e.RequestPath.Contains("GET/parameter/"))
{
// Get Parameter response
if (!e.ResponseText.Contains("["))
ProcessGetParameterResponse(JsonConvert.DeserializeObject<EvertzPortRestResponse>(e.ResponseText));
else if (e.ResponseText.Contains("["))
{
List<EvertzPortRestResponse> test = JsonConvert.DeserializeObject<List<EvertzPortRestResponse>>(e.ResponseText);
foreach (var thing in test)
{
ProcessGetParameterResponse(thing);
}
}
}
else if (e.RequestPath.Contains("SERVERSTATUS"))
{
PollAll();
ProcessServerStatusRequest(JsonConvert.DeserializeObject<EvertsStatusRequesstResponse>(e.ResponseText));
}
}
}
public class EvertzPortsRestResponse
{
List<EvertzPortRestResponse> test;
}
public class EvertzPortRestResponse
{
public string id;
public string name;
public string type;
public string value;
}
public class EvertzEndpointPort
{
public string PortName;
public string SyncVarID;
public string ResolutionVarID;
public bool SyncDetected;
public string Resolution;
public BoolFeedback SyncDetectedFeedback;
public EvertzEndpointPort (string portName, string syncVarId, string resolutionVarId)
{
PortName = portName;
SyncVarID = syncVarId;
ResolutionVarID = resolutionVarId;
SyncDetectedFeedback = new BoolFeedback(() => { return SyncDetected; });
}
}
}
}

View File

@@ -0,0 +1,26 @@
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.Devices.Common
{
/// <summary>
///
/// </summary>
public class EvertzEndpointPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
public string userName { get; set; }
public string password { get; set; }
public string address { get; set; }
public string controllerKey { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common
{
public class EvertzEndpointVarIds
{
private string HdmiPort01SyncStatus = "136.0";
}
}

View File

@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Net.Http;
using PepperDash.Core;
using PepperDash.Core.DebugThings;
namespace PepperDash.Essentials.Devices.Common
{
public class GenericHttpClient : Device, IBasicCommunication
{
public HttpClient Client;
public event EventHandler<GenericHttpClientEventArgs> ResponseRecived;
public GenericHttpClient(string key, string name, string hostname)
: base(key, name)
{
Client = new HttpClient();
Client.HostName = hostname;
}
/// <summary>
///
/// </summary>
/// <param name="path"></param>
public void SendText(string path)
{
HttpClientRequest request = new HttpClientRequest();
string url = string.Format("http://{0}/{1}", Client.HostName, path);
request.Url = new UrlParser(url);
HttpClient.DISPATCHASYNC_ERROR error = Client.DispatchAsyncEx(request, Response, request);
Debug.Console(2, this, "GenericHttpClient SentRequest TX:'{0}'", url);
}
public void SendText(string format, params object[] items)
{
HttpClientRequest request = new HttpClientRequest();
string url = string.Format("http://{0}/{1}", Client.HostName, string.Format(format, items));
request.Url = new UrlParser(url);
HttpClient.DISPATCHASYNC_ERROR error = Client.DispatchAsyncEx(request, Response, request);
Debug.Console(2, this, "GenericHttpClient SentRequest TX:'{0}'", url);
}
public void SendTextNoResponse(string format, params object[] items)
{
HttpClientRequest request = new HttpClientRequest();
string url = string.Format("http://{0}/{1}", Client.HostName, string.Format(format, items));
request.Url = new UrlParser(url);
Client.Dispatch(request);
Debug.Console(2, this, "GenericHttpClient SentRequest TX:'{0}'", url);
}
private void Response(HttpClientResponse response, HTTP_CALLBACK_ERROR error, object request)
{
if (error == HTTP_CALLBACK_ERROR.COMPLETED)
{
var responseReceived = response;
if (responseReceived.ContentString.Length > 0)
{
if (ResponseRecived != null)
ResponseRecived(this, new GenericHttpClientEventArgs(responseReceived.ContentString, (request as HttpClientRequest).Url.ToString(), error));
Debug.Console(2, this, "GenericHttpClient ResponseReceived");
Debug.Console(2, this, "RX:{0}", responseReceived.ContentString);
Debug.Console(2, this, "TX:{0}", (request as HttpClientRequest).Url.ToString());
}
}
}
#region IBasicCommunication Members
public void SendBytes(byte[] bytes)
{
throw new NotImplementedException();
}
#endregion
#region ICommunicationReceiver Members
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
public void Connect()
{
throw new NotImplementedException();
}
public void Disconnect()
{
throw new NotImplementedException();
}
public bool IsConnected
{
get { return true; }
}
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
#endregion
}
public class GenericHttpClientEventArgs : EventArgs
{
public string ResponseText { get; private set; }
public string RequestPath { get; private set; }
public HTTP_CALLBACK_ERROR Error { get; set; }
public GenericHttpClientEventArgs(string response, string request, HTTP_CALLBACK_ERROR error)
{
ResponseText = response;
RequestPath = request;
Error = error;
}
}
}

View File

@@ -0,0 +1,407 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.GeneralIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.CrestronIO;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Devices.Common.DSP;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.Occupancy;
using PepperDash.Essentials.Devices.Common.Environment;
namespace PepperDash.Essentials.Devices.Common
{
public class DeviceFactory
{
public static IKeyed GetDevice(DeviceConfig dc)
{
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var propAnon = new {};
JsonConvert.DeserializeAnonymousType(dc.Properties.ToString(), propAnon);
var typeName = dc.Type.ToLower();
var groupName = dc.Group.ToLower();
if (typeName == "appletv")
{
var irCont = IRPortHelper.GetIrOutputPortController(dc);
return new AppleTV(key, name, irCont);
}
else if (typeName == "analogwaylivecore")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<AnalogWayLiveCorePropertiesConfig>(
properties.ToString());
return new AnalogWayLiveCore(key, name, comm, props);
}
else if (typeName == "basicirdisplay")
{
var ir = IRPortHelper.GetIrPort(properties);
if (ir != null)
{
var display = new BasicIrDisplay(key, name, ir.Port, ir.FileName);
display.IrPulseTime = 200; // Set default pulse time for IR commands.
return display;
}
}
else if (typeName == "biamptesira")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<BiampTesiraFortePropertiesConfig>(
properties.ToString());
return new BiampTesiraForteDsp(key, name, comm, props);
}
else if (typeName == "cameravisca")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<Cameras.CameraPropertiesConfig>(
properties.ToString());
return new Cameras.CameraVisca(key, name, comm, props);
}
else if (typeName == "cenrfgwex")
{
return CenRfgwController.GetNewExGatewayController(key, name,
properties.Value<string>("id"), properties.Value<string>("gatewayType"));
}
else if (typeName == "cenerfgwpoe")
{
return CenRfgwController.GetNewErGatewayController(key, name,
properties.Value<string>("id"), properties.Value<string>("gatewayType"));
}
else if (groupName == "discplayer") // (typeName == "irbluray")
{
if (properties["control"]["method"].Value<string>() == "ir")
{
var irCont = IRPortHelper.GetIrOutputPortController(dc);
return new IRBlurayBase(key, name, irCont);
}
else if (properties["control"]["method"].Value<string>() == "com")
{
Debug.Console(0, "[{0}] COM Device type not implemented YET!", key);
}
}
else if (typeName == "digitallogger")
{
// var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<DigitalLoggerPropertiesConfig>(
properties.ToString());
return new DigitalLogger(key, name, props);
}
else if (groupName == "evertzendpoint")
{
// var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<EvertzEndpointPropertiesConfig>(
properties.ToString());
return new EvertzEndpoint(key, name, props, typeName);
}
else if (typeName == "evertzendpointstatusserver")
{
var server = CommFactory.CreateCommForDevice(dc) as GenericUdpServer;
var props = JsonConvert.DeserializeObject<EvertzEndpointStatusServerPropertiesConfig>(
properties.ToString());
return new EvertzEndpointStatusServer(key, name, server, props);
}
else if (typeName == "genericaudiooutwithvolume")
{
var zone = dc.Properties.Value<uint>("zone");
return new GenericAudioOutWithVolume(key, name,
dc.Properties.Value<string>("volumeDeviceKey"), zone);
}
else if (groupName == "genericsource")
{
return new GenericSource(key, name);
}
else if (typeName == "inroompc")
{
return new InRoomPc(key, name);
}
else if (typeName == "laptop")
{
return new Laptop(key, name);
}
else if (typeName == "mockvc")
{
return new VideoCodec.MockVC(dc);
}
else if (typeName == "mockac")
{
var props = JsonConvert.DeserializeObject<AudioCodec.MockAcPropertiesConfig>(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")
{
var comm = CommFactory.CreateCommForDevice(dc);
return new VideoCodec.ZoomRoom.ZoomRoom(dc, comm);
}
else if (typeName == "digitalinput")
{
var props = JsonConvert.DeserializeObject<IOPortConfig>(properties.ToString());
IDigitalInputPorts portDevice;
if (props.PortDeviceKey == "processor")
portDevice = Global.ControlSystem as IDigitalInputPorts;
else
portDevice = DeviceManager.GetDeviceForKey(props.PortDeviceKey) as IDigitalInputPorts;
if (portDevice == null)
Debug.Console(0, "ERROR: Unable to add digital input device with key '{0}'. Port Device does not support digital inputs", key);
else
{
var cs = (portDevice as CrestronControlSystem);
if (cs == null)
{
Debug.Console(0, "ERROR: Port device for [{0}] is not control system", props.PortDeviceKey);
return null;
}
if (cs.SupportsVersiport)
{
Debug.Console(1, "Attempting to add Digital Input device to Versiport port '{0}'", props.PortNumber);
if (props.PortNumber > cs.NumberOfVersiPorts)
{
Debug.Console(0, "WARNING: Cannot add Vesiport {0} on {1}. Out of range",
props.PortNumber, props.PortDeviceKey);
return null;
}
Versiport vp = cs.VersiPorts[props.PortNumber];
if (!vp.Registered)
{
var regSuccess = vp.Register();
if (regSuccess == eDeviceRegistrationUnRegistrationResponse.Success)
{
Debug.Console(1, "Successfully Created Digital Input Device on Versiport");
return new GenericVersiportDigitalInputDevice(key, vp, props);
}
else
{
Debug.Console(0, "WARNING: Attempt to register versiport {0} on device with key '{1}' failed: {2}",
props.PortNumber, props.PortDeviceKey, regSuccess);
return null;
}
}
}
else if (cs.SupportsDigitalInput)
{
Debug.Console(1, "Attempting to add Digital Input device to Digital Input port '{0}'", props.PortNumber);
if (props.PortNumber > cs.NumberOfDigitalInputPorts)
{
Debug.Console(0, "WARNING: Cannot register DIO port {0} on {1}. Out of range",
props.PortNumber, props.PortDeviceKey);
return null;
}
DigitalInput digitalInput = cs.DigitalInputPorts[props.PortNumber];
if (!digitalInput.Registered)
{
if (digitalInput.Register() == eDeviceRegistrationUnRegistrationResponse.Success)
{
Debug.Console(1, "Successfully Created Digital Input Device on Digital Input");
return new GenericDigitalInputDevice(key, digitalInput);
}
else
Debug.Console(0, "WARNING: Attempt to register digital input {0} on device with key '{1}' failed.",
props.PortNumber, props.PortDeviceKey);
}
}
}
}
else if (typeName == "relayoutput")
{
var props = JsonConvert.DeserializeObject<IOPortConfig>(properties.ToString());
IRelayPorts portDevice;
if (props.PortDeviceKey == "processor")
portDevice = Global.ControlSystem as IRelayPorts;
else
portDevice = DeviceManager.GetDeviceForKey(props.PortDeviceKey) as IRelayPorts;
if (portDevice == null)
Debug.Console(0, "Unable to add relay device with key '{0}'. Port Device does not support relays", key);
else
{
var cs = (portDevice as CrestronControlSystem);
if (cs != null)
{
// The relay is on a control system processor
if (!cs.SupportsRelay || props.PortNumber > cs.NumberOfRelayPorts)
{
Debug.Console(0, "Port Device: {0} does not support relays or does not have enough relays");
return null;
}
}
else
{
// The relay is on another device type
if (props.PortNumber > portDevice.NumberOfRelayPorts)
{
Debug.Console(0, "Port Device: {0} does not have enough relays");
return null;
}
}
Relay relay = portDevice.RelayPorts[props.PortNumber];
if (!relay.Registered)
{
if (relay.Register() == eDeviceRegistrationUnRegistrationResponse.Success)
return new GenericRelayDevice(key, relay);
else
Debug.Console(0, "Attempt to register relay {0} on device with key '{1}' failed.", props.PortNumber, props.PortDeviceKey);
}
// Future: Check if portDevice is 3-series card or other non control system that supports versiports
}
}
else if (typeName == "microphoneprivacycontroller")
{
var props = JsonConvert.DeserializeObject<Microphones.MicrophonePrivacyControllerConfig>(properties.ToString());
return new Microphones.MicrophonePrivacyController(key, props);
}
else if (typeName == "roku")
{
var irCont = IRPortHelper.GetIrOutputPortController(dc);
return new Roku2(key, name, irCont);
}
else if (groupName == "settopbox") //(typeName == "irstbbase")
{
var irCont = IRPortHelper.GetIrOutputPortController(dc);
var config = dc.Properties.ToObject<SetTopBoxPropertiesConfig>();
var stb = new IRSetTopBoxBase(key, name, irCont, config);
//stb.HasDvr = properties.Value<bool>("hasDvr");
var listName = properties.Value<string>("presetsList");
if (listName != null)
stb.LoadPresets(listName);
return stb;
}
else if (typeName == "tvonecorio")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<TVOneCorioPropertiesConfig>(
properties.ToString());
return new TVOneCorio(key, name, comm, props);
}
else if (typeName == "glsoirccn")
{
var comm = CommFactory.GetControlPropertiesConfig(dc);
GlsOccupancySensorBase occSensor = null;
occSensor = new GlsOirCCn(comm.CresnetIdInt, Global.ControlSystem);
if (occSensor != null)
return new EssentialsGlsOccupancySensorBaseController(key, name, occSensor);
else
Debug.Console(0, "ERROR: Unable to create Occupancy Sensor Device. Key: '{0}'", key);
}
else if (typeName == "glsodtccn")
{
var comm = CommFactory.GetControlPropertiesConfig(dc);
GlsOccupancySensorBase occSensor = null;
occSensor = new GlsOdtCCn(comm.CresnetIdInt, Global.ControlSystem);
if (occSensor != null)
return new EssentialsGlsOccupancySensorBaseController(key, name, occSensor);
else
Debug.Console(0, "ERROR: Unable to create Occupancy Sensor Device. Key: '{0}'", key);
}
else if (groupName == "lighting")
{
if (typeName == "lutronqs")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<Environment.Lutron.LutronQuantumPropertiesConfig>(properties.ToString());
return new Environment.Lutron.LutronQuantumArea(key, name, comm, props);
}
else if (typeName == "din8sw8")
{
var comm = CommFactory.GetControlPropertiesConfig(dc);
return new Environment.Lighting.Din8sw8Controller(key, comm.CresnetIdInt);
}
}
else if (groupName == "environment")
{
if (typeName == "shadecontroller")
{
var props = JsonConvert.DeserializeObject<Core.Shades.ShadeControllerConfigProperties>(properties.ToString());
return new Core.Shades.ShadeController(key, name, props);
}
else if (typeName == "relaycontrolledshade")
{
var props = JsonConvert.DeserializeObject<Environment.Somfy.RelayControlledShadeConfigProperties>(properties.ToString());
return new Environment.Somfy.RelayControlledShade(key, name, props);
}
}
//else if (typeName == "qscdsp")
//{
// var comm = CommFactory.CreateCommForDevice(dc);
// var props = JsonConvert.DeserializeObject<QscDspPropertiesConfig>(
// properties.ToString());
// return new QscDsp(key, name, comm, props);
//}
return null;
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Common
{
public class GenericSource : Device, IUiDisplayInfo, IRoutingOutputs, IUsageTracking
{
public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } }
public GenericSource(string key, string name)
: base(key, name)
{
AnyOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this);
OutputPorts = new RoutingPortCollection<RoutingOutputPort> { AnyOut };
}
#region IRoutingOutputs Members
public RoutingOutputPort AnyOut { get; private set; }
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
#region IUsageTracking Members
public UsageTracking UsageTracker { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,24 @@
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.Devices.Common
{
/// <summary>
///
/// </summary>
public class AnalogWayLiveCorePropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
public string userName { get; set; }
public string password { get; set; }
}
}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common
{
public class AnalogWayLiveCore : Device
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public string userName;
public string password;
private bool OnlineStatus;
public BoolFeedback OnlineFeedback;
private ushort CurrentPreset;
public IntFeedback PresetFeedback;
// new public Dictionary<string, QscDspLevelControl> LevelControlPoints { get; private set; }
// public List<QscDspPresets> PresetList = new List<QscDspPresets>();
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public AnalogWayLiveCore(string key, string name, IBasicCommunication comm, AnalogWayLiveCorePropertiesConfig props) :
base(key, name)
{
this.userName = props.userName;
this.password = props.password;
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "System.Status\x0A\x0D");
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
OnlineFeedback = new BoolFeedback(() => { return OnlineStatus; });
PresetFeedback = new IntFeedback(() => { return CurrentPreset; });
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
OnlineStatus = true;
OnlineFeedback.FireUpdate();
}
else
{
OnlineStatus = false;
OnlineFeedback.FireUpdate();
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "TVOneCurio RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("login") > -1)
{
SendLine(string.Format("Login({0},{1})", this.userName, this.password));
}
else if (args.Text.IndexOf("!Done Preset.Take =") > -1)
{
string presetNumberParse = args.Text.Remove(0, args.Text.IndexOf("=") + 2);
Debug.Console(1, this, "Preset Parse: {0}", presetNumberParse);
CurrentPreset = ushort.Parse(presetNumberParse);
PresetFeedback.FireUpdate();
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TVOne Cusio TX: '{0}'", s);
Communication.SendText(s + "\x0d\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
public void CallPreset(ushort presetNumber)
{
SendLine(string.Format("Preset.Take = {0}", presetNumber));
// SendLine("cgp 1");
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
// public QscDspControlPoint ControlPoint { get; set; }
}
}
}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common
{
public class TVOneCorio : Device
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public string userName;
public string password;
private bool OnlineStatus;
public BoolFeedback OnlineFeedback;
private ushort CurrentPreset;
public IntFeedback PresetFeedback;
// new public Dictionary<string, QscDspLevelControl> LevelControlPoints { get; private set; }
// public List<QscDspPresets> PresetList = new List<QscDspPresets>();
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public TVOneCorio(string key, string name, IBasicCommunication comm, TVOneCorioPropertiesConfig props) :
base(key, name)
{
this.userName = props.userName;
this.password = props.password;
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "System.Status\x0A\x0D");
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
OnlineFeedback = new BoolFeedback(() => { return OnlineStatus; });
PresetFeedback = new IntFeedback(() => { return CurrentPreset; });
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
OnlineStatus = true;
OnlineFeedback.FireUpdate();
}
else
{
OnlineStatus = false;
OnlineFeedback.FireUpdate();
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "TVOneCurio RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("login") > -1)
{
SendLine(string.Format("Login({0},{1})", this.userName, this.password));
}
else if (args.Text.IndexOf("!Done Preset.Take =") > -1)
{
string presetNumberParse = args.Text.Remove(0, args.Text.IndexOf("=") + 2);
Debug.Console(1, this, "Preset Parse: {0}", presetNumberParse);
CurrentPreset = ushort.Parse(presetNumberParse);
PresetFeedback.FireUpdate();
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TVOne Cusio TX: '{0}'", s);
Communication.SendText(s + "\x0d\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
public void CallPreset(ushort presetNumber)
{
SendLine(string.Format("Preset.Take = {0}", presetNumber));
// SendLine("cgp 1");
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
// public QscDspControlPoint ControlPoint { get; set; }
}
}
}

View File

@@ -0,0 +1,24 @@
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.Devices.Common
{
/// <summary>
///
/// </summary>
public class TVOneCorioPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
public string userName { get; set; }
public string password { get; set; }
}
}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common
{
public class TVOneCorio : Device
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public string userName;
public string password;
private bool OnlineStatus;
public BoolFeedback OnlineFeedback;
private ushort CurrentPreset;
public IntFeedback PresetFeedback;
// new public Dictionary<string, QscDspLevelControl> LevelControlPoints { get; private set; }
// public List<QscDspPresets> PresetList = new List<QscDspPresets>();
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public TVOneCorio(string key, string name, IBasicCommunication comm, TVOneCorioPropertiesConfig props) :
base(key, name)
{
this.userName = props.userName;
this.password = props.password;
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "System.Status\x0A\x0D");
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
OnlineFeedback = new BoolFeedback(() => { return OnlineStatus; });
PresetFeedback = new IntFeedback(() => { return CurrentPreset; });
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
OnlineStatus = true;
OnlineFeedback.FireUpdate();
}
else
{
OnlineStatus = false;
OnlineFeedback.FireUpdate();
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
Debug.Console(2, this, "TVOneCurio RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("login") > -1)
{
SendLine(string.Format("Login({0},{1})", this.userName, this.password));
}
else if (args.Text.IndexOf("!Done Preset.Take =") > -1)
{
string presetNumberParse = args.Text.Remove(0, args.Text.IndexOf("=") + 2);
Debug.Console(1, this, "Preset Parse: {0}", presetNumberParse);
CurrentPreset = ushort.Parse(presetNumberParse);
PresetFeedback.FireUpdate();
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TVOne Cusio TX: '{0}'", s);
Communication.SendText(s + "\x0d\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
public void CallPreset(ushort presetNumber)
{
SendLine(string.Format("Preset.Take = {0}", presetNumber));
// SendLine("cgp 1");
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
// public QscDspControlPoint ControlPoint { get; set; }
}
}
}

View File

@@ -0,0 +1,24 @@
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.Devices.Common
{
/// <summary>
///
/// </summary>
public class TVOneCorioPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
public string userName { get; set; }
public string password { get; set; }
}
}

View File

@@ -0,0 +1,226 @@
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.CrestronIO;
namespace PepperDash.Essentials.Devices.Common.Microphones
{
/// <summary>
/// Used for applications where one or more microphones with momentary contact closure outputs are used to
/// toggle the privacy state of the room. Privacy state feedback is represented
/// </summary>
public class MicrophonePrivacyController : Device
{
MicrophonePrivacyControllerConfig Config;
bool initialized;
public bool EnableLeds
{
get
{
return _enableLeds;
}
set
{
_enableLeds = value;
if (initialized)
{
if (value)
{
CheckPrivacyMode();
SetLedStates();
}
else
TurnOffAllLeds();
}
}
}
bool _enableLeds;
public List<IDigitalInput> Inputs { get; private set; }
public GenericRelayDevice RedLedRelay { get; private set; }
bool _redLedRelayState;
public GenericRelayDevice GreenLedRelay { get; private set; }
bool _greenLedRelayState;
public IPrivacy PrivacyDevice { get; private set; }
public MicrophonePrivacyController(string key, MicrophonePrivacyControllerConfig config) :
base(key)
{
Config = config;
Inputs = new List<IDigitalInput>();
}
public override bool CustomActivate()
{
foreach (var i in Config.Inputs)
{
var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput;
if(input != null)
AddInput(input);
}
var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice;
if (greenLed != null)
GreenLedRelay = greenLed;
else
Debug.Console(0, this, "Unable to add Green LED device");
var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice;
if (redLed != null)
RedLedRelay = redLed;
else
Debug.Console(0, this, "Unable to add Red LED device");
CheckPrivacyMode();
initialized = true;
return base.CustomActivate();
}
public void SetPrivacyDevice(IPrivacy privacyDevice)
{
PrivacyDevice = privacyDevice;
PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange;
}
void PrivacyModeIsOnFeedback_OutputChange(object sender, EventArgs e)
{
Debug.Console(1, this, "Privacy mode change: {0}", sender as BoolFeedback);
CheckPrivacyMode();
}
void CheckPrivacyMode()
{
if (PrivacyDevice != null)
{
var privacyState = PrivacyDevice.PrivacyModeIsOnFeedback.BoolValue;
if (privacyState)
TurnOnRedLeds();
else
TurnOnGreenLeds();
}
}
void AddInput(IDigitalInput input)
{
Inputs.Add(input);
input.InputStateFeedback.OutputChange += InputStateFeedback_OutputChange;
}
void RemoveInput(IDigitalInput input)
{
var tempInput = Inputs.FirstOrDefault(i => i.Equals(input));
if (tempInput != null)
tempInput.InputStateFeedback.OutputChange -= InputStateFeedback_OutputChange;
Inputs.Remove(input);
}
void SetRedLedRelay(GenericRelayDevice relay)
{
RedLedRelay = relay;
}
void SetGreenLedRelay(GenericRelayDevice relay)
{
GreenLedRelay = relay;
}
/// <summary>
/// Check the state of the input change and handle accordingly
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void InputStateFeedback_OutputChange(object sender, EventArgs e)
{
if ((sender as BoolFeedback).BoolValue == true)
TogglePrivacyMute();
}
/// <summary>
/// Toggles the state of the privacy mute
/// </summary>
public void TogglePrivacyMute()
{
PrivacyDevice.PrivacyModeToggle();
}
void TurnOnRedLeds()
{
_greenLedRelayState = false;
_redLedRelayState = true;
SetLedStates();
}
void TurnOnGreenLeds()
{
_redLedRelayState = false;
_greenLedRelayState = true;
SetLedStates();
}
/// <summary>
/// If enabled, sets the actual state of the relays
/// </summary>
void SetLedStates()
{
if (_enableLeds)
{
SetRelayStates();
}
else
TurnOffAllLeds();
}
/// <summary>
/// Turns off all LEDs
/// </summary>
void TurnOffAllLeds()
{
_redLedRelayState = false;
_greenLedRelayState = false;
SetRelayStates();
}
void SetRelayStates()
{
if (RedLedRelay != null)
{
if (_redLedRelayState)
RedLedRelay.CloseRelay();
else
RedLedRelay.OpenRelay();
}
if(GreenLedRelay != null)
{
if (_greenLedRelayState)
GreenLedRelay.CloseRelay();
else
GreenLedRelay.OpenRelay();
}
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core.CrestronIO;
namespace PepperDash.Essentials.Devices.Common.Microphones
{
public class MicrophonePrivacyControllerConfig
{
public List<KeyedDevice> Inputs { get; set; }
public KeyedDevice GreenLedRelay { get; set; }
public KeyedDevice RedLedRelay { get; set; }
}
public class KeyedDevice
{
public string DeviceKey { get; set; }
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Occupancy
{
public class EssentialsGlsOccupancySensorBaseController : CrestronGenericBaseDevice, IOccupancyStatusProvider
{
public GlsOccupancySensorBase OccSensor { get; private set; }
public BoolFeedback RoomIsOccupiedFeedback { get; private set; }
// Debug properties
public bool InTestMode { get; private set; }
public bool TestRoomIsOccupiedFeedback { get; private set; }
public Func<bool> RoomIsOccupiedFeedbackFunc
{
get
{
return () => InTestMode ? TestRoomIsOccupiedFeedback : OccSensor.OccupancyDetectedFeedback.BoolValue;
}
}
public EssentialsGlsOccupancySensorBaseController(string key, string name, GlsOccupancySensorBase sensor)
: base(key, name, sensor)
{
OccSensor = sensor;
RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc);
OccSensor.BaseEvent += new Crestron.SimplSharpPro.BaseEventHandler(OccSensor_BaseEvent);
}
void OccSensor_BaseEvent(Crestron.SimplSharpPro.GenericBase device, Crestron.SimplSharpPro.BaseEventArgs args)
{
Debug.Console(2, this, "GlsOccupancySensorChange EventId: {0}", args.EventId);
if (args.EventId == Crestron.SimplSharpPro.GeneralIO.GlsOccupancySensorBase.RoomOccupiedFeedbackEventId
|| args.EventId == Crestron.SimplSharpPro.GeneralIO.GlsOccupancySensorBase.RoomVacantFeedbackEventId)
{
Debug.Console(1, this, "Occupancy State: {0}", OccSensor.OccupancyDetectedFeedback.BoolValue);
RoomIsOccupiedFeedback.FireUpdate();
}
}
public void SetTestMode(bool mode)
{
InTestMode = mode;
Debug.Console(1, this, "In Mock Mode: '{0}'", InTestMode);
}
public void SetTestOccupiedState(bool state)
{
if (!InTestMode)
Debug.Console(1, "Mock mode not enabled");
else
{
TestRoomIsOccupiedFeedback = state;
RoomIsOccupiedFeedback.FireUpdate();
}
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Occupancy
{
public class EssentialsGlsOccupancySensorBaseController : CrestronGenericBaseDevice, IOccupancyStatusProvider
{
public GlsOccupancySensorBase OccSensor { get; private set; }
public BoolFeedback RoomIsOccupiedFeedback { get; private set; }
<<<<<<< HEAD
/// <summary>
/// Set by debugging functions
/// </summary>
public bool InMockMode { get; private set; }
public bool MockRoomIsOccupiedFeedback { get; private set; }
=======
// Debug properties
public bool InTestMode { get; private set; }
public bool TestRoomIsOccupiedFeedback { get; private set; }
>>>>>>> origin/feature/ecs-342-neil
public Func<bool> RoomIsOccupiedFeedbackFunc
{
get
{
<<<<<<< HEAD
return () => InMockMode ? MockRoomIsOccupiedFeedback : OccSensor.OccupancyDetectedFeedback.BoolValue;
=======
return () => InTestMode ? TestRoomIsOccupiedFeedback : OccSensor.OccupancyDetectedFeedback.BoolValue;
>>>>>>> origin/feature/ecs-342-neil
}
}
public EssentialsGlsOccupancySensorBaseController(string key, string name, GlsOccupancySensorBase sensor, GlsOccupancySensorConfigurationProperties props)
: base(key, name, sensor)
{
OccSensor = sensor;
RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc);
OccSensor.GlsOccupancySensorChange += new GlsOccupancySensorChangeEventHandler(sensor_GlsOccupancySensorChange);
}
void sensor_GlsOccupancySensorChange(GlsOccupancySensorBase device, GlsOccupancySensorChangeEventArgs args)
{
RoomIsOccupiedFeedback.FireUpdate();
}
public void SetTestMode(bool mode)
{
InTestMode = mode;
Debug.Console(1, this, "In Mock Mode: '{0}'", InTestMode);
}
public void SetTestOccupiedState(bool state)
{
if (!InTestMode)
Debug.Console(1, "Mock mode not enabled");
else
{
TestRoomIsOccupiedFeedback = state;
RoomIsOccupiedFeedback.FireUpdate();
}
}
}
/// <summary>
///
/// </summary>
public class GlsOccupancySensorConfigurationProperties
{
public string CresnetId { get; set; }
public string Model { get; set; }
}
}

View File

@@ -0,0 +1,45 @@
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.Devices.Common.Occupancy
{
/// <summary>
/// Aggregates the RoomIsOccupied feedbacks of one or more IOccupancyStatusProvider objects
/// </summary>
public class EssentialsOccupancyAggregator : Device, IOccupancyStatusProvider
{
/// <summary>
/// Aggregated feedback of all linked IOccupancyStatusProvider devices
/// </summary>
public BoolFeedback RoomIsOccupiedFeedback
{
get
{
return AggregatedOccupancyStatus.Output;
}
}
private BoolFeedbackOr AggregatedOccupancyStatus;
public EssentialsOccupancyAggregator(string key, string name)
: base(key, name)
{
AggregatedOccupancyStatus = new BoolFeedbackOr();
}
/// <summary>
/// Adds an IOccupancyStatusProvider device
/// </summary>
/// <param name="statusProvider"></param>
public void AddOccupancyStatusProvider(IOccupancyStatusProvider statusProvider)
{
AggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback);
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Occupancy
{
public interface IOccupancyStatusProvider
{
BoolFeedback RoomIsOccupiedFeedback { get; }
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharpPro;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Core;
namespace PepperDash.Essentials.Devices.Common
{
/// <summary>
/// This DVD class should cover most IR, one-way DVD and Bluray fuctions
/// </summary>
public class InRoomPc : Device, IHasFeedback, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking
{
public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } }
public string IconName { get; set; }
public BoolFeedback HasPowerOnFeedback { get; private set; }
public RoutingOutputPort AnyVideoOut { get; private set; }
#region IRoutingOutputs Members
/// <summary>
/// Options: hdmi
/// </summary>
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
public InRoomPc(string key, string name)
: base(key, name)
{
IconName = "PC";
HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback",
() => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus);
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.None, 0, this));
}
#region IHasFeedback Members
/// <summary>
/// Passes through the VideoStatuses list
/// </summary>
public FeedbackCollection<Feedback> Feedbacks
{
get
{
var newList = new FeedbackCollection<Feedback>();
newList.AddRange(this.GetVideoStatuses().ToList());
return newList;
}
}
#endregion
#region IUsageTracking Members
public UsageTracking UsageTracker { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharpPro;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Core;
namespace PepperDash.Essentials.Devices.Common
{
/// <summary>
/// This DVD class should cover most IR, one-way DVD and Bluray fuctions
/// </summary>
public class Laptop : Device, IHasFeedback, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking
{
public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } }
public string IconName { get; set; }
public BoolFeedback HasPowerOnFeedback { get; private set; }
public RoutingOutputPort AnyVideoOut { get; private set; }
#region IRoutingOutputs Members
/// <summary>
/// Options: hdmi
/// </summary>
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
public Laptop(string key, string name)
: base(key, name)
{
IconName = "Laptop";
HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback",
() => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus);
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.None, 0, this));
}
#region IHasFeedback Members
/// <summary>
/// Passes through the VideoStatuses list
/// </summary>
public FeedbackCollection<Feedback> Feedbacks
{
get
{
var newList = new FeedbackCollection<Feedback>();
newList.AddRange(this.GetVideoStatuses().ToList());
return newList;
}
}
#endregion
#region IUsageTracking Members
public UsageTracking UsageTracker { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,25 @@
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.Devices.Common
{
/// <summary>
///
/// </summary>
public class DigitalLoggerPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public ControlPropertiesConfig Control { get; set; }
public string userName { get; set; }
public string password { get; set; }
public string address { get; set; }
}
}

View File

@@ -0,0 +1,313 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Essentials.Devices.Common
{
public class DigitalLogger : Device
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
private HttpClient WebClient;
public string userName;
public string password;
public string address;
private bool OnlineStatus;
public BoolFeedback OnlineFeedback;
private ushort CurrentPreset;
public IntFeedback PresetFeedback;
public Dictionary<uint, DigitalLoggerCircuit> CircuitStatus;
public uint CircuitCount;
public Dictionary<uint, StringFeedback> CircuitNameFeedbacks { get; private set; }
public Dictionary<uint, BoolFeedback> CircuitIsCritical{ get; private set; }
public Dictionary<uint, BoolFeedback> CircuitState { get; private set; }
// new public Dictionary<string, QscDspLevelControl> LevelControlPoints { get; private set; }
// public List<QscDspPresets> PresetList = new List<QscDspPresets>();
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public DigitalLogger(string key, string name, DigitalLoggerPropertiesConfig props) :
base(key, name)
{
CircuitCount = 8;
this.userName = props.userName;
this.password = props.password;
CommandQueue = new CrestronQueue(100);
WebClient = new HttpClient();
WebClient.UserName = this.userName;
WebClient.Password = this.password;
this.address = props.address;
WebClient.HostAddress = props.address;
}
public override bool CustomActivate()
{
/*
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
*/
OnlineFeedback = new BoolFeedback(() => { return OnlineStatus; });
CircuitStatus = new Dictionary<uint, DigitalLoggerCircuit>();
CircuitNameFeedbacks = new Dictionary<uint, StringFeedback>();
CircuitIsCritical = new Dictionary<uint, BoolFeedback>();
CircuitState = new Dictionary<uint, BoolFeedback>();
for (uint i = 0; i < CircuitCount; i++)
{
uint circuit = i;
CircuitStatus[circuit] = new DigitalLoggerCircuit();
CircuitNameFeedbacks[circuit] = new StringFeedback(() => {
if (CircuitStatus[circuit].name != null)
{
return CircuitStatus[circuit].name;
}
else
{
return "";
}
});
CircuitIsCritical[circuit] = new BoolFeedback(() =>
{
if (CircuitStatus[circuit].critical != null)
{
return CircuitStatus[circuit].critical;
}
else
{
return false;
}
});
CircuitState[circuit] = new BoolFeedback(() =>
{
if (CircuitStatus[circuit].state != null)
{
return CircuitStatus[circuit].state;
}
else
{
return false;
}
});
PollCircuit(circuit);
}
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
OnlineStatus = true;
OnlineFeedback.FireUpdate();
}
else
{
OnlineStatus = false;
OnlineFeedback.FireUpdate();
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
public void PollCircuit(uint circuit)
{
try
{
string PollCircuitResponse = SendRequest(String.Format("/restapi/relay/outlets/{0}/", circuit));
CircuitStatus[circuit] = JsonConvert.DeserializeObject<DigitalLoggerCircuit>(PollCircuitResponse);
DigitalLoggerCircuit temp = CircuitStatus[circuit];
Debug.Console(2, this, "DigitalLogger Circuit {0} Name: {1} State:{2}'", circuit, CircuitStatus[circuit].name, CircuitStatus[circuit].state);
CircuitNameFeedbacks[circuit].FireUpdate();
CircuitState[circuit].FireUpdate();
CircuitIsCritical[circuit].FireUpdate();
}
catch (Exception e)
{
Debug.Console(0, this, "PollCircuit {0}", e);
}
}
void Port_LineReceived(string response, HTTP_CALLBACK_ERROR error)
{
}
public string SendRequest(string s)
{
HttpClientRequest request = new HttpClientRequest();
string url = string.Format("http://{0}{1}", this.address, s);
request.Url = new UrlParser(url);
HttpClientResponse response = WebClient.Dispatch(request);
Debug.Console(2, this, "DigitalLogger TX:\n'{0}'\nRX:\n'{1}'", url, response.ContentString);
return response.ContentString;
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
///
public void SendLine(string s)
{
HttpClientRequest request = new HttpClientRequest();
string url = string.Format("http://{0}{1}", this.address, s);
request.Url = new UrlParser(url);
HttpClientResponse response = WebClient.Dispatch(request);
Debug.Console(2, this, "DigitalLogger TX:\n'{0}'\nRX:\n'{1}'", url, response.ContentString);
}
public void CycleCircuit(uint circuit)
{
SendLine(String.Format("/outlet?{0}=CCL", circuit));
//PollCircuit(circuit);
}
public void TurnOnCircuit(uint circuit)
{
SendLine(String.Format("/outlet?{0}=ON", circuit));
//PollCircuit(circuit);
}
public void TurnOffCircuit(uint circuit)
{
SendLine(String.Format("/outlet?{0}=Off", circuit));
//PollCircuit(circuit);
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
public void CallPreset(ushort presetNumber)
{
SendLine(string.Format("Preset.Take = {0}", presetNumber));
// SendLine("cgp 1");
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
// public QscDspControlPoint ControlPoint { get; set; }
}
public class DigitalLoggerCircuit
{
public string name;
public bool locked;
public bool critical;
public bool transient_state;
public bool physical_state;
//public int cycle_delay;
public bool state;
}
}
}

View File

@@ -0,0 +1,7 @@
using System.Reflection;
[assembly: AssemblyTitle("Essentials_Devices_Common")]
[assembly: AssemblyCompany("PepperDash Technology Corp")]
[assembly: AssemblyProduct("Essentials_Devices_Common")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyVersion("1.3.*")]

View File

@@ -0,0 +1,343 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Presets;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Common
{
public class IRSetTopBoxBase : Device, ISetTopBoxControls, IUiDisplayInfo, IRoutingOutputs, IUsageTracking
{
public IrOutputPortController IrPort { get; private set; }
public uint DisplayUiType { get { return DisplayUiConstants.TypeDirecTv; } }
public bool HasPresets { get; set; }
public bool HasDvr { get; set; }
public bool HasDpad { get; set; }
public bool HasNumeric { get; set; }
public DevicePresetsModel PresetsModel { get; private set; }
public IRSetTopBoxBase(string key, string name, IrOutputPortController portCont,
SetTopBoxPropertiesConfig props)
: base(key, name)
{
IrPort = portCont;
DeviceManager.AddDevice(portCont);
HasPresets = props.HasPresets;
HasDvr = props.HasDvr;
HasDpad = props.HasDpad;
HasNumeric = props.HasNumeric;
HasKeypadAccessoryButton1 = true;
KeypadAccessoryButton1Command = "Dash";
KeypadAccessoryButton1Label = "-";
HasKeypadAccessoryButton2 = true;
KeypadAccessoryButton2Command = "NumericEnter";
KeypadAccessoryButton2Label = "Enter";
AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this);
AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio,
eRoutingPortConnectionType.DigitalAudio, null, this);
OutputPorts = new RoutingPortCollection<RoutingOutputPort> { AnyVideoOut, AnyAudioOut };
}
public void LoadPresets(string filePath)
{
PresetsModel = new DevicePresetsModel(Key + "-presets", this, filePath);
DeviceManager.AddDevice(PresetsModel);
}
#region ISetTopBoxControls Members
public void DvrList(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_DVR, pressRelease);
}
public void Replay(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease);
}
#endregion
#region IDPad Members
public void Up(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease);
}
public void Down(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease);
}
public void Left(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease);
}
public void Right(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease);
}
public void Select(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease);
}
public void Menu(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease);
}
public void Exit(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease);
}
#endregion
#region INumericKeypad Members
public void Digit0(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_0, pressRelease);
}
public void Digit1(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_1, pressRelease);
}
public void Digit2(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_2, pressRelease);
}
public void Digit3(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_3, pressRelease);
}
public void Digit4(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_4, pressRelease);
}
public void Digit5(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_5, pressRelease);
}
public void Digit6(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_6, pressRelease);
}
public void Digit7(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_7, pressRelease);
}
public void Digit8(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_8, pressRelease);
}
public void Digit9(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_9, pressRelease);
}
/// <summary>
/// Defaults to true
/// </summary>
public bool HasKeypadAccessoryButton1 { get; set; }
/// <summary>
/// Defaults to "-"
/// </summary>
public string KeypadAccessoryButton1Label { get; set; }
/// <summary>
/// Defaults to "Dash"
/// </summary>
public string KeypadAccessoryButton1Command { get; set; }
public void KeypadAccessoryButton1(bool pressRelease)
{
IrPort.PressRelease(KeypadAccessoryButton1Command, pressRelease);
}
/// <summary>
/// Defaults to true
/// </summary>
public bool HasKeypadAccessoryButton2 { get; set; }
/// <summary>
/// Defaults to "Enter"
/// </summary>
public string KeypadAccessoryButton2Label { get; set; }
/// <summary>
/// Defaults to "Enter"
/// </summary>
public string KeypadAccessoryButton2Command { get; set; }
public void KeypadAccessoryButton2(bool pressRelease)
{
IrPort.PressRelease(KeypadAccessoryButton2Command, pressRelease);
}
#endregion
#region ISetTopBoxNumericKeypad Members
/// <summary>
/// Corresponds to "dash" IR command
/// </summary>
public void Dash(bool pressRelease)
{
IrPort.PressRelease("dash", pressRelease);
}
/// <summary>
/// Corresponds to "numericEnter" IR command
/// </summary>
public void KeypadEnter(bool pressRelease)
{
IrPort.PressRelease("numericEnter", pressRelease);
}
#endregion
#region IChannelFunctions Members
public void ChannelUp(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_CH_PLUS, pressRelease);
}
public void ChannelDown(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_CH_MINUS, pressRelease);
}
public void LastChannel(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_LAST, pressRelease);
}
public void Guide(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_GUIDE, pressRelease);
}
public void Info(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_INFO, pressRelease);
}
#endregion
#region IColorFunctions Members
public void Red(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RED, pressRelease);
}
public void Green(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_GREEN, pressRelease);
}
public void Yellow(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_YELLOW, pressRelease);
}
public void Blue(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_BLUE, pressRelease);
}
#endregion
#region IRoutingOutputs Members
public RoutingOutputPort AnyVideoOut { get; private set; }
public RoutingOutputPort AnyAudioOut { get; private set; }
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
#region ITransport Members
public void ChapMinus(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease);
}
public void ChapPlus(bool pressRelease)
{
}
public void FFwd(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease);
}
public void Pause(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease);
}
public void Play(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease);
}
public void Record(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RECORD, pressRelease);
}
public void Rewind(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease);
}
public void Stop(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_STOP, pressRelease);
}
#endregion
#region IUsageTracking Members
public UsageTracking UsageTracker { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Essentials.Devices.Common
{
public class SetTopBoxPropertiesConfig : PepperDash.Essentials.Core.Config.SourceDevicePropertiesConfigBase
{
public bool HasPresets { get; set; }
public bool HasDvr { get; set; }
public bool HasDpad { get; set; }
public bool HasNumeric { get; set; }
public ControlPropertiesConfig Control { get; set; }
}
}

View File

@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Common
{
public class AppleTV : Device, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs
{
public IrOutputPortController IrPort { get; private set; }
public const string StandardDriverName = "Apple AppleTV-v2.ir";
public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } }
public AppleTV(string key, string name, IrOutputPortController portCont)
: base(key, name)
{
IrPort = portCont;
DeviceManager.AddDevice(portCont);
HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this);
AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio,
eRoutingPortConnectionType.DigitalAudio, null, this);
OutputPorts = new RoutingPortCollection<RoutingOutputPort> { HdmiOut, AnyAudioOut };
}
#region IDPad Members
public void Up(bool pressRelease)
{
IrPort.PressRelease("+", pressRelease);
}
public void Down(bool pressRelease)
{
IrPort.PressRelease("-", pressRelease);
}
public void Left(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_TRACK_MINUS, pressRelease);
}
public void Right(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_TRACK_PLUS, pressRelease);
}
public void Select(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease);
}
public void Menu(bool pressRelease)
{
IrPort.PressRelease("Menu", pressRelease);
}
public void Exit(bool pressRelease)
{
}
#endregion
#region ITransport Members
public void Play(bool pressRelease)
{
IrPort.PressRelease("PLAY/PAUSE", pressRelease);
}
public void Pause(bool pressRelease)
{
IrPort.PressRelease("PLAY/PAUSE", pressRelease);
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void Rewind(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void FFwd(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void ChapMinus(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void ChapPlus(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void Stop(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void Record(bool pressRelease)
{
}
#endregion
#region IRoutingOutputs Members
public RoutingOutputPort HdmiOut { get; private set; }
public RoutingOutputPort AnyAudioOut { get; private set; }
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
}
}

View File

@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Devices.Common
{
public class Roku2 : Device, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs
{
[Api]
public IrOutputPortController IrPort { get; private set; }
public const string StandardDriverName = "Roku XD_S.ir";
[Api]
public uint DisplayUiType { get { return DisplayUiConstants.TypeRoku; } }
public Roku2(string key, string name, IrOutputPortController portCont)
: base(key, name)
{
IrPort = portCont;
DeviceManager.AddDevice(portCont);;
HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this);
OutputPorts = new RoutingPortCollection<RoutingOutputPort> { HdmiOut };
}
#region IDPad Members
[Api]
public void Up(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease);
}
[Api]
public void Down(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease);
}
[Api]
public void Left(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease);
}
[Api]
public void Right(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease);
}
[Api]
public void Select(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease);
}
[Api]
public void Menu(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease);
}
[Api]
public void Exit(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease);
}
#endregion
#region ITransport Members
[Api]
public void Play(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease);
}
[Api]
public void Pause(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_PAUSE, pressRelease);
}
[Api]
public void Rewind(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease);
}
[Api]
public void FFwd(bool pressRelease)
{
IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease);
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void ChapMinus(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void ChapPlus(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void Stop(bool pressRelease)
{
}
/// <summary>
/// Not implemented
/// </summary>
/// <param name="pressRelease"></param>
public void Record(bool pressRelease)
{
}
#endregion
#region IRoutingOutputs Members
public RoutingOutputPort HdmiOut { get; private set; }
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
}
}

View File

@@ -0,0 +1,379 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.Codec;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public class CiscoCodecBookings
{
public class TotalRows
{
public string Value { get; set; }
}
public class ResultInfo
{
public TotalRows TotalRows { get; set; }
}
public class LastUpdated
{
string _value;
public DateTime Value {
get
{
DateTime _valueDateTime;
try
{
_valueDateTime = DateTime.Parse(_value);
return _valueDateTime;
}
catch
{
return new DateTime();
}
}
set
{
_value = value.ToString();
}
}
}
public class Id
{
public string Value { get; set; }
}
public class Title
{
public string Value { get; set; }
}
public class Agenda
{
public string Value { get; set; }
}
public class Privacy
{
public string Value { get; set; }
}
public class FirstName
{
public string Value { get; set; }
}
public class LastName
{
public string Value { get; set; }
}
public class Email
{
public string Value { get; set; }
}
public class Id2
{
public string Value { get; set; }
}
public class Organizer
{
public FirstName FirstName { get; set; }
public LastName LastName { get; set; }
public Email Email { get; set; }
public Id2 Id { get; set; }
public Organizer()
{
FirstName = new FirstName();
LastName = new LastName();
Email = new Email();
}
}
public class StartTime
{
public DateTime Value { get; set; }
}
public class StartTimeBuffer
{
public string Value { get; set; }
}
public class EndTime
{
public DateTime Value { get; set; }
}
public class EndTimeBuffer
{
public string Value { get; set; }
}
public class Time
{
public StartTime StartTime { get; set; }
public StartTimeBuffer StartTimeBuffer { get; set; }
public EndTime EndTime { get; set; }
public EndTimeBuffer EndTimeBuffer { get; set; }
public Time()
{
StartTime = new StartTime();
EndTime = new EndTime();
}
}
public class MaximumMeetingExtension
{
public string Value { get; set; }
}
public class MeetingExtensionAvailability
{
public string Value { get; set; }
}
public class BookingStatus
{
public string Value { get; set; }
}
public class BookingStatusMessage
{
public string Value { get; set; }
}
public class Enabled
{
public string Value { get; set; }
}
public class Url
{
public string Value { get; set; }
}
public class MeetingNumber
{
public string Value { get; set; }
}
public class Password
{
public string Value { get; set; }
}
public class HostKey
{
public string Value { get; set; }
}
public class DialInNumbers
{
}
public class Webex
{
public Enabled Enabled { get; set; }
public Url Url { get; set; }
public MeetingNumber MeetingNumber { get; set; }
public Password Password { get; set; }
public HostKey HostKey { get; set; }
public DialInNumbers DialInNumbers { get; set; }
}
public class Encryption
{
public string Value { get; set; }
}
public class Role
{
public string Value { get; set; }
}
public class Recording
{
public string Value { get; set; }
}
public class Number
{
public string Value { get; set; }
}
public class Protocol
{
public string Value { get; set; }
}
public class CallRate
{
public string Value { get; set; }
}
public class CallType
{
public string Value { get; set; }
}
public class Call
{
public string id { get; set; }
public Number Number { get; set; }
public Protocol Protocol { get; set; }
public CallRate CallRate { get; set; }
public CallType CallType { get; set; }
}
public class Calls
{
public List<Call> Call {get; set;}
}
public class ConnectMode
{
public string Value { get; set; }
}
public class DialInfo
{
public Calls Calls { get; set; }
public ConnectMode ConnectMode { get; set; }
public DialInfo()
{
Calls = new Calls();
ConnectMode = new ConnectMode();
}
}
public class Booking
{
public string id { get; set; }
public Id Id { get; set; }
public Title Title { get; set; }
public Agenda Agenda { get; set; }
public Privacy Privacy { get; set; }
public Organizer Organizer { get; set; }
public Time Time { get; set; }
public MaximumMeetingExtension MaximumMeetingExtension { get; set; }
public MeetingExtensionAvailability MeetingExtensionAvailability { get; set; }
public BookingStatus BookingStatus { get; set; }
public BookingStatusMessage BookingStatusMessage { get; set; }
public Webex Webex { get; set; }
public Encryption Encryption { get; set; }
public Role Role { get; set; }
public Recording Recording { get; set; }
public DialInfo DialInfo { get; set; }
public Booking()
{
Time = new Time();
Id = new Id();
Organizer = new Organizer();
Title = new Title();
Agenda = new Agenda();
Privacy = new Privacy();
DialInfo = new DialInfo();
}
}
public class BookingsListResult
{
public string status { get; set; }
public ResultInfo ResultInfo { get; set; }
//public LastUpdated LastUpdated { get; set; }
public List<Booking> Booking { get; set; }
}
public class CommandResponse
{
public BookingsListResult BookingsListResult { get; set; }
}
public class RootObject
{
public CommandResponse CommandResponse { get; set; }
}
/// <summary>
/// Extracts the necessary meeting values from the Cisco bookings response ans converts them to the generic class
/// </summary>
/// <param name="bookings"></param>
/// <returns></returns>
public static List<Meeting> GetGenericMeetingsFromBookingResult(List<Booking> bookings)
{
var meetings = new List<Meeting>();
if (Debug.Level > 0)
{
Debug.Console(1, "Meetings List:\n");
}
foreach(Booking b in bookings)
{
var meeting = new Meeting();
if(b.Id != null)
meeting.Id = b.Id.Value;
if(b.Organizer != null)
meeting.Organizer = string.Format("{0}, {1}", b.Organizer.LastName.Value, b.Organizer.FirstName.Value);
if(b.Title != null)
meeting.Title = b.Title.Value;
if(b.Agenda != null)
meeting.Agenda = b.Agenda.Value;
if(b.Time != null)
meeting.StartTime = b.Time.StartTime.Value;
meeting.EndTime = b.Time.EndTime.Value;
if(b.Privacy != null)
meeting.Privacy = CodecCallPrivacy.ConvertToDirectionEnum(b.Privacy.Value);
//#warning Update this ConnectMode conversion after testing onsite. Expected value is "OBTP", but in PD NYC Test scenarios, "Manual" is being returned for OBTP meetings
if (b.DialInfo.ConnectMode != null)
if (b.DialInfo.ConnectMode.Value.ToLower() == "obtp" || b.DialInfo.ConnectMode.Value.ToLower() == "manual")
meeting.IsOneButtonToPushMeeting = true;
if (b.DialInfo.Calls.Call != null)
{
foreach (Call c in b.DialInfo.Calls.Call)
{
meeting.Calls.Add(new PepperDash.Essentials.Devices.Common.Codec.Call()
{
Number = c.Number.Value,
Protocol = c.Protocol.Value,
CallRate = c.CallRate.Value,
CallType = c.CallType.Value
});
}
}
meetings.Add(meeting);
if(Debug.Level > 0)
{
Debug.Console(1, "Title: {0}, ID: {1}, Organizer: {2}, Agenda: {3}", meeting.Title, meeting.Id, meeting.Organizer, meeting.Agenda);
Debug.Console(1, " Start Time: {0}, End Time: {1}, Duration: {2}", meeting.StartTime, meeting.EndTime, meeting.Duration);
Debug.Console(1, " Joinable: {0}\n", meeting.Joinable);
}
}
meetings.OrderBy(m => m.StartTime);
return meetings;
}
}
}

View File

@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public class CiscoCallHistory
{
public class CallbackNumber
{
public string Value { get; set; }
}
public class DisplayName
{
public string Value { get; set; }
}
public class LastOccurrenceStartTime
{
public DateTime Value { get; set; }
}
public class LastOccurrenceDaysAgo
{
public string Value { get; set; }
}
public class LastOccurrenceHistoryId
{
public string Value { get; set; }
}
public class OccurrenceType
{
public string Value { get; set; }
}
public class IsAcknowledged
{
public string Value { get; set; }
}
public class OccurrenceCount
{
public string Value { get; set; }
}
public class Entry
{
public string id { get; set; }
public CallbackNumber CallbackNumber { get; set; }
public DisplayName DisplayName { get; set; }
public LastOccurrenceStartTime LastOccurrenceStartTime { get; set; }
public LastOccurrenceDaysAgo LastOccurrenceDaysAgo { get; set; }
public LastOccurrenceHistoryId LastOccurrenceHistoryId { get; set; }
public OccurrenceType OccurrenceType { get; set; }
public IsAcknowledged IsAcknowledged { get; set; }
public OccurrenceCount OccurrenceCount { get; set; }
}
public class Offset
{
public string Value { get; set; }
}
public class Limit
{
public string Value { get; set; }
}
public class ResultInfo
{
public Offset Offset { get; set; }
public Limit Limit { get; set; }
}
public class CallHistoryRecentsResult
{
public string status { get; set; }
public List<Entry> Entry { get; set; }
public ResultInfo ResultInfo { get; set; }
}
public class CommandResponse
{
public CallHistoryRecentsResult CallHistoryRecentsResult { get; set; }
}
public class RootObject
{
public CommandResponse CommandResponse { get; set; }
}
}
}

View File

@@ -0,0 +1,312 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
public class CiscoFarEndCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera
{
protected CiscoSparkCodec ParentCodec { get; private set; }
protected string CallId {
get
{
return (ParentCodec as CiscoSparkCodec).GetCallId();
}
}
public CiscoFarEndCamera(string key, string name, CiscoSparkCodec codec)
: base(key, name)
{
Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom;
ParentCodec = codec;
}
#region IHasCameraPtzControl Members
public void PositionHome()
{
// Not supported on far end camera
}
#endregion
#region IHasCameraPanControl Members
public void PanLeft()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Left CallId: {0}", CallId));
}
public void PanRight()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Right CallId: {0}", CallId));
}
public void PanStop()
{
Stop();
}
#endregion
#region IHasCameraTiltControl Members
public void TiltDown()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Down CallId: {0}", CallId));
}
public void TiltUp()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: Up CallId: {0}", CallId));
}
public void TiltStop()
{
Stop();
}
#endregion
#region IHasCameraZoomControl Members
public void ZoomIn()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomIn CallId: {0}", CallId));
}
public void ZoomOut()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Move Value: ZoomOut CallId: {0}", CallId));
}
public void ZoomStop()
{
Stop();
}
#endregion
void Stop()
{
ParentCodec.SendText(string.Format("xCommand Call FarEndControl Camera Stop CallId: {0}", CallId));
}
}
public class CiscoSparkCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl
{
/// <summary>
/// The codec this camera belongs to
/// </summary>
protected CiscoSparkCodec ParentCodec { get; private set; }
/// <summary>
/// The ID of the camera on the codec
/// </summary>
protected uint CameraId { get; private set; }
/// <summary>
/// Valid range 1-15
/// </summary>
protected uint PanSpeed { get; private set; }
/// <summary>
/// Valid range 1-15
/// </summary>
protected uint TiltSpeed { get; private set; }
/// <summary>
/// Valid range 1-15
/// </summary>
protected uint ZoomSpeed { get; private set; }
private bool isPanning;
private bool isTilting;
private bool isZooming;
private bool isFocusing;
private bool isMoving
{
get
{
return isPanning || isTilting || isZooming || isFocusing;
}
}
public CiscoSparkCamera(string key, string name, CiscoSparkCodec codec, uint id)
: base(key, name)
{
// Default to all capabilties
Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus;
ParentCodec = codec;
CameraId = id;
// Set default speeds
PanSpeed = 7;
TiltSpeed = 7;
ZoomSpeed = 7;
}
// Takes a string from the camera capabilities value and converts from "ptzf" to enum bitmask
public void SetCapabilites(string capabilites)
{
var c = capabilites.ToLower();
if (c.Contains("p"))
Capabilities = Capabilities | eCameraCapabilities.Pan;
if (c.Contains("t"))
Capabilities = Capabilities | eCameraCapabilities.Tilt;
if (c.Contains("z"))
Capabilities = Capabilities | eCameraCapabilities.Zoom;
if (c.Contains("f"))
Capabilities = Capabilities | eCameraCapabilities.Focus;
}
#region IHasCameraPtzControl Members
public void PositionHome()
{
// Not supported on Internal Spark Camera
}
#endregion
#region IHasCameraPanControl Members
public void PanLeft()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Left PanSpeed: {1}", CameraId, PanSpeed));
isPanning = true;
}
}
public void PanRight()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Right PanSpeed: {1}", CameraId, PanSpeed));
isPanning = true;
}
}
public void PanStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Pan: Stop", CameraId));
isPanning = false;
}
#endregion
#region IHasCameraTiltControl Members
public void TiltDown()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Down TiltSpeed: {1}", CameraId, TiltSpeed));
isTilting = true;
}
}
public void TiltUp()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Up TiltSpeed: {1}", CameraId, TiltSpeed));
isTilting = true;
}
}
public void TiltStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Tilt: Stop", CameraId));
isTilting = false;
}
#endregion
#region IHasCameraZoomControl Members
public void ZoomIn()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: In ZoomSpeed: {1}", CameraId, ZoomSpeed));
isZooming = true;
}
}
public void ZoomOut()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Out ZoomSpeed: {1}", CameraId, ZoomSpeed));
isZooming = true;
}
}
public void ZoomStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Zoom: Stop", CameraId));
isZooming = false;
}
#endregion
#region IHasCameraFocusControl Members
public void FocusNear()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Near", CameraId));
isFocusing = true;
}
}
public void FocusFar()
{
if (!isMoving)
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Far", CameraId));
isFocusing = true;
}
}
public void FocusStop()
{
ParentCodec.SendText(string.Format("xCommand Camera Ramp CameraId: {0} Focus: Stop", CameraId));
isFocusing = false;
}
public void TriggerAutoFocus()
{
ParentCodec.SendText(string.Format("xCommand Camera TriggerAutofocus CameraId: {0}", CameraId));
}
#endregion
}
}

View File

@@ -0,0 +1,33 @@
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.Devices.Common.Codec
{
public class CiscoSparkCodecPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public List<CodecActiveCallItem> Favorites { get; set; }
/// <summary>
/// Valid values: "Local" or "Corporate"
/// </summary>
public string PhonebookMode { get; set; }
public bool ShowSelfViewByDefault { get; set; }
public SharingProperties Sharing { get; set; }
}
public class SharingProperties
{
public bool AutoShareContentWhileInCall { get; set; }
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Net.Http;
using PepperDash.Core;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
public class HttpApiServer
{
public static Dictionary<string, string> ExtensionContentTypes;
public event EventHandler<OnHttpRequestArgs> ApiRequest;
public Crestron.SimplSharp.Net.Http.HttpServer HttpServer { get; private set; }
public string HtmlRoot { get; set; }
/// <summary>
/// SIMPL+ can only execute the default constructor. If you have variables that require initialization, please
/// use an Initialize method
/// </summary>
public HttpApiServer()
{
ExtensionContentTypes = new Dictionary<string, string>
{
{ ".css", "text/css" },
{ ".htm", "text/html" },
{ ".html", "text/html" },
{ ".jpg", "image/jpeg" },
{ ".jpeg", "image/jpeg" },
{ ".js", "application/javascript" },
{ ".json", "application/json" },
{ ".xml", "text/xml" },
{ ".map", "application/x-navimap" },
{ ".pdf", "application.pdf" },
{ ".png", "image/png" },
{ ".txt", "text/plain" },
};
HtmlRoot = @"\HTML";
}
public void Start(int port)
{
// TEMP - this should be inserted by configuring class
HttpServer = new Crestron.SimplSharp.Net.Http.HttpServer();
HttpServer.ServerName = "Cisco API Server";
HttpServer.KeepAlive = true;
HttpServer.Port = port;
HttpServer.OnHttpRequest += Server_Request;
HttpServer.Open();
CrestronEnvironment.ProgramStatusEventHandler += (a) =>
{
if (a == eProgramStatusEventType.Stopping)
{
HttpServer.Close();
Debug.Console(1, "Shutting down HTTP Server on port {0}", HttpServer.Port);
}
};
}
void Server_Request(object sender, OnHttpRequestArgs args)
{
if (args.Request.Header.RequestType == "OPTIONS")
{
Debug.Console(2, "Asking for OPTIONS");
args.Response.Header.SetHeaderValue("Access-Control-Allow-Origin", "*");
args.Response.Header.SetHeaderValue("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
return;
}
string path = Uri.UnescapeDataString(args.Request.Path);
var host = args.Request.DataConnection.RemoteEndPointAddress;
//string authToken;
Debug.Console(2, "HTTP Request: {2}: Path='{0}' ?'{1}'", path, args.Request.QueryString, host);
// ----------------------------------- ADD AUTH HERE
if (path.StartsWith("/cisco/api"))
{
var handler = ApiRequest;
if (ApiRequest != null)
ApiRequest(this, args);
}
}
public static string GetContentType(string extension)
{
string type;
if (ExtensionContentTypes.ContainsKey(extension))
type = ExtensionContentTypes[extension];
else
type = "text/plain";
return type;
}
}
}

View File

@@ -0,0 +1,397 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.Codec;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public class CiscoCodecPhonebook
{
public class Offset
{
public string Value { get; set; }
}
public class Limit
{
public string Value { get; set; }
}
public class TotalRows
{
public string Value { get; set; }
}
public class ResultInfo
{
public Offset Offset { get; set; }
public Limit Limit { get; set; }
public TotalRows TotalRows { get; set; }
}
public class LocalId
{
public string Value { get; set; }
}
public class FolderId
{
public string Value { get; set; }
}
public class ParentFolderId
{
public string Value { get; set; }
}
public class Name
{
public string Value { get; set; }
}
public class Folder
{
public string id { get; set; }
public LocalId LocalId { get; set; }
public FolderId FolderId { get; set; }
public Name Name { get; set; }
public ParentFolderId ParentFolderId { get; set; }
}
public class Name2
{
public string Value { get; set; }
}
public class ContactId
{
public string Value { get; set; }
}
public class FolderId2
{
public string Value { get; set; }
}
public class Title
{
public string Value { get; set; }
}
public class ContactMethodId
{
public string Value { get; set; }
}
public class Number
{
public string Value { get; set; }
}
public class Device
{
public string Value { get; set; }
}
public class CallType
{
public string Value { get; set; }
}
public class ContactMethod
{
public string id { get; set; }
public ContactMethodId ContactMethodId { get; set; }
public Number Number { get; set; }
public Device Device { get; set; }
public CallType CallType { get; set; }
public ContactMethod()
{
ContactMethodId = new ContactMethodId();
Number = new Number();
Device = new Device();
CallType = new CallType();
}
}
public class Contact
{
public string id { get; set; }
public Name2 Name { get; set; }
public ContactId ContactId { get; set; }
public FolderId2 FolderId { get; set; }
public Title Title { get; set; }
public List<ContactMethod> ContactMethod { get; set; }
public Contact()
{
Name = new Name2();
ContactId = new ContactId();
FolderId = new FolderId2();
Title = new Title();
ContactMethod = new List<ContactMethod>();
}
}
public class PhonebookSearchResult
{
public string status { get; set; }
public ResultInfo ResultInfo { get; set; }
public List<Folder> Folder { get; set; }
public List<Contact> Contact { get; set; }
public PhonebookSearchResult()
{
Folder = new List<Folder>();
Contact = new List<Contact>();
ResultInfo = new ResultInfo();
}
}
public class CommandResponse
{
public PhonebookSearchResult PhonebookSearchResult { get; set; }
}
public class RootObject
{
public CommandResponse CommandResponse { get; set; }
}
/// <summary>
/// Extracts the folders with no ParentFolder and returns them sorted alphabetically
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public static List<DirectoryItem> GetRootFoldersFromSearchResult(PhonebookSearchResult result)
{
var rootFolders = new List<DirectoryItem>();
if (result.Folder.Count == 0)
{
return null;
}
else if (result.Folder.Count > 0)
{
if (Debug.Level > 0)
Debug.Console(1, "Phonebook Folders:\n");
foreach (Folder f in result.Folder)
{
var folder = new DirectoryFolder();
folder.Name = f.Name.Value;
folder.FolderId = f.FolderId.Value;
if (f.ParentFolderId == null)
rootFolders.Add(folder);
if (Debug.Level > 0)
Debug.Console(1, "+ {0}", folder.Name);
}
}
rootFolders.OrderBy(f => f.Name);
return rootFolders;
}
/// <summary>
/// Extracts the contacts with no FolderId and returns them sorted alphabetically
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public static List<DirectoryItem> GetRootContactsFromSearchResult(PhonebookSearchResult result)
{
var rootContacts = new List<DirectoryItem>();
if (result.Contact.Count == 0)
{
return null;
}
else if (result.Contact.Count > 0)
{
if (Debug.Level > 0)
Debug.Console(1, "Root Contacts:\n");
foreach (Contact c in result.Contact)
{
var contact = new DirectoryContact();
if (string.IsNullOrEmpty(c.FolderId.Value))
{
contact.Name = c.Name.Value;
contact.ContactId = c.ContactId.Value;
if(!string.IsNullOrEmpty(c.Title.Value))
contact.Title = c.Title.Value;
if (Debug.Level > 0)
Debug.Console(1, "{0}\nContact Methods:", contact.Name);
foreach (ContactMethod m in c.ContactMethod)
{
var tempContactMethod = new PepperDash.Essentials.Devices.Common.Codec.ContactMethod();
eContactMethodCallType callType = eContactMethodCallType.Unknown;
if (!string.IsNullOrEmpty(m.CallType.Value))
{
if (!string.IsNullOrEmpty(m.CallType.Value))
{
if (m.CallType.Value.ToLower() == "audio")
callType = eContactMethodCallType.Audio;
else if (m.CallType.Value.ToLower() == "video")
callType = eContactMethodCallType.Video;
tempContactMethod.CallType = callType;
}
}
eContactMethodDevice device = eContactMethodDevice.Unknown;
if (!string.IsNullOrEmpty(m.Device.Value))
{
if (m.Device.Value.ToLower() == "mobile")
device = eContactMethodDevice.Mobile;
else if (m.Device.Value.ToLower() == "telephone")
device = eContactMethodDevice.Telephone;
else if (m.Device.Value.ToLower() == "video")
device = eContactMethodDevice.Video;
else if (m.Device.Value.ToLower() == "other")
device = eContactMethodDevice.Other;
tempContactMethod.Device = device;
}
if (Debug.Level > 0)
Debug.Console(1, "Number: {0}", m.Number.Value);
tempContactMethod.Number = m.Number.Value;
tempContactMethod.ContactMethodId = m.ContactMethodId.Value;
contact.ContactMethods.Add(tempContactMethod);
}
rootContacts.Add(contact);
}
}
}
rootContacts.OrderBy(f => f.Name);
return rootContacts;
}
/// <summary>
/// Converts data returned from a cisco codec to the generic Directory format.
/// </summary>
/// <param name="result"></param>
/// <param name="resultFolder"></param>
/// <returns></returns>
public static CodecDirectory ConvertCiscoPhonebookToGeneric(PhonebookSearchResult result)
{
var directory = new Codec.CodecDirectory();
var folders = new List<Codec.DirectoryItem>();
var contacts = new List<Codec.DirectoryItem>();
try
{
if (result.Folder.Count > 0)
{
foreach (Folder f in result.Folder)
{
var folder = new DirectoryFolder();
folder.Name = f.Name.Value;
folder.FolderId = f.FolderId.Value;
if (f.ParentFolderId != null)
{
folder.ParentFolderId = f.ParentFolderId.Value;
}
folders.Add(folder);
}
folders.OrderBy(f => f.Name);
directory.AddFoldersToDirectory(folders);
}
if (result.Contact.Count > 0)
{
foreach (Contact c in result.Contact)
{
var contact = new DirectoryContact();
contact.Name = c.Name.Value;
contact.ContactId = c.ContactId.Value;
if (!string.IsNullOrEmpty(c.Title.Value))
contact.Title = c.Title.Value;
if (c.FolderId != null)
{
contact.FolderId = c.FolderId.Value;
}
foreach (ContactMethod m in c.ContactMethod)
{
eContactMethodCallType callType = eContactMethodCallType.Unknown;
if (!string.IsNullOrEmpty(m.CallType.Value))
{
if (m.CallType.Value.ToLower() == "audio")
callType = eContactMethodCallType.Audio;
else if (m.CallType.Value.ToLower() == "video")
callType = eContactMethodCallType.Video;
}
eContactMethodDevice device = eContactMethodDevice.Unknown;
if (!string.IsNullOrEmpty(m.Device.Value))
{
if (m.Device.Value.ToLower() == "mobile")
device = eContactMethodDevice.Mobile;
else if (m.Device.Value.ToLower() == "telephone")
device = eContactMethodDevice.Telephone;
else if (m.Device.Value.ToLower() == "video")
device = eContactMethodDevice.Video;
else if (m.Device.Value.ToLower() == "other")
device = eContactMethodDevice.Other;
}
contact.ContactMethods.Add(new PepperDash.Essentials.Devices.Common.Codec.ContactMethod()
{
Number = m.Number.Value,
ContactMethodId = m.ContactMethodId.Value,
CallType = callType,
Device = device
});
}
contacts.Add(contact);
}
contacts.OrderBy(c => c.Name);
directory.AddContactsToDirectory(contacts);
}
}
catch (Exception e)
{
Debug.Console(1, "Error converting Cisco Phonebook results to generic: {0}", e);
}
return directory;
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
/// <summary>
/// Interface for camera presets
/// </summary>
public interface IHasCodecRoomPresets
{
event EventHandler<EventArgs> CodecRoomPresetsListHasChanged;
List<CodecRoomPreset> NearEndPresets { get; }
List<CodecRoomPreset> FarEndRoomPresets { get; }
void CodecRoomPresetSelect(int preset);
void CodecRoomPresetStore(int preset, string description);
}
public static class RoomPresets
{
/// <summary>
/// Converts Cisco RoomPresets to generic CameraPresets
/// </summary>
/// <param name="presets"></param>
/// <returns></returns>
public static List<CodecRoomPreset> GetGenericPresets(List<CiscoCodecStatus.RoomPreset> presets)
{
var cameraPresets = new List<CodecRoomPreset>();
if (Debug.Level > 0)
{
Debug.Console(1, "Presets List:");
}
foreach (CiscoCodecStatus.RoomPreset preset in presets)
{
try
{
var cameraPreset = new CodecRoomPreset(UInt16.Parse(preset.id), preset.Description.Value, preset.Defined.BoolValue, true);
cameraPresets.Add(cameraPreset);
if (Debug.Level > 0)
{
Debug.Console(1, "Added Preset ID: {0}, Description: {1}, IsDefined: {2}, isDefinable: {3}", cameraPreset.ID, cameraPreset.Description, cameraPreset.Defined, cameraPreset.IsDefinable);
}
}
catch (Exception e)
{
Debug.Console(2, "Unable to convert preset: {0}. Error: {1}", preset.id, e);
}
}
return cameraPresets;
}
}
/// <summary>
/// Represents a room preset on a video coded. Typically stores camera position(s) and video routing. Can be recalled by Far End if enabled.
/// </summary>
public class CodecRoomPreset
{
[JsonProperty("id")]
public int ID { get; set; }
/// <summary>
/// Used to store the name of the preset
/// </summary>
[JsonProperty("description")]
public string Description { get; set; }
/// <summary>
/// Indicates if the preset is defined(stored) in the codec
/// </summary>
[JsonProperty("defined")]
public bool Defined { get; set; }
/// <summary>
/// Indicates if the preset has the capability to be defined
/// </summary>
[JsonProperty("isDefinable")]
public bool IsDefinable { get; set; }
public CodecRoomPreset(int id, string description, bool def, bool isDef)
{
ID = id;
Description = description;
Defined = def;
IsDefinable = isDef;
}
}
}

View File

@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{
/// <summary>
/// This class exists to capture serialized data sent back by a Cisco codec in JSON output mode
/// </summary>
public class CiscoCodecEvents
{
public class CauseValue
{
public string id { get; set; }
public string Value { get; set; }
}
public class CauseType
{
public string id { get; set; }
public string Value { get; set; }
}
public class CauseString
{
public string id { get; set; }
public string Value { get; set; }
}
public class OrigCallDirection
{
public string id { get; set; }
public string Value { get; set; }
}
public class RemoteURI
{
public string id { get; set; }
public string Value { get; set; }
}
public class DisplayName
{
public string id { get; set; }
public string Value { get; set; }
}
public class CallId
{
public string id { get; set; }
public string Value { get; set; }
}
public class CauseCode
{
public string id { get; set; }
public string Value { get; set; }
}
public class CauseOrigin
{
public string id { get; set; }
public string Value { get; set; }
}
public class Protocol
{
public string id { get; set; }
public string Value { get; set; }
}
public class Duration
{
public string id { get; set; }
public string Value { get; set; }
}
public class CallType
{
public string id { get; set; }
public string Value { get; set; }
}
public class CallRate
{
public string id { get; set; }
public string Value { get; set; }
}
public class Encryption
{
public string id { get; set; }
public string Value { get; set; }
}
public class RequestedURI
{
public string id { get; set; }
public string Value { get; set; }
}
public class PeopleCountAverage
{
public string id { get; set; }
public string Value { get; set; }
}
public class CallDisconnect
{
public string id { get; set; }
public CauseValue CauseValue { get; set; }
public CauseType CauseType { get; set; }
public CauseString CauseString { get; set; }
public OrigCallDirection OrigCallDirection { get; set; }
public RemoteURI RemoteURI { get; set; }
public DisplayName DisplayName { get; set; }
public CallId CallId { get; set; }
public CauseCode CauseCode { get; set; }
public CauseOrigin CauseOrigin { get; set; }
public Protocol Protocol { get; set; }
public Duration Duration { get; set; }
public CallType CallType { get; set; }
public CallRate CallRate { get; set; }
public Encryption Encryption { get; set; }
public RequestedURI RequestedURI { get; set; }
public PeopleCountAverage PeopleCountAverage { get; set; }
}
public class Event
{
public CallDisconnect CallDisconnect { get; set; }
}
public class RootObject
{
public Event Event { get; set; }
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public class CodecActiveCallItem
{
public string Name { get; set; }
public string Number { get; set; }
<<<<<<< HEAD
public eCodecCallType Type { get; private set; }
public CodecActiveCallItem(string name, string number, eCodecCallType type)
{
Name = name;
Number = number;
Type = type;
}
=======
public eCodecCallType Type { get; set; }
public eCodecCallStatus Status { get; set; }
public string Id { get; set; }
>>>>>>> origin/feature/cisco-spark-2
}
public enum eCodecCallType
{
None, Audio, Video
}
public enum eCodecCallStatus
{
Dialing, Established, Incoming
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Cameras
{
public enum eCameraControlMode
{
Off = 0,
Manual,
Auto
}
public interface IHasCameras
{
event EventHandler<CameraSelectedEventArgs> CameraSelected;
List<CameraBase> Cameras { get; }
CameraBase SelectedCamera { get; }
StringFeedback SelectedCameraFeedback { get; }
void SelectCamera(string key);
}
/// <summary>
/// Aggregates far end cameras with near end cameras
/// </summary>
public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl
{
}
/// <summary>
/// To be implmented on codecs that can disable their camera(s) to blank the near end video
/// </summary>
public interface IHasCameraOff
{
BoolFeedback CameraIsOffFeedback { get; }
void CameraOff();
}
public class CameraSelectedEventArgs : EventArgs
{
public CameraBase SelectedCamera { get; private set; }
public CameraSelectedEventArgs(CameraBase camera)
{
SelectedCamera = camera;
}
}
public interface IHasFarEndCameraControl
{
CameraBase FarEndCamera { get; }
BoolFeedback ControllingFarEndCameraFeedback { get; }
}
/// <summary>
/// Used to decorate a camera as a far end
/// </summary>
public interface IAmFarEndCamera
{
}
/// <summary>
/// Aggregates the pan, tilt and zoom interfaces
/// </summary>
public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl
{
/// <summary>
/// Resets the camera position
/// </summary>
void PositionHome();
}
/// <summary>
/// Interface for camera pan control
/// </summary>
public interface IHasCameraPanControl
{
void PanLeft();
void PanRight();
void PanStop();
}
/// <summary>
/// Interface for camera tilt control
/// </summary>
public interface IHasCameraTiltControl
{
void TiltDown();
void TiltUp();
void TiltStop();
}
/// <summary>
/// Interface for camera zoom control
/// </summary>
public interface IHasCameraZoomControl
{
void ZoomIn();
void ZoomOut();
void ZoomStop();
}
/// <summary>
/// Interface for camera focus control
/// </summary>
public interface IHasCameraFocusControl
{
void FocusNear();
void FocusFar();
void FocusStop();
void TriggerAutoFocus();
}
public interface IHasCameraAutoMode
{
void CameraAutoModeOn();
void CameraAutoModeOff();
void CameraAutoModeToggle();
BoolFeedback CameraAutoModeIsOnFeedback { get; }
}
}

Some files were not shown because too many files have changed in this diff Show More