From 1654c93f35197c6b325fe8216b631a37b555ee1a Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 26 Apr 2024 15:39:59 -0600 Subject: [PATCH] feat: adds 4 series solution and implements IHasInputs. Needs to be revisited for correct solution and nuget build --- epi-sony-bravia.4Series/DebugLevels.cs | 206 ++++ epi-sony-bravia.4Series/Directory.Build.props | 21 + .../Directory.Build.targets | 28 + .../Properties/AssemblyInfo.cs | 36 + epi-sony-bravia.4Series/Rs232Commands.cs | 252 +++++ epi-sony-bravia.4Series/Rs232ParsingUtils.cs | 126 +++ epi-sony-bravia.4Series/SimpleIpCommands.cs | 51 + .../SimpleIpParsingUtils.cs | 15 + epi-sony-bravia.4Series/SonyBraviaConfig.cs | 15 + epi-sony-bravia.4Series/SonyBraviaDevice.cs | 914 ++++++++++++++++++ epi-sony-bravia.4Series/SonyBraviaFactory.cs | 35 + epi-sony-bravia.4Series/SonyBraviaInputs.cs | 98 ++ epi-sony-bravia.4Series/app.config | 11 + .../epi-sony-bravia.4Series.csproj | 214 ++++ .../epi-sony-bravia.4Series.sln | 25 + epi-sony-bravia.4Series/packages.config | 21 + 16 files changed, 2068 insertions(+) create mode 100644 epi-sony-bravia.4Series/DebugLevels.cs create mode 100644 epi-sony-bravia.4Series/Directory.Build.props create mode 100644 epi-sony-bravia.4Series/Directory.Build.targets create mode 100644 epi-sony-bravia.4Series/Properties/AssemblyInfo.cs create mode 100644 epi-sony-bravia.4Series/Rs232Commands.cs create mode 100644 epi-sony-bravia.4Series/Rs232ParsingUtils.cs create mode 100644 epi-sony-bravia.4Series/SimpleIpCommands.cs create mode 100644 epi-sony-bravia.4Series/SimpleIpParsingUtils.cs create mode 100644 epi-sony-bravia.4Series/SonyBraviaConfig.cs create mode 100644 epi-sony-bravia.4Series/SonyBraviaDevice.cs create mode 100644 epi-sony-bravia.4Series/SonyBraviaFactory.cs create mode 100644 epi-sony-bravia.4Series/SonyBraviaInputs.cs create mode 100644 epi-sony-bravia.4Series/app.config create mode 100644 epi-sony-bravia.4Series/epi-sony-bravia.4Series.csproj create mode 100644 epi-sony-bravia.4Series/epi-sony-bravia.4Series.sln create mode 100644 epi-sony-bravia.4Series/packages.config diff --git a/epi-sony-bravia.4Series/DebugLevels.cs b/epi-sony-bravia.4Series/DebugLevels.cs new file mode 100644 index 0000000..e6973a5 --- /dev/null +++ b/epi-sony-bravia.4Series/DebugLevels.cs @@ -0,0 +1,206 @@ +using System; +using Crestron.SimplSharp; +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace SonyBraviaEpi +{ + /// + /// Has debug levels interface + /// + public interface IHasDebugLevels + { + // LogLevel enum + // - https://docs.microsoft.com/en-us/javascript/api/@aspnet/signalr/loglevel?view=signalr-js-latest + + /// + /// Trace level (0) + /// + /// + /// Log level for very low severity diagnostic messages. + /// + uint TraceLevel { get; set; } + + /// + /// Debug level (1) + /// + /// + /// Log level for low severity diagnostic messages. + /// + uint DebugLevel { get; set; } + + /// + /// Error Level (2) + /// + /// + /// Log level for diagnostic messages that indicate a failure in the current operation. + /// + uint ErrorLevel { get; set; } + + /// + /// Sets the device debug levels to the value + /// + /// uint value + void SetDebugLevels(uint value); + + /// + /// Resets the device debug levels to the standard values + /// + void ResetDebugLevels(); + + + } + + /// + /// Debug level + /// + static public class DebugLevels + { + private const string ConsoleCommand = "setplugindebuglevel"; + private const string ConsoleHelpMessage = "set plugin debug level [deviceKey] [off | on] ([minutes])"; + private const string ConsoleHelpMessageExtended = @"SETPLUGINDEBUGLEVEL [{devicekey}] [OFF | ON] [timeOutInMinutes] + {deviceKey} [OFF | ON] [timeOutInMinutes] - Device to set plugin debug level + timeOutInMinutes - Set timeout for plugin debug level. Default is 15 minutes +"; + private const long DebugTimerDefaultMs = 90000; // 15-minutes (90,000-ms) + + /// + /// Key of this instance + /// + public static string Key { get; set; } + + /// + /// Trace level (0) + /// + /// + /// Log level for very low severity diagnostic messages. + /// + public static uint TraceLevel { get; private set; } + + /// + /// Debug level (1) + /// + /// + /// Log level for low severity diagnostic messages. + /// + public static uint DebugLevel { get; private set; } + + /// + /// Error Level (2) + /// + /// + /// Log level for diagnostic messages that indicate a failure in the current operation. + /// + public static uint ErrorLevel { get; private set; } + + + private static CTimer _debugTimer; + private static bool _timerActive; + + private static void ResetDebugLevels() + { + CrestronConsole.ConsoleCommandResponse(@"SETPLUGINDEBUGLEVEL level defaults set"); + TraceLevel = Convert.ToUInt16(Debug.ErrorLogLevel.Error); + DebugLevel = Convert.ToUInt16(Debug.ErrorLogLevel.Warning); + ErrorLevel = Convert.ToUInt16(Debug.ErrorLogLevel.Notice); + } + + private static void SetDebugLevels(uint value) + { + if (value > 2) + { + CrestronConsole.ConsoleCommandResponse(@"SETPLUGINDEBUGLEVEL level '{0}' invalid", value); + return; + } + + CrestronConsole.ConsoleCommandResponse(@"SETPLUGINDEBUGLEVEL level '{0}' set", value); + + TraceLevel = value; + DebugLevel = value; + ErrorLevel = value; + } + + /// + /// Constructor + /// + static DebugLevels() + { + // set the default values + ResetDebugLevels(); + + CrestronConsole.AddNewConsoleCommand( + ProcessConsoleCommand, + ConsoleCommand, + ConsoleHelpMessage, + ConsoleAccessLevelEnum.AccessOperator); + } + + /// + /// Sets the plugin debug level + /// + /// + /// SETPLUGINDEBUGLEVEL [{devicekey}] [OFF | ON] [timeOutInMinutes] + /// + /// command parameters in string format, not including the command + public static void ProcessConsoleCommand(string command) + { + var data = command.Split(' '); + + if (data == null || data.Length == 0 || string.IsNullOrEmpty(data[0]) || data[0].Contains("?")) + { + CrestronConsole.ConsoleCommandResponse(ConsoleHelpMessageExtended); + return; + } + + var key = string.IsNullOrEmpty(data[0]) ? string.Empty : data[0]; + var param = string.IsNullOrEmpty(data[1]) ? string.Empty : data[1]; + var timerLen = (long) ((data.Length < 3 || data[2] == null) ? DebugTimerDefaultMs : TimeSpan.FromMinutes(Convert.ToUInt16(data[2])).TotalMilliseconds); + + if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(param)) + return; + + var device = DeviceManager.GetDeviceForKey(key); + if (device == null) + { + CrestronConsole.ConsoleCommandResponse("SETPLUGINDEBUGLEVEL unable to get device with key: '{0}'", key); + return; + } + + switch (param) + { + case "off": + { + if (!_timerActive) break; + + _debugTimer.Stop(); + if (!_debugTimer.Disposed) + _debugTimer.Dispose(); + + _timerActive = false; + + ResetDebugLevels(); + + break; + } + case "on": + { + if (_debugTimer == null) + _debugTimer = new CTimer(t => ResetDebugLevels(), timerLen); + else + _debugTimer.Reset(); + + _timerActive = true; + + SetDebugLevels(0); + + break; + } + default: + { + CrestronConsole.ConsoleCommandResponse("SETPLUGINDEBUGLEVEL invalid parameter: '{0}'", param); + break; + } + } + } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/Directory.Build.props b/epi-sony-bravia.4Series/Directory.Build.props new file mode 100644 index 0000000..c8d6c96 --- /dev/null +++ b/epi-sony-bravia.4Series/Directory.Build.props @@ -0,0 +1,21 @@ + + + 1.0.0-local + $(Version) + PepperDash Technologies + PepperDash Technologies + PepperDash Sony Bravia Display + Copyright © 2023 + https://github.com/PepperDash/epi-mobile-control + git + Crestron; 4series + ../output + True + LICENSE.md + README.md + + + + + + diff --git a/epi-sony-bravia.4Series/Directory.Build.targets b/epi-sony-bravia.4Series/Directory.Build.targets new file mode 100644 index 0000000..807679e --- /dev/null +++ b/epi-sony-bravia.4Series/Directory.Build.targets @@ -0,0 +1,28 @@ + + + + true + content; + + + true + content; + + + + + + + + + + + + + + + + + + + diff --git a/epi-sony-bravia.4Series/Properties/AssemblyInfo.cs b/epi-sony-bravia.4Series/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0baac11 --- /dev/null +++ b/epi-sony-bravia.4Series/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("epi-sony-bravia.4Series")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("epi-sony-bravia.4Series")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aac28a64-228b-46e2-85d7-4f20c8107ed2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/epi-sony-bravia.4Series/Rs232Commands.cs b/epi-sony-bravia.4Series/Rs232Commands.cs new file mode 100644 index 0000000..abdd7ba --- /dev/null +++ b/epi-sony-bravia.4Series/Rs232Commands.cs @@ -0,0 +1,252 @@ +using System; +using System.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core.Queues; + +namespace SonyBraviaEpi +{ + public static class Rs232Commands + { + public static readonly byte[] PowerOn = {0x8c, 0x00, 0x00, 0x02, 0x01}; + public static readonly byte[] PowerOff = {0x8c, 0x00, 0x00, 0x02, 0x00}; + public static readonly byte[] PowerQuery = {0x83, 0x00, 0x00, 0xFF, 0xFF}; + public static readonly byte[] InputVideo1 = {0x8C, 0x00, 0x02, 0x03, 0x02, 0x01}; + public static readonly byte[] InputVideo2 = {0x8C, 0x00, 0x02, 0x03, 0x02, 0x02}; + public static readonly byte[] InputVideo3 = {0x8C, 0x00, 0x02, 0x03, 0x02, 0x03}; + public static readonly byte[] InputComponent1 = {0x8C, 0x00, 0x02, 0x03, 0x03, 0x01}; + public static readonly byte[] InputComponent2 = {0x8C, 0x00, 0x02, 0x03, 0x03, 0x02}; + public static readonly byte[] InputComponent3 = {0x8C, 0x00, 0x02, 0x03, 0x03, 0x03}; + public static readonly byte[] InputHdmi1 = {0x8C, 0x00, 0x02, 0x03, 0x04, 0x01}; + public static readonly byte[] InputHdmi2 = {0x8C, 0x00, 0x02, 0x03, 0x04, 0x02}; + public static readonly byte[] InputHdmi3 = {0x8C, 0x00, 0x02, 0x03, 0x04, 0x03}; + public static readonly byte[] InputHdmi4 = {0x8C, 0x00, 0x02, 0x03, 0x04, 0x04}; + public static readonly byte[] InputHdmi5 = {0x8C, 0x00, 0x02, 0x03, 0x04, 0x05}; + public static readonly byte[] InputPc1 = {0x8C, 0x00, 0x02, 0x03, 0x05, 0x01}; + public static readonly byte[] InputQuery = {0x83, 0x00, 0x02, 0xFF, 0xFF}; + + public static byte CalculateChecksum(this byte[] data) + { + // Total sum from byte[0] to byte[n] (last byte), if vlaue is over 0xFF (1-byte), the last byte of data is used + var result = data.Aggregate(0x00, (current, b) => current + b); + + //return Convert.ToByte(result > 0xff ? data[data.Length - 1] : result); + return Convert.ToByte(result > 0xff ? result & 0xFF : result); + } + + public static byte[] WithChecksum(this byte[] data) + { + var checksum = data.CalculateChecksum(); + var newArray = data.ToList(); + newArray.Add(checksum); + return newArray.ToArray(); + } + + public static IQueueMessage GetPowerOn(IBasicCommunication coms) + { + return new ComsMessage(coms, PowerOn.WithChecksum()); + } + + public static IQueueMessage GetPowerOff(IBasicCommunication coms) + { + return new ComsMessage(coms, PowerOff.WithChecksum()); + } + + public static IQueueMessage GetPowerQuery(IBasicCommunication coms) + { + return new ComsMessage(coms, PowerQuery.WithChecksum()); + } + + public static IQueueMessage GetHdmi1(IBasicCommunication coms) + { + return new ComsMessage(coms, InputHdmi1.WithChecksum()); + } + + public static IQueueMessage GetHdmi2(IBasicCommunication coms) + { + return new ComsMessage(coms, InputHdmi2.WithChecksum()); + } + + public static IQueueMessage GetHdmi3(IBasicCommunication coms) + { + return new ComsMessage(coms, InputHdmi3.WithChecksum()); + } + + public static IQueueMessage GetHdmi4(IBasicCommunication coms) + { + return new ComsMessage(coms, InputHdmi4.WithChecksum()); + } + + public static IQueueMessage GetHdmi5(IBasicCommunication coms) + { + return new ComsMessage(coms, InputHdmi5.WithChecksum()); + } + + public static IQueueMessage GetVideo1(IBasicCommunication coms) + { + return new ComsMessage(coms, InputVideo1.WithChecksum()); + } + + public static IQueueMessage GetVideo2(IBasicCommunication coms) + { + return new ComsMessage(coms, InputVideo2.WithChecksum()); + } + + public static IQueueMessage GetVideo3(IBasicCommunication coms) + { + return new ComsMessage(coms, InputVideo3.WithChecksum()); + } + + public static IQueueMessage GetComponent1(IBasicCommunication coms) + { + return new ComsMessage(coms, InputComponent1.WithChecksum()); + } + + public static IQueueMessage GetComponent2(IBasicCommunication coms) + { + return new ComsMessage(coms, InputComponent2.WithChecksum()); + } + + public static IQueueMessage GetComponent3(IBasicCommunication coms) + { + return new ComsMessage(coms, InputComponent3.WithChecksum()); + } + + public static IQueueMessage GetPc(IBasicCommunication coms) + { + return new ComsMessage(coms, InputPc1.WithChecksum()); + } + + public static IQueueMessage GetInputQuery(IBasicCommunication coms) + { + return new ComsMessage(coms, InputQuery.WithChecksum()); + } + /*const commands = { + "power_on": [0x8C, 0x00, 0x00, 0x02, 0x01], + "power_off": [0x8C, 0x00, 0x00, 0x02, 0x00], + "power_get": [0x83, 0x00, 0x00, 0xFF, 0xFF], + "standby_on": [0x8C, 0x00, 0x01, 0x02, 0x01], + "standby_off": [0x8C, 0x00, 0x01, 0x02, 0x00], + "input_select_toggle": [0x8C, 0x00, 0x02, 0x02, 0x00], + "input_select_video1": [0x8C, 0x00, 0x02, 0x03, 0x02, 0x01], + "input_select_video2": [0x8C, 0x00, 0x02, 0x03, 0x02, 0x02], + "input_select_video2": [0x8C, 0x00, 0x02, 0x03, 0x02, 0x03], + "input_select_component1": [0x8C, 0x00, 0x02, 0x03, 0x03, 0x01], + "input_select_component2": [0x8C, 0x00, 0x02, 0x03, 0x03, 0x02], + "input_select_component3": [0x8C, 0x00, 0x02, 0x03, 0x03, 0x03], + "input_select_hdmi1": [0x8C, 0x00, 0x02, 0x03, 0x04, 0x01], + "input_select_hdmi2": [0x8C, 0x00, 0x02, 0x03, 0x04, 0x02], + "input_select_hdmi3": [0x8C, 0x00, 0x02, 0x03, 0x04, 0x03], + "input_select_hdmi4": [0x8C, 0x00, 0x02, 0x03, 0x04, 0x04], + "input_select_hdmi5": [0x8C, 0x00, 0x02, 0x03, 0x04, 0x05], + "input_select_pc1": [0x8C, 0x00, 0x02, 0x03, 0x05, 0x01], + "input_select_shared1": [0x8C, 0x00, 0x02, 0x03, 0x07, 0x01], + "input_select_get": [0x83, 0x00, 0x02, 0xFF, 0xFF], + "volume_control_up": [0x8C, 0x00, 0x05, 0x03, 0x00, 0x00], + "volume_control_down": [0x8C, 0x00, 0x05, 0x03, 0x00, 0x01], + "volume_control_direct": [0x8C, 0x00, 0x05, 0x03, 0x01, 0x00], + "muting_toggle": [0x8C, 0x00, 0x06, 0x02, 0x00], + "muting_off": [0x8C, 0x00, 0x06, 0x03, 0x01, 0x00], + "muting_on": [0x8C, 0x00, 0x06, 0x03, 0x01, 0x01], + "off_timer_toggle": [0x8C, 0x00, 0x0C, 0x02, 0x00], + "off_timer_direct": [0x8C, 0x00, 0x0C, 0x03, 0x01, 0x00], + "picture_on": [0x8C, 0x00, 0x0D, 0x03, 0x01, 0x01], + "picture_off": [0x8C, 0x00, 0x0D, 0x03, 0x01, 0x00], + "teletext_tottle": [0x8C, 0x00, 0x0E, 0x02, 0x00], + "teletext_direct_off": [0x8C, 0x00, 0x0E, 0x03, 0x01, 0x00], + "teletext_direct_text": [0x8C, 0x00, 0x0E, 0x03, 0x01, 0x01], + "teletext_direct_mix": [0x8C, 0x00, 0x0E, 0x03, 0x01, 0x02], + "display_toggle": [0x8C, 0x00, 0x0F, 0x02, 0x00], + "closed_caption_toggle": [0x8C, 0x00, 0x10, 0x02, 0x00], + "closed_caption_off": [0x8C, 0x00, 0x10, 0x03, 0x01, 0x00], + "closed_caption_on": [0x8C, 0x00, 0x10, 0x03, 0x01, 0x01], + "closed_caption_analog_cc1": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x01], + "closed_caption_analog_cc2": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x02], + "closed_caption_analog_cc3": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x03], + "closed_caption_analog_cc4": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x04], + "closed_caption_analog_text1": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x05], + "closed_caption_analog_text2": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x06], + "closed_caption_analog_text3": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x07], + "closed_caption_analog_text4": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x00, 0x08], + "closed_caption_digital_service1": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x01], + "closed_caption_digital_service2": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x02], + "closed_caption_digital_service3": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x03], + "closed_caption_digital_service4": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x04], + "closed_caption_digital_service5": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x05], + "closed_caption_digital_service6": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x06], + "closed_caption_digital_cc1": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x07], + "closed_caption_digital_cc2": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x08], + "closed_caption_digital_cc3": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x09], + "closed_caption_digital_cc4": [0x8C, 0x00, 0x10, 0x04, 0x02, 0x01, 0x0A], + "picture_mode_toggle": [0x8C, 0x00, 0x20, 0x02, 0x00], + "picture_mode_vivid": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x00], + "picture_mode_standard": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x01], + "picture_mode_cinema": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x02], + "picture_mode_custom": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x03], + "picture_mode_cine2": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x04], + "picture_mode_sports": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x05], + "picture_mode_game": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x06], + "picture_mode_graphics": [0x8C, 0x00, 0x20, 0x03, 0x01, 0x07], + "sound_mode_standard": [0x8C, 0x00, 0x30, 0x03, 0x01, 0x01], + "sound_mode_cinema": [0x8C, 0x00, 0x30, 0x03, 0x01, 0x04], + "sound_mode_sports": [0x8C, 0x00, 0x30, 0x03, 0x01, 0x05], + "sound_mode_music": [0x8C, 0x00, 0x30, 0x03, 0x01, 0x06], + "sound_mode_game": [0x8C, 0x00, 0x30, 0x03, 0x01, 0x07], + "speaker_toggle": [0x8C, 0x00, 0x36, 0x02, 0x00], + "speaker_off": [0x8C, 0x00, 0x36, 0x03, 0x01, 0x00], + "speaker_on": [0x8C, 0x00, 0x36, 0x03, 0x01, 0x01], + "h_shift_up": [0x8C, 0x00, 0x41, 0x03, 0x00, 0x00], + "h_shift_down": [0x8C, 0x00, 0x41, 0x03, 0x00, 0x01], + "h_shift_plus": [0x8C, 0x00, 0x41, 0x04, 0x01, 0x00, 0x00], + "h_shift_minus": [0x8C, 0x00, 0x41, 0x04, 0x01, 0x01, 0x00], + "v_size_up": [0x8C, 0x00, 0x42, 0x03, 0x00, 0x00], + "v_size_down": [0x8C, 0x00, 0x42, 0x03, 0x00, 0x01], + "v_size_plus": [0x8C, 0x00, 0x42, 0x04, 0x01, 0x00, 0x00], + "v_size_minus": [0x8C, 0x00, 0x42, 0x04, 0x01, 0x01, 0x00], + "v_shift_up": [0x8C, 0x00, 0x43, 0x03, 0x00, 0x00], + "v_shift_down": [0x8C, 0x00, 0x43, 0x03, 0x00, 0x01], + "v_shift_plus": [0x8C, 0x00, 0x43, 0x04, 0x01, 0x00, 0x00], + "v_shift_minus": [0x8C, 0x00, 0x43, 0x04, 0x01, 0x01, 0x00], + "wide_toggle": [0x8C, 0x00, 0x44, 0x02, 0x00], + "wide_widezoom": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x00], + "wide_full": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x01], + "wide_zoom": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x02], + "wide_normal": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x03], + "wide_pc_normal": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x05], + "wide_pc_full1": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x06], + "wide_pc_full2": [0x8C, 0x00, 0x44, 0x03, 0x01, 0x07], + "auto_wide_toggle": [0x8C, 0x00, 0x45, 0x02, 0x00], + "auto_wide_off": [0x8C, 0x00, 0x45, 0x03, 0x01, 0x00], + "auto_wide_on": [0x8C, 0x00, 0x45, 0x03, 0x01, 0x01], + "mode43_toggle": [0x8C, 0x00, 0x45, 0x02, 0x00], + "mode43_normal": [0x8C, 0x00, 0x45, 0x03, 0x01, 0x04], + "mode43_widezoom": [0x8C, 0x00, 0x45, 0x03, 0x01, 0x03], + "mode43_off": [0x8C, 0x00, 0x45, 0x03, 0x01, 0x00], + "cinemotion_off": [0x8C, 0x00, 0x2A, 0x02, 0x00], + "cinemotion_auto": [0x8C, 0x00, 0x2A, 0x02, 0x01], + "picture_up": [0x8C, 0x00, 0x23, 0x03, 0x00, 0x00], + "picture_down": [0x8C, 0x00, 0x23, 0x03, 0x00, 0x01], + "picture_direct": [0x8C, 0x00, 0x23, 0x03, 0x01, 0x00], + "brightness_up": [0x8C, 0x00, 0x24, 0x03, 0x00, 0x00], + "brightness_down": [0x8C, 0x00, 0x24, 0x03, 0x00, 0x01], + "brightness_direct": [0x8C, 0x00, 0x24, 0x03, 0x01, 0x00], + "color_up": [0x8C, 0x00, 0x25, 0x03, 0x00, 0x00], + "color_down": [0x8C, 0x00, 0x25, 0x03, 0x00, 0x01], + "color_direct": [0x8C, 0x00, 0x25, 0x03, 0x01, 0x00], + "hue_red_up": [0x8C, 0x00, 0x26, 0x04, 0x00, 0x00, 0x00], + "hue_red_down": [0x8C, 0x00, 0x26, 0x04, 0x00, 0x00, 0x01], + "hue_green_up": [0x8C, 0x00, 0x26, 0x04, 0x00, 0x01, 0x00], + "hue_green_down": [0x8C, 0x00, 0x26, 0x04, 0x00, 0x01, 0x01], + "hue_red_direct": [0x8C, 0x00, 0x26, 0x04, 0x01, 0x00, 0x00], + "hue_green_direct": [0x8C, 0x00, 0x26, 0x04, 0x01, 0x01, 0x00], + "sharpness_up": [0x8C, 0x00, 0x28, 0x03, 0x00, 0x00], + "sharpness_down": [0x8C, 0x00, 0x28, 0x03, 0x00, 0x01], + "sharpness_direct": [0x8C, 0x00, 0x28, 0x03, 0x01, 0x00], + "sircs_emulation": [0x8C, 0x00, 0x67, 0x03, 0x00, 0x00], + "sircs_emulation_home": [0x8C, 0x00, 0x67, 0x03, 0x01, 0x60], + "signage_id_command": [0x83, 0x00, 0x6F, 0xFF, 0xFF], + "signage_productinfo1": [0x83, 0x00, 0x6E, 0xFF, 0xFF], + "signage_productinfo2": [0x83, 0x00, 0x6D, 0xFF, 0xFF], + "signage_productinfo3": [0x83, 0x00, 0x6C, 0xFF, 0xFF] +}*/ + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/Rs232ParsingUtils.cs b/epi-sony-bravia.4Series/Rs232ParsingUtils.cs new file mode 100644 index 0000000..7386c0f --- /dev/null +++ b/epi-sony-bravia.4Series/Rs232ParsingUtils.cs @@ -0,0 +1,126 @@ +using System; +using System.Linq; +using PepperDash.Core; + +namespace SonyBraviaEpi +{ + public static class Rs232ParsingUtils + { + private const byte Header = 0x70; + + public static bool ParsePowerResponse(this byte[] response, out bool power) + { + // TODO [ ] actually add in parsing + Debug.Console(DebugLevels.DebugLevel, "ParsePowerResponse response: {0}", response.ToReadableString()); + + if (response[2] == 0x00) + { + power = response[3] == 0x01; + return true; + } + + if (response[2] == 0x02) + { + power = response[3] != 0x00; + return true; + } + + power = false; + return false; + } + + public static bool ParseInputResponse(this byte[] response, out string input) + { + // TODO [ ] actually add in parsing + Debug.Console(DebugLevels.DebugLevel, "ParseInputResponse response: {0}", response.ToReadableString()); + + if (response[2] == 0x02) + { + input = ""; + //return true; + } + + input = ""; + return false; + } + + public static bool IsComplete(this byte[] message) + { + var returnDataSize = message[2]; + var totalDataSize = returnDataSize + 3; + return message.Length == totalDataSize; + } + + public static bool ContainsHeader(this byte[] bytes) + { + return bytes.Any(IsHeader()); + } + + public static int NumberOfHeaders(this byte[] bytes) + { + return bytes.Count(IsHeader()); + } + + public static int FirstHeaderIndex(this byte[] bytes) + { + return bytes.ToList().IndexOf(Header); + } + + private static byte[] GetFirstMessageWithMultipleHeaders(this byte[] bytes) + { + // any less than 3-bytes, we don't have a complete message + if (bytes.Length < 3) return bytes; + + var secondHeaderIndex = bytes.ToList().FindIndex(1, IsHeader().ToPredicate()); + + // ex. 0x70,0x00,0x70 (valid ACK response) - skip to byte[3] + if ((bytes[0] + bytes[1] == bytes[2]) && (bytes[2] == Header)) secondHeaderIndex++; + + if (secondHeaderIndex <= 0) secondHeaderIndex = bytes.Length; + + return bytes.Take(secondHeaderIndex).ToArray(); + } + + public static byte[] GetFirstMessage(this byte[] bytes) + { + return (bytes.NumberOfHeaders() <= 1) ? bytes : bytes.GetFirstMessageWithMultipleHeaders(); + } + + public static byte[] CleanToFirstHeader(this byte[] bytes) + { + var firstHeaderIndex = bytes.FirstHeaderIndex(); + return bytes.Skip(firstHeaderIndex).ToArray(); + } + + public static byte[] CleanOutFirstMessage(this byte[] bytes) + { + // any less than 3-bytes, we don't have a complete message + if (bytes.Length < 3) return bytes; + + var secondHeaderIndex = bytes.ToList().FindIndex(1, IsHeader().ToPredicate()); + + // ex. 0x70,0x00,0x70 (valid ACK response) - skip to byte[3] + if ((bytes[0] + bytes[1] == bytes[2]) && (bytes[2] == Header)) secondHeaderIndex++; + + if (secondHeaderIndex <= 0) secondHeaderIndex = bytes.Length; + + return bytes.Skip(secondHeaderIndex).ToArray(); + } + + public static string ToReadableString(this byte[] bytes) + { + return BitConverter.ToString(bytes); + } + + private static Func IsHeader() + { + const byte header = Header; + return t => t == header; + } + + private static Predicate ToPredicate(this Func func) + { + return new Predicate(func); + } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/SimpleIpCommands.cs b/epi-sony-bravia.4Series/SimpleIpCommands.cs new file mode 100644 index 0000000..c232a49 --- /dev/null +++ b/epi-sony-bravia.4Series/SimpleIpCommands.cs @@ -0,0 +1,51 @@ +using System; +using PepperDash.Core; +using PepperDash.Essentials.Core.Queues; + +namespace SonyBraviaEpi +{ + public class SimpleIpCommands + { + public static readonly string Header = "*S"; + public static readonly string Footer = "\x0A"; + + public enum MessageTypes + { + Control = 0x43, // Control "C" (67) + Query = 0x45, // Enquiries "E" (69) + Answer = 0x41, // Answers "A" (65) (with or without success) + Notify = 0x4E // Notify "N" (78) + } + + public enum InputTypes + { + Hdmi = 1, + Composite = 3, + Component = 4, + ScreenMirroring = 5 + } + + public static readonly int PowerOn = 0; + public static readonly int PowerOff = 1; + + public static IQueueMessage GetControlCommand(IBasicCommunication coms, string cmd, int value) + { + // *SCPOWR00000000000000010A + return new ComsMessage(coms, string.Format("{0}{1}{2}{3:D16}{4}", Header, Convert.ToChar(MessageTypes.Control), cmd, value, Footer)); + } + + public static IQueueMessage GetQueryCommand(IBasicCommunication coms, string cmd) + { + // *SEINPT################0A + return new ComsMessage(coms, string.Format("{0}{1}{2}{3}{4}", Header, Convert.ToChar(MessageTypes.Query), cmd, new string('#', 16), Footer)); + } + + public static IQueueMessage GetInputCommand(IBasicCommunication coms, InputTypes inputType, int inputValue) + { + // *SCINPT{0:D8}{D:8}0A + // *SCINPT00000001000000010A + var input = string.Format("{0:D8}{1:D8}", (int) inputType, inputValue); + return new ComsMessage(coms, string.Format("{0}{1}{2}{3}{4}", Header, Convert.ToChar(MessageTypes.Control), "INPT", input, Footer)); + } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/SimpleIpParsingUtils.cs b/epi-sony-bravia.4Series/SimpleIpParsingUtils.cs new file mode 100644 index 0000000..431b041 --- /dev/null +++ b/epi-sony-bravia.4Series/SimpleIpParsingUtils.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace SonyBraviaEpi +{ + public static class SimpleIpParsingUtils + { + public static IEnumerable SplitInParts(this String s, Int32 partLength) + { + if ((s == null) || (partLength <= 0)) yield break; + for (var i = 0; i < s.Length; i += partLength) + yield return s.Substring(i, Math.Min(partLength, s.Length - i)); + } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/SonyBraviaConfig.cs b/epi-sony-bravia.4Series/SonyBraviaConfig.cs new file mode 100644 index 0000000..94d58bb --- /dev/null +++ b/epi-sony-bravia.4Series/SonyBraviaConfig.cs @@ -0,0 +1,15 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace SonyBraviaEpi +{ + public class SonyBraviaConfig + { + public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } + public ControlPropertiesConfig Control { get; set; } + + public long? WarmingTimeMs { get; set; } + public long? CoolingTimeMs { get; set; } + public bool ForceRs232 { get; set; } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/SonyBraviaDevice.cs b/epi-sony-bravia.4Series/SonyBraviaDevice.cs new file mode 100644 index 0000000..d09896d --- /dev/null +++ b/epi-sony-bravia.4Series/SonyBraviaDevice.cs @@ -0,0 +1,914 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.CrestronThread; +using Crestron.SimplSharpPro.DeviceSupport; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Queues; +using PepperDash.Essentials.Core.Routing; +using PepperDash.Essentials.Devices.Displays; + +namespace SonyBraviaEpi +{ + public class SonyBraviaDevice : TwoWayDisplayBase, ICommunicationMonitor, IBridgeAdvanced, + IInputHdmi1, IInputHdmi2, IInputHdmi3, IInputHdmi4, IInputVga1, + IOnline + #if SERIES4 + ,IHasInputs +#endif + { + private readonly IBasicCommunication _coms; + private readonly bool _comsIsRs232; + public static GenericQueue CommandQueue; + + public static readonly CommunicationMonitorConfig DefaultMonitorConfig = new CommunicationMonitorConfig + { + PollInterval = 30000, + TimeToWarning = 60000, + TimeToError = 120000 + }; + + private readonly CTimer _pollTimer; + private readonly IQueueMessage _powerOffCommand; + private readonly IQueueMessage _powerOnCommand; + + private readonly CrestronQueue _queueRs232; + private readonly CrestronQueue _queueSimpleIp; + private string _currentInput; + private bool _powerIsOn; + private bool _isCooling; + private bool _isWarming; + private readonly long _coolingTimeMs; + private readonly long _warmingtimeMs; + + /// + /// Constructor + /// + /// + /// + public SonyBraviaDevice(DeviceConfig config, IBasicCommunication comms) + : base(config.Key, config.Name) + { + DebugLevels.Key = Key; + + var props = config.Properties.ToObject(); + _coolingTimeMs = props.CoolingTimeMs ?? 20000; + _warmingtimeMs = props.WarmingTimeMs ?? 20000; + + IQueueMessage powerQuery; + IQueueMessage inputQuery; + + _coms = comms; + var socket = _coms as ISocketStatus; + _comsIsRs232 = socket == null || props.ForceRs232; + if (_comsIsRs232) + { + _queueRs232 = new CrestronQueue(50); + _coms.BytesReceived += (sender, args) => _queueRs232.Enqueue(args.Bytes); + + _powerOnCommand = Rs232Commands.GetPowerOn(_coms); + _powerOffCommand = Rs232Commands.GetPowerOff(_coms); + powerQuery = Rs232Commands.GetPowerQuery(_coms); + inputQuery = Rs232Commands.GetInputQuery(_coms); + } + else + { + _queueSimpleIp = new CrestronQueue(50); + var comsGather = new CommunicationGather(_coms, "\x0A"); + comsGather.LineReceived += (sender, args) => _queueSimpleIp.Enqueue(args.Text); + + _powerOnCommand = SimpleIpCommands.GetControlCommand(_coms, "POWR", 1); + _powerOffCommand = SimpleIpCommands.GetControlCommand(_coms, "POWR", 0); + powerQuery = SimpleIpCommands.GetQueryCommand(_coms, "POWR"); + inputQuery = SimpleIpCommands.GetQueryCommand(_coms, "INPT"); + } + + if (CommandQueue == null) + CommandQueue = new GenericQueue(string.Format("{0}-commandQueue", config.Key), 50); + + var monitorConfig = props.CommunicationMonitorProperties ?? DefaultMonitorConfig; + CommunicationMonitor = new GenericCommunicationMonitor( + this, _coms, monitorConfig.PollInterval, monitorConfig.TimeToWarning, monitorConfig.TimeToError, + PowerPoll); + + BuildInputRoutingPorts(); + +#if SERIES4 + SetupInputs(); +#endif + + var worker = _comsIsRs232 + ? new Thread(ProcessRs232Response, null) + : new Thread(ProcessSimpleIpResponse, null); + + _pollTimer = new CTimer(Poll, new[] { powerQuery, inputQuery }, Timeout.Infinite); + + CrestronEnvironment.ProgramStatusEventHandler += type => + { + try + { + if (type != eProgramStatusEventType.Stopping) + return; + + worker.Abort(); + + _pollTimer.Stop(); + _pollTimer.Dispose(); + } + catch (Exception ex) + { + Debug.Console(DebugLevels.ErrorLevel, this, Debug.ErrorLogLevel.Notice, "Caught an exception at program stop: {0}{1}", + ex.Message, ex.StackTrace); + } + }; + + DeviceManager.AllDevicesActivated += (sender, args) => + { + try + { + _coms.Connect(); + CommunicationMonitor.Start(); + _pollTimer.Reset(5000, 15000); + } + catch (Exception ex) + { + Debug.Console(DebugLevels.ErrorLevel, this, Debug.ErrorLogLevel.Notice, "Caught an exception at AllDevicesActivated: {0}{1}", + ex.Message, ex.StackTrace); + } + }; + } + + /// + /// Device power is on + /// + public bool PowerIsOn + { + get { return _powerIsOn; } + set + { + _powerIsOn = value; + if (_powerIsOn) + { + IsWarming = true; + + WarmupTimer = new CTimer(o => + { + IsWarming = false; + }, _warmingtimeMs); + } + else + { + IsCooling = true; + + CooldownTimer = new CTimer(o => + { + IsCooling = false; + }, _coolingTimeMs); + } + } + } + + /// + /// Device is cooling + /// + public bool IsCooling + { + get { return _isCooling; } + set + { + _isCooling = value; + IsCoolingDownFeedback.FireUpdate(); + } + } + + /// + /// Device is cooling + /// + public bool IsWarming + { + get { return _isWarming; } + set + { + _isWarming = value; + IsWarmingUpFeedback.FireUpdate(); + } + } + + protected override Func IsCoolingDownFeedbackFunc + { + get { return () => IsCooling; } + } + + protected override Func IsWarmingUpFeedbackFunc + { + get { return () => IsWarming; } + } + + protected override Func CurrentInputFeedbackFunc + { + get { return () => _currentInput; } + } + + protected override Func PowerIsOnFeedbackFunc + { + get { return () => PowerIsOn; } + } + + /// + /// Link to API + /// + /// + /// + /// + /// + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); + } + + public StatusMonitorBase CommunicationMonitor { get; private set; } + + public BoolFeedback IsOnline { get { return CommunicationMonitor.IsOnlineFeedback; } } + + public ISelectableItems Inputs { get; private set; } + + /// + /// Poll device + /// + /// + public static void Poll(object o) + { + var commands = o as IEnumerable; + if (commands == null) + return; + + commands + .ToList() + .ForEach(command => + { + CommandQueue.Enqueue(command); + Thread.Sleep(100); + }); + } + + /// + /// Turn device power on + /// + public override void PowerOn() + { + CommandQueue.Enqueue(_powerOnCommand); + _pollTimer.Reset(1000, 15000); + } + + /// + /// Turn device power off + /// + public override void PowerOff() + { + CommandQueue.Enqueue(_powerOffCommand); + _pollTimer.Reset(1000, 15000); + } + + /// + /// Toggle device power + /// + public override void PowerToggle() + { + if (PowerIsOn) + { + PowerOff(); + } + else + { + PowerOn(); + } + } + + /// + /// Poll device for power state + /// + public void PowerPoll() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetPowerQuery(_coms) + : SimpleIpCommands.GetQueryCommand(_coms, "POWR")); + } + + /// + /// Print a list of input routing ports + /// + public void ListRoutingInputPorts() + { + var seperator = new string('*', 50); + + Debug.Console(DebugLevels.TraceLevel, this, seperator); + foreach (var inputPort in InputPorts) + { + Debug.Console(DebugLevels.TraceLevel, this, "inputPort key: {0}, connectionType: {1}, feedbackMatchObject: {2}, port: {3}", + inputPort.Key, inputPort.ConnectionType, inputPort.FeedbackMatchObject, inputPort.Port); + } + Debug.Console(DebugLevels.TraceLevel, this, seperator); + } + + private void AddInputRoutingPort(RoutingInputPort input, int port) + { + input.Port = port; + InputPorts.Add(input); + } + + /// + /// Build input routing ports + /// + public void BuildInputRoutingPorts() + { + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, + new Action(InputHdmi1), this), 1); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, + new Action(InputHdmi2), this), 2); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, + new Action(InputHdmi3), this), 3); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, + new Action(InputHdmi4), this), 4); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.HdmiIn5, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, + new Action(InputHdmi5), this), 5); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.VgaIn1, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Vga, + new Action(InputVga1), this), 6); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.CompositeIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Composite, + new Action(InputVideo1), this), 7); + + AddInputRoutingPort(new RoutingInputPort( + "CompositeIn2", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Composite, + new Action(InputVideo2), this), 8); + + AddInputRoutingPort(new RoutingInputPort( + "CompositeIn2", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Composite, + new Action(InputVideo3), this), 9); + + AddInputRoutingPort(new RoutingInputPort( + RoutingPortNames.ComponentIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Component, + new Action(InputVideo3), this), 10); + + AddInputRoutingPort(new RoutingInputPort( + "componentIn2", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Component, + new Action(InputComponent2), this), 11); + + AddInputRoutingPort(new RoutingInputPort( + "componentIn3", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Component, + new Action(InputComponent3), this), 12); + } + +#if SERIES4 + private void SetupInputs() + { + Inputs = new SonyBraviaInputs + { + Items = new Dictionary + { + { + "hdmi1", new SonyBraviaInput("Hdmi1", "HDMI 1", this, + _comsIsRs232 ? Rs232Commands.GetHdmi1(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 1))}, + { + + "hdmi2", new SonyBraviaInput("hdmi2", "HDMI 2", this, + _comsIsRs232 ? Rs232Commands.GetHdmi2(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 2)) + }, + { + "hdmi3", new SonyBraviaInput("hdmi3", "HDMI 3", this, + _comsIsRs232 ? Rs232Commands.GetHdmi3(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 3)) + }, + { + "hdmi4", new SonyBraviaInput("hdmi4", "HDMI 4", this, + _comsIsRs232 ? Rs232Commands.GetHdmi4(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 4)) + }, + { + "hdmi5", new SonyBraviaInput("hdmi5", "HDMI 5", this, + _comsIsRs232 ? Rs232Commands.GetHdmi5(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 5)) + }, + { + "video1", new SonyBraviaInput("video1", "Video 1", this, + _comsIsRs232 ? Rs232Commands.GetVideo1(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Composite, 1)) + }, + { + "video2", new SonyBraviaInput("video2", "Video 2", this, + _comsIsRs232 ? Rs232Commands.GetVideo2(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Composite, 2)) + }, + { + "video3", new SonyBraviaInput("video3", "Video 3", this, + _comsIsRs232 ? Rs232Commands.GetVideo3(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Composite, 3)) + }, + { + "component1", new SonyBraviaInput("component1", "Component 1", this, + _comsIsRs232 ? Rs232Commands.GetComponent1(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Component, 1)) + }, + { + "component2", new SonyBraviaInput("component2", "Component 2", this, + _comsIsRs232 ? Rs232Commands.GetComponent2(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Component, 2)) + }, + { + "component3", new SonyBraviaInput("component3", "Component 3", this, + _comsIsRs232 ? Rs232Commands.GetComponent3(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Component, 3)) + }, + { + "vga1", new SonyBraviaInput("vga1", "VGA 1", this, + _comsIsRs232 ? Rs232Commands.GetComponent1(_coms) + : null) + } + } + }; + } +#endif + + /// + /// Select HDMI 1 input + /// + public void InputHdmi1() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetHdmi1(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 1)); + } + + /// + /// Select HDMI 2 input + /// + public void InputHdmi2() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetHdmi2(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 2)); + } + + /// + /// Select HDMI 3 input + /// + public void InputHdmi3() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetHdmi3(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 3)); + } + + /// + /// Select HDMI 4 input + /// + public void InputHdmi4() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetHdmi4(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 4)); + } + + /// + /// Select HDMI 5 input + /// + public void InputHdmi5() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetHdmi5(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Hdmi, 5)); + } + + /// + /// Select Video 1 input + /// + public void InputVideo1() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetVideo1(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Composite, 1)); + } + + /// + /// Select Video 2 input + /// + public void InputVideo2() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetVideo2(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Composite, 2)); + } + + /// + /// Select Video 3 input + /// + public void InputVideo3() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetVideo3(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Composite, 3)); + } + + /// + /// Select Component 1 input + /// + public void InputComponent1() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetComponent1(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Component, 1)); + } + + /// + /// Select Component 2 input + /// + public void InputComponent2() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetComponent2(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Component, 2)); + } + + /// + /// Select Component 3 input + /// + public void InputComponent3() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetComponent3(_coms) + : SimpleIpCommands.GetInputCommand(_coms, SimpleIpCommands.InputTypes.Component, 3)); + } + + /// + /// Select PC input using the IInputVga1 interface + /// + public void InputVga1() + { + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetComponent1(_coms) + : null); + } + + /// + /// Poll device for input state + /// + public void InputPoll() + { + // byte[] poll = { 0x83, 0x00, 0x02, 0xFF, 0xFF, 0x83 }; + //CommandQueue.Enqueue(Rs232Commands.GetInputQuery(_coms)); + CommandQueue.Enqueue(_comsIsRs232 + ? Rs232Commands.GetInputQuery(_coms) + : SimpleIpCommands.GetQueryCommand(_coms, "INPT")); + } + + /// + /// Execute switch + /// + /// + public override void ExecuteSwitch(object selector) + { + if (PowerIsOn) + { + var action = selector as Action; + if (action == null) return; + + action(); + } + else + { + EventHandler handler = null; + handler = (sender, args) => + { + if (IsWarming) + return; + + IsWarmingUpFeedback.OutputChange -= handler; + + var action = selector as Action; + if (action == null) return; + + action(); + }; + + IsWarmingUpFeedback.OutputChange += handler; + PowerOn(); + } + } + + private object ProcessRs232Response(object _) + { + var seperator = new string('-', 50); + + byte[] buffer = null; + while (true) + { + try + { + var bytes = _queueRs232.Dequeue(); + if (bytes == null) + { + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: _queueRs232.Dequeue failed, object was null"); + return null; + } + + Debug.Console(DebugLevels.ErrorLevel, this, seperator); + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: bytes-'{0}' (len-'{1}')", + bytes.ToReadableString(), bytes.Length); + + if (buffer == null) + buffer = bytes; + else + { + var newBuffer = new byte[buffer.Length + bytes.Length]; + buffer.CopyTo(newBuffer, 0); + bytes.CopyTo(newBuffer, buffer.Length); + buffer = newBuffer; + } + + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: bytes-'{0}' (len-'{1}') | buffer-'{2}' (len-'{3}')", + bytes.ToReadableString(), bytes.Length, buffer.ToReadableString(), buffer.Length); + + if (!buffer.ContainsHeader()) + { + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: buffer-'{0}' (len-'{1}') did not contain a header", + buffer.ToReadableString(), buffer.Length); + + continue; + } + + if (buffer.ElementAtOrDefault(0) != 0x70) + buffer = buffer.CleanToFirstHeader(); + + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: bytes-'{0}' (len-'{1}') | buffer-'{2}' (len-'{3}')", + bytes.ToReadableString(), bytes.Length, buffer.ToReadableString(), buffer.Length); + + const int safety = 10; + var numberOfSpins = 0; + while (buffer.Length >= 3 && numberOfSpins <= safety) + { + ++numberOfSpins; + if (numberOfSpins == safety) + Debug.Console(0, + this, + Debug.ErrorLogLevel.Notice, + "We hit our safety limit, something is wrong... Buffer:{0}, Bytes:{1}", + buffer.ToReadableString(), + bytes.ToReadableString()); + + var message = buffer.GetFirstMessage(); + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: bytes-'{0}' (len-'{1}') | buffer-'{2}' (len-'{3}') | message-'{4}' (len-'{5}')", + bytes.ToReadableString(), bytes.Length, + buffer.ToReadableString(), buffer.Length, + message.ToReadableString(), message.Length); + + if (message.Length < 4) + { + // we have an ACK in here, let's print it out and keep moving + switch (message.ToReadableString()) + { + // response to query request (abnormal end) - Command Cancelled + // package is recieved normally, but the request is not acceptable in the current display status + case "07-00-70": + { + Debug.Console(DebugLevels.DebugLevel, this, "Control complete ({0})", message.ToReadableString()); + break; + } + case "07-01-71": + { + Debug.Console(DebugLevels.DebugLevel, this, "Abnormal End: over maximum value ({0})", message.ToReadableString()); + break; + } + case "07-02-72": + { + Debug.Console(DebugLevels.DebugLevel, this, "Abnormal End: under minimum value ({0})", message.ToReadableString()); + break; + } + case "70-03-73": + { + Debug.Console(DebugLevels.DebugLevel, this, "Abnormal End: command cancelled ({0})", message.ToReadableString()); + break; + } + case "70-04-74": + { + Debug.Console(DebugLevels.DebugLevel, this, "Abnormal End: parse error/data format error ({0})", message.ToReadableString()); + break; + } + default: + { + Debug.Console(DebugLevels.DebugLevel, this, "Unknown Response: {0}", message.ToReadableString()); + break; + } + } + + buffer = buffer.CleanOutFirstMessage(); + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: buffer-'{0}' (len-'{1}')", + buffer.ToReadableString(), buffer.Length); + + continue; + } + + // we have a full message, lets check it out + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessRs232Response: message-'{0}' (len-'{1}')", + message.ToReadableString(), message.Length); + + var dataSize = message[2]; + var totalDataSize = dataSize + 3; + var isComplete = totalDataSize == message.Length; + Debug.Console( + DebugLevels.ErrorLevel, this, "ProcessRs232Response: dataSize-'{0}' | totalDataSize-'{1}' | message.Length-'{2}'", + dataSize, totalDataSize, message.Length); + + if (!isComplete) + { + Debug.Console(DebugLevels.DebugLevel, this, "Message is incomplete... spinning around"); + break; + } + + bool powerResult; + if (buffer.ParsePowerResponse(out powerResult)) + { + PowerIsOn = powerResult; + PowerIsOnFeedback.FireUpdate(); + } + + string input; + if (buffer.ParseInputResponse(out input)) + { + _currentInput = input; + CurrentInputFeedback.FireUpdate(); + } + + buffer = buffer.NumberOfHeaders() > 1 ? buffer.CleanOutFirstMessage() : new byte[0]; + + Debug.Console(DebugLevels.DebugLevel, this, seperator); + } + } + catch (Exception ex) + { + Debug.Console(DebugLevels.TraceLevel, this, Debug.ErrorLogLevel.Error, "ProcessRs232Response Exception: {0}", ex.Message); + Debug.Console(DebugLevels.DebugLevel, this, Debug.ErrorLogLevel.Error, "ProcessRs232Response Exception Stack Trace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugLevels.ErrorLevel, this, Debug.ErrorLogLevel.Error, "ProcessRs232Response Inner Exception: {0}", ex.InnerException); + + Debug.Console(DebugLevels.DebugLevel, this, seperator); + } + } + } + + private object ProcessSimpleIpResponse(object _) + { + var seperator = new string('-', 50); + + while (true) + { + try + { + var response = _queueSimpleIp.Dequeue(); + if (response == null) + { + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessSimpleIpResponse: _queueSimpleIp.Dequeue failed, object was null"); + return null; + } + + Debug.Console(DebugLevels.ErrorLevel, this, seperator); + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessSimpleIpResponse: raw '{0}'", response); + + // http://regexstorm.net/tester + // *([A,C,E,N])(?POWR|INPT|VOLU|AMUT)(?.[Ff]+|\d+) + // *(?[A,C,E,N]{1})(?[A-Za-z]{4})(?.\w+) + // - CPOWR0000000000000000\n + // - AINPT0000000000000001\n + // - CVOLU0000000000000001\n + // - AAMUTFFFFFFFFFFFFFFFF\n + var expression = new Regex(@"(?[A,C,E,N]{1})(?[A-Za-z]{4})(?.\w+)", RegexOptions.None); + var matches = expression.Match(response); + + if (!matches.Success) + { + Debug.Console(DebugLevels.TraceLevel, this, "ProcessSimpleIpResponse: unknown response '{0}'", response); + return null; + } + + var type = matches.Groups["type"].Value; + var command = matches.Groups["command"].Value; + var parameters = matches.Groups["parameters"].Value; + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessSimpleIpResponse: type-'{0}' | command-'{1}' | parameters-'{2}'", + type, command, parameters); + + // display off input response: + // - '*SAINPTFFFFFFFFFFFFFFFF' + // - '*SAINPTNNNNNNNNNNNNNNNN' + if (parameters.Contains('F') || parameters.Contains('N')) continue; + + switch (command) + { + case "POWR": + { + PowerIsOn = Convert.ToInt16(parameters) == 1; + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessSimpleIpResponse: PowerIsOn == '{0}'", PowerIsOn.ToString()); + break; + } + case "INPT": + { + // display on response: + // - '*SAINPT0000000100000001' (hdmi 1) + // - '*SAINPT0000000400000001' (component 1) + var parts = parameters.SplitInParts(8); + var inputParts = parts as IList ?? parts.ToList(); + var inputType = (SimpleIpCommands.InputTypes)Convert.ToInt16(inputParts.ElementAt(0)); + var inputNumber = Convert.ToInt16(inputParts.ElementAt(1)); + + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessSimpleIpResponse: inputType == '{0}' | inputNumber == '{1}'", + inputType, inputNumber); + + switch (inputType) + { + case SimpleIpCommands.InputTypes.Hdmi: + { + _currentInput = inputNumber.ToString(CultureInfo.InvariantCulture); + break; + } + case SimpleIpCommands.InputTypes.Component: + { + var index = inputNumber + 9; + _currentInput = index.ToString(CultureInfo.InvariantCulture); + break; + } + case SimpleIpCommands.InputTypes.Composite: + { + var index = inputNumber + 6; + _currentInput = index.ToString(CultureInfo.InvariantCulture); + break; + } + default: + { + // unknown input type + break; + } + } + + Debug.Console(DebugLevels.ErrorLevel, this, "ProcessSimpleIpResponse: _currentInput == '{0}'", _currentInput); + + break; + } + default: + { + Debug.Console(DebugLevels.DebugLevel, this, "ProcessSimpleIpResponse: unhandled response '{0}' == '{1}'", + command, parameters); + break; + } + } + + Debug.Console(DebugLevels.ErrorLevel, this, seperator); + } + catch (Exception ex) + { + Debug.Console(DebugLevels.TraceLevel, this, Debug.ErrorLogLevel.Error, + "ProcessSimpleIpResponse Exception: {0}", ex.Message); + Debug.Console(DebugLevels.DebugLevel, this, Debug.ErrorLogLevel.Error, + "ProcessSimpleIpResponse Exception Stack Trace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugLevels.ErrorLevel, this, Debug.ErrorLogLevel.Error, + "ProcessSimpleIpResponse Inner Exception: {0}", ex.InnerException); + + Debug.Console(DebugLevels.DebugLevel, this, seperator); + } + } + } + + public void EnqueueCommand(IQueueMessage command) + { + CommandQueue.Enqueue(command); + } + + public void SetInput(string selector) + { + var input = Inputs.Items[selector]; + + if(input != null) + { + input.Select(); + } + } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/SonyBraviaFactory.cs b/epi-sony-bravia.4Series/SonyBraviaFactory.cs new file mode 100644 index 0000000..1222a19 --- /dev/null +++ b/epi-sony-bravia.4Series/SonyBraviaFactory.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; + +namespace SonyBraviaEpi +{ + public class SonyBraviaFactory : EssentialsPluginDeviceFactory + { + public SonyBraviaFactory() + { + TypeNames = new List { "sonybravia", "sonybraviarest", "sonybraviasimpleip" }; + + MinimumEssentialsFrameworkVersion = "1.8.5"; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(DebugLevels.TraceLevel, "[{0}] Building {1} plugin instance...", dc.Name, dc.Type); + + var props = dc.Properties.ToObject(); + if (props == null) + { + Debug.Console(DebugLevels.TraceLevel, "[{0}] Failed to build {1} plugin", dc.Name, dc.Type); + return null; + } + + var comms = CommFactory.CreateCommForDevice(dc); + if (comms != null) return new SonyBraviaDevice(dc, comms); + + Debug.Console(DebugLevels.TraceLevel, "[{0}] Failed to build {1} plugin using {2}", dc.Name, dc.Type, props.Control.Method); + return null; + } + } +} \ No newline at end of file diff --git a/epi-sony-bravia.4Series/SonyBraviaInputs.cs b/epi-sony-bravia.4Series/SonyBraviaInputs.cs new file mode 100644 index 0000000..56f4599 --- /dev/null +++ b/epi-sony-bravia.4Series/SonyBraviaInputs.cs @@ -0,0 +1,98 @@ +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Queues; +using SonyBraviaEpi; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SonyBraviaEpi +{ + public class SonyBraviaInputs : ISelectableItems + { + private Dictionary _items = new Dictionary(); + + public Dictionary Items + { + get + { + return _items; + } + set + { + if (_items == value) + return; + + _items = value; + + ItemsUpdated?.Invoke(this, null); + } + } + + private string _currentItem; + + public string CurrentItem + { + get + { + return _currentItem; + } + set + { + if (_currentItem == value) + return; + + _currentItem = value; + + CurrentItemChanged?.Invoke(this, null); + } + } + + public event EventHandler ItemsUpdated; + public event EventHandler CurrentItemChanged; + + } + + public class SonyBraviaInput : ISelectableItem + { + private bool _isSelected; + + private readonly IQueueMessage _inputCommand; + private readonly SonyBraviaDevice _parent; + + public SonyBraviaInput(string key, string name, SonyBraviaDevice parent, IQueueMessage inputCommand) + { + Key = key; + Name = name; + _parent = parent; + _inputCommand = inputCommand; + } + + public string Key { get; private set; } + public string Name { get; private set; } + + public event EventHandler ItemUpdated; + + public bool IsSelected + { + get { return _isSelected; } + set + { + if (value == _isSelected) + return; + + _isSelected = value; + var handler = ItemUpdated; + if (handler != null) + handler(this, EventArgs.Empty); + } + } + + public void Select() + { + _parent.EnqueueCommand(_inputCommand); + } + } + +} diff --git a/epi-sony-bravia.4Series/app.config b/epi-sony-bravia.4Series/app.config new file mode 100644 index 0000000..f4cb499 --- /dev/null +++ b/epi-sony-bravia.4Series/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/epi-sony-bravia.4Series/epi-sony-bravia.4Series.csproj b/epi-sony-bravia.4Series/epi-sony-bravia.4Series.csproj new file mode 100644 index 0000000..eb9c3ec --- /dev/null +++ b/epi-sony-bravia.4Series/epi-sony-bravia.4Series.csproj @@ -0,0 +1,214 @@ + + + + + Debug + AnyCPU + {AAC28A64-228B-46E2-85D7-4F20C8107ED2} + Library + Properties + epi_sony_bravia._4Series + epi-sony-bravia.4Series + v4.7.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + packages\BouncyCastle.1.8.9\lib\BouncyCastle.Crypto.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.AudioDistribution.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.CrestronConnected.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.DeviceSupport.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.DM.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.EthernetCommunications.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Fusion.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Gateways.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.GeneralIO.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Keypads.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Lighting.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Media.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Remotes.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Shades.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.Thermostats.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.ThreeSeriesCards.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.UC.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\Crestron.SimplSharpPro.UI.dll + + + packages\PepperDash.Essentials.Devices.Common.2.0.0-alpha-2424\lib\net472\Essentials Devices Common.dll + + + packages\PepperDashCore.2.0.0-alpha-402\lib\net472\PepperDashCore.dll + + + packages\PepperDashEssentials.2.0.0-alpha-2424\lib\net472\PepperDashEssentials.dll + + + packages\PepperDash.Essentials.Core.2.0.0-alpha-2424\lib\net472\PepperDash_Essentials_Core.dll + + + packages\Serilog.3.1.1\lib\net471\Serilog.dll + + + packages\Serilog.Formatting.Compact.2.0.0\lib\net471\Serilog.Formatting.Compact.dll + + + packages\Serilog.Sinks.Console.5.0.0\lib\net471\Serilog.Sinks.Console.dll + + + packages\Serilog.Sinks.File.5.0.0\lib\net45\Serilog.Sinks.File.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpAutoUpdateInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpCloudClientInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpCryptographyInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpCustomAttributesInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpCWSHelperInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpExchangeWebServices.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpHelperInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpNewtonsoft.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpOnvifInterface.dll + + + packages\Crestron.SimplSharp.SDK.ProgramLibrary.2.20.42\lib\net47\SimplSharpPro.exe + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpProgrammingInterfaces.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpReflectionInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpSQLHelperInterface.dll + + + packages\Crestron.SimplSharp.SDK.Library.2.20.42\lib\net47\SimplSharpTimerEventInterface.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + packages\System.Diagnostics.DiagnosticSource.7.0.2\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + + + + + + packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + \ No newline at end of file diff --git a/epi-sony-bravia.4Series/epi-sony-bravia.4Series.sln b/epi-sony-bravia.4Series/epi-sony-bravia.4Series.sln new file mode 100644 index 0000000..220ed0d --- /dev/null +++ b/epi-sony-bravia.4Series/epi-sony-bravia.4Series.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34408.163 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "epi-sony-bravia.4Series", "epi-sony-bravia.4Series.csproj", "{AAC28A64-228B-46E2-85D7-4F20C8107ED2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AAC28A64-228B-46E2-85D7-4F20C8107ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAC28A64-228B-46E2-85D7-4F20C8107ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAC28A64-228B-46E2-85D7-4F20C8107ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAC28A64-228B-46E2-85D7-4F20C8107ED2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1A42D0D1-A36A-48D1-9D08-5062C15CD57D} + EndGlobalSection +EndGlobal diff --git a/epi-sony-bravia.4Series/packages.config b/epi-sony-bravia.4Series/packages.config new file mode 100644 index 0000000..1b01617 --- /dev/null +++ b/epi-sony-bravia.4Series/packages.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file