cec: added a callback that is called when libCEC's configuration changed.
authorLars Op den Kamp <lars@opdenkamp.eu>
Wed, 15 Feb 2012 12:07:28 +0000 (13:07 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Wed, 15 Feb 2012 12:09:59 +0000 (13:09 +0100)
include/cectypes.h
src/LibCecSharp/CecSharpTypes.h
src/LibCecSharp/LibCecSharp.cpp
src/cec-config-gui/CecConfigGUI.cs
src/cec-config/cec-config.cpp
src/lib/CECProcessor.cpp
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/testclient/main.cpp

index 808fb95a15fc7b8c13945d12907bbfd329fc7a0b..41d124e9a6d8ccee0778879220a3bcec64714b6f 100644 (file)
@@ -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
index e88166746116a63e47d46609757dd828479ffaee..2a32724a6d1c6935619bbdc719b321bcf831d1d7 100644 (file)
@@ -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<COMMANDCB>(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<CONFIGCB>(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;
-       };
 }
index 4e76ead7a6ab264252ef97040448e9909fb93729..1c073d9baedaae0e15989df8daf2821f54447c63 100644 (file)
@@ -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<const char*>(m_configuration->DeviceName));
+                       _snprintf_s(config.strDeviceName, 13, context->marshal_as<const char*>(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;
        };
 }
index b8c2b54fa68ca7031ef3b410c72639a63f9e732c..e41c292be80901d16658a6f00ad4189a54cb2bc3 100644 (file)
@@ -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;
   }
 }
index ceef2d931cc5cac1051c618acc1f381809f31cad..02e812663993b86f48ebcd5ad91b5bc5414f0ee3 100644 (file)
@@ -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);
 }
 
index b8e4ba59b79bdc761c169e4e6807b96ae4000bd5..ef2bbd10c4a0a7724b64d30223ee72d846a7a877 100644 (file)
@@ -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;
 }
 
index e18108af64f00c91f6a3226034e96c636d55892b..f7159d502ce6a6fb6206579f4cb2b484446e7c73 100644 (file)
@@ -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.
index 9619dd4a6cb86fc22d2c5d322f96a4c4c73e048a..2df5b63ec1973751f3c35428a2910bb40b90641d 100644 (file)
@@ -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);
 
index 2e7fee43c4f5beacc92500958d6f6c2c1183d855..a8f03a51b184ff276894f057dff061358f853e1b 100644 (file)
@@ -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);
 }