Compare commits

...

21 Commits

Author SHA1 Message Date
Andrew Welker
669f9e71bc Merge branch 'development' into feature/device-info 2020-11-11 13:04:58 -07:00
Andrew Welker
5d2f20efd5 initial implementations for DM Rmc & DGE 2020-11-11 13:02:12 -07:00
Andrew Welker
e705f67333 Merge pull request #480 from PepperDash/feature/resolve-cisco-bugs
Feature/resolve cisco bugs
2020-11-11 13:41:53 -06:00
Neil Dorin
7d72d54862 Gets ExternalSourceSwitching feedback working 2020-11-11 12:08:30 -07:00
Andrew Welker
ed6ad6ae76 updates for device info 2020-11-11 11:29:43 -07:00
Andrew Welker
1689b15d95 make IDeviceInfoProvider inherit from IKeyed 2020-11-10 12:00:58 -07:00
Trevor Payne
010fdde45c Fixes issues with Adding HDMI LoopOut Ports 2020-11-10 11:46:51 -06:00
Andrew Welker
10509991c1 updates for getting connected IP stuff 2020-11-10 10:39:49 -07:00
Andrew Welker
c686ee394d update event to use delegate 2020-11-10 10:28:39 -07:00
Neil Dorin
985902092e Merge branch 'feature/add-camera-config-props' into feature/resolve-cisco-bugs 2020-11-10 09:33:06 -07:00
Neil Dorin
944b72e2a8 Adds IHasCameraOff to CameraVisca 2020-11-10 09:32:16 -07:00
Neil Dorin
d074be323c Remove zoom speeds 2020-11-10 09:31:37 -07:00
Neil Dorin
0098401584 Adds SpeedTimer implmentation to CameraVisca 2020-11-10 09:31:37 -07:00
Neil Dorin
0d7d5fe380 Adds feedback parsing to CameraVisca as well as some new focus controls. 2020-11-10 09:31:35 -07:00
Neil Dorin
1cb9fb6058 Removes unnecessary null check in SendDtmf method 2020-11-10 09:29:37 -07:00
Andrew Welker
5076ba405e add logic to update device info when IP-ID comes online 2020-11-10 09:23:51 -07:00
Andrew Welker
3c60dfdf7b add IDeviceInfoProvider & start implementation 2020-11-10 09:14:43 -07:00
Andrew Welker
5d44b5f3ef Merge pull request #477 from PepperDash/feature/update-ipower-interface
Feature/update ipower interface
2020-11-09 21:11:32 -06:00
Andrew Welker
51e338749a Implement IDeviceInfoProvider on DGE100 2020-11-09 12:11:39 -07:00
Andrew Welker
e37fb33afe add DeviceInfo class 2020-11-09 12:10:44 -07:00
Andrew Welker
47af06578a added IDeviceInfoProvider interface 2020-11-09 09:58:51 -07:00
14 changed files with 743 additions and 76 deletions

View File

@@ -71,7 +71,7 @@
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.41.31808, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.42.30563, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
</Reference>

View File

@@ -194,7 +194,7 @@ namespace PepperDash.Essentials
var vc = VideoCodec as IHasExternalSourceSwitching;
if (vc != null)
{
vc.SetSelectedSource(_CurrentSourceInfo.SourceKey);
vc.SetSelectedSource(CurrentSourceInfoKey);
}
}
}

View File

