mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-11 10:45:00 +00:00
Major update to remove eRoutingSignalType.AudioVideo in favor of bitmasked values and adding UsbOutput and UsbInput types. Updated all affected routing ports and ExecuteSwitch method calls. Need to review and test routing to ensure bitwise operators are all correct.
720 lines
24 KiB
C#
720 lines
24 KiB
C#
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.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi1), this), InputHdmi1Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi2), this), InputHdmi2Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi3), this), InputHdmi3Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi4), this), InputHdmi4Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.HdmiIn5, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.Hdmi, new Action(InputHdmi5), this), InputHdmi5Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.DisplayPortIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.DisplayPort, new Action(InputDisplayPort1), this), InputDisplayPort1Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
eRoutingPortConnectionType.Dvi, new Action(InputVga1), this), InputVga1Value);
|
|
|
|
AddRoutingInputPort(new RoutingInputPort(RoutingPortNames.IpcOps, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
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
|
|
}
|
|
} |