From f9717bcc6224db67d0f40f54588c6fb47990f155 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Mon, 1 Oct 2012 12:57:43 +0200 Subject: [PATCH] updated documentation, formatting --- include/cec.h | 11 + src/LibCecSharp/CecSharpTypes.h | 2350 +++++++++++++++++-------------- src/LibCecSharp/LibCecSharp.cpp | 1147 +++++++-------- 3 files changed, 1866 insertions(+), 1642 deletions(-) diff --git a/include/cec.h b/include/cec.h index e7ee890..40df4ce 100644 --- a/include/cec.h +++ b/include/cec.h @@ -40,6 +40,17 @@ namespace CEC { + /*! + * To create a new libCEC instance, call CECInitialise() and pass the + * configuration as argument. Then call Open() to open a connection to the + * adapter. Close() closes the connection and CECDestroy() cleans up the + * libCEC instance. + * + * libCEC can send commands to other devices on the CEC bus via the methods + * on this interface, and all commands that libCEC received are sent back + * to the application via callback methods. The callback methods can be + * found in cectypes.h, ICECCallbacks. + */ class ICECAdapter { public: diff --git a/src/LibCecSharp/CecSharpTypes.h b/src/LibCecSharp/CecSharpTypes.h index 52c0b20..368c52e 100644 --- a/src/LibCecSharp/CecSharpTypes.h +++ b/src/LibCecSharp/CecSharpTypes.h @@ -1,35 +1,35 @@ #pragma once /* - * This file is part of the libCEC(R) library. - * - * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. - * libCEC(R) is an original work, containing original code. - * - * libCEC(R) is a trademark of Pulse-Eight Limited. - * - * This program is dual-licensed; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * - * Alternatively, you can license this library under a commercial license, - * please contact Pulse-Eight Licensing for more information. - * - * For more information contact: - * Pulse-Eight Licensing - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ +* This file is part of the libCEC(R) library. +* +* libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. +* libCEC(R) is an original work, containing original code. +* +* libCEC(R) is a trademark of Pulse-Eight Limited. +* +* This program is dual-licensed; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* +* Alternatively, you can license this library under a commercial license, +* please contact Pulse-Eight Licensing for more information. +* +* For more information contact: +* Pulse-Eight Licensing +* http://www.pulse-eight.com/ +* http://www.pulse-eight.net/ +*/ #include "../lib/platform/threads/mutex.h" #include @@ -41,977 +41,1269 @@ namespace CecSharp { - public enum class CecDeviceType - { - Tv = 0, - RecordingDevice = 1, - Reserved = 2, - Tuner = 3, - PlaybackDevice = 4, - AudioSystem = 5 - }; - - public enum class CecLogLevel - { - None = 0, - Error = 1, - Warning = 2, - Notice = 4, - Traffic = 8, - Debug = 16, - All = 31 - }; - - public enum class CecLogicalAddress - { - Unknown = -1, //not a valid logical address - Tv = 0, - RecordingDevice1 = 1, - RecordingDevice2 = 2, - Tuner1 = 3, - PlaybackDevice1 = 4, - AudioSystem = 5, - Tuner2 = 6, - Tuner3 = 7, - PlaybackDevice2 = 8, - RecordingDevice3 = 9, - Tuner4 = 10, - PlaybackDevice3 = 11, - Reserved1 = 12, - Reserved2 = 13, - FreeUse = 14, - Unregistered = 15, - Broadcast = 15 - }; - - public enum class CecAlert - { - ServiceDevice = 1 - }; - - public enum class CecParameterType - { - ParameterTypeString = 1 - }; - - public ref class CecParameter - { - public: - CecParameter(CecParameterType type, System::String ^ strData) - { - Type = type; - Data = strData; - } - - property CecParameterType Type; - property System::String ^ Data; - }; - - public enum class CecPowerStatus - { - On = 0x00, - Standby = 0x01, - InTransitionStandbyToOn = 0x02, - InTransitionOnToStandby = 0x03, - Unknown = 0x99 - }; - - public enum class CecVersion - { - Unknown = 0x00, - V1_2 = 0x01, - V1_2A = 0x02, - V1_3 = 0x03, - V1_3A = 0x04, - V1_4 = 0x05 - }; - - public enum class CecDisplayControl - { - DisplayForDefaultTime = 0x00, - DisplayUntilCleared = 0x40, - ClearPreviousMessage = 0x80, - ReservedForFutureUse = 0xC0 - }; - - public enum class CecMenuState - { - Activated = 0, - Deactivated = 1 - }; - - public enum class CecDeckControlMode - { - SkipForwardWind = 1, - SkipReverseRewind = 2, - Stop = 3, - Eject = 4 - }; - - public enum class CecDeckInfo - { - Play = 0x11, - Record = 0x12, - Reverse = 0x13, - Still = 0x14, - Slow = 0x15, - SlowReverse = 0x16, - FastForward = 0x17, - FastReverse = 0x18, - NoMedia = 0x19, - Stop = 0x1A, - SkipForwardWind = 0x1B, - SkipReverseRewind = 0x1C, - IndexSearchForward = 0x1D, - IndexSearchReverse = 0x1E, - OtherStatus = 0x1F - }; - - public enum class CecUserControlCode - { - Select = 0x00, - Up = 0x01, - Down = 0x02, - Left = 0x03, - Right = 0x04, - RightUp = 0x05, - RightDown = 0x06, - LeftUp = 0x07, - LeftDown = 0x08, - RootMenu = 0x09, - SetupMenu = 0x0A, - ContentsMenu = 0x0B, - FavoriteMenu = 0x0C, - Exit = 0x0D, - Number0 = 0x20, - Number1 = 0x21, - Number2 = 0x22, - Number3 = 0x23, - Number4 = 0x24, - Number5 = 0x25, - Number6 = 0x26, - Number7 = 0x27, - Number8 = 0x28, - Number9 = 0x29, - Dot = 0x2A, - Enter = 0x2B, - Clear = 0x2C, - NextFavorite = 0x2F, - ChannelUp = 0x30, - ChannelDown = 0x31, - PreviousChannel = 0x32, - SoundSelect = 0x33, - InputSelect = 0x34, - DisplayInformation = 0x35, - Help = 0x36, - PageUp = 0x37, - PageDown = 0x38, - Power = 0x40, - VolumeUp = 0x41, - VolumeDown = 0x42, - Mute = 0x43, - Play = 0x44, - Stop = 0x45, - Pause = 0x46, - Record = 0x47, - Rewind = 0x48, - FastForward = 0x49, - Eject = 0x4A, - Forward = 0x4B, - Backward = 0x4C, - StopRecord = 0x4D, - PauseRecord = 0x4E, - Angle = 0x50, - SubPicture = 0x51, - VideoOnDemand = 0x52, - ElectronicProgramGuide = 0x53, - TimerProgramming = 0x54, - InitialConfiguration = 0x55, - PlayFunction = 0x60, - PausePlayFunction = 0x61, - RecordFunction = 0x62, - PauseRecordFunction = 0x63, - StopFunction = 0x64, - MuteFunction = 0x65, - RestoreVolumeFunction = 0x66, - TuneFunction = 0x67, - SelectMediaFunction = 0x68, - SelectAVInputFunction = 0x69, - SelectAudioInputFunction = 0x6A, - PowerToggleFunction = 0x6B, - PowerOffFunction = 0x6C, - PowerOnFunction = 0x6D, - F1Blue = 0x71, - F2Red = 0X72, - F3Green = 0x73, - F4Yellow = 0x74, - F5 = 0x75, - Data = 0x76, - Max = 0x76, - SamsungReturn = 0x91, - Unknown - }; - - public enum class CecVendorId - { - Samsung = 0x0000F0, - LG = 0x00E091, - Panasonic = 0x008045, - Pioneer = 0x00E036, - Onkyo = 0x0009B0, - Yamaha = 0x00A0DE, - Philips = 0x00903E, - Sony = 0x080046, - Toshiba = 0x000039, - Akai = 0x0020C7, - Benq = 0x8065E9, - Daewoo = 0x009053, - Grundig = 0x00D0D5, - Medion = 0x000CB8, - Sharp = 0x08001F, - Vizio = 0x6B746D, - Unknown = 0 - }; - - public enum class CecAudioStatus - { - MuteStatusMask = 0x80, - VolumeStatusMask = 0x7F, - VolumeMin = 0x00, - VolumeMax = 0x64, - VolumeStatusUnknown = 0x7F - }; - - public enum class CecOpcode - { - ActiveSource = 0x82, - ImageViewOn = 0x04, - TextViewOn = 0x0D, - InactiveSource = 0x9D, - RequestActiveSource = 0x85, - RoutingChange = 0x80, - RoutingInformation = 0x81, - SetStreamPath = 0x86, - Standby = 0x36, - RecordOff = 0x0B, - RecordOn = 0x09, - RecordStatus = 0x0A, - RecordTvScreen = 0x0F, - ClearAnalogueTimer = 0x33, - ClearDigitalTimer = 0x99, - ClearExternalTimer = 0xA1, - SetAnalogueTimer = 0x34, - SetDigitalTimer = 0x97, - SetExternalTimer = 0xA2, - SetTimerProgramTitle = 0x67, - TimerClearedStatus = 0x43, - TimerStatus = 0x35, - CecVersion = 0x9E, - GetCecVersion = 0x9F, - GivePhysicalAddress = 0x83, - GetMenuLanguage = 0x91, - ReportPhysicalAddress = 0x84, - SetMenuLanguage = 0x32, - DeckControl = 0x42, - DeckStatus = 0x1B, - GiveDeckStatus = 0x1A, - Play = 0x41, - GiveTunerDeviceStatus = 0x08, - SelectAnalogueService = 0x92, - SelectDigtalService = 0x93, - TunerDeviceStatus = 0x07, - TunerStepDecrement = 0x06, - TunerStepIncrement = 0x05, - DeviceVendorId = 0x87, - GiveDeviceVendorId = 0x8C, - VendorCommand = 0x89, - VendorCommandWithId = 0xA0, - VendorRemoteButtonDown = 0x8A, - VendorRemoteButtonUp = 0x8B, - SetOsdString = 0x64, - GiveOsdName = 0x46, - SetOsdName = 0x47, - MenuRequest = 0x8D, - MenuStatus = 0x8E, - UserControlPressed = 0x44, - UserControlRelease = 0x45, - GiveDevicePowerStatus = 0x8F, - ReportPowerStatus = 0x90, - FeatureAbort = 0x00, - Abort = 0xFF, - GiveAudioStatus = 0x71, - GiveSystemAudioMode = 0x7D, - ReportAudioStatus = 0x7A, - SetSystemAudioMode = 0x72, - SystemAudioModeRequest = 0x70, - SystemAudioModeStatus = 0x7E, - SetAudioRate = 0x9A, - /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */ - None = 0xFD - }; - - public enum class CecSystemAudioStatus - { - Off = 0, - On = 1 - }; - - public enum class CecClientVersion - { - VersionPre1_5 = 0, - Version1_5_0 = 0x1500, - Version1_5_1 = 0x1501, - Version1_5_2 = 0x1502, - Version1_5_3 = 0x1503, - Version1_6_0 = 0x1600, - Version1_6_1 = 0x1601, - Version1_6_2 = 0x1602, - Version1_6_3 = 0x1603, - Version1_7_0 = 0x1700, - Version1_7_1 = 0x1701, - Version1_7_2 = 0x1702, - Version1_8_0 = 0x1800, - Version1_8_1 = 0x1801, - Version1_8_2 = 0x1802, - Version1_9_0 = 0x1900 - }; - - public enum class CecServerVersion - { - VersionPre1_5 = 0, - Version1_5_0 = 0x1500, - Version1_5_1 = 0x1501, - Version1_5_2 = 0x1502, - Version1_5_3 = 0x1503, - Version1_6_0 = 0x1600, - Version1_6_1 = 0x1601, - Version1_6_2 = 0x1602, - Version1_6_3 = 0x1603, - Version1_7_0 = 0x1700, - Version1_7_1 = 0x1701, - Version1_7_2 = 0x1702, - Version1_8_0 = 0x1800, - Version1_8_1 = 0x1801, - Version1_8_2 = 0x1802, - Version1_9_0 = 0x1900 - }; - - public ref class CecAdapter - { - public: - CecAdapter(System::String ^ strPath, System::String ^ strComPort) - { - Path = strPath; - ComPort = strComPort; - } - - property System::String ^ Path; - property System::String ^ ComPort; - }; - - public ref class CecDeviceTypeList - { - public: - CecDeviceTypeList(void) - { - Types = gcnew array(5); - for (unsigned int iPtr = 0; iPtr < 5; iPtr++) - Types[iPtr] = CecDeviceType::Reserved; - } - - property array ^ Types; - }; - - public ref class CecLogicalAddresses - { - public: - CecLogicalAddresses(void) - { - Addresses = gcnew array(16); - Clear(); - } - - void Clear(void) - { - Primary = CecLogicalAddress::Unknown; - for (unsigned int iPtr = 0; iPtr < 16; iPtr++) - Addresses[iPtr] = CecLogicalAddress::Unknown; - } - - bool IsSet(CecLogicalAddress iAddress) - { - return Addresses[(unsigned int)iAddress] != CecLogicalAddress::Unknown; - } - - void Set(CecLogicalAddress iAddress) - { - Addresses[(unsigned int)iAddress] = iAddress; - if (Primary == CecLogicalAddress::Unknown) - Primary = iAddress; - } - - property CecLogicalAddress Primary; - property array ^ Addresses; - }; - - public ref class CecDatapacket - { - public: - CecDatapacket(void) - { - Data = gcnew array(100); - Size = 0; - } - - void PushBack(uint8_t data) - { - if (Size < 100) - { - Data[Size] = data; - Size++; - } - } - - property array ^ Data; - property uint8_t Size; - }; - - public ref class CecCommand - { - public: - CecCommand(CecLogicalAddress iInitiator, CecLogicalAddress iDestination, bool bAck, bool bEom, CecOpcode iOpcode, int32_t iTransmitTimeout) - { - Initiator = iInitiator; - Destination = iDestination; - Ack = bAck; - Eom = bEom; - Opcode = iOpcode; - OpcodeSet = true; - TransmitTimeout = iTransmitTimeout; - Parameters = gcnew CecDatapacket; - Empty = false; - } - - CecCommand(void) - { - Initiator = CecLogicalAddress::Unknown; - Destination = CecLogicalAddress::Unknown; - Ack = false; - Eom = false; - Opcode = CecOpcode::None; - OpcodeSet = false; - TransmitTimeout = 0; - Parameters = gcnew CecDatapacket; - Empty = true; - } - - void PushBack(uint8_t data) - { - if (Initiator == CecLogicalAddress::Unknown && Destination == CecLogicalAddress::Unknown) - { - Initiator = (CecLogicalAddress) (data >> 4); - Destination = (CecLogicalAddress) (data & 0xF); - } - else if (!OpcodeSet) - { - OpcodeSet = true; - Opcode = (CecOpcode)data; - } - else - { - Parameters->PushBack(data); - } - } - - property bool Empty; - property CecLogicalAddress Initiator; - property CecLogicalAddress Destination; - property bool Ack; - property bool Eom; - property CecOpcode Opcode; - property CecDatapacket ^ Parameters; - property bool OpcodeSet; - property int32_t TransmitTimeout; - }; - - public ref class CecKeypress - { - public: - CecKeypress(CecUserControlCode iKeycode, unsigned int iDuration) - { - Keycode = iKeycode; - Duration = iDuration; - Empty = false; - } - - CecKeypress(void) - { - Keycode = CecUserControlCode::Unknown; - Duration = 0; - Empty = true; - } - - property bool Empty; - property CecUserControlCode Keycode; - property unsigned int Duration; - }; - - public ref class CecLogMessage - { - public: - CecLogMessage(System::String ^ strMessage, CecLogLevel iLevel, int64_t iTime) - { - Message = strMessage; - Level = iLevel; - Time = iTime; - Empty = false; - } - - CecLogMessage(void) - { - Message = ""; - Level = CecLogLevel::None; - Time = 0; - Empty = true; - } - - property bool Empty; - property System::String ^Message; - property CecLogLevel Level; - property int64_t Time; - }; - - ref class CecCallbackMethods; //forward - public ref class LibCECConfiguration - { - public: - LibCECConfiguration(void) - { - DeviceName = ""; - DeviceTypes = gcnew CecDeviceTypeList(); - AutodetectAddress = true; - PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS; - BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE; - HDMIPort = CEC_DEFAULT_HDMI_PORT; - ClientVersion = CecClientVersion::VersionPre1_5; - ServerVersion = CecServerVersion::VersionPre1_5; - TvVendor = CecVendorId::Unknown; - - GetSettingsFromROM = false; - UseTVMenuLanguage = CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE == 1; - ActivateSource = CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1; - - WakeDevices = gcnew CecLogicalAddresses(); - if (CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1) - WakeDevices->Set(CecLogicalAddress::Tv); - - PowerOffDevices = gcnew CecLogicalAddresses(); - if (CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1) - PowerOffDevices->Set(CecLogicalAddress::Broadcast); - - PowerOffScreensaver = CEC_DEFAULT_SETTING_POWER_OFF_SCREENSAVER == 1; - PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1; - - SendInactiveSource = CEC_DEFAULT_SETTING_SEND_INACTIVE_SOURCE == 1; - LogicalAddresses = gcnew CecLogicalAddresses(); - FirmwareVersion = 1; - PowerOffDevicesOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_DEVICES_STANDBY == 1; - ShutdownOnStandby = CEC_DEFAULT_SETTING_SHUTDOWN_ON_STANDBY == 1; - DeviceLanguage = ""; - } - - void SetCallbacks(CecCallbackMethods ^callbacks) - { - Callbacks = callbacks; - } - - void Update(const CEC::libcec_configuration &config) - { - DeviceName = gcnew System::String(config.strDeviceName); - - for (unsigned int iPtr = 0; iPtr < 5; iPtr++) - DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr]; - - AutodetectAddress = config.bAutodetectAddress == 1; - PhysicalAddress = config.iPhysicalAddress; - BaseDevice = (CecLogicalAddress)config.baseDevice; - HDMIPort = config.iHDMIPort; - ClientVersion = (CecClientVersion)config.clientVersion; - ServerVersion = (CecServerVersion)config.serverVersion; - TvVendor = (CecVendorId)config.tvVendor; - - // player specific settings - GetSettingsFromROM = config.bGetSettingsFromROM == 1; - UseTVMenuLanguage = config.bUseTVMenuLanguage == 1; - ActivateSource = config.bActivateSource == 1; - - WakeDevices->Clear(); - for (uint8_t iPtr = 0; iPtr <= 16; iPtr++) - if (config.wakeDevices[iPtr]) - WakeDevices->Set((CecLogicalAddress)iPtr); - - PowerOffDevices->Clear(); - for (uint8_t iPtr = 0; iPtr <= 16; iPtr++) - if (config.powerOffDevices[iPtr]) - PowerOffDevices->Set((CecLogicalAddress)iPtr); - - PowerOffScreensaver = config.bPowerOffScreensaver == 1; - PowerOffOnStandby = config.bPowerOffOnStandby == 1; - - if (ServerVersion >= CecServerVersion::Version1_5_1) - SendInactiveSource = config.bSendInactiveSource == 1; - - if (ServerVersion >= CecServerVersion::Version1_5_3) - { - LogicalAddresses->Clear(); - for (uint8_t iPtr = 0; iPtr <= 16; iPtr++) - if (config.logicalAddresses[iPtr]) - LogicalAddresses->Set((CecLogicalAddress)iPtr); - } - - if (ServerVersion >= CecServerVersion::Version1_6_0) - { - FirmwareVersion = config.iFirmwareVersion; - PowerOffDevicesOnStandby = config.bPowerOffDevicesOnStandby == 1; - ShutdownOnStandby = config.bShutdownOnStandby == 1; - } - - if (ServerVersion >= CecServerVersion::Version1_6_2) - DeviceLanguage = gcnew System::String(config.strDeviceLanguage); - - if (ServerVersion >= CecServerVersion::Version1_6_3) - MonitorOnlyClient = config.bMonitorOnly == 1; - } - - property System::String ^ DeviceName; - property CecDeviceTypeList ^ DeviceTypes; - property bool AutodetectAddress; - property uint16_t PhysicalAddress; - property CecLogicalAddress BaseDevice; - property uint8_t HDMIPort; - property CecClientVersion ClientVersion; - property CecServerVersion ServerVersion; - property CecVendorId TvVendor; - - // player specific settings - property bool GetSettingsFromROM; - property bool UseTVMenuLanguage; - property bool ActivateSource; - property CecLogicalAddresses ^WakeDevices; - property CecLogicalAddresses ^PowerOffDevices; - property bool PowerOffScreensaver; - property bool PowerOffOnStandby; - property bool SendInactiveSource; - property CecLogicalAddresses ^LogicalAddresses; - property uint16_t FirmwareVersion; - property bool PowerOffDevicesOnStandby; - property bool ShutdownOnStandby; - property bool MonitorOnlyClient; - property System::String ^ DeviceLanguage; - property CecCallbackMethods ^ Callbacks; - }; - - // the callback methods are called by unmanaged code, so we need some delegates for this - #pragma unmanaged - // unmanaged callback methods - typedef int (__stdcall *LOGCB) (const CEC::cec_log_message &message); - typedef int (__stdcall *KEYCB) (const CEC::cec_keypress &key); - typedef int (__stdcall *COMMANDCB)(const CEC::cec_command &command); - typedef int (__stdcall *CONFIGCB) (const CEC::libcec_configuration &config); - typedef int (__stdcall *ALERTCB) (const CEC::libcec_alert, const CEC::libcec_parameter &data); - typedef int (__stdcall *MENUCB) (const CEC::cec_menu_state newVal); - typedef void (__stdcall *ACTICB) (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated); - - typedef struct - { - LOGCB logCB; - KEYCB keyCB; - COMMANDCB commandCB; - CONFIGCB configCB; - ALERTCB alertCB; - MENUCB menuCB; - ACTICB sourceActivatedCB; - } UnmanagedCecCallbacks; - - static PLATFORM::CMutex g_callbackMutex; - static std::vector g_unmanagedCallbacks; + public enum class CecDeviceType + { + Tv = 0, + RecordingDevice = 1, + Reserved = 2, + Tuner = 3, + PlaybackDevice = 4, + AudioSystem = 5 + }; + + public enum class CecLogLevel + { + None = 0, + Error = 1, + Warning = 2, + Notice = 4, + Traffic = 8, + Debug = 16, + All = 31 + }; + + public enum class CecLogicalAddress + { + Unknown = -1, //not a valid logical address + Tv = 0, + RecordingDevice1 = 1, + RecordingDevice2 = 2, + Tuner1 = 3, + PlaybackDevice1 = 4, + AudioSystem = 5, + Tuner2 = 6, + Tuner3 = 7, + PlaybackDevice2 = 8, + RecordingDevice3 = 9, + Tuner4 = 10, + PlaybackDevice3 = 11, + Reserved1 = 12, + Reserved2 = 13, + FreeUse = 14, + Unregistered = 15, + Broadcast = 15 + }; + + public enum class CecAlert + { + ServiceDevice = 1 + }; + + public enum class CecParameterType + { + ParameterTypeString = 1 + }; + + public ref class CecParameter + { + public: + CecParameter(CecParameterType type, System::String ^ strData) + { + Type = type; + Data = strData; + } + + property CecParameterType Type; + property System::String ^ Data; + }; + + public enum class CecPowerStatus + { + On = 0x00, + Standby = 0x01, + InTransitionStandbyToOn = 0x02, + InTransitionOnToStandby = 0x03, + Unknown = 0x99 + }; + + public enum class CecVersion + { + Unknown = 0x00, + V1_2 = 0x01, + V1_2A = 0x02, + V1_3 = 0x03, + V1_3A = 0x04, + V1_4 = 0x05 + }; + + public enum class CecDisplayControl + { + DisplayForDefaultTime = 0x00, + DisplayUntilCleared = 0x40, + ClearPreviousMessage = 0x80, + ReservedForFutureUse = 0xC0 + }; + + public enum class CecMenuState + { + Activated = 0, + Deactivated = 1 + }; + + public enum class CecDeckControlMode + { + SkipForwardWind = 1, + SkipReverseRewind = 2, + Stop = 3, + Eject = 4 + }; + + public enum class CecDeckInfo + { + Play = 0x11, + Record = 0x12, + Reverse = 0x13, + Still = 0x14, + Slow = 0x15, + SlowReverse = 0x16, + FastForward = 0x17, + FastReverse = 0x18, + NoMedia = 0x19, + Stop = 0x1A, + SkipForwardWind = 0x1B, + SkipReverseRewind = 0x1C, + IndexSearchForward = 0x1D, + IndexSearchReverse = 0x1E, + OtherStatus = 0x1F + }; + + public enum class CecUserControlCode + { + Select = 0x00, + Up = 0x01, + Down = 0x02, + Left = 0x03, + Right = 0x04, + RightUp = 0x05, + RightDown = 0x06, + LeftUp = 0x07, + LeftDown = 0x08, + RootMenu = 0x09, + SetupMenu = 0x0A, + ContentsMenu = 0x0B, + FavoriteMenu = 0x0C, + Exit = 0x0D, + Number0 = 0x20, + Number1 = 0x21, + Number2 = 0x22, + Number3 = 0x23, + Number4 = 0x24, + Number5 = 0x25, + Number6 = 0x26, + Number7 = 0x27, + Number8 = 0x28, + Number9 = 0x29, + Dot = 0x2A, + Enter = 0x2B, + Clear = 0x2C, + NextFavorite = 0x2F, + ChannelUp = 0x30, + ChannelDown = 0x31, + PreviousChannel = 0x32, + SoundSelect = 0x33, + InputSelect = 0x34, + DisplayInformation = 0x35, + Help = 0x36, + PageUp = 0x37, + PageDown = 0x38, + Power = 0x40, + VolumeUp = 0x41, + VolumeDown = 0x42, + Mute = 0x43, + Play = 0x44, + Stop = 0x45, + Pause = 0x46, + Record = 0x47, + Rewind = 0x48, + FastForward = 0x49, + Eject = 0x4A, + Forward = 0x4B, + Backward = 0x4C, + StopRecord = 0x4D, + PauseRecord = 0x4E, + Angle = 0x50, + SubPicture = 0x51, + VideoOnDemand = 0x52, + ElectronicProgramGuide = 0x53, + TimerProgramming = 0x54, + InitialConfiguration = 0x55, + PlayFunction = 0x60, + PausePlayFunction = 0x61, + RecordFunction = 0x62, + PauseRecordFunction = 0x63, + StopFunction = 0x64, + MuteFunction = 0x65, + RestoreVolumeFunction = 0x66, + TuneFunction = 0x67, + SelectMediaFunction = 0x68, + SelectAVInputFunction = 0x69, + SelectAudioInputFunction = 0x6A, + PowerToggleFunction = 0x6B, + PowerOffFunction = 0x6C, + PowerOnFunction = 0x6D, + F1Blue = 0x71, + F2Red = 0X72, + F3Green = 0x73, + F4Yellow = 0x74, + F5 = 0x75, + Data = 0x76, + Max = 0x76, + SamsungReturn = 0x91, + Unknown + }; + + public enum class CecVendorId + { + Samsung = 0x0000F0, + LG = 0x00E091, + Panasonic = 0x008045, + Pioneer = 0x00E036, + Onkyo = 0x0009B0, + Yamaha = 0x00A0DE, + Philips = 0x00903E, + Sony = 0x080046, + Toshiba = 0x000039, + Akai = 0x0020C7, + Benq = 0x8065E9, + Daewoo = 0x009053, + Grundig = 0x00D0D5, + Medion = 0x000CB8, + Sharp = 0x08001F, + Vizio = 0x6B746D, + Unknown = 0 + }; + + public enum class CecAudioStatus + { + MuteStatusMask = 0x80, + VolumeStatusMask = 0x7F, + VolumeMin = 0x00, + VolumeMax = 0x64, + VolumeStatusUnknown = 0x7F + }; + + public enum class CecOpcode + { + ActiveSource = 0x82, + ImageViewOn = 0x04, + TextViewOn = 0x0D, + InactiveSource = 0x9D, + RequestActiveSource = 0x85, + RoutingChange = 0x80, + RoutingInformation = 0x81, + SetStreamPath = 0x86, + Standby = 0x36, + RecordOff = 0x0B, + RecordOn = 0x09, + RecordStatus = 0x0A, + RecordTvScreen = 0x0F, + ClearAnalogueTimer = 0x33, + ClearDigitalTimer = 0x99, + ClearExternalTimer = 0xA1, + SetAnalogueTimer = 0x34, + SetDigitalTimer = 0x97, + SetExternalTimer = 0xA2, + SetTimerProgramTitle = 0x67, + TimerClearedStatus = 0x43, + TimerStatus = 0x35, + CecVersion = 0x9E, + GetCecVersion = 0x9F, + GivePhysicalAddress = 0x83, + GetMenuLanguage = 0x91, + ReportPhysicalAddress = 0x84, + SetMenuLanguage = 0x32, + DeckControl = 0x42, + DeckStatus = 0x1B, + GiveDeckStatus = 0x1A, + Play = 0x41, + GiveTunerDeviceStatus = 0x08, + SelectAnalogueService = 0x92, + SelectDigtalService = 0x93, + TunerDeviceStatus = 0x07, + TunerStepDecrement = 0x06, + TunerStepIncrement = 0x05, + DeviceVendorId = 0x87, + GiveDeviceVendorId = 0x8C, + VendorCommand = 0x89, + VendorCommandWithId = 0xA0, + VendorRemoteButtonDown = 0x8A, + VendorRemoteButtonUp = 0x8B, + SetOsdString = 0x64, + GiveOsdName = 0x46, + SetOsdName = 0x47, + MenuRequest = 0x8D, + MenuStatus = 0x8E, + UserControlPressed = 0x44, + UserControlRelease = 0x45, + GiveDevicePowerStatus = 0x8F, + ReportPowerStatus = 0x90, + FeatureAbort = 0x00, + Abort = 0xFF, + GiveAudioStatus = 0x71, + GiveSystemAudioMode = 0x7D, + ReportAudioStatus = 0x7A, + SetSystemAudioMode = 0x72, + SystemAudioModeRequest = 0x70, + SystemAudioModeStatus = 0x7E, + SetAudioRate = 0x9A, + /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */ + None = 0xFD + }; + + public enum class CecSystemAudioStatus + { + Off = 0, + On = 1 + }; + + public enum class CecClientVersion + { + VersionPre1_5 = 0, + Version1_5_0 = 0x1500, + Version1_5_1 = 0x1501, + Version1_5_2 = 0x1502, + Version1_5_3 = 0x1503, + Version1_6_0 = 0x1600, + Version1_6_1 = 0x1601, + Version1_6_2 = 0x1602, + Version1_6_3 = 0x1603, + Version1_7_0 = 0x1700, + Version1_7_1 = 0x1701, + Version1_7_2 = 0x1702, + Version1_8_0 = 0x1800, + Version1_8_1 = 0x1801, + Version1_8_2 = 0x1802, + Version1_9_0 = 0x1900 + }; + + public enum class CecServerVersion + { + VersionPre1_5 = 0, + Version1_5_0 = 0x1500, + Version1_5_1 = 0x1501, + Version1_5_2 = 0x1502, + Version1_5_3 = 0x1503, + Version1_6_0 = 0x1600, + Version1_6_1 = 0x1601, + Version1_6_2 = 0x1602, + Version1_6_3 = 0x1603, + Version1_7_0 = 0x1700, + Version1_7_1 = 0x1701, + Version1_7_2 = 0x1702, + Version1_8_0 = 0x1800, + Version1_8_1 = 0x1801, + Version1_8_2 = 0x1802, + Version1_9_0 = 0x1900 + }; + + /// + /// Descriptor of a CEC adapter, + /// + public ref class CecAdapter + { + public: + /// + /// Create a new CEC adapter descriptor + /// + /// The path descriptor for this CEC adapter + /// The COM port of this CEC adapter + CecAdapter(System::String ^ path, System::String ^ comPort) + { + Path = path; + ComPort = comPort; + } + + /// + /// The path descriptor for this CEC adapter + /// + property System::String ^ Path; + + /// + /// The COM port of this CEC adapter + /// + property System::String ^ ComPort; + }; + + /// + /// A list of CEC device types + /// + public ref class CecDeviceTypeList + { + public: + /// + /// Create a new empty list of CEC device types + /// + CecDeviceTypeList(void) + { + Types = gcnew array(5); + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + Types[iPtr] = CecDeviceType::Reserved; + } + + /// + /// The array with CecDeviceType instances in this list. + /// + property array ^ Types; + }; + + /// + /// A list of logical addresses + /// + public ref class CecLogicalAddresses + { + public: + /// + /// Create a new empty list of logical addresses + /// + CecLogicalAddresses(void) + { + Addresses = gcnew array(16); + Clear(); + } + + /// + /// Clears this list + /// + void Clear(void) + { + Primary = CecLogicalAddress::Unknown; + for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + Addresses[iPtr] = CecLogicalAddress::Unknown; + } + + /// + /// Checks whether a logical address is set in this list. + /// + /// The address to check. + /// True when set, false otherwise + bool IsSet(CecLogicalAddress address) + { + return Addresses[(unsigned int)address] != CecLogicalAddress::Unknown; + } + + /// + /// Add a logical address to this list (if it's not set already) + /// + /// The address to add. + void Set(CecLogicalAddress address) + { + Addresses[(unsigned int)address] = address; + if (Primary == CecLogicalAddress::Unknown) + Primary = address; + } + + /// + /// The primary (first) address in this list + /// + property CecLogicalAddress Primary; + + /// + /// The list of addresses + /// + property array ^ Addresses; + }; + + + /// + /// Byte array used for CEC command parameters + /// + public ref class CecDatapacket + { + public: + /// + /// Create a new byte array with maximum size 100 + /// + CecDatapacket(void) + { + Data = gcnew array(100); + Size = 0; + } + + /// + /// Adds a byte to this byte array + /// + /// The byte to add. + void PushBack(uint8_t data) + { + if (Size < 100) + { + Data[Size] = data; + Size++; + } + } + + /// + /// Array data + /// + property array ^ Data; + + /// + /// Current data size + /// + property uint8_t Size; + }; + + /// + /// A CEC command that is received or transmitted over the CEC bus + /// + public ref class CecCommand + { + public: + /// + /// Create a new CEC command instance + /// + /// The initiator of the command + /// The receiver of the command + /// True when the ack bit is set, false otherwise + /// True when the eom bit is set, false otherwise + /// The CEC opcode of this command + /// The timeout to use when transmitting a command + CecCommand(CecLogicalAddress initiator, CecLogicalAddress destination, bool ack, bool eom, CecOpcode opcode, int32_t transmitTimeout) + { + Initiator = initiator; + Destination = destination; + Ack = ack; + Eom = eom; + Opcode = opcode; + OpcodeSet = true; + TransmitTimeout = transmitTimeout; + Parameters = gcnew CecDatapacket; + Empty = false; + } + + /// + /// Create a new empty CEC command instance + /// + CecCommand(void) + { + Initiator = CecLogicalAddress::Unknown; + Destination = CecLogicalAddress::Unknown; + Ack = false; + Eom = false; + Opcode = CecOpcode::None; + OpcodeSet = false; + TransmitTimeout = 0; + Parameters = gcnew CecDatapacket; + Empty = true; + } + + /// + /// Pushes a byte of data to this CEC command + /// + /// The byte to add + void PushBack(uint8_t data) + { + if (Initiator == CecLogicalAddress::Unknown && Destination == CecLogicalAddress::Unknown) + { + Initiator = (CecLogicalAddress) (data >> 4); + Destination = (CecLogicalAddress) (data & 0xF); + } + else if (!OpcodeSet) + { + OpcodeSet = true; + Opcode = (CecOpcode)data; + } + else + { + Parameters->PushBack(data); + } + } + + /// + /// True when this command is empty, false otherwise. + /// + property bool Empty; + /// + /// The initiator of the command + /// + property CecLogicalAddress Initiator; + /// + /// The destination of the command + /// + property CecLogicalAddress Destination; + /// + /// True when the ack bit is set, false otherwise + /// + property bool Ack; + /// + /// True when the eom bit is set, false otherwise + /// + property bool Eom; + /// + /// The CEC opcode of the command + /// + property CecOpcode Opcode; + /// + /// The parameters of this command + /// + property CecDatapacket ^ Parameters; + /// + /// True when an opcode is set, false otherwise (poll message) + /// + property bool OpcodeSet; + /// + /// The timeout to use when transmitting a command + /// + property int32_t TransmitTimeout; + }; + + /// + /// A key press that was received + /// + public ref class CecKeypress + { + public: + /// + /// Create a new key press instance + /// + /// The key code of this key press + /// The duration of this key press in milliseconds + CecKeypress(CecUserControlCode keycode, unsigned int duration) + { + Keycode = keycode; + Duration = duration; + Empty = false; + } + + /// + /// Create a new empty key press instance + /// + CecKeypress(void) + { + Keycode = CecUserControlCode::Unknown; + Duration = 0; + Empty = true; + } + + /// + /// True when empty, false otherwise + /// + property bool Empty; + /// + /// The key code of this key press + /// + property CecUserControlCode Keycode; + /// + /// The duration of this key press in milliseconds + /// + property unsigned int Duration; + }; + + /// + /// A log message that libCEC generated + /// + public ref class CecLogMessage + { + public: + /// + /// Create a new log message + /// + /// The actual message + /// The log level, so the application can choose what type information to display + /// The timestamp of this message, in milliseconds after connecting + CecLogMessage(System::String ^ message, CecLogLevel level, int64_t time) + { + Message = message; + Level = level; + Time = time; + Empty = false; + } + + /// + /// Create a new empty log message + /// + CecLogMessage(void) + { + Message = ""; + Level = CecLogLevel::None; + Time = 0; + Empty = true; + } + + /// + /// True when empty, false otherwise. + /// + property bool Empty; + /// + /// The actual message + /// + property System::String ^Message; + /// + /// The log level, so the application can choose what type information to display + /// + property CecLogLevel Level; + /// + /// The timestamp of this message, in milliseconds after connecting + /// + property int64_t Time; + }; + + ref class CecCallbackMethods; //forward declaration + + /// + /// The configuration that libCEC uses. + /// + public ref class LibCECConfiguration + { + public: + /// + /// Create a new configuration instance with default settings. + /// + LibCECConfiguration(void) + { + DeviceName = ""; + DeviceTypes = gcnew CecDeviceTypeList(); + AutodetectAddress = true; + PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS; + BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE; + HDMIPort = CEC_DEFAULT_HDMI_PORT; + ClientVersion = CecClientVersion::VersionPre1_5; + ServerVersion = CecServerVersion::VersionPre1_5; + TvVendor = CecVendorId::Unknown; + + GetSettingsFromROM = false; + UseTVMenuLanguage = CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE == 1; + ActivateSource = CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1; + + WakeDevices = gcnew CecLogicalAddresses(); + if (CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1) + WakeDevices->Set(CecLogicalAddress::Tv); + + PowerOffDevices = gcnew CecLogicalAddresses(); + if (CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1) + PowerOffDevices->Set(CecLogicalAddress::Broadcast); + + PowerOffScreensaver = CEC_DEFAULT_SETTING_POWER_OFF_SCREENSAVER == 1; + PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1; + + SendInactiveSource = CEC_DEFAULT_SETTING_SEND_INACTIVE_SOURCE == 1; + LogicalAddresses = gcnew CecLogicalAddresses(); + FirmwareVersion = 1; + PowerOffDevicesOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_DEVICES_STANDBY == 1; + ShutdownOnStandby = CEC_DEFAULT_SETTING_SHUTDOWN_ON_STANDBY == 1; + DeviceLanguage = ""; + } + + /// + /// Change the callback method pointers in this configuration instance. + /// + /// The new callbacks + void SetCallbacks(CecCallbackMethods ^callbacks) + { + Callbacks = callbacks; + } + + /// + /// Update this configuration with data received from libCEC + /// + /// The configuration that was received from libCEC + void Update(const CEC::libcec_configuration &config) + { + DeviceName = gcnew System::String(config.strDeviceName); + + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr]; + + AutodetectAddress = config.bAutodetectAddress == 1; + PhysicalAddress = config.iPhysicalAddress; + BaseDevice = (CecLogicalAddress)config.baseDevice; + HDMIPort = config.iHDMIPort; + ClientVersion = (CecClientVersion)config.clientVersion; + ServerVersion = (CecServerVersion)config.serverVersion; + TvVendor = (CecVendorId)config.tvVendor; + + // player specific settings + GetSettingsFromROM = config.bGetSettingsFromROM == 1; + UseTVMenuLanguage = config.bUseTVMenuLanguage == 1; + ActivateSource = config.bActivateSource == 1; + + WakeDevices->Clear(); + for (uint8_t iPtr = 0; iPtr <= 16; iPtr++) + if (config.wakeDevices[iPtr]) + WakeDevices->Set((CecLogicalAddress)iPtr); + + PowerOffDevices->Clear(); + for (uint8_t iPtr = 0; iPtr <= 16; iPtr++) + if (config.powerOffDevices[iPtr]) + PowerOffDevices->Set((CecLogicalAddress)iPtr); + + PowerOffScreensaver = config.bPowerOffScreensaver == 1; + PowerOffOnStandby = config.bPowerOffOnStandby == 1; + + if (ServerVersion >= CecServerVersion::Version1_5_1) + SendInactiveSource = config.bSendInactiveSource == 1; + + if (ServerVersion >= CecServerVersion::Version1_5_3) + { + LogicalAddresses->Clear(); + for (uint8_t iPtr = 0; iPtr <= 16; iPtr++) + if (config.logicalAddresses[iPtr]) + LogicalAddresses->Set((CecLogicalAddress)iPtr); + } + + if (ServerVersion >= CecServerVersion::Version1_6_0) + { + FirmwareVersion = config.iFirmwareVersion; + PowerOffDevicesOnStandby = config.bPowerOffDevicesOnStandby == 1; + ShutdownOnStandby = config.bShutdownOnStandby == 1; + } + + if (ServerVersion >= CecServerVersion::Version1_6_2) + DeviceLanguage = gcnew System::String(config.strDeviceLanguage); + + if (ServerVersion >= CecServerVersion::Version1_6_3) + MonitorOnlyClient = config.bMonitorOnly == 1; + } + + /// + /// The device name to use on the CEC bus + /// + property System::String ^ DeviceName; + + /// + /// The device type(s) to use on the CEC bus for libCEC + /// + property CecDeviceTypeList ^ DeviceTypes; + + /// + /// True to try to autodetect the physical address, false otherwise + /// + property bool AutodetectAddress; + + /// + /// The physical address that libCEC uses on the CEC bus + /// + property uint16_t PhysicalAddress; + + /// + /// The logical address of the device to which the CEC adapter is connected, only used when PhysicalAddress isn't set + /// + property CecLogicalAddress BaseDevice; + + /// + /// The hdmi port number on the device to which the CEC adapter is connected, only used when PhysicalAddress isn't set + /// + property uint8_t HDMIPort; + + /// + /// The client API version to use + /// + property CecClientVersion ClientVersion; + + /// + /// The version of libCEC + /// + property CecServerVersion ServerVersion; + + /// + /// Override the vendor ID of the TV when set (for quirks mode) + /// + property CecVendorId TvVendor; + + /// + /// True to read the settings from the EEPROM, which possibly override the settings passed here + /// + property bool GetSettingsFromROM; + + /// + /// Use the language setting of the TV in the client application. Must be implemented by the client application. + /// + property bool UseTVMenuLanguage; + + /// + /// Make libCEC the active source when starting the client application + /// + property bool ActivateSource; + + /// + /// List of devices to send a power on command to when starting the client application + /// + property CecLogicalAddresses ^WakeDevices; + + /// + /// List of devices to send a standby command to when exiting the client application + /// + property CecLogicalAddresses ^PowerOffDevices; + + /// + /// Send standby commands when the client application activates the screensaver. Must be implemented by the client application. + /// + property bool PowerOffScreensaver; + + /// + /// Power off the PC when the TV powers off. Must be implemented by the client application. + /// + property bool PowerOffOnStandby; + + /// + /// Send an inactive source message when exiting the client application. + /// + property bool SendInactiveSource; + + /// + /// The list of logical addresses that libCEC is using + /// + property CecLogicalAddresses ^LogicalAddresses; + + /// + /// The firmware version of the adapter to which libCEC is connected + /// + property uint16_t FirmwareVersion; + + /// + /// Send standby commands when the client application activates standby mode (S3). Must be implemented by the client application. + /// + property bool PowerOffDevicesOnStandby; + property bool ShutdownOnStandby; + + /// + /// True to start a monitor-only client, false to start a standard client. + /// + property bool MonitorOnlyClient; + + /// + /// The language code of the menu language that libCEC reports to other devices. + /// + property System::String ^ DeviceLanguage; + + /// + /// The callback methods to use. + /// + property CecCallbackMethods ^ Callbacks; + }; + + // the callback methods are called by unmanaged code, so we need some delegates for this +#pragma unmanaged + // unmanaged callback methods + typedef int (__stdcall *LOGCB) (const CEC::cec_log_message &message); + typedef int (__stdcall *KEYCB) (const CEC::cec_keypress &key); + typedef int (__stdcall *COMMANDCB)(const CEC::cec_command &command); + typedef int (__stdcall *CONFIGCB) (const CEC::libcec_configuration &config); + typedef int (__stdcall *ALERTCB) (const CEC::libcec_alert, const CEC::libcec_parameter &data); + typedef int (__stdcall *MENUCB) (const CEC::cec_menu_state newVal); + typedef void (__stdcall *ACTICB) (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated); + + typedef struct + { + LOGCB logCB; + KEYCB keyCB; + COMMANDCB commandCB; + CONFIGCB configCB; + ALERTCB alertCB; + MENUCB menuCB; + ACTICB sourceActivatedCB; + } UnmanagedCecCallbacks; + + static PLATFORM::CMutex g_callbackMutex; + static std::vector g_unmanagedCallbacks; static CEC::ICECCallbacks g_cecCallbacks; - int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - return g_unmanagedCallbacks[iPtr].logCB(message); - } - return 0; - } - - int CecKeyPressCB(void *cbParam, const CEC::cec_keypress &key) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - return g_unmanagedCallbacks[iPtr].keyCB(key); - } - return 0; - } - - int CecCommandCB(void *cbParam, const CEC::cec_command &command) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - return g_unmanagedCallbacks[iPtr].commandCB(command); - } - return 0; - } + int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message) + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + return g_unmanagedCallbacks[iPtr].logCB(message); + } + return 0; + } + + int CecKeyPressCB(void *cbParam, const CEC::cec_keypress &key) + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + return g_unmanagedCallbacks[iPtr].keyCB(key); + } + return 0; + } + + int CecCommandCB(void *cbParam, const CEC::cec_command &command) + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + return g_unmanagedCallbacks[iPtr].commandCB(command); + } + return 0; + } int CecConfigCB(void *cbParam, const CEC::libcec_configuration &config) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - return g_unmanagedCallbacks[iPtr].configCB(config); - } - return 0; - } - - int CecAlertCB(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter &data) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - return g_unmanagedCallbacks[iPtr].alertCB(alert, data); - } - return 0; - } - - int CecMenuCB(void *cbParam, const CEC::cec_menu_state newVal) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - return g_unmanagedCallbacks[iPtr].menuCB(newVal); - } - return 0; - } - - void CecSourceActivatedCB(void *cbParam, const CEC::cec_logical_address logicalAddress, const uint8_t bActivated) - { - if (cbParam) - { - size_t iPtr = (size_t)cbParam; - PLATFORM::CLockObject lock(g_callbackMutex); - if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) - g_unmanagedCallbacks[iPtr].sourceActivatedCB(logicalAddress, bActivated); - } - } - - #pragma managed - // delegates for the unmanaged callback methods - public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &); - public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &); - public delegate int CecCommandManagedDelegate(const CEC::cec_command &); - public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &); - public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &); - public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state newVal); - public delegate void CecSourceActivatedManagedDelegate(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated); - - void AssignCallbacks() - { - g_cecCallbacks.CBCecLogMessage = CecLogMessageCB; - g_cecCallbacks.CBCecKeyPress = CecKeyPressCB; - g_cecCallbacks.CBCecCommand = CecCommandCB; - g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB; - g_cecCallbacks.CBCecAlert = CecAlertCB; - g_cecCallbacks.CBCecMenuStateChanged = CecMenuCB; - g_cecCallbacks.CBCecSourceActivated = CecSourceActivatedCB; - } + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + return g_unmanagedCallbacks[iPtr].configCB(config); + } + return 0; + } + + int CecAlertCB(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter &data) + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + return g_unmanagedCallbacks[iPtr].alertCB(alert, data); + } + return 0; + } + + int CecMenuCB(void *cbParam, const CEC::cec_menu_state newVal) + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + return g_unmanagedCallbacks[iPtr].menuCB(newVal); + } + return 0; + } - // callback method interface - public ref class CecCallbackMethods - { - public: + void CecSourceActivatedCB(void *cbParam, const CEC::cec_logical_address logicalAddress, const uint8_t bActivated) + { + if (cbParam) + { + size_t iPtr = (size_t)cbParam; + PLATFORM::CLockObject lock(g_callbackMutex); + if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size()) + g_unmanagedCallbacks[iPtr].sourceActivatedCB(logicalAddress, bActivated); + } + } + +#pragma managed + // delegates for the unmanaged callback methods + public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &); + public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &); + public delegate int CecCommandManagedDelegate(const CEC::cec_command &); + public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &); + public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &); + public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state newVal); + public delegate void CecSourceActivatedManagedDelegate(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated); + + void AssignCallbacks() + { + g_cecCallbacks.CBCecLogMessage = CecLogMessageCB; + g_cecCallbacks.CBCecKeyPress = CecKeyPressCB; + g_cecCallbacks.CBCecCommand = CecCommandCB; + g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB; + g_cecCallbacks.CBCecAlert = CecAlertCB; + g_cecCallbacks.CBCecMenuStateChanged = CecMenuCB; + g_cecCallbacks.CBCecSourceActivated = CecSourceActivatedCB; + } + + /// + /// The callback methods that libCEC uses + /// + public ref class CecCallbackMethods + { + public: CecCallbackMethods(void) { - m_iCallbackPtr = -1; - AssignCallbacks(); + m_iCallbackPtr = -1; + AssignCallbacks(); m_bHasCallbacks = false; m_bDelegatesCreated = false; } - ~CecCallbackMethods(void) + ~CecCallbackMethods(void) { DestroyDelegates(); } - size_t GetCallbackPtr(void) - { - PLATFORM::CLockObject lock(g_callbackMutex); - return m_iCallbackPtr; - } - - protected: - !CecCallbackMethods(void) - { - DestroyDelegates(); - } - - public: - virtual void DisableCallbacks(void) - { - DestroyDelegates(); - } - - virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) - { + size_t GetCallbackPtr(void) + { + PLATFORM::CLockObject lock(g_callbackMutex); + return m_iCallbackPtr; + } + + protected: + !CecCallbackMethods(void) + { + DestroyDelegates(); + } + + public: + virtual void DisableCallbacks(void) + { + DestroyDelegates(); + } + + virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) + { CreateDelegates(); - if (!m_bHasCallbacks) - { - m_bHasCallbacks = true; - m_callbacks = callbacks; - return true; - } - - return false; - } - - virtual int ReceiveLogMessage(CecLogMessage ^ message) - { - return 0; - } - - virtual int ReceiveKeypress(CecKeypress ^ key) - { - return 0; - } - - virtual int ReceiveCommand(CecCommand ^ command) - { - return 0; - } - - virtual int ConfigurationChanged(LibCECConfiguration ^ config) - { - return 0; - } - - virtual int ReceiveAlert(CecAlert alert, CecParameter ^ data) - { - return 0; - } - - virtual int ReceiveMenuStateChange(CecMenuState newVal) - { - return 0; - } - - virtual void SourceActivated(CecLogicalAddress logicalAddress, bool bActivated) - { - } - - protected: - // managed callback methods - int CecLogMessageManaged(const CEC::cec_log_message &message) - { - int iReturn(0); - if (m_bHasCallbacks) - iReturn = m_callbacks->ReceiveLogMessage(gcnew CecLogMessage(gcnew System::String(message.message), (CecLogLevel)message.level, message.time)); - return iReturn; - } - - int CecKeyPressManaged(const CEC::cec_keypress &key) - { - int iReturn(0); - if (m_bHasCallbacks) - iReturn = m_callbacks->ReceiveKeypress(gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration)); - return iReturn; - } - - int CecCommandManaged(const CEC::cec_command &command) - { - int iReturn(0); - if (m_bHasCallbacks) - { - CecCommand ^ newCommand = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout); - for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) - newCommand->Parameters->PushBack(command.parameters[iPtr]); - iReturn = m_callbacks->ReceiveCommand(newCommand); - } - return iReturn; - } - - int CecConfigManaged(const CEC::libcec_configuration &config) - { - int iReturn(0); - if (m_bHasCallbacks) - { - LibCECConfiguration ^netConfig = gcnew LibCECConfiguration(); - netConfig->Update(config); - iReturn = m_callbacks->ConfigurationChanged(netConfig); - } - return iReturn; - } - - int CecAlertManaged(const CEC::libcec_alert alert, const CEC::libcec_parameter &data) - { - int iReturn(0); - if (m_bHasCallbacks) - { - CecParameterType newType = (CecParameterType)data.paramType; - if (newType == CecParameterType::ParameterTypeString) - { - System::String ^ newData = gcnew System::String((const char *)data.paramData, 0, 128); - CecParameter ^ newParam = gcnew CecParameter(newType, newData); - iReturn = m_callbacks->ReceiveAlert((CecAlert)alert, newParam); - } - } - return iReturn; - } - - int CecMenuManaged(const CEC::cec_menu_state newVal) - { - int iReturn(0); - if (m_bHasCallbacks) - { - iReturn = m_callbacks->ReceiveMenuStateChange((CecMenuState)newVal); - } - return iReturn; - } - - void CecSourceActivatedManaged(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated) - { - if (m_bHasCallbacks) - m_callbacks->SourceActivated((CecLogicalAddress)logicalAddress, bActivated == 1); - } - - void DestroyDelegates() - { + if (!m_bHasCallbacks) + { + m_bHasCallbacks = true; + m_callbacks = callbacks; + return true; + } + + return false; + } + + /// + /// Called by libCEC to send back a log message to the application + /// + /// The log message + virtual int ReceiveLogMessage(CecLogMessage ^ message) + { + return 0; + } + + /// + /// Called by libCEC to send back a key press to the application + /// + /// The key press command that libCEC received + virtual int ReceiveKeypress(CecKeypress ^ key) + { + return 0; + } + + /// + /// Called by libCEC to send back raw CEC data to the application + /// + /// The raw CEC data + virtual int ReceiveCommand(CecCommand ^ command) + { + return 0; + } + + /// + /// Called by libCEC to send back an updated configuration to the application + /// + /// The new configuration + virtual int ConfigurationChanged(LibCECConfiguration ^ config) + { + return 0; + } + + /// + /// Called by libCEC to send back an alert message to the application + /// + /// The alert message + virtual int ReceiveAlert(CecAlert alert, CecParameter ^ data) + { + return 0; + } + + /// + /// Called by libCEC to send back a menu stata change to the application + /// + /// The new menu state + virtual int ReceiveMenuStateChange(CecMenuState newVal) + { + return 0; + } + + /// + /// Called by libCEC to notify the application that the source that is handled by libCEC was (de)activated + /// + /// The logical address that was (de)activated + /// True when activated, false when deactivated + virtual void SourceActivated(CecLogicalAddress logicalAddress, bool activated) + { + } + + protected: + // managed callback methods + int CecLogMessageManaged(const CEC::cec_log_message &message) + { + int iReturn(0); + if (m_bHasCallbacks) + iReturn = m_callbacks->ReceiveLogMessage(gcnew CecLogMessage(gcnew System::String(message.message), (CecLogLevel)message.level, message.time)); + return iReturn; + } + + int CecKeyPressManaged(const CEC::cec_keypress &key) + { + int iReturn(0); + if (m_bHasCallbacks) + iReturn = m_callbacks->ReceiveKeypress(gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration)); + return iReturn; + } + + int CecCommandManaged(const CEC::cec_command &command) + { + int iReturn(0); + if (m_bHasCallbacks) + { + CecCommand ^ newCommand = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout); + for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) + newCommand->Parameters->PushBack(command.parameters[iPtr]); + iReturn = m_callbacks->ReceiveCommand(newCommand); + } + return iReturn; + } + + int CecConfigManaged(const CEC::libcec_configuration &config) + { + int iReturn(0); + if (m_bHasCallbacks) + { + LibCECConfiguration ^netConfig = gcnew LibCECConfiguration(); + netConfig->Update(config); + iReturn = m_callbacks->ConfigurationChanged(netConfig); + } + return iReturn; + } + + int CecAlertManaged(const CEC::libcec_alert alert, const CEC::libcec_parameter &data) + { + int iReturn(0); + if (m_bHasCallbacks) + { + CecParameterType newType = (CecParameterType)data.paramType; + if (newType == CecParameterType::ParameterTypeString) + { + System::String ^ newData = gcnew System::String((const char *)data.paramData, 0, 128); + CecParameter ^ newParam = gcnew CecParameter(newType, newData); + iReturn = m_callbacks->ReceiveAlert((CecAlert)alert, newParam); + } + } + return iReturn; + } + + int CecMenuManaged(const CEC::cec_menu_state newVal) + { + int iReturn(0); + if (m_bHasCallbacks) + { + iReturn = m_callbacks->ReceiveMenuStateChange((CecMenuState)newVal); + } + return iReturn; + } + + void CecSourceActivatedManaged(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated) + { + if (m_bHasCallbacks) + m_callbacks->SourceActivated((CecLogicalAddress)logicalAddress, bActivated == 1); + } + + void DestroyDelegates() + { m_bHasCallbacks = false; - if (m_bDelegatesCreated) - { + if (m_bDelegatesCreated) + { m_bDelegatesCreated = false; - m_logMessageGCHandle.Free(); - m_keypressGCHandle.Free(); - m_commandGCHandle.Free(); - m_alertGCHandle.Free(); - m_menuGCHandle.Free(); - m_sourceActivatedGCHandle.Free(); - } - } + m_logMessageGCHandle.Free(); + m_keypressGCHandle.Free(); + m_commandGCHandle.Free(); + m_alertGCHandle.Free(); + m_menuGCHandle.Free(); + m_sourceActivatedGCHandle.Free(); + } + } void CreateDelegates() { @@ -1024,87 +1316,87 @@ namespace CecSharp // create the delegate method for the log message callback m_logMessageDelegate = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged); m_logMessageGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate); - m_logMessageCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer()); + m_logMessageCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer()); // create the delegate method for the keypress callback m_keypressDelegate = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged); m_keypressGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate); - m_keypressCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer()); + m_keypressCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer()); // create the delegate method for the command callback m_commandDelegate = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged); m_commandGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate); - m_commandCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer()); + m_commandCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer()); // create the delegate method for the configuration change callback m_configDelegate = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged); m_configGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate); - m_configCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer()); + m_configCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer()); // create the delegate method for the alert callback m_alertDelegate = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged); m_alertGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate); - m_alertCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer()); + m_alertCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer()); // create the delegate method for the menu callback m_menuDelegate = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged); m_menuGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate); - m_menuCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer()); + m_menuCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer()); - // create the delegate method for the source activated callback + // create the delegate method for the source activated callback m_sourceActivatedDelegate = gcnew CecSourceActivatedManagedDelegate(this, &CecCallbackMethods::CecSourceActivatedManaged); m_sourceActivatedGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_sourceActivatedDelegate); - m_sourceActivatedCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_sourceActivatedDelegate).ToPointer()); + m_sourceActivatedCallback = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_sourceActivatedDelegate).ToPointer()); delete context; - UnmanagedCecCallbacks unmanagedCallbacks; - unmanagedCallbacks.logCB = m_logMessageCallback; - unmanagedCallbacks.keyCB = m_keypressCallback; - unmanagedCallbacks.commandCB = m_commandCallback; - unmanagedCallbacks.configCB = m_configCallback; - unmanagedCallbacks.alertCB = m_alertCallback; - unmanagedCallbacks.menuCB = m_menuCallback; - unmanagedCallbacks.sourceActivatedCB = m_sourceActivatedCallback; - - PLATFORM::CLockObject lock(g_callbackMutex); - g_unmanagedCallbacks.push_back(unmanagedCallbacks); - m_iCallbackPtr = g_unmanagedCallbacks.size() - 1; - m_bDelegatesCreated = true; + UnmanagedCecCallbacks unmanagedCallbacks; + unmanagedCallbacks.logCB = m_logMessageCallback; + unmanagedCallbacks.keyCB = m_keypressCallback; + unmanagedCallbacks.commandCB = m_commandCallback; + unmanagedCallbacks.configCB = m_configCallback; + unmanagedCallbacks.alertCB = m_alertCallback; + unmanagedCallbacks.menuCB = m_menuCallback; + unmanagedCallbacks.sourceActivatedCB = m_sourceActivatedCallback; + + PLATFORM::CLockObject lock(g_callbackMutex); + g_unmanagedCallbacks.push_back(unmanagedCallbacks); + m_iCallbackPtr = g_unmanagedCallbacks.size() - 1; + m_bDelegatesCreated = true; } } - CecLogMessageManagedDelegate ^ m_logMessageDelegate; - static System::Runtime::InteropServices::GCHandle m_logMessageGCHandle; - LOGCB m_logMessageCallback; + CecLogMessageManagedDelegate ^ m_logMessageDelegate; + static System::Runtime::InteropServices::GCHandle m_logMessageGCHandle; + LOGCB m_logMessageCallback; - CecKeyPressManagedDelegate ^ m_keypressDelegate; - static System::Runtime::InteropServices::GCHandle m_keypressGCHandle; - KEYCB m_keypressCallback; + CecKeyPressManagedDelegate ^ m_keypressDelegate; + static System::Runtime::InteropServices::GCHandle m_keypressGCHandle; + KEYCB m_keypressCallback; - CecCommandManagedDelegate ^ m_commandDelegate; - static System::Runtime::InteropServices::GCHandle m_commandGCHandle; - COMMANDCB m_commandCallback; + CecCommandManagedDelegate ^ m_commandDelegate; + static System::Runtime::InteropServices::GCHandle m_commandGCHandle; + COMMANDCB m_commandCallback; - CecConfigManagedDelegate ^ m_configDelegate; - static System::Runtime::InteropServices::GCHandle m_configGCHandle; - CONFIGCB m_configCallback; + CecConfigManagedDelegate ^ m_configDelegate; + static System::Runtime::InteropServices::GCHandle m_configGCHandle; + CONFIGCB m_configCallback; - CecAlertManagedDelegate ^ m_alertDelegate; - static System::Runtime::InteropServices::GCHandle m_alertGCHandle; - ALERTCB m_alertCallback; + CecAlertManagedDelegate ^ m_alertDelegate; + static System::Runtime::InteropServices::GCHandle m_alertGCHandle; + ALERTCB m_alertCallback; - CecMenuManagedDelegate ^ m_menuDelegate; - static System::Runtime::InteropServices::GCHandle m_menuGCHandle; - MENUCB m_menuCallback; + CecMenuManagedDelegate ^ m_menuDelegate; + static System::Runtime::InteropServices::GCHandle m_menuGCHandle; + MENUCB m_menuCallback; - CecSourceActivatedManagedDelegate ^ m_sourceActivatedDelegate; - static System::Runtime::InteropServices::GCHandle m_sourceActivatedGCHandle; - ACTICB m_sourceActivatedCallback; + CecSourceActivatedManagedDelegate ^ m_sourceActivatedDelegate; + static System::Runtime::InteropServices::GCHandle m_sourceActivatedGCHandle; + ACTICB m_sourceActivatedCallback; - CecCallbackMethods ^ m_callbacks; - bool m_bHasCallbacks; + CecCallbackMethods ^ m_callbacks; + bool m_bHasCallbacks; bool m_bDelegatesCreated; - size_t m_iCallbackPtr; - }; + size_t m_iCallbackPtr; + }; } diff --git a/src/LibCecSharp/LibCecSharp.cpp b/src/LibCecSharp/LibCecSharp.cpp index bf33d1f..073ae77 100644 --- a/src/LibCecSharp/LibCecSharp.cpp +++ b/src/LibCecSharp/LibCecSharp.cpp @@ -1,34 +1,34 @@ /* - * This file is part of the libCEC(R) library. - * - * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. - * libCEC(R) is an original work, containing original code. - * - * libCEC(R) is a trademark of Pulse-Eight Limited. - * - * This program is dual-licensed; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * - * Alternatively, you can license this library under a commercial license, - * please contact Pulse-Eight Licensing for more information. - * - * For more information contact: - * Pulse-Eight Licensing - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ +* This file is part of the libCEC(R) library. +* +* libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. +* libCEC(R) is an original work, containing original code. +* +* libCEC(R) is a trademark of Pulse-Eight Limited. +* +* This program is dual-licensed; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* +* Alternatively, you can license this library under a commercial license, +* please contact Pulse-Eight Licensing for more information. +* +* For more information contact: +* Pulse-Eight Licensing +* http://www.pulse-eight.com/ +* http://www.pulse-eight.net/ +*/ #include "CecSharpTypes.h" #using @@ -40,720 +40,568 @@ using namespace msclr::interop; namespace CecSharp { - public ref class LibCecSharp : public CecCallbackMethods - { - public: - LibCecSharp(LibCECConfiguration ^config) - { + /// + /// Create a LibCecSharp instance and pass the configuration as argument. + /// Then call Open() to open a connection to the adapter. Close() closes the + /// connection. + /// + /// libCEC can send commands to other devices on the CEC bus via the methods + /// on this interface, and all commands that libCEC received are sent back + /// to the application via callback methods. The callback methods can be + /// found in CecSharpTypes.h, CecCallbackMethods. + /// + public ref class LibCecSharp : public CecCallbackMethods + { + public: + /// + /// Create a new LibCecSharp instance. + /// + /// The configuration to pass to libCEC. + LibCecSharp(LibCECConfiguration ^config) + { m_callbacks = config->Callbacks; - CecCallbackMethods::EnableCallbacks(m_callbacks); - if (!InitialiseLibCec(config)) - throw gcnew Exception("Could not initialise LibCecSharp"); - } - - LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes) - { - m_callbacks = gcnew CecCallbackMethods(); - LibCECConfiguration ^config = gcnew LibCECConfiguration(); - config->SetCallbacks(this); - config->DeviceName = strDeviceName; - config->DeviceTypes = deviceTypes; - if (!InitialiseLibCec(config)) - throw gcnew Exception("Could not initialise LibCecSharp"); - } - - ~LibCecSharp(void) - { - Close(); - m_libCec = NULL; - } - - private: - !LibCecSharp(void) - { - Close(); - m_libCec = NULL; - } - - bool InitialiseLibCec(LibCECConfiguration ^config) - { - marshal_context ^ context = gcnew marshal_context(); - libcec_configuration libCecConfig; - ConvertConfiguration(context, config, libCecConfig); - - m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig); - config->Update(libCecConfig); - - delete context; - return m_libCec != NULL; - } - - void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config) - { - config.Clear(); - - const char *strDeviceName = context->marshal_as(netConfig->DeviceName); - memcpy_s(config.strDeviceName, 13, strDeviceName, 13); - for (unsigned int iPtr = 0; iPtr < 5; iPtr++) - config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr]; - - config.bAutodetectAddress = netConfig->AutodetectAddress ? 1 : 0; - config.iPhysicalAddress = netConfig->PhysicalAddress; - config.baseDevice = (cec_logical_address)netConfig->BaseDevice; - config.iHDMIPort = netConfig->HDMIPort; - config.clientVersion = (cec_client_version)netConfig->ClientVersion; - config.bGetSettingsFromROM = netConfig->GetSettingsFromROM ? 1 : 0; - config.bActivateSource = netConfig->ActivateSource ? 1 : 0; - config.tvVendor = (cec_vendor_id)netConfig->TvVendor; - config.wakeDevices.Clear(); - for (int iPtr = 0; iPtr < 16; iPtr++) - { - if (netConfig->WakeDevices->IsSet((CecLogicalAddress)iPtr)) - config.wakeDevices.Set((cec_logical_address)iPtr); - } - config.powerOffDevices.Clear(); - for (int iPtr = 0; iPtr < 16; iPtr++) - { - if (netConfig->PowerOffDevices->IsSet((CecLogicalAddress)iPtr)) - config.powerOffDevices.Set((cec_logical_address)iPtr); - } - config.bPowerOffScreensaver = netConfig->PowerOffScreensaver ? 1 : 0; - config.bPowerOffOnStandby = netConfig->PowerOffOnStandby ? 1 : 0; - - if (netConfig->ServerVersion >= CecServerVersion::Version1_5_1) - config.bSendInactiveSource = netConfig->SendInactiveSource ? 1 : 0; - - if (netConfig->ServerVersion >= CecServerVersion::Version1_6_0) - { - config.bPowerOffDevicesOnStandby = netConfig->PowerOffDevicesOnStandby ? 1 : 0; - config.bShutdownOnStandby = netConfig->ShutdownOnStandby ? 1 : 0; - } - - if (netConfig->ServerVersion >= CecServerVersion::Version1_6_2) - { - const char *strDeviceLanguage = context->marshal_as(netConfig->DeviceLanguage); - memcpy_s(config.strDeviceLanguage, 3, strDeviceLanguage, 3); - } - - if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3) - config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0; - - config.callbacks = &g_cecCallbacks; - } - - public: - /// + CecCallbackMethods::EnableCallbacks(m_callbacks); + if (!InitialiseLibCec(config)) + throw gcnew Exception("Could not initialise LibCecSharp"); + } + + ~LibCecSharp(void) + { + Close(); + m_libCec = NULL; + } + + /// /// Try to find all connected CEC adapters. /// /// The path filter for adapters. Leave empty to return all adapters. /// The adapters that were found. - array ^ FindAdapters(String ^ path) - { - cec_adapter *devices = new cec_adapter[10]; + array ^ FindAdapters(String ^ path) + { + cec_adapter *devices = new cec_adapter[10]; - marshal_context ^ context = gcnew marshal_context(); - const char* strPathC = path->Length > 0 ? context->marshal_as(path) : NULL; + marshal_context ^ context = gcnew marshal_context(); + const char* strPathC = path->Length > 0 ? context->marshal_as(path) : NULL; - uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL); + uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL); - array ^ adapters = gcnew array(iDevicesFound); - for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++) - adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm)); + array ^ adapters = gcnew array(iDevicesFound); + for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++) + adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm)); - delete devices; - delete context; - return adapters; - } + delete devices; + delete context; + return adapters; + } /// /// Open a connection to the CEC adapter. /// - /// The COM port of the adapter - /// Connection timeout in milliseconds + /// The COM port of the adapter + /// Connection timeout in milliseconds /// True when a connection was opened, false otherwise. - bool Open(String ^ strPort, int iTimeoutMs) - { + bool Open(String ^ strPort, int iTimeoutMs) + { CecCallbackMethods::EnableCallbacks(m_callbacks); EnableCallbacks(m_callbacks); - marshal_context ^ context = gcnew marshal_context(); - const char* strPortC = context->marshal_as(strPort); - bool bReturn = m_libCec->Open(strPortC, iTimeoutMs); - delete context; - return bReturn; - } - - /// + marshal_context ^ context = gcnew marshal_context(); + const char* strPortC = context->marshal_as(strPort); + bool bReturn = m_libCec->Open(strPortC, iTimeoutMs); + delete context; + return bReturn; + } + + /// /// Close the connection to the CEC adapter /// - void Close(void) - { - DisableCallbacks(); - m_libCec->Close(); - } + void Close(void) + { + DisableCallbacks(); + m_libCec->Close(); + } - /// + /// /// Disable all calls to callback methods. /// - virtual void DisableCallbacks(void) override - { - // delete the callbacks, since these might already have been destroyed in .NET - CecCallbackMethods::DisableCallbacks(); - if (m_libCec) - m_libCec->EnableCallbacks(NULL, NULL); - } + virtual void DisableCallbacks(void) override + { + // delete the callbacks, since these might already have been destroyed in .NET + CecCallbackMethods::DisableCallbacks(); + if (m_libCec) + m_libCec->EnableCallbacks(NULL, NULL); + } - /// + /// /// Enable or change the callback methods that libCEC uses to send changes to the client application. /// /// The new callback methods to use. /// True when the callbacks were changed, false otherwise - virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override - { - if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks)) - return m_libCec->EnableCallbacks((void*)GetCallbackPtr(), &g_cecCallbacks); + virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override + { + if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks)) + return m_libCec->EnableCallbacks((void*)GetCallbackPtr(), &g_cecCallbacks); - return false; - } + return false; + } - /// + /// /// Sends a ping command to the adapter, to check if it's responding. /// /// True when the ping was succesful, false otherwise - bool PingAdapter(void) - { - return m_libCec->PingAdapter(); - } + bool PingAdapter(void) + { + return m_libCec->PingAdapter(); + } - /// + /// /// Start the bootloader of the CEC adapter. Closes the connection when successful. /// /// True when the command was sent successfully, false otherwise. - bool StartBootloader(void) - { - return m_libCec->StartBootloader(); - } - - /// - /// Get the minimal version of libCEC that this version of libCEC can interface with. - /// - /// Deprecated: use LibCECConfiguration instead - /// The minimal version - int GetMinLibVersion(void) - { - return m_libCec->GetMinLibVersion(); - } - - /// - /// Get the major version of libCEC. - /// - /// Deprecated: use LibCECConfiguration instead - /// The major version - int GetLibVersionMajor(void) - { - return m_libCec->GetLibVersionMajor(); - } - - /// - /// Get the minor version of libCEC. - /// - /// Deprecated: use LibCECConfiguration instead - /// The minor version - int GetLibVersionMinor(void) - { - return m_libCec->GetLibVersionMinor(); - } - - /// - /// Get the next log message from the buffer, if there is one. - /// - /// Deprecated: use callback methods instead - /// The next log message in the buffer, or an empty message if there is none - CecLogMessage ^ GetNextLogMessage(void) - { - cec_log_message msg; - if (m_libCec->GetNextLogMessage(&msg)) - { - return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time); - } - - return gcnew CecLogMessage(); - } - - /// - /// Get the next keypress from the buffer, if there is one. - /// - /// Deprecated: use callback methods instead - /// The next keypress in the buffer, or an empty keypress if there is none - CecKeypress ^ GetNextKeypress(void) - { - cec_keypress key; - if (m_libCec->GetNextKeypress(&key)) - { - return gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration); - } - - return gcnew CecKeypress(); - } - - /// - /// Get the next CEC command that was received from the buffer, if there is one. - /// - /// Deprecated: use callback methods instead - /// The next CEC command in the buffer, or an empty CEC command if there is none - CecCommand ^ GetNextCommand(void) - { - cec_command command; - if (m_libCec->GetNextCommand(&command)) - { - CecCommand ^ retVal = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout); - for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) - retVal->Parameters->PushBack(command.parameters[iPtr]); - return retVal; - } - - return gcnew CecCommand(); - } - - /// + bool StartBootloader(void) + { + return m_libCec->StartBootloader(); + } + + /// /// Transmit a raw CEC command over the CEC line. /// /// The command to transmit /// True when the data was sent and acked, false otherwise. - bool Transmit(CecCommand ^ command) - { - cec_command ccommand; - cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode); - ccommand.transmit_timeout = command->TransmitTimeout; - ccommand.eom = command->Eom; - ccommand.ack = command->Ack; - for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++) - ccommand.parameters.PushBack(command->Parameters->Data[iPtr]); - - return m_libCec->Transmit(ccommand); - } - - /// + bool Transmit(CecCommand ^ command) + { + cec_command ccommand; + cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode); + ccommand.transmit_timeout = command->TransmitTimeout; + ccommand.eom = command->Eom; + ccommand.ack = command->Ack; + for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++) + ccommand.parameters.PushBack(command->Parameters->Data[iPtr]); + + return m_libCec->Transmit(ccommand); + } + + /// /// Change the logical address on the CEC bus of the CEC adapter. libCEC automatically assigns a logical address, and this method is only available for debugging purposes. /// /// The CEC adapter's new logical address. /// True when the logical address was set successfully, false otherwise. - bool SetLogicalAddress(CecLogicalAddress logicalAddress) - { - return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress); - } + bool SetLogicalAddress(CecLogicalAddress logicalAddress) + { + return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress); + } - /// + /// /// Change the physical address (HDMI port) of the CEC adapter. libCEC will try to autodetect the physical address when connecting. If it did, it's set in libcec_configuration. /// /// The CEC adapter's new physical address. /// True when the physical address was set successfully, false otherwise. - bool SetPhysicalAddress(uint16_t physicalAddress) - { - return m_libCec->SetPhysicalAddress(physicalAddress); - } + bool SetPhysicalAddress(uint16_t physicalAddress) + { + return m_libCec->SetPhysicalAddress(physicalAddress); + } - /// + /// /// Power on the given CEC capable devices. If CECDEVICE_BROADCAST is used, then wakeDevice in libcec_configuration will be used. /// /// The logical address to power on. /// True when the command was sent succesfully, false otherwise. - bool PowerOnDevices(CecLogicalAddress logicalAddress) - { - return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress); - } + bool PowerOnDevices(CecLogicalAddress logicalAddress) + { + return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress); + } - /// + /// /// Put the given CEC capable devices in standby mode. If CECDEVICE_BROADCAST is used, then standbyDevices in libcec_configuration will be used. /// /// The logical address of the device to put in standby. /// True when the command was sent succesfully, false otherwise. - bool StandbyDevices(CecLogicalAddress logicalAddress) - { - return m_libCec->StandbyDevices((cec_logical_address) logicalAddress); - } + bool StandbyDevices(CecLogicalAddress logicalAddress) + { + return m_libCec->StandbyDevices((cec_logical_address) logicalAddress); + } - /// + /// /// Sends a POLL message to a device, to check if it's present and responding. /// /// The device to send the message to. /// True if the POLL was acked, false otherwise. - bool PollDevice(CecLogicalAddress logicalAddress) - { - return m_libCec->PollDevice((cec_logical_address) logicalAddress); - } + bool PollDevice(CecLogicalAddress logicalAddress) + { + return m_libCec->PollDevice((cec_logical_address) logicalAddress); + } - /// + /// /// Change the active source to a device type handled by libCEC. Use CEC_DEVICE_TYPE_RESERVED to make the default type used by libCEC active. /// /// The new active source. Use CEC_DEVICE_TYPE_RESERVED to use the primary type /// True when the command was sent succesfully, false otherwise. - bool SetActiveSource(CecDeviceType type) - { - return m_libCec->SetActiveSource((cec_device_type) type); - } + bool SetActiveSource(CecDeviceType type) + { + return m_libCec->SetActiveSource((cec_device_type) type); + } - /// + /// /// Change the deck control mode, if this adapter is registered as playback or recording device. /// /// The new control mode. - /// True to send the new status over the CEC line. + /// True to send the new status over the CEC line. /// True if set, false otherwise. - bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate) - { - return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate); - } + bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate) + { + return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate); + } - /// + /// /// Change the deck info, if this adapter is a playback or recording device. /// /// The new deck info. - /// True to send the new status over the CEC line. + /// True to send the new status over the CEC line. /// True if set, false otherwise. - bool SetDeckInfo(CecDeckInfo info, bool sendUpdate) - { - return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate); - } + bool SetDeckInfo(CecDeckInfo info, bool sendUpdate) + { + return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate); + } - /// + /// /// Broadcast a message that notifies connected CEC capable devices that this device is no longer the active source. /// /// True when the command was sent succesfully, false otherwise. - bool SetInactiveView(void) - { - return m_libCec->SetInactiveView(); - } + bool SetInactiveView(void) + { + return m_libCec->SetInactiveView(); + } - /// + /// /// Change the menu state. This value is already changed by libCEC automatically if a device is (de)activated. /// /// The new state. - /// True to send the new status over the CEC line. + /// True to send the new status over the CEC line. /// True if set, false otherwise. - bool SetMenuState(CecMenuState state, bool sendUpdate) - { - return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate); - } + bool SetMenuState(CecMenuState state, bool sendUpdate) + { + return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate); + } - /// + /// /// Display a message on the device with the given logical address. Not supported by most TVs. /// /// The logical address of the device to display the message on. - /// The duration of the message - /// The message to display. + /// The duration of the message + /// The message to display. /// True when the command was sent, false otherwise. - bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message) - { - marshal_context ^ context = gcnew marshal_context(); - const char* strMessageC = context->marshal_as(message); + bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message) + { + marshal_context ^ context = gcnew marshal_context(); + const char* strMessageC = context->marshal_as(message); - bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC); + bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC); - delete context; - return bReturn; - } + delete context; + return bReturn; + } - /// + /// /// Enable or disable monitoring mode, for debugging purposes. If monitoring mode is enabled, libCEC won't respond to any command, but only log incoming data. /// /// True to enable, false to disable. /// True when switched successfully, false otherwise. - bool SwitchMonitoring(bool enable) - { - return m_libCec->SwitchMonitoring(enable); - } + bool SwitchMonitoring(bool enable) + { + return m_libCec->SwitchMonitoring(enable); + } - /// + /// /// Get the CEC version of the device with the given logical address /// /// The logical address of the device to get the CEC version for. /// The version or CEC_VERSION_UNKNOWN when the version couldn't be fetched. - CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress) - { - return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress); - } + CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress) + { + return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress); + } - /// + /// /// Get the menu language of the device with the given logical address /// /// The logical address of the device to get the menu language for. /// The requested menu language. - String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress) - { - cec_menu_language lang; - if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang)) - { - return gcnew String(lang.language); - } - - return gcnew String(""); - } - - /// + String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress) + { + cec_menu_language lang; + if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang)) + { + return gcnew String(lang.language); + } + + return gcnew String(""); + } + + /// /// Get the vendor ID of the device with the given logical address. /// /// The logical address of the device to get the vendor ID for. /// The vendor ID or 0 if it wasn't found. - CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress) - { - return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress); - } + CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress) + { + return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress); + } - /// + /// /// Get the power status of the device with the given logical address. /// /// The logical address of the device to get the power status for. /// The power status or CEC_POWER_STATUS_UNKNOWN if it wasn't found. - CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress) - { - return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress); - } + CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress) + { + return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress); + } - /// + /// /// Tell libCEC to poll for active devices on the bus. /// - void RescanActiveDevices(void) - { - m_libCec->RescanActiveDevices(); - } + void RescanActiveDevices(void) + { + m_libCec->RescanActiveDevices(); + } - /// + /// /// Get the logical addresses of the devices that are active on the bus, including those handled by libCEC. /// /// The logical addresses of the active devices - CecLogicalAddresses ^ GetActiveDevices(void) - { - CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses(); - unsigned int iDevices = 0; + CecLogicalAddresses ^ GetActiveDevices(void) + { + CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses(); + unsigned int iDevices = 0; - cec_logical_addresses activeDevices = m_libCec->GetActiveDevices(); + cec_logical_addresses activeDevices = m_libCec->GetActiveDevices(); - for (uint8_t iPtr = 0; iPtr < 16; iPtr++) - if (activeDevices[iPtr]) - retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr; + for (uint8_t iPtr = 0; iPtr < 16; iPtr++) + if (activeDevices[iPtr]) + retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr; - return retVal; - } + return retVal; + } - /// + /// /// Check whether a device is active on the bus. /// /// The address to check. /// True when active, false otherwise. - bool IsActiveDevice(CecLogicalAddress logicalAddress) - { - return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress); - } + bool IsActiveDevice(CecLogicalAddress logicalAddress) + { + return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress); + } - /// + /// /// Check whether a device of the given type is active on the bus. /// /// The type to check. /// True when active, false otherwise. - bool IsActiveDeviceType(CecDeviceType type) - { - return m_libCec->IsActiveDeviceType((cec_device_type)type); - } + bool IsActiveDeviceType(CecDeviceType type) + { + return m_libCec->IsActiveDeviceType((cec_device_type)type); + } - /// + /// /// Changes the active HDMI port. /// /// The device to which this libCEC is connected. - /// The new port number. + /// The new port number. /// True when changed, false otherwise. - bool SetHDMIPort(CecLogicalAddress address, uint8_t port) - { - return m_libCec->SetHDMIPort((cec_logical_address)address, port); - } + bool SetHDMIPort(CecLogicalAddress address, uint8_t port) + { + return m_libCec->SetHDMIPort((cec_logical_address)address, port); + } - /// + /// /// Sends a volume up keypress to an audiosystem if it's present. /// /// Send a key release after the keypress. /// The new audio status. - uint8_t VolumeUp(bool sendRelease) - { - return m_libCec->VolumeUp(sendRelease); - } + uint8_t VolumeUp(bool sendRelease) + { + return m_libCec->VolumeUp(sendRelease); + } - /// + /// /// Sends a volume down keypress to an audiosystem if it's present. /// /// Send a key release after the keypress. /// The new audio status. - uint8_t VolumeDown(bool sendRelease) - { - return m_libCec->VolumeDown(sendRelease); - } + uint8_t VolumeDown(bool sendRelease) + { + return m_libCec->VolumeDown(sendRelease); + } - /// + /// /// Sends a mute keypress to an audiosystem if it's present. /// /// Send a key release after the keypress. /// The new audio status. - uint8_t MuteAudio(bool sendRelease) - { - return m_libCec->MuteAudio(sendRelease); - } + uint8_t MuteAudio(bool sendRelease) + { + return m_libCec->MuteAudio(sendRelease); + } - /// + /// /// Send a keypress to a device on the CEC bus. /// /// The logical address of the device to send the message to. - /// The key to send. - /// True to wait for a response, false otherwise. + /// The key to send. + /// True to wait for a response, false otherwise. /// True when the keypress was acked, false otherwise. - bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait) - { - return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait); - } + bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait) + { + return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait); + } - /// + /// /// Send a key release to a device on the CEC bus. /// /// The logical address of the device to send the message to. - /// True to wait for a response, false otherwise. + /// True to wait for a response, false otherwise. /// True when the key release was acked, false otherwise. - bool SendKeyRelease(CecLogicalAddress destination, bool wait) - { - return m_libCec->SendKeyRelease((cec_logical_address)destination, wait); - } + bool SendKeyRelease(CecLogicalAddress destination, bool wait) + { + return m_libCec->SendKeyRelease((cec_logical_address)destination, wait); + } - /// + /// /// Get the OSD name of a device on the CEC bus. /// /// The logical address of the device to get the OSD name for. /// The OSD name. - String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress) - { - cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress); - return gcnew String(osd.name); - } + String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress) + { + cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress); + return gcnew String(osd.name); + } - /// + /// /// Get the logical address of the device that is currently the active source on the CEC bus. /// /// The active source or CECDEVICE_UNKNOWN when unknown. - CecLogicalAddress GetActiveSource() - { - return (CecLogicalAddress)m_libCec->GetActiveSource(); - } + CecLogicalAddress GetActiveSource() + { + return (CecLogicalAddress)m_libCec->GetActiveSource(); + } - /// + /// /// Check whether a device is currently the active source on the CEC bus. /// /// The logical address of the device to check. /// True when it is the active source, false otherwise. - bool IsActiveSource(CecLogicalAddress logicalAddress) - { - return m_libCec->IsActiveSource((cec_logical_address)logicalAddress); - } + bool IsActiveSource(CecLogicalAddress logicalAddress) + { + return m_libCec->IsActiveSource((cec_logical_address)logicalAddress); + } - /// + /// /// Get the physical address of the device with the given logical address. /// /// The logical address of the device to get the physical address for. /// The physical address or 0 if it wasn't found. - uint16_t GetDevicePhysicalAddress(CecLogicalAddress address) - { - return m_libCec->GetDevicePhysicalAddress((cec_logical_address)address); - } + uint16_t GetDevicePhysicalAddress(CecLogicalAddress address) + { + return m_libCec->GetDevicePhysicalAddress((cec_logical_address)address); + } - /// + /// /// Sets the stream path to the device on the given logical address. /// /// The address to activate. /// True when the command was sent, false otherwise. - bool SetStreamPath(CecLogicalAddress address) - { - return m_libCec->SetStreamPath((cec_logical_address)address); - } + bool SetStreamPath(CecLogicalAddress address) + { + return m_libCec->SetStreamPath((cec_logical_address)address); + } - /// + /// /// Sets the stream path to the device on the given physical address. /// /// The address to activate. /// True when the command was sent, false otherwise. - bool SetStreamPath(uint16_t physicalAddress) - { - return m_libCec->SetStreamPath(physicalAddress); - } + bool SetStreamPath(uint16_t physicalAddress) + { + return m_libCec->SetStreamPath(physicalAddress); + } - /// + /// /// Get the list of logical addresses that libCEC is controlling /// /// The list of logical addresses that libCEC is controlling - CecLogicalAddresses ^GetLogicalAddresses(void) - { - CecLogicalAddresses ^addr = gcnew CecLogicalAddresses(); - cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses(); - for (unsigned int iPtr = 0; iPtr < 16; iPtr++) - addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr]; - addr->Primary = (CecLogicalAddress)libAddr.primary; - return addr; - } - - /// + CecLogicalAddresses ^GetLogicalAddresses(void) + { + CecLogicalAddresses ^addr = gcnew CecLogicalAddresses(); + cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses(); + for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr]; + addr->Primary = (CecLogicalAddress)libAddr.primary; + return addr; + } + + /// /// Get libCEC's current configuration. /// /// The configuration. /// True when the configuration was updated, false otherwise. - bool GetCurrentConfiguration(LibCECConfiguration ^configuration) - { - libcec_configuration config; - config.Clear(); - - if (m_libCec->GetCurrentConfiguration(&config)) - { - configuration->Update(config); - return true; - } - return false; - } - - /// + bool GetCurrentConfiguration(LibCECConfiguration ^configuration) + { + libcec_configuration config; + config.Clear(); + + if (m_libCec->GetCurrentConfiguration(&config)) + { + configuration->Update(config); + return true; + } + return false; + } + + /// /// Check whether the CEC adapter can persist a configuration. /// /// True when this CEC adapter can persist the user configuration, false otherwise. bool CanPersistConfiguration(void) - { - return m_libCec->CanPersistConfiguration(); - } + { + return m_libCec->CanPersistConfiguration(); + } - /// + /// /// Persist the given configuration in adapter (if supported) /// /// The configuration to store. /// True when the configuration was persisted, false otherwise. bool PersistConfiguration(LibCECConfiguration ^configuration) - { - marshal_context ^ context = gcnew marshal_context(); - libcec_configuration config; - ConvertConfiguration(context, configuration, config); + { + marshal_context ^ context = gcnew marshal_context(); + libcec_configuration config; + ConvertConfiguration(context, configuration, config); - bool bReturn = m_libCec->PersistConfiguration(&config); + bool bReturn = m_libCec->PersistConfiguration(&config); - delete context; - return bReturn; - } + delete context; + return bReturn; + } - /// + /// /// Change libCEC's configuration. /// /// The new configuration. /// True when the configuration was changed successfully, false otherwise. - bool SetConfiguration(LibCECConfiguration ^configuration) - { - marshal_context ^ context = gcnew marshal_context(); - libcec_configuration config; - ConvertConfiguration(context, configuration, config); + bool SetConfiguration(LibCECConfiguration ^configuration) + { + marshal_context ^ context = gcnew marshal_context(); + libcec_configuration config; + ConvertConfiguration(context, configuration, config); - bool bReturn = m_libCec->SetConfiguration(&config); + bool bReturn = m_libCec->SetConfiguration(&config); - delete context; - return bReturn; - } + delete context; + return bReturn; + } - /// + /// /// Check whether libCEC is the active source on the bus. /// /// True when libCEC is the active source on the bus, false otherwise. @@ -762,12 +610,12 @@ namespace CecSharp return m_libCec->IsLibCECActiveSource(); } - /// + /// /// Get information about the given CEC adapter. /// /// The COM port to which the device is connected - /// The device configuration - /// The timeout in milliseconds + /// The device configuration + /// The timeout in milliseconds /// True when the device was found, false otherwise bool GetDeviceInformation(String ^ port, LibCECConfiguration ^configuration, uint32_t timeoutMs) { @@ -775,116 +623,189 @@ namespace CecSharp marshal_context ^ context = gcnew marshal_context(); libcec_configuration config; - config.Clear(); + config.Clear(); const char* strPortC = port->Length > 0 ? context->marshal_as(port) : NULL; if (m_libCec->GetDeviceInformation(strPortC, &config, timeoutMs)) - { - configuration->Update(config); + { + configuration->Update(config); bReturn = true; - } + } delete context; return bReturn; } - String ^ ToString(CecLogicalAddress iAddress) - { - const char *retVal = m_libCec->ToString((cec_logical_address)iAddress); - return gcnew String(retVal); - } - - String ^ ToString(CecVendorId iVendorId) - { - const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId); - return gcnew String(retVal); - } - - String ^ ToString(CecVersion iVersion) - { - const char *retVal = m_libCec->ToString((cec_version)iVersion); - return gcnew String(retVal); - } - - String ^ ToString(CecPowerStatus iState) - { - const char *retVal = m_libCec->ToString((cec_power_status)iState); - return gcnew String(retVal); - } - - String ^ ToString(CecMenuState iState) - { - const char *retVal = m_libCec->ToString((cec_menu_state)iState); - return gcnew String(retVal); - } - - String ^ ToString(CecDeckControlMode iMode) - { - const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode); - return gcnew String(retVal); - } - - String ^ ToString(CecDeckInfo status) - { - const char *retVal = m_libCec->ToString((cec_deck_info)status); - return gcnew String(retVal); - } - - String ^ ToString(CecOpcode opcode) - { - const char *retVal = m_libCec->ToString((cec_opcode)opcode); - return gcnew String(retVal); - } - - String ^ ToString(CecSystemAudioStatus mode) - { - const char *retVal = m_libCec->ToString((cec_system_audio_status)mode); - return gcnew String(retVal); - } - - String ^ ToString(CecAudioStatus status) - { - const char *retVal = m_libCec->ToString((cec_audio_status)status); - return gcnew String(retVal); - } - - String ^ ToString(CecClientVersion version) - { - const char *retVal = m_libCec->ToString((cec_client_version)version); - return gcnew String(retVal); - } - - String ^ ToString(CecServerVersion version) - { - const char *retVal = m_libCec->ToString((cec_server_version)version); - return gcnew String(retVal); - } - - /// + String ^ ToString(CecLogicalAddress iAddress) + { + const char *retVal = m_libCec->ToString((cec_logical_address)iAddress); + return gcnew String(retVal); + } + + String ^ ToString(CecVendorId iVendorId) + { + const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId); + return gcnew String(retVal); + } + + String ^ ToString(CecVersion iVersion) + { + const char *retVal = m_libCec->ToString((cec_version)iVersion); + return gcnew String(retVal); + } + + String ^ ToString(CecPowerStatus iState) + { + const char *retVal = m_libCec->ToString((cec_power_status)iState); + return gcnew String(retVal); + } + + String ^ ToString(CecMenuState iState) + { + const char *retVal = m_libCec->ToString((cec_menu_state)iState); + return gcnew String(retVal); + } + + String ^ ToString(CecDeckControlMode iMode) + { + const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode); + return gcnew String(retVal); + } + + String ^ ToString(CecDeckInfo status) + { + const char *retVal = m_libCec->ToString((cec_deck_info)status); + return gcnew String(retVal); + } + + String ^ ToString(CecOpcode opcode) + { + const char *retVal = m_libCec->ToString((cec_opcode)opcode); + return gcnew String(retVal); + } + + String ^ ToString(CecSystemAudioStatus mode) + { + const char *retVal = m_libCec->ToString((cec_system_audio_status)mode); + return gcnew String(retVal); + } + + String ^ ToString(CecAudioStatus status) + { + const char *retVal = m_libCec->ToString((cec_audio_status)status); + return gcnew String(retVal); + } + + String ^ ToString(CecClientVersion version) + { + const char *retVal = m_libCec->ToString((cec_client_version)version); + return gcnew String(retVal); + } + + String ^ ToString(CecServerVersion version) + { + const char *retVal = m_libCec->ToString((cec_server_version)version); + return gcnew String(retVal); + } + + /// /// Get a string with information about how libCEC was compiled. /// /// A string with information about how libCEC was compiled. - String ^ GetLibInfo() - { - const char *retVal = m_libCec->GetLibInfo(); - return gcnew String(retVal); - } + String ^ GetLibInfo() + { + const char *retVal = m_libCec->GetLibInfo(); + return gcnew String(retVal); + } - /// + /// /// Calling this method will initialise the host on which libCEC is running. - /// On the RPi, it calls bcm_host_init(), which may only be called once per process, and is called by any process using + /// On the RPi, it calls bcm_host_init(), which may only be called once per process, and is called by any process using /// the video api on that system. So only call this method if libCEC is used in an application that /// does not already initialise the video api. /// /// Should be called as first call to libCEC, directly after CECInitialise() and before using Open() - void InitVideoStandalone() - { - m_libCec->InitVideoStandalone(); - } + void InitVideoStandalone() + { + m_libCec->InitVideoStandalone(); + } + + private: + !LibCecSharp(void) + { + Close(); + m_libCec = NULL; + } + + bool InitialiseLibCec(LibCECConfiguration ^config) + { + marshal_context ^ context = gcnew marshal_context(); + libcec_configuration libCecConfig; + ConvertConfiguration(context, config, libCecConfig); + + m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig); + config->Update(libCecConfig); + + delete context; + return m_libCec != NULL; + } + + void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config) + { + config.Clear(); + + const char *strDeviceName = context->marshal_as(netConfig->DeviceName); + memcpy_s(config.strDeviceName, 13, strDeviceName, 13); + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr]; + + config.bAutodetectAddress = netConfig->AutodetectAddress ? 1 : 0; + config.iPhysicalAddress = netConfig->PhysicalAddress; + config.baseDevice = (cec_logical_address)netConfig->BaseDevice; + config.iHDMIPort = netConfig->HDMIPort; + config.clientVersion = (cec_client_version)netConfig->ClientVersion; + config.bGetSettingsFromROM = netConfig->GetSettingsFromROM ? 1 : 0; + config.bActivateSource = netConfig->ActivateSource ? 1 : 0; + config.tvVendor = (cec_vendor_id)netConfig->TvVendor; + config.wakeDevices.Clear(); + for (int iPtr = 0; iPtr < 16; iPtr++) + { + if (netConfig->WakeDevices->IsSet((CecLogicalAddress)iPtr)) + config.wakeDevices.Set((cec_logical_address)iPtr); + } + config.powerOffDevices.Clear(); + for (int iPtr = 0; iPtr < 16; iPtr++) + { + if (netConfig->PowerOffDevices->IsSet((CecLogicalAddress)iPtr)) + config.powerOffDevices.Set((cec_logical_address)iPtr); + } + config.bPowerOffScreensaver = netConfig->PowerOffScreensaver ? 1 : 0; + config.bPowerOffOnStandby = netConfig->PowerOffOnStandby ? 1 : 0; + + if (netConfig->ServerVersion >= CecServerVersion::Version1_5_1) + config.bSendInactiveSource = netConfig->SendInactiveSource ? 1 : 0; + + if (netConfig->ServerVersion >= CecServerVersion::Version1_6_0) + { + config.bPowerOffDevicesOnStandby = netConfig->PowerOffDevicesOnStandby ? 1 : 0; + config.bShutdownOnStandby = netConfig->ShutdownOnStandby ? 1 : 0; + } + + if (netConfig->ServerVersion >= CecServerVersion::Version1_6_2) + { + const char *strDeviceLanguage = context->marshal_as(netConfig->DeviceLanguage); + memcpy_s(config.strDeviceLanguage, 3, strDeviceLanguage, 3); + } + + if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3) + config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0; + + config.callbacks = &g_cecCallbacks; + } + - private: - ICECAdapter * m_libCec; + ICECAdapter * m_libCec; CecCallbackMethods ^ m_callbacks; - }; + }; } -- 2.34.1