@@ -0,0 +1,11 @@
namespace PepperDash.Essentials.Core.DeviceInfo
{
public class DeviceInfo
{
public string HostName { get; set; }
public string IpAddress { get; set; }
public string MacAddress { get; set; }
public string SerialNumber { get; set; }
public string FirmwareVersion { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace PepperDash.Essentials.Core.DeviceInfo
{
public class DeviceInfoEventArgs:EventArgs
{
public DeviceInfo DeviceInfo { get; set; }
public DeviceInfoEventArgs()
{
}
public DeviceInfoEventArgs(DeviceInfo devInfo)
{
DeviceInfo = devInfo;
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.DeviceInfo
{
public interface IDeviceInfoProvider:IKeyed
{
DeviceInfo DeviceInfo { get; }
event DeviceInfoChangeHandler DeviceInfoChanged;
void UpdateDeviceInfo();
}
public delegate void DeviceInfoChangeHandler(IKeyed device, DeviceInfoEventArgs args);
}

View File

@@ -83,7 +83,7 @@
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.41.31808, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.42.30563, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
</Reference>
@@ -183,6 +183,9 @@
<Compile Include="Crestron IO\Relay\GenericRelayDevice.cs" />
<Compile Include="Crestron IO\Relay\ISwitchedOutput.cs" />
<Compile Include="Crestron IO\StatusSign\StatusSignController.cs" />
<Compile Include="Device Info\DeviceInfo.cs" />
<Compile Include="Device Info\DeviceInfoEventArgs.cs" />
<Compile Include="Device Info\IDeviceInfoProvider.cs" />
<Compile Include="Devices\CodecInterfaces.cs" />
<Compile Include="Devices\CrestronProcessor.cs" />
<Compile Include="Devices\DeviceApiBase.cs" />

View File

@@ -774,10 +774,15 @@ namespace PepperDash.Essentials.DM
{
var portKey = string.Format("{0}--{1}", cardName, portName);
Debug.Console(2, this, "Adding output port '{0}'", portKey);
OutputPorts.Add(new RoutingOutputPort(portKey, sigType, portType, selector, this)
var outputPort = new RoutingOutputPort(portKey, sigType, portType, selector, this);
if (portName.IndexOf("Loop", StringComparison.InvariantCultureIgnoreCase) < 0)
{
FeedbackMatchObject = Chassis.Outputs[(uint)selector]
});
outputPort.FeedbackMatchObject = Chassis.Outputs[(uint) selector];
}
OutputPorts.Add(outputPort);
}
/// <summary>
@@ -786,12 +791,13 @@ namespace PepperDash.Essentials.DM
void AddOutputPortWithDebug(string cardName, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, object selector, ICec cecPort)
{
var portKey = string.Format("{0}--{1}", cardName, portName);
Debug.Console(2, this, "Adding output port '{0}'", portKey);
var outputPort = new RoutingOutputPort(portKey, sigType, portType, selector, this)
Debug.Console(2, this, "Adding output port '{0}'", portKey);
var outputPort = new RoutingOutputPort(portKey, sigType, portType, selector, this);
if (portName.IndexOf("Loop", StringComparison.InvariantCultureIgnoreCase) < 0)
{
FeedbackMatchObject = Chassis.Outputs[(uint)selector]
}; ;
outputPort.FeedbackMatchObject = Chassis.Outputs[(uint)selector];
}
if (cecPort != null)
outputPort.Port = cecPort;

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
@@ -14,15 +15,19 @@ using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Essentials.Core.DeviceInfo;
namespace PepperDash.Essentials.DM.Endpoints.DGEs
{
[Description("Wrapper class for DGE-100")]
public class Dge100Controller : CrestronGenericBaseDevice, IComPorts, IIROutputPorts, IHasBasicTriListWithSmartObject, ICec
public class Dge100Controller : CrestronGenericBaseDevice, IComPorts, IIROutputPorts, IHasBasicTriListWithSmartObject, ICec, IDeviceInfoProvider
{
private const int CtpPort = 41795;
private readonly Dge100 _dge;
private readonly TsxCcsUcCodec100EthernetReservedSigs _dgeEthernetInfo;
public BasicTriListWithSmartObject Panel { get { return _dge; } }
private DeviceConfig _dc;
@@ -32,7 +37,14 @@ namespace PepperDash.Essentials.DM.Endpoints.DGEs
public Dge100Controller(string key, string name, Dge100 device, DeviceConfig dc, CrestronTouchpanelPropertiesConfig props)
:base(key, name, device)
{
_dge = device;
_dge = device;
_dgeEthernetInfo = _dge.ExtenderEthernetReservedSigs;
_dgeEthernetInfo.DeviceExtenderSigChange += (extender, args) => UpdateDeviceInfo();
_dgeEthernetInfo.Use();
DeviceInfo = new DeviceInfo();
_dge.OnlineStatusChange += (currentDevice, args) => { if (args.DeviceOnLine) UpdateDeviceInfo(); };
_dc = dc;
@@ -69,8 +81,86 @@ namespace PepperDash.Essentials.DM.Endpoints.DGEs
#region ICec Members
public Cec StreamCec { get { return _dge.HdmiOut.StreamCec; } }
#endregion
#endregion
#region Implementation of IDeviceInfoProvider
public DeviceInfo DeviceInfo { get; private set; }
public event DeviceInfoChangeHandler DeviceInfoChanged;
public void UpdateDeviceInfo()
{
DeviceInfo.IpAddress = _dgeEthernetInfo.IpAddressFeedback.StringValue;
DeviceInfo.MacAddress = _dgeEthernetInfo.MacAddressFeedback.StringValue;
GetFirmwareAndSerialInfo();
OnDeviceInfoChange();
}
private void GetFirmwareAndSerialInfo()
{
if (String.IsNullOrEmpty(_dgeEthernetInfo.IpAddressFeedback.StringValue))
{
Debug.Console(1, this, "IP Address information not yet received. No device is online");
return;
}
var tcpClient = new GenericTcpIpClient("", _dgeEthernetInfo.IpAddressFeedback.StringValue, CtpPort, 1024){AutoReconnect = false};
var gather = new CommunicationGather(tcpClient, "\r\n\r\n");
tcpClient.ConnectionChange += (sender, args) =>
{
if (!args.Client.IsConnected)
{
return;
}
args.Client.SendText("ver\r\n");
};
gather.LineReceived += (sender, args) =>
{
if (args.Text.ToLower().Contains("host"))
{
DeviceInfo.HostName = args.Text.Split(';')[1].Trim();
tcpClient.Disconnect();
return;
}
//ignore console prompt
if (args.Text.ToLower().Contains(">"))
{
return;
}
if (!args.Text.ToLower().Contains("dge"))
{
return;
}
DeviceInfo.SerialNumber = args.Text.Split('[')[1].Split(' ')[4].Replace("#", "");
DeviceInfo.FirmwareVersion = args.Text.Split('[')[1].Split(' ')[1];
tcpClient.SendText("host\r\n");
};
tcpClient.Connect();
}
private void OnDeviceInfoChange()
{
var handler = DeviceInfoChanged;
if (handler == null) return;
handler(this, new DeviceInfoEventArgs(DeviceInfo));
}
#endregion
}
public class Dge100ControllerFactory : EssentialsDeviceFactory<Dge100Controller>

View File

@@ -8,14 +8,16 @@ using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.DeviceInfo;
using PepperDash.Essentials.DM.Config;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.DM
{
[Description("Wrapper class for all DM-RMC variants")]
public abstract class DmRmcControllerBase : CrestronGenericBridgeableBaseDevice
public abstract class DmRmcControllerBase : CrestronGenericBridgeableBaseDevice, IDeviceInfoProvider
{
private const int CtpPort = 41795;
private readonly EndpointReceiverBase _rmc; //kept here just in case. Only property or method on this class that's not device-specific is the DMOutput that it's attached to.
public StringFeedback VideoOutputResolutionFeedback { get; protected set; }
@@ -32,6 +34,10 @@ namespace PepperDash.Essentials.DM
PreventRegistration = _rmc.DMOutput != null;
AddToFeedbackList(VideoOutputResolutionFeedback, EdidManufacturerFeedback, EdidSerialNumberFeedback, EdidNameFeedback, EdidPreferredTimingFeedback);
DeviceInfo = new DeviceInfo();
_rmc.OnlineStatusChange += (currentDevice, args) => { if (args.DeviceOnLine) UpdateDeviceInfo(); };
}
protected void LinkDmRmcToApi(DmRmcControllerBase rmc, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
@@ -79,7 +85,106 @@ namespace PepperDash.Essentials.DM
trilist.SetUShortSigAction(joinMap.AudioVideoSource.JoinNumber, a => routing.ExecuteNumericSwitch(a, 1, eRoutingSignalType.AudioVideo));
}
}
#region Implementation of IDeviceInfoProvider
public DeviceInfo DeviceInfo { get; private set; }
public event DeviceInfoChangeHandler DeviceInfoChanged;
public void UpdateDeviceInfo()
{
Debug.Console(1, this, "Updating Device Info");
if (_rmc.ConnectedIpList.Count == 0)
{
Debug.Console(1, this, "IP Address information not yet received. No device is online");
return;
}
DeviceInfo.IpAddress = _rmc.ConnectedIpList[0].DeviceIpAddress;
foreach (var ip in _rmc.ConnectedIpList)
{
Debug.Console(0, this, "Connected IP Address: {0}", ip.DeviceIpAddress);
}
GetFirmwareAndSerialInfo();
OnDeviceInfoChange();
}
private void GetFirmwareAndSerialInfo()
{
var tcpClient = new GenericTcpIpClient(String.Format("{0}-devInfoSocket", Key), _rmc.ConnectedIpList[0].DeviceIpAddress, CtpPort, 1024)
{
AutoReconnect = false,
};
var gather = new CommunicationGather(tcpClient, "\r\n\r\n");
tcpClient.ConnectionChange += (sender, args) =>
{
if (!args.Client.IsConnected)
{
OnDeviceInfoChange();
return;
}
args.Client.SendText("ver\r\n");
};
gather.LineReceived += (sender, args) =>
{
//ignore console prompt
if (args.Text.ToLower().Contains(">"))
{
return;
}
if (args.Text.ToLower().Contains("host"))
{
DeviceInfo.HostName = args.Text.Split(':')[1].Trim();
tcpClient.SendText("maca\r\n");
return;
}
if (args.Text.ToLower().Contains("mac"))
{
DeviceInfo.MacAddress = args.Text.Split(':')[1].Trim().Replace(" ", ":");
tcpClient.Disconnect();
return;
}
if (!args.Text.ToLower().Contains("rmc"))
{
return;
}
DeviceInfo.SerialNumber = args.Text.Split('[')[1].Split(' ')[4].Replace("#", "");
DeviceInfo.FirmwareVersion = args.Text.Split('[')[1].Split(' ')[1];
tcpClient.SendText("host\r\n");
};
tcpClient.Connect();
}
private void OnDeviceInfoChange()
{
var handler = DeviceInfoChanged;
if (handler == null) return;
handler(this, new DeviceInfoEventArgs(DeviceInfo));
}
#endregion
}
public abstract class DmHdBaseTControllerBase : CrestronGenericBaseDevice
{

View File

@@ -59,7 +59,7 @@
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.41.31808, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.42.30563, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
</Reference>

View File

@@ -92,8 +92,6 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
/// </summary>
public interface IHasCameraPanControl : IHasCameraControls
{
// void PanLeft(bool pressRelease);
// void PanRight(bool pressRelease);
void PanLeft();
void PanRight();
void PanStop();
@@ -104,8 +102,6 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
/// </summary>
public interface IHasCameraTiltControl : IHasCameraControls
{
// void TiltDown(bool pressRelease);
// void TildUp(bool pressRelease);
void TiltDown();
void TiltUp();
void TiltStop();
@@ -116,8 +112,6 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
/// </summary>
public interface IHasCameraZoomControl : IHasCameraControls
{
// void ZoomIn(bool pressRelease);
// void ZoomOut(bool pressRelease);
void ZoomIn();
void ZoomOut();
void ZoomStop();
@@ -135,6 +129,13 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
void TriggerAutoFocus();
}
public interface IHasAutoFocusMode
{
void SetFocusModeAuto();
void SetFocusModeManual();
void ToggleFocusMode();
}
public interface IHasCameraAutoMode : IHasCameraControls
{
void CameraAutoModeOn();

View File

@@ -12,29 +12,86 @@ using PepperDash.Essentials.Devices.Common.Codec;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.Reflection;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Cameras
{
public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced
public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode
{
CameraViscaPropertiesConfig PropertiesConfig;
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;
/// <summary>
/// Used to store the actions to parse inquiry responses as the inquiries are sent
/// </summary>
private CrestronQueue<Action<byte[]>> InquiryResponseQueue;
/// <summary>
/// Camera ID (Default 1)
/// </summary>
public byte ID = 0x01;
public byte ResponseID;
public byte PanSpeedSlow = 0x10;
public byte TiltSpeedSlow = 0x10;
public byte PanSpeedFast = 0x13;
public byte TiltSpeedFast = 0x13;
private bool IsMoving;
private bool IsZooming;
public bool PowerIsOn { get; private set; }
bool _powerIsOn;
public bool PowerIsOn
{
get
{
return _powerIsOn;
}
private set
{
if (value != _powerIsOn)
{
_powerIsOn = value;
PowerIsOnFeedback.FireUpdate();
CameraIsOffFeedback.FireUpdate();
}
}
}
const byte ZoomInCmd = 0x02;
const byte ZoomOutCmd = 0x03;
const byte ZoomStopCmd = 0x00;
/// <summary>
/// Used to determine when to move the camera at a faster speed if a direction is held
/// </summary>
CTimer SpeedTimer;
// TODO: Implment speed timer for PTZ controls
long FastSpeedHoldTimeMs = 2000;
byte[] IncomingBuffer = new byte[] { };
public BoolFeedback PowerIsOnFeedback { get; private set; }
public CameraVisca(string key, string name, IBasicCommunication comm, CameraPropertiesConfig props) :
public CameraVisca(string key, string name, IBasicCommunication comm, CameraViscaPropertiesConfig props) :
base(key, name)
{
InquiryResponseQueue = new CrestronQueue<Action<byte[]>>(15);
Presets = props.Presets;
PropertiesConfig = props;
ID = (byte)(props.Id + 0x80);
ResponseID = (byte)((props.Id * 0x10) + 0x80);
SetupCameraSpeeds();
OutputPorts.Add(new RoutingOutputPort("videoOut", eRoutingSignalType.Video, eRoutingPortConnectionType.None, null, this, true));
// Default to all capabilties
@@ -51,11 +108,10 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\xFF");
Communication.BytesReceived += new EventHandler<GenericCommMethodReceiveBytesArgs>(Communication_BytesReceived);
PowerIsOnFeedback = new BoolFeedback(() => { return PowerIsOn; });
CameraIsOffFeedback = new BoolFeedback(() => { return !PowerIsOn; });
if (props.CommunicationMonitorProperties != null)
{
@@ -66,9 +122,38 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "\x81\x09\x04\x00\xFF");
}
DeviceManager.AddDevice(CommunicationMonitor);
}
/// <summary>
/// Sets up camera speed values based on config
/// </summary>
void SetupCameraSpeeds()
{
if (PropertiesConfig.FastSpeedHoldTimeMs > 0)
{
FastSpeedHoldTimeMs = PropertiesConfig.FastSpeedHoldTimeMs;
}
if (PropertiesConfig.PanSpeedSlow > 0)
{
PanSpeedSlow = (byte)PropertiesConfig.PanSpeedSlow;
}
if (PropertiesConfig.PanSpeedFast > 0)
{
PanSpeedFast = (byte)PropertiesConfig.PanSpeedFast;
}
if (PropertiesConfig.TiltSpeedSlow > 0)
{
TiltSpeedSlow = (byte)PropertiesConfig.TiltSpeedSlow;
}
if (PropertiesConfig.TiltSpeedFast > 0)
{
TiltSpeedFast = (byte)PropertiesConfig.TiltSpeedFast;
}
}
public override bool CustomActivate()
{
Communication.Connect();
@@ -110,40 +195,245 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
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));
}
var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length];
try
{
// This is probably not thread-safe buffering
// Append the incoming bytes with whatever is in the buffer
IncomingBuffer.CopyTo(newBytes, 0);
e.Bytes.CopyTo(newBytes, IncomingBuffer.Length);
if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
Debug.Console(2, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes));
private void SendPanTiltCommand (byte[] cmd)
byte[] message = new byte[] { };
// Search for the delimiter 0xFF character
for (int i = 0; i < newBytes.Length; i++)
{
if (newBytes[i] == 0xFF)
{
// i will be the index of the delmiter character
message = newBytes.Take(i).ToArray();
// Skip over what we just took and save the rest for next time
newBytes = newBytes.Skip(i).ToArray();
}
}
if (message.Length > 0)
{
// Check for matching ID
if (message[0] != ResponseID)
{
return;
}
switch (message[1])
{
case 0x40:
{
// ACK received
Debug.Console(2, this, "ACK Received");
break;
}
case 0x50:
{
if (message[2] == 0xFF)
{
// Completion received
Debug.Console(2, this, "Completion Received");
}
else
{
// Inquiry response received. Dequeue the next response handler and invoke it
if (InquiryResponseQueue.Count > 0)
{
var inquiryAction = InquiryResponseQueue.Dequeue();
inquiryAction.Invoke(message.Skip(2).ToArray());
}
else
{
Debug.Console(2, this, "Response Queue is empty. Nothing to dequeue.");
}
}
break;
}
case 0x60:
{
// Error message
switch (message[2])
{
case 0x01:
{
// Message Length Error
Debug.Console(2, this, "Error from device: Message Length Error");
break;
}
case 0x02:
{
// Syntax Error
Debug.Console(2, this, "Error from device: Syntax Error");
break;
}
case 0x03:
{
// Command Buffer Full
Debug.Console(2, this, "Error from device: Command Buffer Full");
break;
}
case 0x04:
{
// Command Cancelled
Debug.Console(2, this, "Error from device: Command Cancelled");
break;
}
case 0x05:
{
// No Socket
Debug.Console(2, this, "Error from device: No Socket");
break;
}
case 0x41:
{
// Command not executable
Debug.Console(2, this, "Error from device: Command not executable");
break;
}
}
break;
}
}
if (message == new byte[] { ResponseID, 0x50, 0x02, 0xFF })
{
PowerIsOn = true;
}
else if (message == new byte[] { ResponseID, 0x50, 0x03, 0xFF })
{
PowerIsOn = false;
}
}
}
catch (Exception err)
{
Debug.Console(2, this, "Error parsing feedback: {0}", err);
}
finally
{
// Save whatever partial message is here
IncomingBuffer = newBytes;
}
}
/// <summary>
/// Sends a pan/tilt command. If the command is not for fastSpeed then it starts a timer to initiate fast speed.
/// </summary>
/// <param name="cmd"></param>
/// <param name="fastSpeed"></param>
private void SendPanTiltCommand (byte[] cmd, bool fastSpeedEnabled)
{
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);
SendBytes(GetPanTiltCommand(cmd, fastSpeedEnabled));
if (!fastSpeedEnabled)
{
if (SpeedTimer != null)
{
StopSpeedTimer();
}
// Start the timer to send fast speed if still moving after FastSpeedHoldTime elapses
SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs);
}
}
private void StopSpeedTimer()
{
if (SpeedTimer != null)
{
SpeedTimer.Stop();
SpeedTimer.Dispose();
SpeedTimer = null;
}
}
/// <summary>
/// Generates the pan/tilt command with either slow or fast speed
/// </summary>
/// <param name="cmd"></param>
/// <param name="fastSpeed"></param>
/// <returns></returns>
private byte[] GetPanTiltCommand(byte[] cmd, bool fastSpeed)
{
byte panSpeed;
byte tiltSpeed;
if (!fastSpeed)
{
panSpeed = PanSpeedSlow;
tiltSpeed = TiltSpeedSlow;
}
else
{
panSpeed = PanSpeedFast;
tiltSpeed = TiltSpeedFast;
}
var temp = new byte[] { ID, 0x01, 0x06, 0x01, panSpeed, tiltSpeed };
int length = temp.Length + cmd.Length + 1;
byte[] sum = new byte[length];
temp.CopyTo(sum, 0);
cmd.CopyTo(sum, temp.Length);
sum[length - 1] = 0xFF;
return sum;
}
void SendPowerQuery()
{
SendBytes(new byte[] { ID, 0x09, 0x04, 0x00, 0xFF });
InquiryResponseQueue.Enqueue(HandlePowerResponse);
}
public void PowerOn()
{
SendBytes(new Byte[] { 0x81, 0x01, 0x04, 0x00, 0x02, 0xFF });
SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x02, 0xFF });
SendPowerQuery();
}
void HandlePowerResponse(byte[] response)
{
switch (response[0])
{
case 0x02:
{
PowerIsOn = true;
break;
}
case 0x03:
{
PowerIsOn = false;
break;
}
}
}
public void PowerOff()
{
SendBytes(new Byte[] {0x81, 0x01, 0x04, 0x00, 0x03, 0xFF});
}
SendBytes(new byte[] {ID, 0x01, 0x04, 0x00, 0x03, 0xFF});
SendPowerQuery();
}
public void PowerToggle()
{
@@ -155,12 +445,12 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
public void PanLeft()
{
SendPanTiltCommand(new byte[] {0x01, 0x03});
SendPanTiltCommand(new byte[] {0x01, 0x03}, false);
IsMoving = true;
}
public void PanRight()
{
SendPanTiltCommand(new byte[] { 0x02, 0x03 });
SendPanTiltCommand(new byte[] { 0x02, 0x03 }, false);
IsMoving = true;
}
public void PanStop()
@@ -169,12 +459,12 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
}
public void TiltDown()
{
SendPanTiltCommand(new byte[] { 0x03, 0x02 });
SendPanTiltCommand(new byte[] { 0x03, 0x02 }, false);
IsMoving = true;
}
public void TiltUp()
{
SendPanTiltCommand(new byte[] { 0x03, 0x01 });
SendPanTiltCommand(new byte[] { 0x03, 0x01 }, false);
IsMoving = true;
}
public void TiltStop()
@@ -184,16 +474,18 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
private void SendZoomCommand (byte cmd)
{
SendBytes(new byte[] {0x81, 0x01, 0x04, 0x07, cmd, 0xFF} );
SendBytes(new byte[] {ID, 0x01, 0x04, 0x07, cmd, 0xFF} );
}
public void ZoomIn()
{
SendZoomCommand(0x02);
SendZoomCommand(ZoomInCmd);
IsZooming = true;
}
public void ZoomOut()
{
SendZoomCommand(0x03);
SendZoomCommand(ZoomOutCmd);
IsZooming = true;
}
public void ZoomStop()
@@ -205,26 +497,28 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
{
if (IsZooming)
{
SendZoomCommand(0x00);
SendZoomCommand(ZoomStopCmd);
IsZooming = false;
}
else
{
SendPanTiltCommand(new byte[] {0x03, 0x03});
StopSpeedTimer();
SendPanTiltCommand(new byte[] { 0x03, 0x03 }, false);
IsMoving = false;
}
}
public void PositionHome()
{
throw new NotImplementedException();
SendBytes(new byte[] { ID, 0x01, 0x06, 0x02, PanSpeedFast, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF });
SendBytes(new byte[] { ID, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF });
}
public void RecallPreset(int presetNumber)
{
SendBytes(new byte[] {0x81, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF} );
SendBytes(new byte[] {ID, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF} );
}
public void SavePreset(int presetNumber)
{
SendBytes(new byte[] { 0x81, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF });
SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF });
}
#region IHasCameraPresets Members
@@ -244,6 +538,90 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
}
#endregion
#region IHasCameraFocusControl Members
public void FocusNear()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x03, 0xFF });
}
public void FocusFar()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x02, 0xFF });
}
public void FocusStop()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x00, 0xFF });
}
public void TriggerAutoFocus()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x18, 0x01, 0xFF });
SendAutoFocusQuery();
}
#endregion
#region IHasAutoFocus Members
public void SetFocusModeAuto()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x02, 0xFF });
SendAutoFocusQuery();
}
public void SetFocusModeManual()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x03, 0xFF });
SendAutoFocusQuery();
}
public void ToggleFocusMode()
{
SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x10, 0xFF });
SendAutoFocusQuery();
}
#endregion
void SendAutoFocusQuery()
{
SendBytes(new byte[] { ID, 0x09, 0x04, 0x38, 0xFF });
InquiryResponseQueue.Enqueue(HandleAutoFocusResponse);
}
void HandleAutoFocusResponse(byte[] response)
{
switch (response[0])
{
case 0x02:
{
// Auto Mode
PowerIsOn = true;
break;
}
case 0x03:
{
// Manual Mode
PowerIsOn = false;
break;
}
}
}
#region IHasCameraOff Members
public BoolFeedback CameraIsOffFeedback { get; private set; }
public void CameraOff()
{
PowerOff();
}
#endregion
}
public class CameraViscaFactory : EssentialsDeviceFactory<CameraVisca>
@@ -257,10 +635,51 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
{
Debug.Console(1, "Factory Attempting to create new CameraVisca Device");
var comm = CommFactory.CreateCommForDevice(dc);
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<Cameras.CameraPropertiesConfig>(
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<Cameras.CameraViscaPropertiesConfig>(
dc.Properties.ToString());
return new Cameras.CameraVisca(dc.Key, dc.Name, comm, props);
}
}
public class CameraViscaPropertiesConfig : CameraPropertiesConfig
{
/// <summary>
/// Control ID of the camera (1-7)
/// </summary>
[JsonProperty("id")]
public uint Id { get; set; }
/// <summary>
/// Slow Pan speed (0-18)
/// </summary>
[JsonProperty("panSpeedSlow")]
public uint PanSpeedSlow { get; set; }
/// <summary>
/// Fast Pan speed (0-18)
/// </summary>
[JsonProperty("panSpeedFast")]
public uint PanSpeedFast { get; set; }
/// <summary>
/// Slow tilt speed (0-18)
/// </summary>
[JsonProperty("tiltSpeedSlow")]
public uint TiltSpeedSlow { get; set; }
/// <summary>
/// Fast tilt speed (0-18)
/// </summary>
[JsonProperty("tiltSpeedFast")]
public uint TiltSpeedFast { get; set; }
/// <summary>
/// Time a button must be held before fast speed is engaged (Milliseconds)
/// </summary>
[JsonProperty("fastSpeedHoldTimeMs")]
public uint FastSpeedHoldTimeMs { get; set; }
}
}

View File

@@ -63,7 +63,7 @@
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Lighting.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.41.31808, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.42.30563, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
</Reference>

View File

@@ -1339,10 +1339,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public override void SendDtmf(string s)
{
if (CallFavorites != null)
{
SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s));
}
SendText(string.Format("xCommand Call DTMFSend CallId: {0} DTMFString: \"{1}\"", GetCallId(), s));
}
public void SelectPresentationSource(int source)