From 32403cc3b1abb8b186ca4bbe14cb7431a492f768 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Wed, 15 Feb 2012 13:07:28 +0100 Subject: [PATCH] cec: added a callback that is called when libCEC's configuration changed. --- include/cectypes.h | 12 ++- src/LibCecSharp/CecSharpTypes.h | 138 ++++++++++++++++++++--------- src/LibCecSharp/LibCecSharp.cpp | 66 ++++++++------ src/cec-config-gui/CecConfigGUI.cs | 23 ++--- src/cec-config/cec-config.cpp | 1 + src/lib/CECProcessor.cpp | 4 + src/lib/LibCEC.cpp | 15 +++- src/lib/LibCEC.h | 5 +- src/testclient/main.cpp | 1 + 9 files changed, 177 insertions(+), 88 deletions(-) diff --git a/include/cectypes.h b/include/cectypes.h index 808fb95..41d124e 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -903,9 +903,12 @@ typedef struct cec_logical_addresses #endif } cec_logical_addresses; -typedef int (CEC_CDECL* CBCecLogMessageType)(void *param, const CEC::cec_log_message &); +struct libcec_configuration; + +typedef int (CEC_CDECL* CBCecLogMessageType)(void *param, const cec_log_message &); typedef int (CEC_CDECL* CBCecKeyPressType)(void *param, const cec_keypress &); typedef int (CEC_CDECL* CBCecCommandType)(void *param, const cec_command &); +typedef int (CEC_CDECL* CBCecConfigurationChangedType)(void *param, const libcec_configuration &); typedef struct ICECCallbacks { @@ -929,6 +932,13 @@ typedef struct ICECCallbacks * @return 1 when ok, 0 otherwise. */ CBCecCommandType CBCecCommand; + + /*! + * @brief Transfer a changed configuration from libCEC to the client + * @param configuration The configuration to transfer + * @return 1 when ok, 0 otherwise + */ + CBCecConfigurationChangedType CBCecConfigurationChanged; } ICECCallbacks; typedef enum cec_client_version diff --git a/src/LibCecSharp/CecSharpTypes.h b/src/LibCecSharp/CecSharpTypes.h index e881667..2a32724 100644 --- a/src/LibCecSharp/CecSharpTypes.h +++ b/src/LibCecSharp/CecSharpTypes.h @@ -325,7 +325,7 @@ namespace CecSharp public enum class CecClientVersion { VersionPre1_5 = 0, - Version1_5_0 = 1 + Version1_5_0 = 0x1500 }; public ref class CecAdapter @@ -500,16 +500,62 @@ namespace CecSharp property int64_t Time; }; + ref class CecCallbackMethods; //forward + public ref class LibCECConfiguration + { + public: + LibCECConfiguration(void) + { + DeviceName = ""; + DeviceTypes = gcnew CecDeviceTypeList(); + PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS; + BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE; + HDMIPort = CEC_DEFAULT_HDMI_PORT; + ClientVersion = CecClientVersion::VersionPre1_5; + + GetSettingsFromROM = false; + UseTVMenuLanguage = CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE == 1; + PowerOnStartup = CEC_DEFAULT_SETTING_POWER_ON_STARTUP == 1; + PowerOffShutdown = CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1; + PowerOffScreensaver = CEC_DEFAULT_SETTING_POWER_OFF_SCREENSAVER == 1; + PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1; + } + + void SetCallbacks(CecCallbackMethods ^callbacks) + { + Callbacks = callbacks; + } + + property System::String ^ DeviceName; + property CecDeviceTypeList ^ DeviceTypes; + property uint16_t PhysicalAddress; + property CecLogicalAddress BaseDevice; + property uint8_t HDMIPort; + property CecClientVersion ClientVersion; + + // player specific settings + property bool GetSettingsFromROM; + property bool UseTVMenuLanguage; + property bool PowerOnStartup; + property bool PowerOffShutdown; + property bool PowerOffScreensaver; + property bool PowerOffOnStandby; + + 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); static LOGCB g_logCB; static KEYCB g_keyCB; static COMMANDCB g_commandCB; + static CONFIGCB g_configCB; static CEC::ICECCallbacks g_cecCallbacks; int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message) @@ -533,11 +579,19 @@ namespace CecSharp return 0; } + int CecConfigCB(void *cbParam, const CEC::libcec_configuration &config) + { + if (g_configCB) + return g_configCB(config); + return 0; + } + #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 &); // callback method interface public ref class CecCallbackMethods @@ -566,6 +620,12 @@ namespace CecSharp g_commandCB = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer()); g_cecCallbacks.CBCecCommand = CecCommandCB; + // 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); + g_configCB = static_cast(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer()); + g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB; + delete context; } @@ -608,6 +668,10 @@ namespace CecSharp return 0; } + virtual int ConfigurationChanged(LibCECConfiguration ^ config) + { + return 0; + } protected: // managed callback methods int CecLogMessageManaged(const CEC::cec_log_message &message) @@ -639,6 +703,31 @@ namespace CecSharp return iReturn; } + int CecConfigManaged(const CEC::libcec_configuration &config) + { + int iReturn(0); + if (m_bHasCallbacks) + { + LibCECConfiguration ^netConfig = gcnew LibCECConfiguration(); + netConfig->DeviceName = gcnew System::String(config.strDeviceName); + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + netConfig->DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr]; + + netConfig->PhysicalAddress = config.iPhysicalAddress; + netConfig->BaseDevice = (CecLogicalAddress)config.baseDevice; + netConfig->HDMIPort = config.iHDMIPort; + netConfig->ClientVersion = (CecClientVersion)config.clientVersion; + netConfig->GetSettingsFromROM = config.bGetSettingsFromROM == 1; + netConfig->PowerOnStartup = config.bPowerOnStartup == 1; + netConfig->PowerOffShutdown = config.bPowerOffShutdown == 1; + netConfig->PowerOffScreensaver = config.bPowerOffScreensaver == 1; + netConfig->PowerOffOnStandby = config.bPowerOffOnStandby == 1; + + iReturn = m_callbacks->ConfigurationChanged(netConfig); + } + return iReturn; + } + void DestroyDelegates() { if (m_bHasCallbacks) @@ -663,50 +752,11 @@ namespace CecSharp static System::Runtime::InteropServices::GCHandle m_commandGCHandle; COMMANDCB m_commandCallback; + CecConfigManagedDelegate ^ m_configDelegate; + static System::Runtime::InteropServices::GCHandle m_configGCHandle; + CONFIGCB m_configCallback; + CecCallbackMethods ^ m_callbacks; bool m_bHasCallbacks; }; - - public ref class LibCECConfiguration - { - public: - LibCECConfiguration(void) - { - DeviceName = ""; - DeviceTypes = gcnew CecDeviceTypeList(); - PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS; - BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE; - HDMIPort = CEC_DEFAULT_HDMI_PORT; - ClientVersion = CecClientVersion::VersionPre1_5; - - GetSettingsFromROM = false; - UseTVMenuLanguage = CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE == 1; - PowerOnStartup = CEC_DEFAULT_SETTING_POWER_ON_STARTUP == 1; - PowerOffShutdown = CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1; - PowerOffScreensaver = CEC_DEFAULT_SETTING_POWER_OFF_SCREENSAVER == 1; - PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1; - } - - void SetCallbacks(CecCallbackMethods ^callbacks) - { - Callbacks = callbacks; - } - - property System::String ^ DeviceName; - property CecDeviceTypeList ^ DeviceTypes; - property uint16_t PhysicalAddress; - property CecLogicalAddress BaseDevice; - property uint8_t HDMIPort; - property CecClientVersion ClientVersion; - - // player specific settings - property bool GetSettingsFromROM; - property bool UseTVMenuLanguage; - property bool PowerOnStartup; - property bool PowerOffShutdown; - property bool PowerOffScreensaver; - property bool PowerOffOnStandby; - - property CecCallbackMethods ^Callbacks; - }; } diff --git a/src/LibCecSharp/LibCecSharp.cpp b/src/LibCecSharp/LibCecSharp.cpp index 4e76ead..1c073d9 100644 --- a/src/LibCecSharp/LibCecSharp.cpp +++ b/src/LibCecSharp/LibCecSharp.cpp @@ -45,19 +45,18 @@ namespace CecSharp public: LibCecSharp(LibCECConfiguration ^config) { - m_configuration = config; - CecCallbackMethods::EnableCallbacks(m_configuration->Callbacks); - if (!InitialiseLibCec()) + CecCallbackMethods::EnableCallbacks(config->Callbacks); + if (!InitialiseLibCec(config)) throw gcnew Exception("Could not initialise LibCecSharp"); } LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes) { - m_configuration = gcnew LibCECConfiguration(); - m_configuration->SetCallbacks(this); - m_configuration->DeviceName = strDeviceName; - m_configuration->DeviceTypes = deviceTypes; - if (!InitialiseLibCec()) + LibCECConfiguration ^config = gcnew LibCECConfiguration(); + config->SetCallbacks(this); + config->DeviceName = strDeviceName; + config->DeviceTypes = deviceTypes; + if (!InitialiseLibCec(config)) throw gcnew Exception("Could not initialise LibCecSharp"); } @@ -74,36 +73,36 @@ namespace CecSharp m_libCec = NULL; } - bool InitialiseLibCec(void) + bool InitialiseLibCec(LibCECConfiguration ^config) { marshal_context ^ context = gcnew marshal_context(); - libcec_configuration config; - GetConfiguration(context, config); + libcec_configuration libCecConfig; + ConvertConfiguration(context, config, libCecConfig); - m_libCec = (ICECAdapter *) CECInitialise(&config); + m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig); delete context; return m_libCec != NULL; } - void GetConfiguration(marshal_context ^context, libcec_configuration &config) + void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config) { config.Clear(); - _snprintf_s(config.strDeviceName, 13, context->marshal_as(m_configuration->DeviceName)); + _snprintf_s(config.strDeviceName, 13, context->marshal_as(netConfig->DeviceName)); for (unsigned int iPtr = 0; iPtr < 5; iPtr++) - config.deviceTypes.types[iPtr] = (cec_device_type)m_configuration->DeviceTypes->Types[iPtr]; + config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr]; - config.iPhysicalAddress = m_configuration->PhysicalAddress; - config.baseDevice = (cec_logical_address)m_configuration->BaseDevice; - config.iHDMIPort = m_configuration->HDMIPort; - config.clientVersion = (cec_client_version)m_configuration->ClientVersion; - config.bGetSettingsFromROM = m_configuration->GetSettingsFromROM; - config.bPowerOnStartup = m_configuration->PowerOnStartup; - config.bPowerOffShutdown = m_configuration->PowerOffShutdown; - config.bPowerOffScreensaver = m_configuration->PowerOffScreensaver; - config.bPowerOffOnStandby = m_configuration->PowerOffOnStandby; - config.callbacks = &g_cecCallbacks; + 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; + config.bPowerOnStartup = netConfig->PowerOnStartup; + config.bPowerOffShutdown = netConfig->PowerOffShutdown; + config.bPowerOffScreensaver = netConfig->PowerOffScreensaver; + config.bPowerOffOnStandby = netConfig->PowerOffOnStandby; + config.callbacks = &g_cecCallbacks; } public: @@ -427,7 +426,7 @@ namespace CecSharp configuration->PowerOnStartup = config.bPowerOnStartup == 1; configuration->UseTVMenuLanguage = config.bUseTVMenuLanguage == 1; for (unsigned int iPtr = 0; iPtr < 5; iPtr++) - m_configuration->DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr]; + configuration->DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr]; return true; } return false; @@ -442,7 +441,7 @@ namespace CecSharp { marshal_context ^ context = gcnew marshal_context(); libcec_configuration config; - GetConfiguration(context, config); + ConvertConfiguration(context, configuration, config); bool bReturn = m_libCec->PersistConfiguration(&config); @@ -450,6 +449,18 @@ namespace CecSharp return bReturn; } + bool SetConfiguration(LibCECConfiguration ^configuration) + { + marshal_context ^ context = gcnew marshal_context(); + libcec_configuration config; + ConvertConfiguration(context, configuration, config); + + bool bReturn = m_libCec->SetConfiguration(&config); + + delete context; + return bReturn; + } + String ^ ToString(CecLogicalAddress iAddress) { const char *retVal = m_libCec->ToString((cec_logical_address)iAddress); @@ -512,6 +523,5 @@ namespace CecSharp private: ICECAdapter * m_libCec; - LibCECConfiguration ^m_configuration; }; } diff --git a/src/cec-config-gui/CecConfigGUI.cs b/src/cec-config-gui/CecConfigGUI.cs index b8c2b54..e41c292 100644 --- a/src/cec-config-gui/CecConfigGUI.cs +++ b/src/cec-config-gui/CecConfigGUI.cs @@ -35,7 +35,7 @@ namespace CecConfigGui CecAdapter[] adapters = Lib.FindAdapters(string.Empty); if (adapters.Length == 0 || !Lib.Open(adapters[0].ComPort, 10000)) { - MessageBox.Show("Could not connect to any CEC adapter. Please check your configuration.", "Pulse-Eight USB-CEC Adapter", MessageBoxButtons.OK); + MessageBox.Show("Could not connect to any CEC adapter. Please check your configuration and try again.", "Pulse-Eight USB-CEC Adapter", MessageBoxButtons.OK); Application.Exit(); } @@ -222,18 +222,14 @@ namespace CecConfigGui this.cecButtonConfigBindingSource.Add(new CecButtonConfigItem("(Samsung) Return", (new CecSharp.CecKeypress() { Keycode = 0x91 }), string.Empty)); } - public int ReceiveCommand(CecCommand command) + public int ConfigurationChanged(LibCECConfiguration config) { - bool bGetNewPhysicalAddress = false; - if (command.Opcode == CecOpcode.ReportPhysicalAddress) - bGetNewPhysicalAddress = true; + SetControlText(this.tbPhysicalAddress, String.Format("{0,4:X}", config.PhysicalAddress)); + return 1; + } - if (bGetNewPhysicalAddress) - { - LibCECConfiguration config = new LibCECConfiguration(); - Lib.GetCurrentConfiguration(config); - SetControlText(this.tbPhysicalAddress, String.Format("{0,4:X}", config.PhysicalAddress)); - } + public int ReceiveCommand(CecCommand command) + { return 1; } @@ -884,6 +880,11 @@ namespace CecConfigGui return Gui.ReceiveLogMessage(message); } + public override int ConfigurationChanged(LibCECConfiguration config) + { + return Gui.ConfigurationChanged(config); + } + private CecConfigGUI Gui; } } diff --git a/src/cec-config/cec-config.cpp b/src/cec-config/cec-config.cpp index ceef2d9..02e8126 100644 --- a/src/cec-config/cec-config.cpp +++ b/src/cec-config/cec-config.cpp @@ -144,6 +144,7 @@ void EnableCallbacks(ICECAdapter *adapter) g_callbacks.CBCecLogMessage = &CecLogMessage; g_callbacks.CBCecKeyPress = &CecKeyPress; g_callbacks.CBCecCommand = &CecCommand; + g_callbacks.CBCecConfigurationChanged = NULL; adapter->EnableCallbacks(NULL, &g_callbacks); } diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index b8e4ba5..ef2bbd1 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -231,6 +231,7 @@ bool CCECProcessor::Initialise(void) WakeDevices(); SetInitialised(bReturn); + CLibCEC::ConfigurationChanged(m_configuration); return bReturn; } @@ -691,6 +692,9 @@ bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpda if (bSendActiveView) SetActiveView(); + if (bReturn) + CLibCEC::ConfigurationChanged(m_configuration); + return bReturn; } diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index e18108a..f7159d5 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -341,7 +341,7 @@ cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress) return retVal; } -void CLibCEC::AddLog(cec_log_level level, const char *strFormat, ...) +void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...) { CStdString strLog; @@ -364,7 +364,7 @@ void CLibCEC::AddLog(cec_log_level level, const char *strFormat, ...) instance->m_logBuffer.Push(message); } -void CLibCEC::AddKey(cec_keypress &key) +void CLibCEC::AddKey(const cec_keypress &key) { CLibCEC *instance = CLibCEC::GetInstance(); CLockObject lock(instance->m_mutex); @@ -380,6 +380,17 @@ void CLibCEC::AddKey(cec_keypress &key) instance->m_buttontime = key.duration > 0 ? 0 : GetTimeMs(); } +void CLibCEC::ConfigurationChanged(const libcec_configuration &config) +{ + CLibCEC *instance = CLibCEC::GetInstance(); + CLockObject lock(instance->m_mutex); + + if (instance->m_callbacks && + config.clientVersion >= CEC_CLIENT_VERSION_1_5_0 && + instance->m_callbacks->CBCecConfigurationChanged != NULL) + instance->m_callbacks->CBCecConfigurationChanged(instance->m_cbParam, config); +} + void CLibCEC::SetCurrentButton(cec_user_control_code iButtonCode) { /* push keypress to the keybuffer with 0 duration. diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index 9619dd4..2df5b63 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -120,10 +120,11 @@ namespace CEC const char *ToString(const cec_client_version version); //@} - static void AddLog(cec_log_level level, const char *strFormat, ...); + static void AddLog(const cec_log_level level, const char *strFormat, ...); static void AddKey(void); - static void AddKey(cec_keypress &key); + static void AddKey(const cec_keypress &key); static void AddCommand(const cec_command &command); + static void ConfigurationChanged(const libcec_configuration &config); static void SetCurrentButton(cec_user_control_code iButtonCode); virtual void CheckKeypressTimeout(void); diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index 2e7fee4..a8f03a5 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -180,6 +180,7 @@ void EnableCallbacks(ICECAdapter *adapter) g_callbacks.CBCecLogMessage = &CecLogMessage; g_callbacks.CBCecKeyPress = &CecKeyPress; g_callbacks.CBCecCommand = &CecCommand; + g_callbacks.CBCecConfigurationChanged = NULL; adapter->EnableCallbacks(NULL, &g_callbacks); } -- 2.34.1