Merge pull request #16 from finson/65894f58514a9ab61ae20e45cfde06c9d45600e4
authorLars Op den Kamp <opdenkamp@gmail.com>
Sun, 8 Jan 2012 22:58:41 +0000 (14:58 -0800)
committerLars Op den Kamp <opdenkamp@gmail.com>
Sun, 8 Jan 2012 22:58:41 +0000 (14:58 -0800)
Resolve difference between method name in LibCECC.cpp and cecc.h.

23 files changed:
ChangeLog
README
debian/changelog
project/libcec.rc
project/testclient.rc
src/CecSharpTester/AssemblyInfo.cs
src/LibCecSharp/AssemblyInfo.cpp
src/lib/AdapterDetection.cpp
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/ANCommandHandler.h
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/implementations/VLCommandHandler.cpp
src/lib/implementations/VLCommandHandler.h
src/lib/platform/threads.cpp
src/lib/platform/threads.h
support/cec-test-device.sh [new file with mode: 0755]

index c24e40090915e5c0880c72a00d24f241c9ee3042..7bd454739b57597e412d02d4b86ef3ea8896573a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,61 @@
+libcec (1.3-3) unstable; urgency=low
+
+   * changed/added:
+     * place in libudev include in an extern C block. fixes compilations on
+       older libudev versions (e.g. on Hardy). closes #2. credits @fbuenemann
+     * added pkg-config to the dependencies list. issue #15
+     * updated README. closes #14
+     * added a script that tests some basic functions of the CEC adapter:
+       /support/cec-test-device.sh
+   * fixed:
+     * don't make libCEC the active source when changing the physical address.
+       don't send active source messages on startup, when not the active source
+       fixes unwanted device power ups
+     * replace the command handler directly after receiving a changed vendor
+       id. change the primary type from recording device to playback device
+       for panasonic TVs
+     * don't send a deck status update when sending an active source message
+       for panasonic TVs
+     * only switch handlers once when using the generic handler
+     * don't switch handlers when not needed
+     * hold a lock in CCECProcessor::SetHDMIPort()
+     * don't send deck status updates when sending an active source message by
+       default
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 3 Jan 2012 22:48:00 +0100
+
+libcec (1.3-2) unstable; urgency=low
+
+   * changed/added:
+     * copy libcec.dll to the XBMC installation dir when XBMC is found
+     * disable background polling. let the client request this info when needed
+     * update the power status of a device when it's set to
+       CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON
+     * wait for the correct response when requesting something, not just any
+       response
+     * don't keep trying the same command/request after receiving a feature
+       abort message
+   * interface changes:
+     * change the previously unused boolean parameter in volume control methods
+       to bSendRelease, and only send a key release when it's true. default to
+       true
+   * fixed:
+     * don't send the power up/down keypress to listeners when in the initial
+       device state (powered off). fixes unexpected shutdown in XBMC when
+       connecting to the CEC adapter.
+     * send a 'menu state activated' command when starting up. bugzid: 113
+     * don't wait for a response when not needed
+     * don't hold a lock while waiting for a response. fixes failed libCEC
+       inits and slow responses
+     * don't replace a command handler when it's being used. fixes possible
+       crash on startup
+     * don't try to do anything before the processor thread has started
+     * don't transmit active source messages when the physical address is
+       still 0xFFFF
+     * don't init the default handler before the physical address is known
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 29 Dec 2011 03:05:00 +0100
+
 libcec (1.3-1) unstable; urgency=low
 
   * changed/added:
diff --git a/README b/README
index 5ef90e3c5f830551c79b8b23a4c46ab7ed973df1..230054aff725c32135aaaac5fd396168c01a0447 100644 (file)
--- a/README
+++ b/README
@@ -1,15 +1,53 @@
 This library provides support for the Pulse-Eight USB-CEC adapter.
 
-To install libCEC on Linux:
+===============================================================================
+                                === Linux ===
+===============================================================================
+
+libCEC needs the following dependencies in order to work correctly:
+* udev v151 or later
+* cdc-acm support compiled into the kernel or available as module
+
+To compile libCEC on Linux, you'll need the following dependencies:
+* autoconf 2.13 or later
+* automake 1.11 or later
+* pkg-config
+* udev development headers v151 or later
+* gcc 4.2 or later
+
+To compile, execute the following commands:
+# autoreconf -vif
+# ./configure --prefix=/usr
+# make
+# sudo make install
+
+===============================================================================
+                                === OS-X ===
+===============================================================================
+
+To compile libCEC on OS-X, you'll need the following dependencies:
+* autoconf 2.13 or later
+* automake 1.11 or later
+* pkg-config
+* xcode (TODO: version?)
+
+To compile, execute the following commands (TODO: please verify):
 # autoreconf -vif
 # ./configure --prefix=/usr
 # make
 # sudo make install
 
-To install libCEC on Windows:
+===============================================================================
+                              === Windows ===
+===============================================================================
+
+To compile libCEC on Windows, you'll need Visual C++ 2010 or Visual Studio 2010
+The installer needs the Windows DDK (Driver Development Kit) and Nullsoft's
+NSIS.
+
+To compile libCEC, follow these instructions:
 * open /project/libcec.sln with Visual C++ 2010 or Visual Studio 2010.
 * build the project.
-* copy libcec.dll and pthreadVC2.dll to your desired destination.
 
 To build an installer on Windows:
 * download and install the Windows DDK.
@@ -17,17 +55,37 @@ To build an installer on Windows:
 * go to /project and execute create-installer.cmd to create the installer.
 * the installer is stored as /project/libCEC-installer.exe
 
-Test the device:
-* run "cec-client -h" to display the options of the test client.
+===============================================================================
+                            === Debugging / Testing ===
+===============================================================================
+
+We provide a test client, named cec-client, to debug the device.
+To check whether the device can be detected, execute the following command:
+* cec-client -l
+
+"cec-client -h" shows a list of commands and options that are available.
 
-For developers:
-* see /include/cec.h for the C++ API and /include/cecc.h for the C version.
-* see src/testclient/main.cpp for an example
+===============================================================================
+                              === Developers ===
+===============================================================================
 
-For .NET developers:
-* build project/libcec.sln first
+We provide a C, C++ and .NET CLR interface to the adapter.
+
+C++ developers:
+* the API can be found in /include/cec.h
+* an example implementation can be found in /src/testclient/main.cpp
+
+C developers:
+* the API can be found in /include/cecc.h
+
+.NET developers:
 * add a reference to LibCecSharp.dll
-* see src\CecSharpTester\CecSharpClient.cs for an example
+* an example can be found in \src\CecSharpTester\CecSharpClient.cs
+
+===============================================================================
+                        === Developers Agreement ===
+===============================================================================
 
-If you wish to contribute to this project, you must first sign our contributors agreement
-Please see http://www.pulse-eight.net/contributors for more information
\ No newline at end of file
+If you wish to contribute to this project, you must first sign our contributors
+agreement. Please see http://www.pulse-eight.net/contributors for more
+information.
index c24e40090915e5c0880c72a00d24f241c9ee3042..7bd454739b57597e412d02d4b86ef3ea8896573a 100644 (file)
@@ -1,3 +1,61 @@
+libcec (1.3-3) unstable; urgency=low
+
+   * changed/added:
+     * place in libudev include in an extern C block. fixes compilations on
+       older libudev versions (e.g. on Hardy). closes #2. credits @fbuenemann
+     * added pkg-config to the dependencies list. issue #15
+     * updated README. closes #14
+     * added a script that tests some basic functions of the CEC adapter:
+       /support/cec-test-device.sh
+   * fixed:
+     * don't make libCEC the active source when changing the physical address.
+       don't send active source messages on startup, when not the active source
+       fixes unwanted device power ups
+     * replace the command handler directly after receiving a changed vendor
+       id. change the primary type from recording device to playback device
+       for panasonic TVs
+     * don't send a deck status update when sending an active source message
+       for panasonic TVs
+     * only switch handlers once when using the generic handler
+     * don't switch handlers when not needed
+     * hold a lock in CCECProcessor::SetHDMIPort()
+     * don't send deck status updates when sending an active source message by
+       default
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 3 Jan 2012 22:48:00 +0100
+
+libcec (1.3-2) unstable; urgency=low
+
+   * changed/added:
+     * copy libcec.dll to the XBMC installation dir when XBMC is found
+     * disable background polling. let the client request this info when needed
+     * update the power status of a device when it's set to
+       CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON
+     * wait for the correct response when requesting something, not just any
+       response
+     * don't keep trying the same command/request after receiving a feature
+       abort message
+   * interface changes:
+     * change the previously unused boolean parameter in volume control methods
+       to bSendRelease, and only send a key release when it's true. default to
+       true
+   * fixed:
+     * don't send the power up/down keypress to listeners when in the initial
+       device state (powered off). fixes unexpected shutdown in XBMC when
+       connecting to the CEC adapter.
+     * send a 'menu state activated' command when starting up. bugzid: 113
+     * don't wait for a response when not needed
+     * don't hold a lock while waiting for a response. fixes failed libCEC
+       inits and slow responses
+     * don't replace a command handler when it's being used. fixes possible
+       crash on startup
+     * don't try to do anything before the processor thread has started
+     * don't transmit active source messages when the physical address is
+       still 0xFFFF
+     * don't init the default handler before the physical address is known
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 29 Dec 2011 03:05:00 +0100
+
 libcec (1.3-1) unstable; urgency=low
 
   * changed/added:
index 1fe06c575219956617b7051aedb1a55d52037348..e18b9a311b2c23052b1cef4c0301dff396674f3b 100644 (file)
Binary files a/project/libcec.rc and b/project/libcec.rc differ
index c63d3c9ebfdb49ffe33cc05778ef8c141e5b6412..339801b3d2bb0e601199803863fe9aa24254f54f 100644 (file)
Binary files a/project/testclient.rc and b/project/testclient.rc differ
index 058bbb9169a8cba681401639ac10004cbc43b75a..73ffc394222fc35a3d70a002c96228bd5639d8a0 100644 (file)
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("Pulse-Eight Ltd.")]
 [assembly: AssemblyProduct("CecSharpClient")]
-[assembly: AssemblyCopyright("Copyright © Pulse-Eight Ltd. 2011")]
+[assembly: AssemblyCopyright("Copyright (c) Pulse-Eight Ltd. 2012)]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.3.2.0")]
+[assembly: AssemblyFileVersion("1.3.2.0")]
index 459ae9f48638415fae6d3155ef8eefa88e79bacd..0624b82a9c91662984d5494958b43fd37f3df380 100644 (file)
@@ -16,7 +16,7 @@ using namespace System::Security::Permissions;
 [assembly:AssemblyConfigurationAttribute("")];
 [assembly:AssemblyCompanyAttribute("Pulse-Eight Ltd.")];
 [assembly:AssemblyProductAttribute("LibCecSharp")];
-[assembly:AssemblyCopyrightAttribute("Copyright (c) Pulse-Eight Ltd. 2011")];
+[assembly:AssemblyCopyrightAttribute("Copyright (c) Pulse-Eight Ltd. 2012")];
 [assembly:AssemblyTrademarkAttribute("")];
 [assembly:AssemblyCultureAttribute("")];
 
@@ -31,7 +31,7 @@ using namespace System::Security::Permissions;
 // You can specify all the value or you can default the Revision and Build Numbers
 // by using the '*' as shown below:
 
-[assembly:AssemblyVersionAttribute("1.0.*")];
+[assembly:AssemblyVersionAttribute("1.3.2.0")];
 
 [assembly:ComVisible(false)];
 
index b304e43561d2eb5c0961a425b140b35bda88cd6a..de1da7c1f3fb2c435d1fbc6f255ec0a9b86eb192 100644 (file)
 static GUID USB_RAW_GUID =  { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
 #elif defined(HAVE_LIBUDEV)
 #include <dirent.h>
-#include <libudev.h>
 #include <poll.h>
+extern "C" {
+#include <libudev.h>
+}
 #endif
 
 #define CEC_VID 0x2548
index 27bca694646f05378cc4a085c4b08e4dcdf08acd..5071ec6ee3f8b87818b8f5733694fedf030126d2 100644 (file)
@@ -49,6 +49,7 @@ using namespace std;
 
 CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
     m_bStarted(false),
+    m_bInitialised(false),
     m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
     m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
     m_lastInitiator(CECDEVICE_UNKNOWN),
@@ -69,6 +70,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec
 
 CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) :
     m_bStarted(false),
+    m_bInitialised(false),
     m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
     m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
     m_strDeviceName(strDeviceName),
@@ -168,20 +170,15 @@ bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */,
     m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName;
 
     /* get the vendor id from the TV, so we are using the correct handler */
-    m_busDevices[CECDEVICE_TV]->GetVendorId();
+    m_busDevices[CECDEVICE_TV]->RequestVendorId();
+    ReplaceHandlers();
 
     bReturn = SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true);
   }
 
-  /* make the primary device the active source */
-  if (bReturn)
-  {
-    m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true;
-    bReturn = m_busDevices[CECDEVICE_TV]->GetHandler()->InitHandler();
-  }
-
   if (bReturn)
   {
+    m_bInitialised = true;
     m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
   }
   else
@@ -235,6 +232,85 @@ bool CCECProcessor::FindLogicalAddressAudioSystem(void)
   return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
 }
 
+bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
+{
+  bool bChanged(false);
+
+  CStdString strLog;
+  strLog.Format("changing device type '%s' into '%s'", ToString(from), ToString(to));
+  AddLog(CEC_LOG_NOTICE, strLog);
+
+  CLockObject lock(&m_mutex);
+  CCECBusDevice *previousDevice = GetDeviceByType(from);
+  m_logicalAddresses.primary = CECDEVICE_UNKNOWN;
+
+  for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+  {
+    if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+      continue;
+
+    if (m_types.types[iPtr] == from)
+    {
+      bChanged = true;
+      m_types.types[iPtr] = to;
+    }
+    else if (m_types.types[iPtr] == to && bChanged)
+    {
+      m_types.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+    }
+  }
+
+  if (bChanged)
+  {
+    FindLogicalAddresses();
+
+    CCECBusDevice *newDevice = GetDeviceByType(to);
+    if (previousDevice && newDevice)
+    {
+      newDevice->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+      previousDevice->SetDeviceStatus(CEC_DEVICE_STATUS_UNKNOWN);
+
+      newDevice->SetCecVersion(previousDevice->GetCecVersion(false));
+      previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN);
+
+      newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false));
+      cec_menu_language lang;
+      lang.device = previousDevice->GetLogicalAddress();
+      for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
+        lang.language[iPtr] = '?';
+      lang.language[3] = 0;
+      previousDevice->SetMenuLanguage(lang);
+
+      newDevice->SetMenuState(previousDevice->GetMenuState());
+      previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+
+      newDevice->SetOSDName(previousDevice->GetOSDName(false));
+      previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress()));
+
+      newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress(false));
+      previousDevice->SetPhysicalAddress(0xFFFF);
+
+      newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false));
+      previousDevice->SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
+
+      newDevice->SetVendorId(previousDevice->GetVendorId(false));
+      previousDevice->SetVendorId(CEC_VENDOR_UNKNOWN);
+
+      if ((from == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || from == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
+          (to == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || to == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+      {
+        ((CCECPlaybackDevice *) newDevice)->SetDeckControlMode(((CCECPlaybackDevice *) previousDevice)->GetDeckControlMode());
+        ((CCECPlaybackDevice *) previousDevice)->SetDeckControlMode(CEC_DECK_CONTROL_MODE_STOP);
+
+        ((CCECPlaybackDevice *) newDevice)->SetDeckStatus(((CCECPlaybackDevice *) previousDevice)->GetDeckStatus());
+        ((CCECPlaybackDevice *) previousDevice)->SetDeckStatus(CEC_DECK_INFO_STOP);
+      }
+    }
+  }
+
+  return true;
+}
+
 bool CCECProcessor::FindLogicalAddresses(void)
 {
   bool bReturn(true);
@@ -265,6 +341,12 @@ bool CCECProcessor::FindLogicalAddresses(void)
   return bReturn;
 }
 
+void CCECProcessor::ReplaceHandlers(void)
+{
+  for (uint8_t iPtr = 0; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
+    m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
+}
+
 void *CCECProcessor::Process(void)
 {
   bool                  bParseFrame(false);
@@ -280,6 +362,7 @@ void *CCECProcessor::Process(void)
 
   while (!IsStopped())
   {
+    ReplaceHandlers();
     command.Clear();
     msg.clear();
 
@@ -338,7 +421,8 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE
     bReturn = m_busDevices[addr]->TransmitActiveSource();
 
     if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
-        m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+        m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
+        m_busDevices[addr]->GetHandler()->SendDeckStatusUpdateOnActiveSource())
     {
       bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV);
     }
@@ -413,6 +497,7 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true *
 bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
 {
   bool bReturn(false);
+  CLockObject lock(&m_mutex);
 
   m_iBaseDevice = iBaseDevice;
   m_iHDMIPort = iPort;
@@ -425,7 +510,11 @@ bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort,
 
   uint16_t iPhysicalAddress(0);
   if (iBaseDevice > CECDEVICE_TV)
+  {
+    lock.Leave();
     iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
+    lock.Lock();
+  }
 
   if (iPhysicalAddress < 0xffff)
   {
@@ -482,6 +571,7 @@ void CCECProcessor::LogOutput(const cec_command &data)
 
 bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
 {
+  CLockObject lock(&m_mutex);
   if (m_logicalAddresses.primary != iLogicalAddress)
   {
     CStdString strLog;
@@ -509,18 +599,23 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru
   return true;
 }
 
-bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress)
+bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate /* = true */)
 {
+  bool bWasActiveSource(false);
+  CLockObject lock(&m_mutex);
   if (!m_logicalAddresses.IsEmpty())
   {
     for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
       if (m_logicalAddresses[iPtr])
       {
+        bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource();
         m_busDevices[iPtr]->SetInactiveSource();
         m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
-        m_busDevices[iPtr]->TransmitPhysicalAddress();
+        if (bSendUpdate)
+          m_busDevices[iPtr]->TransmitPhysicalAddress();
       }
-    return SetActiveView();
+
+    return bWasActiveSource && bSendUpdate ? SetActiveView() : true;
   }
   return false;
 }
@@ -602,9 +697,9 @@ CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const
 {
   CCECBusDevice *device = NULL;
 
-  for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+  for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
   {
-    if (m_busDevices[iPtr]->m_type == type)
+    if (m_busDevices[iPtr]->m_type == type && m_logicalAddresses[iPtr])
     {
       device = m_busDevices[iPtr];
       break;
@@ -989,6 +1084,27 @@ bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bW
   return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
 }
 
+const char *CCECProcessor::ToString(const cec_device_type type)
+{
+  switch (type)
+  {
+  case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
+    return "audio system";
+  case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
+    return "playback device";
+  case CEC_DEVICE_TYPE_RECORDING_DEVICE:
+      return "recording device";
+  case CEC_DEVICE_TYPE_RESERVED:
+      return "reserved";
+  case CEC_DEVICE_TYPE_TUNER:
+      return "tuner";
+  case CEC_DEVICE_TYPE_TV:
+      return "TV";
+  default:
+    return "unknown";
+  }
+}
+
 const char *CCECProcessor::ToString(const cec_menu_state state)
 {
   switch (state)
index e2705fd007c1853aa6e31a12789cf25983157f48..8c007b8aeacbbf54fc416d19f34d20a15eb9f135 100644 (file)
@@ -78,6 +78,7 @@ namespace CEC
       virtual bool                  IsStarted(void) const { return m_bStarted; }
       virtual cec_logical_address   GetActiveSource(void);
       virtual bool                  IsActiveSource(cec_logical_address iAddress);
+      virtual bool                  IsInitialised(void) const { return m_bInitialised; }
 
       virtual bool SetActiveView(void);
       virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
@@ -87,7 +88,7 @@ namespace CEC
       virtual bool TransmitInactiveSource(void);
       virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
       virtual bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
-      virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress);
+      virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate = true);
       virtual bool SetActiveSource(uint16_t iStreamPath);
       virtual bool SwitchMonitoring(bool bEnable);
       virtual bool PollDevice(cec_logical_address iAddress);
@@ -102,6 +103,7 @@ namespace CEC
 
       bool SetLineTimeout(uint8_t iTimeout);
 
+      const char *ToString(const cec_device_type type);
       const char *ToString(const cec_menu_state state);
       const char *ToString(const cec_version version);
       const char *ToString(const cec_power_status status);
@@ -123,6 +125,7 @@ namespace CEC
       virtual void AddKey(void);
       virtual void AddLog(cec_log_level level, const CStdString &strMessage);
 
+      virtual bool ChangeDeviceType(cec_device_type from, cec_device_type to);
       virtual bool FindLogicalAddresses(void);
       virtual bool SetAckMask(uint16_t iMask);
 
@@ -133,6 +136,7 @@ namespace CEC
       CMutex         m_transmitMutex;
 
   private:
+      void ReplaceHandlers(void);
       void ScanCECBus(void);
       bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
       bool TryLogicalAddress(cec_logical_address address);
@@ -147,6 +151,7 @@ namespace CEC
       void ParseCommand(cec_command &command);
 
       bool                   m_bStarted;
+      bool                   m_bInitialised;
       uint8_t                m_iHDMIPort;
       cec_logical_address    m_iBaseDevice;
       cec_command            m_currentframe;
index 6279de948712b051e1dd4d2d7eaffa61a2a72380..9e9145c0e76af2f4b2abcd70c60182f189166722 100644 (file)
@@ -50,11 +50,13 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi
   m_powerStatus(CEC_POWER_STATUS_UNKNOWN),
   m_processor(processor),
   m_vendor(CEC_VENDOR_UNKNOWN),
+  m_bReplaceHandler(false),
   m_menuState(CEC_MENU_STATE_ACTIVATED),
   m_bActiveSource(false),
   m_iLastActive(0),
   m_cecVersion(CEC_VERSION_UNKNOWN),
-  m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN)
+  m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN),
+  m_handlerMutex(false)
 {
   m_handler = new CCECCommandHandler(this);
 
@@ -117,7 +119,7 @@ bool CCECBusDevice::PowerOn(void)
   strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
   AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
-  if (m_handler->TransmitPowerOn(GetMyLogicalAddress(), m_iLogicalAddress))
+  if (m_handler->TransmitImageViewOn(GetMyLogicalAddress(), m_iLogicalAddress))
   {
     {
       CLockObject lock(&m_mutex);
@@ -154,24 +156,33 @@ bool CCECBusDevice::Standby(void)
 //@{
 cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
 {
-  CLockObject lock(&m_mutex);
-  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
-      (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN))
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(&m_mutex);
+    bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN));
+  }
+
+  if (bRequestUpdate)
     RequestCecVersion();
 
+  CLockObject lock(&m_mutex);
   return m_cecVersion;
 }
 
 bool CCECBusDevice::RequestCecVersion(void)
 {
   bool bReturn(false);
+
   if (!MyLogicalAddressContains(m_iLogicalAddress))
   {
+    m_handler->MarkBusy();
     CStdString strLog;
     strLog.Format("<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     AddLog(CEC_LOG_NOTICE, strLog);
 
     bReturn = m_handler->TransmitRequestCecVersion(GetMyLogicalAddress(), m_iLogicalAddress);
+    m_handler->MarkReady();
   }
   return bReturn;
 }
@@ -183,28 +194,43 @@ const char* CCECBusDevice::GetLogicalAddressName(void) const
 
 cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
 {
-  CLockObject lock(&m_mutex);
-  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
-      (bUpdate || !strcmp(m_menuLanguage.language, "???")))
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(&m_mutex);
+    bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+        (bUpdate || !strcmp(m_menuLanguage.language, "???")));
+  }
+
+  if (bRequestUpdate)
     RequestMenuLanguage();
 
+  CLockObject lock(&m_mutex);
   return m_menuLanguage;
 }
 
 bool CCECBusDevice::RequestMenuLanguage(void)
 {
   bool bReturn(false);
+
   if (!MyLogicalAddressContains(m_iLogicalAddress) &&
       !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
   {
+    m_handler->MarkBusy();
     CStdString strLog;
     strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     AddLog(CEC_LOG_NOTICE, strLog);
     bReturn = m_handler->TransmitRequestMenuLanguage(GetMyLogicalAddress(), m_iLogicalAddress);
+    m_handler->MarkReady();
   }
   return bReturn;
 }
 
+cec_menu_state CCECBusDevice::GetMenuState(void)
+{
+  CLockObject lock(&m_mutex);
+  return m_menuState;
+}
+
 cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
 {
   return m_processor->GetLogicalAddress();
@@ -217,98 +243,134 @@ uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
 
 CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
 {
-  CLockObject lock(&m_mutex);
-  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
-      (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
-      m_type != CEC_DEVICE_TYPE_TV)
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(&m_mutex);
+    bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+        (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
+        m_type != CEC_DEVICE_TYPE_TV);
+  }
+
+  if (bRequestUpdate)
     RequestOSDName();
 
+  CLockObject lock(&m_mutex);
   return m_strDeviceName;
 }
 
 bool CCECBusDevice::RequestOSDName(void)
 {
   bool bReturn(false);
+
   if (!MyLogicalAddressContains(m_iLogicalAddress) &&
       !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
   {
+    m_handler->MarkBusy();
     CStdString strLog;
     strLog.Format("<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     AddLog(CEC_LOG_NOTICE, strLog);
     bReturn = m_handler->TransmitRequestOSDName(GetMyLogicalAddress(), m_iLogicalAddress);
+    m_handler->MarkReady();
   }
   return bReturn;
 }
 
 uint16_t CCECBusDevice::GetPhysicalAddress(bool bUpdate /* = false */)
 {
-  CLockObject lock(&m_mutex);
-  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
-      (m_iPhysicalAddress == 0xFFFF || bUpdate))
+  bool bRequestUpdate(false);
   {
-    if (!RequestPhysicalAddress())
-      AddLog(CEC_LOG_ERROR, "failed to request the physical address");
+    CLockObject lock(&m_mutex);
+    bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+        (m_iPhysicalAddress == 0xFFFF || bUpdate));
   }
 
+  if (bRequestUpdate && !RequestPhysicalAddress())
+    AddLog(CEC_LOG_ERROR, "failed to request the physical address (1)");
+
+  CLockObject lock(&m_mutex);
   return m_iPhysicalAddress;
 }
 
 bool CCECBusDevice::RequestPhysicalAddress(void)
 {
   bool bReturn(false);
+
   if (!MyLogicalAddressContains(m_iLogicalAddress))
   {
+    m_handler->MarkBusy();
     CStdString strLog;
     strLog.Format("<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     AddLog(CEC_LOG_NOTICE, strLog);
     bReturn = m_handler->TransmitRequestPhysicalAddress(GetMyLogicalAddress(), m_iLogicalAddress);
+    m_handler->MarkReady();
   }
   return bReturn;
 }
 
 cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
 {
-  CLockObject lock(&m_mutex);
-  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
-      (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN))
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(&m_mutex);
+    bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+        (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
+            m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON));
+  }
+
+  if (bRequestUpdate)
     RequestPowerStatus();
 
+  CLockObject lock(&m_mutex);
   return m_powerStatus;
 }
 
 bool CCECBusDevice::RequestPowerStatus(void)
 {
   bool bReturn(false);
+
   if (!MyLogicalAddressContains(m_iLogicalAddress) &&
       !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
   {
+    m_handler->MarkBusy();
     CStdString strLog;
     strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     AddLog(CEC_LOG_NOTICE, strLog);
     bReturn = m_handler->TransmitRequestPowerStatus(GetMyLogicalAddress(), m_iLogicalAddress);
+    m_handler->MarkReady();
   }
   return bReturn;
 }
 
 cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */)
 {
-  CLockObject lock(&m_mutex);
-  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
-      (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN))
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(&m_mutex);
+    bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+        (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+  }
+
+  if (bRequestUpdate)
     RequestVendorId();
 
+  CLockObject lock(&m_mutex);
   return m_vendor;
 }
 
 bool CCECBusDevice::RequestVendorId(void)
 {
   bool bReturn(false);
+
   if (!MyLogicalAddressContains(m_iLogicalAddress))
   {
+    m_handler->MarkBusy();
     CStdString strLog;
     strLog.Format("<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     AddLog(CEC_LOG_NOTICE, strLog);
     bReturn = m_handler->TransmitRequestVendorId(GetMyLogicalAddress(), m_iLogicalAddress);
+    m_handler->MarkReady();
+
+    ReplaceHandler(true);
   }
   return bReturn;
 }
@@ -451,6 +513,12 @@ void CCECBusDevice::SetInactiveSource(void)
 void CCECBusDevice::SetActiveSource(void)
 {
   CLockObject lock(&m_mutex);
+  if (!m_bActiveSource)
+  {
+    CStdString strLog;
+    strLog.Format("making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_DEBUG, strLog);
+  }
 
   for (int iPtr = 0; iPtr < 16; iPtr++)
     if (iPtr != m_iLogicalAddress)
@@ -558,41 +626,63 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
   }
 }
 
-bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */)
+bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
 {
-  bool bVendorChanged(false);
+  CLockObject lock(&m_mutex);
+  CLockObject handlerLock(&m_handlerMutex);
 
+  if (m_vendor != m_handler->GetVendorId())
   {
-    CLockObject lock(&m_mutex);
-    bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
-    m_vendor = (cec_vendor_id)iVendorId;
+    if (CCECCommandHandler::HasSpecificHandler(m_vendor))
+    {
+      CStdString strLog;
+      if (m_handler->InUse())
+      {
+        strLog.Format("handler for device '%s' (%x) is being used. not replacing the command handler", GetLogicalAddressName(), GetLogicalAddress());
+        m_processor->AddLog(CEC_LOG_DEBUG, strLog);
+        return false;
+      }
 
-    if (bVendorChanged)
+      strLog.Format("replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+      m_processor->AddLog(CEC_LOG_DEBUG, strLog);
       delete m_handler;
 
-    switch (iVendorId)
-    {
-    case CEC_VENDOR_SAMSUNG:
-      if (bVendorChanged)
+      switch (m_vendor)
+      {
+      case CEC_VENDOR_SAMSUNG:
         m_handler = new CANCommandHandler(this);
-      break;
-    case CEC_VENDOR_LG:
-      if (bVendorChanged)
+        break;
+      case CEC_VENDOR_LG:
         m_handler = new CSLCommandHandler(this);
-      break;
-    case CEC_VENDOR_PANASONIC:
-      if (bVendorChanged)
+        break;
+      case CEC_VENDOR_PANASONIC:
         m_handler = new CVLCommandHandler(this);
-      break;
-    default:
-      if (bVendorChanged)
+        break;
+      default:
         m_handler = new CCECCommandHandler(this);
-      break;
+        break;
+      }
+
+      m_handler->SetVendorId(m_vendor);
+      m_handler->InitHandler();
+
+      if (bActivateSource && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised() && IsActiveSource())
+        m_handler->ActivateSource();
     }
   }
 
-  if (bVendorChanged && bInitHandler && m_handler->GetVendorId() != CEC_VENDOR_UNKNOWN)
-    m_handler->InitHandler();
+  return true;
+}
+
+bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
+{
+  bool bVendorChanged(false);
+
+  {
+    CLockObject lock(&m_mutex);
+    bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
+    m_vendor = (cec_vendor_id)iVendorId;
+  }
 
   CStdString strLog;
   strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
@@ -631,7 +721,14 @@ bool CCECBusDevice::TransmitActiveSource(void)
     }
   }
 
-  return bSendActiveSource ? m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress) : false;
+  if (bSendActiveSource)
+  {
+    m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+    m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+    return true;
+  }
+
+  return false;
 }
 
 bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
@@ -814,4 +911,11 @@ void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
 {
   m_unsupportedFeatures.insert(opcode);
 }
+
+bool CCECBusDevice::ActivateSource(void)
+{
+  CLockObject lock(&m_mutex);
+  return m_handler->ActivateSource();
+}
+
 //@}
index 0ca662afe471a6c5117321cfc909c3513e725500..6157e0a7448adf81a235d9631fc28b37f5e8718d 100644 (file)
@@ -62,6 +62,7 @@ namespace CEC
     virtual cec_logical_address   GetLogicalAddress(void) const { return m_iLogicalAddress; }
     virtual const char*           GetLogicalAddressName(void) const;
     virtual cec_menu_language &   GetMenuLanguage(bool bUpdate = false);
+    virtual cec_menu_state        GetMenuState(void);
     virtual cec_logical_address   GetMyLogicalAddress(void) const;
     virtual uint16_t              GetMyPhysicalAddress(void) const;
     virtual CStdString            GetOSDName(bool bUpdate = false);
@@ -80,6 +81,7 @@ namespace CEC
     virtual void SetInactiveSource(void);
     virtual void SetActiveSource(void);
     virtual bool TryLogicalAddress(void);
+    virtual bool ActivateSource(void);
 
     virtual void SetDeviceStatus(const cec_bus_device_status newStatus);
     virtual void SetPhysicalAddress(uint16_t iNewAddress);
@@ -88,7 +90,7 @@ namespace CEC
     virtual void SetMenuLanguage(const cec_menu_language &menuLanguage);
     virtual void SetOSDName(CStdString strName);
     virtual void SetMenuState(const cec_menu_state state);
-    virtual bool SetVendorId(uint64_t iVendorId, bool bInitHandler = true);
+    virtual bool SetVendorId(uint64_t iVendorId);
     virtual void SetPowerStatus(const cec_power_status powerStatus);
 
     virtual bool TransmitActiveSource(void);
@@ -105,6 +107,8 @@ namespace CEC
     virtual bool TransmitKeyRelease(bool bWait = true);
 
   protected:
+    bool ReplaceHandler(bool bInitHandler = true);
+
     bool RequestCecVersion(void);
     bool RequestMenuLanguage(void);
     bool RequestPowerStatus(void);
@@ -124,6 +128,7 @@ namespace CEC
     CCECProcessor      *  m_processor;
     CCECCommandHandler *  m_handler;
     cec_vendor_id         m_vendor;
+    bool                  m_bReplaceHandler;
     cec_menu_state        m_menuState;
     bool                  m_bActiveSource;
     uint64_t              m_iLastActive;
@@ -131,5 +136,6 @@ namespace CEC
     cec_bus_device_status m_deviceStatus;
     std::set<cec_opcode>  m_unsupportedFeatures;
     CMutex                m_mutex;
+    CMutex                m_handlerMutex;
   };
 };
index e9674baafb22f84ca8f575d46e407884156cf8a4..248a959368c6eacdf9f6cf470958a5711af720ad 100644 (file)
@@ -40,6 +40,8 @@ using namespace CEC;
 CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
     CCECCommandHandler(busDevice)
 {
+  m_vendorId = CEC_VENDOR_SAMSUNG;
+  m_bOPTSendDeckStatusUpdateOnActiveSource = false;
 }
 
 bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
index 0207a6321f67c435c9d627b66481b0ca320446ee..8966c1a13fb4c986cdcb1e109d3d6da0f1cf700e 100644 (file)
@@ -42,9 +42,6 @@ namespace CEC
     virtual ~CANCommandHandler(void) {};
 
     virtual bool HandleCommand(const cec_command &command);
-
-    virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_SAMSUNG; };
-
   protected:
     virtual bool HandleVendorRemoteButtonDown(const cec_command &command);
   };
index 23fd550b068ea9a2a4ee15550faadb6dbb2faa6e..40b4f07ecda8755a9065b49c18a3c87327c9bfaa 100644 (file)
@@ -45,19 +45,26 @@ CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
     m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
     m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
     m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
-    m_bHandlerInited(false)
+    m_bHandlerInited(false),
+    m_iUseCounter(0),
+    m_expectedResponse(CEC_OPCODE_NONE),
+    m_bOPTSendDeckStatusUpdateOnActiveSource(false),
+    m_vendorId(CEC_VENDOR_UNKNOWN)
 {
 }
 
 CCECCommandHandler::~CCECCommandHandler(void)
 {
+  CLockObject lock(&m_processor->m_transmitMutex);
+  CLockObject receiveLock(&m_receiveMutex);
   m_condition.Broadcast();
 }
 
 bool CCECCommandHandler::HandleCommand(const cec_command &command)
 {
-  bool bHandled(true), bHandlerChanged(false);
+  bool bHandled(true);
 
+  MarkBusy();
   CStdString strLog;
   strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode);
   m_busDevice->AddLog(CEC_LOG_NOTICE, strLog);
@@ -76,49 +83,61 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleSetMenuLanguage(command);
     break;
   case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
-    HandleGivePhysicalAddress(command);
+    if (m_processor->IsInitialised())
+      HandleGivePhysicalAddress(command);
     break;
   case CEC_OPCODE_GIVE_OSD_NAME:
-     HandleGiveOSDName(command);
+    if (m_processor->IsInitialised())
+      HandleGiveOSDName(command);
     break;
   case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-    HandleGiveDeviceVendorId(command);
+    if (m_processor->IsInitialised())
+      HandleGiveDeviceVendorId(command);
     break;
   case CEC_OPCODE_DEVICE_VENDOR_ID:
-    bHandlerChanged = HandleDeviceVendorId(command);
+    HandleDeviceVendorId(command);
     break;
   case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
     HandleDeviceVendorCommandWithId(command);
     break;
   case CEC_OPCODE_GIVE_DECK_STATUS:
-    HandleGiveDeckStatus(command);
+    if (m_processor->IsInitialised())
+      HandleGiveDeckStatus(command);
     break;
   case CEC_OPCODE_DECK_CONTROL:
     HandleDeckControl(command);
     break;
   case CEC_OPCODE_MENU_REQUEST:
-    HandleMenuRequest(command);
+    if (m_processor->IsInitialised())
+      HandleMenuRequest(command);
     break;
   case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-    HandleGiveDevicePowerStatus(command);
+    if (m_processor->IsInitialised())
+      HandleGiveDevicePowerStatus(command);
     break;
   case CEC_OPCODE_GET_CEC_VERSION:
-    HandleGetCecVersion(command);
+    if (m_processor->IsInitialised())
+      HandleGetCecVersion(command);
     break;
   case CEC_OPCODE_USER_CONTROL_PRESSED:
-    HandleUserControlPressed(command);
+    if (m_processor->IsInitialised())
+      HandleUserControlPressed(command);
     break;
   case CEC_OPCODE_USER_CONTROL_RELEASE:
-    HandleUserControlRelease(command);
+    if (m_processor->IsInitialised())
+      HandleUserControlRelease(command);
     break;
   case CEC_OPCODE_GIVE_AUDIO_STATUS:
-    HandleGiveAudioStatus(command);
+    if (m_processor->IsInitialised())
+      HandleGiveAudioStatus(command);
     break;
   case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
-    HandleGiveSystemAudioModeStatus(command);
+    if (m_processor->IsInitialised())
+      HandleGiveSystemAudioModeStatus(command);
     break;
   case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
-    HandleSystemAudioModeRequest(command);
+    if (m_processor->IsInitialised())
+      HandleSystemAudioModeRequest(command);
     break;
   case CEC_OPCODE_REPORT_AUDIO_STATUS:
     HandleReportAudioStatus(command);
@@ -130,7 +149,8 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleSetSystemAudioMode(command);
     break;
   case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
-    HandleRequestActiveSource(command);
+    if (m_processor->IsInitialised())
+      HandleRequestActiveSource(command);
     break;
   case CEC_OPCODE_SET_STREAM_PATH:
     HandleSetStreamPath(command);
@@ -142,7 +162,8 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleRoutingInformation(command);
     break;
   case CEC_OPCODE_STANDBY:
-    HandleStandby(command);
+    if (m_processor->IsInitialised())
+      HandleStandby(command);
     break;
   case CEC_OPCODE_ACTIVE_SOURCE:
     HandleActiveSource(command);
@@ -162,18 +183,24 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
   case CEC_OPCODE_FEATURE_ABORT:
     HandleFeatureAbort(command);
     break;
+  case CEC_OPCODE_VENDOR_COMMAND:
+    HandleVendorCommand(command);
+    break;
   default:
     UnhandledCommand(command);
     bHandled = false;
     break;
   }
 
-  if (bHandled && !bHandlerChanged)
+  if (bHandled)
   {
     CLockObject lock(&m_receiveMutex);
-    m_condition.Signal();
+    if (m_expectedResponse == CEC_OPCODE_NONE ||
+        m_expectedResponse == command.opcode)
+      m_condition.Signal();
   }
 
+  MarkReady();
   return bHandled;
 }
 
@@ -704,12 +731,12 @@ bool CCECCommandHandler::HandleReceiveFailed(void)
   return true;
 }
 
-bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -717,7 +744,7 @@ bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, c
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -725,7 +752,7 @@ bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iIn
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION);
 
-  return Transmit(command);
+  return Transmit(command, true, CEC_OPCODE_CEC_VERSION);
 }
 
 bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -733,7 +760,7 @@ bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address i
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE);
 
-  return Transmit(command);
+  return Transmit(command, true, CEC_OPCODE_SET_MENU_LANGUAGE);
 }
 
 bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -741,7 +768,7 @@ bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iIniti
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME);
 
-  return Transmit(command);
+  return Transmit(command, true, CEC_OPCODE_SET_OSD_NAME);
 }
 
 bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -749,7 +776,7 @@ bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_addres
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
 
-  return Transmit(command);
+  return Transmit(command, true, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
 }
 
 bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -757,7 +784,7 @@ bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iI
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
 
-  return Transmit(command);
+  return Transmit(command, true, CEC_OPCODE_REPORT_POWER_STATUS);
 }
 
 bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -765,7 +792,7 @@ bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInit
   cec_command command;
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
 
-  return Transmit(command);
+  return Transmit(command, true, CEC_OPCODE_DEVICE_VENDOR_ID);
 }
 
 bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
@@ -775,7 +802,7 @@ bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiat
   command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
   command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion)
@@ -784,7 +811,7 @@ bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION);
   command.parameters.PushBack((uint8_t)cecVersion);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
@@ -794,7 +821,7 @@ bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iIniti
   command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF);
   command.parameters.PushBack(iPhysicalAddress & 0xFF);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState)
@@ -803,7 +830,7 @@ bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator,
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS);
   command.parameters.PushBack((uint8_t)menuState);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName)
@@ -813,7 +840,7 @@ bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, c
   for (unsigned int iPtr = 0; iPtr < strDeviceName.length(); iPtr++)
     command.parameters.PushBack(strDeviceName.at(iPtr));
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage)
@@ -828,7 +855,7 @@ bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator,
   for (unsigned int iPtr = 0; iPtr < iLen; iPtr++)
     command.parameters.PushBack(strMessage[iPtr]);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type)
@@ -839,7 +866,7 @@ bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInit
   command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
   command.parameters.PushBack((uint8_t) (type));
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
@@ -856,7 +883,7 @@ bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS);
   command.parameters.PushBack((uint8_t) state);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId)
@@ -868,7 +895,7 @@ bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator,
   command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF));
   command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF));
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state)
@@ -877,7 +904,7 @@ bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiato
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS);
   command.parameters.PushBack(state);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
@@ -886,7 +913,7 @@ bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iI
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
   command.parameters.PushBack((uint8_t)state);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
@@ -895,7 +922,7 @@ bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
   command.parameters.PushBack((uint8_t)state);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state)
@@ -904,7 +931,7 @@ bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator
   cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS);
   command.PushBack((uint8_t)state);
 
-  return Transmit(command);
+  return Transmit(command, false);
 }
 
 bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
@@ -924,23 +951,36 @@ bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator
   return Transmit(command, bWait);
 }
 
-bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */)
+bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */, cec_opcode expectedResponse /* = CEC_OPCODE_NONE */)
 {
+  bool bReturn(false);
+  MarkBusy();
   command.transmit_timeout = m_iTransmitTimeout;
 
-  CLockObject writeLock(&m_processor->m_transmitMutex);
-  CLockObject receiveLock(&m_receiveMutex);
-  if (m_processor->Transmit(command))
   {
-    if (bExpectResponse)
-      return m_condition.Wait(&m_receiveMutex, m_iTransmitWait);
-    return true;
+    uint8_t iTries(0), iMaxTries(command.opcode == CEC_OPCODE_NONE ? 1 : m_iTransmitRetries + 1);
+    CLockObject writeLock(&m_processor->m_transmitMutex);
+    CLockObject receiveLock(&m_receiveMutex);
+    ++m_iUseCounter;
+    while (!bReturn && ++iTries <= iMaxTries)
+    {
+      m_expectedResponse = expectedResponse;
+      if (m_processor->Transmit(command))
+      {
+        m_processor->AddLog(CEC_LOG_DEBUG, "command transmitted");
+        bReturn = bExpectResponse ?
+            m_condition.Wait(&m_receiveMutex, m_iTransmitWait) :
+            true;
+      }
+    }
+    --m_iUseCounter;
   }
 
-  return false;
+  MarkReady();
+  return bReturn;
 }
 
-bool CCECCommandHandler::InitHandler(void)
+bool CCECCommandHandler::ActivateSource(void)
 {
   if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
   {
@@ -957,3 +997,21 @@ bool CCECCommandHandler::InitHandler(void)
   }
   return true;
 }
+
+void CCECCommandHandler::MarkBusy(void)
+{
+  CLockObject receiveLock(&m_receiveMutex);
+  ++m_iUseCounter;
+}
+
+bool CCECCommandHandler::MarkReady(void)
+{
+  CLockObject receiveLock(&m_receiveMutex);
+  return m_iUseCounter > 0 ? (--m_iUseCounter == 0) : true;
+}
+
+bool CCECCommandHandler::InUse(void)
+{
+  CLockObject receiveLock(&m_receiveMutex);
+  return m_iUseCounter > 0;
+}
index 0469b31e0eaf6412360f6ced970c8f4cad619a4e..0e3602d9871a5cecaa929cb21110cacdc472ec9f 100644 (file)
@@ -48,14 +48,17 @@ namespace CEC
     virtual ~CCECCommandHandler(void);
 
     virtual bool HandleCommand(const cec_command &command);
-    virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_UNKNOWN; };
+    virtual cec_vendor_id GetVendorId(void) { return m_vendorId; };
+    virtual void SetVendorId(cec_vendor_id vendorId) { m_vendorId = vendorId; }
     virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
     virtual bool HandleReceiveFailed(void);
+    static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC;}
 
-    virtual bool InitHandler(void);
+    virtual bool InitHandler(void) { return true; }
+    virtual bool ActivateSource(void);
     virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; }
 
-    virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
     virtual bool TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination);
     virtual bool TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination);
     virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination);
@@ -80,6 +83,12 @@ namespace CEC
     virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
     virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true);
 
+    virtual void MarkBusy(void);
+    virtual bool MarkReady(void);
+    virtual bool InUse(void);
+
+    virtual bool SendDeckStatusUpdateOnActiveSource(void) const { return m_bOPTSendDeckStatusUpdateOnActiveSource; };
+
   protected:
     virtual bool HandleActiveSource(const cec_command &command);
     virtual bool HandleDeckControl(const cec_command &command);
@@ -113,6 +122,7 @@ namespace CEC
     virtual bool HandleTextViewOn(const cec_command &command);
     virtual bool HandleUserControlPressed(const cec_command &command);
     virtual bool HandleUserControlRelease(const cec_command &command);
+    virtual bool HandleVendorCommand(const cec_command &command) { return true; }
     virtual void UnhandledCommand(const cec_command &command);
 
     virtual unsigned int GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
@@ -123,7 +133,7 @@ namespace CEC
     virtual bool SetVendorId(const cec_command &command);
     virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
 
-    virtual bool Transmit(cec_command &command, bool bExpectResponse = true);
+    virtual bool Transmit(cec_command &command, bool bExpectResponse = true, cec_opcode expectedResponse = CEC_OPCODE_NONE);
 
     CCECBusDevice *m_busDevice;
     CCECProcessor *m_processor;
@@ -131,6 +141,10 @@ namespace CEC
     int32_t        m_iTransmitWait;
     int8_t         m_iTransmitRetries;
     bool           m_bHandlerInited;
+    uint8_t        m_iUseCounter;
+    cec_opcode     m_expectedResponse;
+    bool           m_bOPTSendDeckStatusUpdateOnActiveSource;
+    cec_vendor_id  m_vendorId;
     CMutex         m_receiveMutex;
     CCondition     m_condition;
   };
index f86a644f2db452804a19baa3c32f4e37fa83d7ba..7a357d319f7d003c5ab086f191448c460016006a 100644 (file)
@@ -35,6 +35,7 @@
 #include "../devices/CECPlaybackDevice.h"
 #include "../CECProcessor.h"
 #include "../platform/timeutils.h"
+#include "../platform/threads.h"
 
 using namespace CEC;
 
@@ -51,10 +52,103 @@ CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
     CCECCommandHandler(busDevice),
     m_bAwaitingReceiveFailed(false),
     m_bSLEnabled(false),
-    m_bVendorIdSent(false)
+    m_bPowerStateReset(false)
 {
-  /* TODO set to powered off until we fixed the connect on start loop issue */
-  m_processor->GetPrimaryDevice()->m_powerStatus = CEC_POWER_STATUS_STANDBY;
+  m_vendorId = CEC_VENDOR_LG;
+  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+
+  /* imitate LG devices */
+  if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+    primary->SetVendorId(CEC_VENDOR_LG);
+  SetLGDeckStatus();
+
+  /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */
+  if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+    m_busDevice->SetCecVersion(CEC_VERSION_1_3A);
+
+  /* LG devices always return "korean" as language */
+  cec_menu_language lang;
+  lang.device = m_busDevice->GetLogicalAddress();
+  snprintf(lang.language, 4, "eng");
+  m_busDevice->SetMenuLanguage(lang);
+}
+
+
+void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  CCECCommandHandler::HandlePoll(iInitiator, iDestination);
+  m_bAwaitingReceiveFailed = true;
+}
+
+bool CSLCommandHandler::HandleReceiveFailed(void)
+{
+  if (m_bAwaitingReceiveFailed)
+  {
+    m_bAwaitingReceiveFailed = false;
+    return false;
+  }
+
+  return true;
+}
+
+bool CSLCommandHandler::InitHandler(void)
+{
+  if (m_bHandlerInited)
+    return true;
+  m_bHandlerInited = true;
+
+  /* reply with LGs vendor id */
+  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+  if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+    primary->TransmitVendorID(CECDEVICE_TV, false);
+
+  primary->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+  return true;
+}
+
+bool CSLCommandHandler::ActivateSource(void)
+{
+  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+  primary->SetActiveSource();
+  primary->TransmitActiveSource();
+  return true;
+}
+
+bool CSLCommandHandler::HandleActiveSource(const cec_command &command)
+{
+  if (command.parameters.size == 2)
+  {
+    uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+    if (iAddress != m_busDevice->GetPhysicalAddress(false))
+      m_bSLEnabled = false;
+    return m_processor->SetActiveSource(iAddress);
+  }
+
+  return true;
+}
+
+bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
+{
+  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+  if (primary->GetPowerStatus(false) == CEC_POWER_STATUS_ON && !m_bPowerStateReset && !m_bSLEnabled)
+  {
+    m_bPowerStateReset = true;
+    primary->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+  }
+
+  return CCECCommandHandler::HandleFeatureAbort(command);
+}
+
+bool CSLCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
+{
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device)
+      return device->TransmitPhysicalAddress();
+  }
+
+  return false;
 }
 
 bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
@@ -87,23 +181,6 @@ bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
   return false;
 }
 
-bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
-{
-  if (command.parameters.size == 1)
-  {
-    if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE ||
-        command.parameters[0] == CEC_STATUS_REQUEST_ON)
-    {
-      TransmitDeckStatus(command.initiator);
-    }
-    else
-    {
-      CCECCommandHandler::HandleGiveDeckStatus(command);
-    }
-  }
-  return true;
-}
-
 void CSLCommandHandler::HandleVendorCommand01(const cec_command &command)
 {
   TransmitVendorCommand0205(command.destination, command.initiator);
@@ -116,17 +193,7 @@ void CSLCommandHandler::TransmitVendorCommand0205(const cec_logical_address iSou
   response.PushBack(SL_COMMAND_UNKNOWN_02);
   response.PushBack(SL_COMMAND_UNKNOWN_03);
 
-  Transmit(response);
-}
-
-void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination)
-{
-  m_bSLEnabled = true;
-  cec_command response;
-  cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
-  response.PushBack(SL_COMMAND_CONNECT_ACCEPT);
-  response.PushBack((uint8_t)iSource);
-  Transmit(response);
+  Transmit(response, false);
 }
 
 void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
@@ -135,22 +202,16 @@ void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
   if (device)
   {
     m_bSLEnabled = true;
-    device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+
+    device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); //XXX
     device->TransmitPowerState(command.initiator);
-    device->TransmitVendorID(command.initiator);
-    TransmitPowerOn(device->GetLogicalAddress(), command.initiator);
-  }
-}
+    device->SetPowerStatus(CEC_POWER_STATUS_ON);
 
-void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
-{
-  m_bSLEnabled = true;
-  m_processor->m_busDevices[command.initiator]->SetActiveSource();
-  m_processor->m_busDevices[command.destination]->TransmitActiveSource();
-  TransmitVendorCommand05(command.destination, command.initiator);
-  TransmitDeckStatus(command.initiator);
+    SetLGDeckStatus();
+    device->SetActiveSource();
+    TransmitImageViewOn(device->GetLogicalAddress(), command.initiator);
+  }
 }
-
 void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &command)
 {
   if (command.destination != CECDEVICE_BROADCAST)
@@ -162,159 +223,35 @@ void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &comm
   }
 }
 
-void CSLCommandHandler::TransmitDeckStatus(const cec_logical_address iDestination)
+void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
 {
-  /* set deck status for the playback device */
+  m_bSLEnabled = true;
+  SetLGDeckStatus();
+
   CCECBusDevice *primary = m_processor->GetPrimaryDevice();
-  if (primary->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
-  {
-    ((CCECPlaybackDevice *)primary)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
-    ((CCECPlaybackDevice *)primary)->TransmitDeckStatus(iDestination);
-  }
+
+  primary->SetActiveSource();
+  TransmitImageViewOn(primary->GetLogicalAddress(), command.initiator);
+  TransmitVendorCommand05(primary->GetLogicalAddress(), command.initiator);
 }
 
-bool CSLCommandHandler::TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination)
 {
   cec_command response;
-  cec_command::Format(response, iInitiator, iDestination, CEC_OPCODE_DEVICE_VENDOR_ID);
-  response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 16) & 0xFF));
-  response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 8) & 0xFF));
-  response.parameters.PushBack((uint8_t) ((uint64_t)CEC_VENDOR_LG & 0xFF));
-
-  Transmit(response);
-  return true;
+  cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+  response.PushBack(SL_COMMAND_CONNECT_ACCEPT);
+  response.PushBack((uint8_t)iSource);
+  Transmit(response, false);
 }
 
-bool CSLCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
+void CSLCommandHandler::SetLGDeckStatus(void)
 {
-  /* imitate LG devices */
-  CCECBusDevice *device = GetDevice(command.destination);
+  /* LG TVs only route keypresses when the deck status is set to 0x20 */
+  CCECBusDevice *device = m_processor->GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
   if (device)
-    device->SetVendorId(CEC_VENDOR_LG);
-
-  return CCECCommandHandler::HandleGiveDeviceVendorId(command);
-}
-
-bool CSLCommandHandler::HandleCommand(const cec_command &command)
-{
-  bool bHandled(false);
-
-  if (m_processor->IsStarted() && (m_busDevice->MyLogicalAddressContains(command.destination) ||
-      command.destination == CECDEVICE_BROADCAST))
-  {
-    switch(command.opcode)
-    {
-    case CEC_OPCODE_VENDOR_COMMAND:
-      bHandled = HandleVendorCommand(command);
-      break;
-    case CEC_OPCODE_FEATURE_ABORT:
-      {
-        if (!m_bVendorIdSent)
-        {
-          m_bVendorIdSent = true;
-          TransmitLGVendorId(m_processor->GetLogicalAddresses().primary, CECDEVICE_BROADCAST);
-        }
-      }
-      bHandled = true;
-    default:
-      break;
-    }
-  }
-
-  if (!bHandled)
-    bHandled = CCECCommandHandler::HandleCommand(command);
-
-  return bHandled;
-}
-
-void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
-{
-  CCECCommandHandler::HandlePoll(iInitiator, iDestination);
-  m_bAwaitingReceiveFailed = true;
-}
-
-bool CSLCommandHandler::HandleReceiveFailed(void)
-{
-  if (m_bAwaitingReceiveFailed)
-  {
-    m_bAwaitingReceiveFailed = false;
-    return false;
-  }
-
-  return true;
-}
-
-bool CSLCommandHandler::InitHandler(void)
-{
-  if (m_bHandlerInited)
-    return true;
-  m_bHandlerInited = true;
+    ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
 
-  m_processor->SetStandardLineTimeout(3);
-  m_processor->SetRetryLineTimeout(3);
-
-  /* increase the number of retries because the tv is keeping the bus busy at times */
-  m_iTransmitWait    = 2000;
-  m_iTransmitRetries = 4;
-  m_iTransmitTimeout = 500;
-
-  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
-  if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
-  {
-    primary->SetVendorId(CEC_VENDOR_LG, false);
-    primary->TransmitVendorID(CECDEVICE_TV, false);
-  }
-
-  if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
-  {
-    /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */
-    m_busDevice->SetCecVersion(CEC_VERSION_1_3A);
-  }
-
-  /* LG devices always return "korean" as language */
-  cec_menu_language lang;
-  lang.device = m_busDevice->GetLogicalAddress();
-  snprintf(lang.language, 4, "eng");
-  m_busDevice->SetMenuLanguage(lang);
-
-  if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
-  {
-    m_processor->SetActiveSource();
-
-    /* LG TVs only route keypresses when the deck status is set to 0x20 */
-    cec_logical_addresses addr = m_processor->GetLogicalAddresses();
-    for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
-    {
-      CCECBusDevice *device = m_processor->m_busDevices[iPtr];
-
-      if (addr[iPtr])
-      {
-        if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
-                       device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
-        {
-          ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
-          ((CCECPlaybackDevice *)device)->TransmitDeckStatus(CECDEVICE_TV);
-        }
-      }
-    }
-  }
-
-  return true;
-}
-
-bool CSLCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
-{
-  if (iDestination != CECDEVICE_BROADCAST &&
-      iDestination != CECDEVICE_TV &&
-      m_processor->m_busDevices[iDestination]->GetVendorId(false) == CEC_VENDOR_LG)
-  {
-    cec_command command;
-    cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_VENDOR_COMMAND);
-    command.parameters.PushBack((uint8_t)SL_COMMAND_POWER_ON);
-    command.parameters.PushBack(0x00);
-    return Transmit(command);
-  }
-
-  return CCECCommandHandler::TransmitPowerOn(iInitiator, iDestination);
+  device = m_processor->GetDeviceByType(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+  if (device)
+    ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
 }
-
index 3a5a779e5195340898b6b08dd6b0a045f98a7086..e398dc878d84af2030526b715a3835abaca45221 100644 (file)
@@ -40,30 +40,32 @@ namespace CEC
   public:
     CSLCommandHandler(CCECBusDevice *busDevice);
     virtual ~CSLCommandHandler(void) {};
-    virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_LG; };
 
-    virtual bool HandleCommand(const cec_command &command);
     virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
     virtual bool HandleReceiveFailed(void);
+
     virtual bool InitHandler(void);
-    virtual bool TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination);
-    virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool ActivateSource(void);
 
   protected:
+    virtual bool HandleActiveSource(const cec_command &command);
+    virtual bool HandleFeatureAbort(const cec_command &command);
+    virtual bool HandleGivePhysicalAddress(const cec_command &command);
+    virtual bool HandleVendorCommand(const cec_command &command);
+
     virtual void HandleVendorCommand01(const cec_command &command);
+    virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
+
     virtual void HandleVendorCommandPowerOn(const cec_command &command);
-    virtual void HandleVendorCommandSLConnect(const cec_command &command);
     virtual void HandleVendorCommandPowerOnStatus(const cec_command &command);
 
-    virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
+    virtual void HandleVendorCommandSLConnect(const cec_command &command);
     virtual void TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination);
-    virtual void TransmitDeckStatus(const cec_logical_address iDestination);
-    virtual bool HandleGiveDeviceVendorId(const cec_command &command);
-    virtual bool HandleVendorCommand(const cec_command &command);
-    virtual bool HandleGiveDeckStatus(const cec_command &command);
+
+    virtual void SetLGDeckStatus(void);
 
     bool    m_bAwaitingReceiveFailed;
     bool    m_bSLEnabled;
-    bool    m_bVendorIdSent;
+    bool    m_bPowerStateReset;
   };
 };
index fbbfa290c9b021690eca84182f97f1737d783257..f0d59dbb0644b2bb3cae4f86d0a4f7d9910f40e6 100644 (file)
 
 #include "VLCommandHandler.h"
 #include "../devices/CECBusDevice.h"
-#include "../util/StdString.h"
+#include "../CECProcessor.h"
 
 using namespace CEC;
 
 CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) :
     CCECCommandHandler(busDevice)
 {
+  m_vendorId = CEC_VENDOR_PANASONIC;
+}
+
+bool CVLCommandHandler::InitHandler(void)
+{
+  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+  if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+  {
+    return m_processor->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+  }
+  return CCECCommandHandler::InitHandler();
 }
index 3959ad79b1f2a3ba6ea8ea6d508aebb9d3796e29..cff1da4dfcdf3eb4aaad5966713fbdea614698eb 100644 (file)
@@ -40,6 +40,6 @@ namespace CEC
   public:
     CVLCommandHandler(CCECBusDevice *busDevice);
     virtual ~CVLCommandHandler(void) {};
-    virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_PANASONIC; };
+    virtual bool InitHandler(void);
   };
 };
index 9ea0008e713f81065aed63d85194e24eafad79a0..d168e906a671ddc8e0caab582c9ae30a58bd2853 100644 (file)
@@ -35,9 +35,9 @@
 
 using namespace CEC;
 
-CMutex::CMutex(void)
+CMutex::CMutex(bool bRecursive /* = true */)
 {
-  pthread_mutex_init(&m_mutex, GetMutexAttribute());
+  pthread_mutex_init(&m_mutex, bRecursive ? GetMutexAttribute() : NULL);
 }
 
 CMutex::~CMutex(void)
index 6b0b870cf85351dd92f56506cbc72f9a4566dc93..a258081ccef8bbdf6a5bc8f33826fbaf26ae6c84 100644 (file)
@@ -56,7 +56,7 @@ namespace CEC
   class CMutex
   {
   public:
-    CMutex(void);
+    CMutex(bool bRecursive = true);
     virtual ~CMutex(void);
 
     bool TryLock(void);
diff --git a/support/cec-test-device.sh b/support/cec-test-device.sh
new file mode 100755 (executable)
index 0000000..d00b483
--- /dev/null
@@ -0,0 +1,123 @@
+#!/bin/bash
+
+## Tests whether the USB-CEC adapter can be accessed correctly
+## Copyright (C) 2011 Pulse-Eight Ltd.
+
+check_lsusb()
+{
+  echo -n "  * searching USB device:             "
+  adapters_found=`lsusb | grep 2548:1001 | wc -l`
+  if [ "x${adapters_found}" = "x0" ]; then
+    echo "NOT FOUND"
+    return 1
+  else
+    echo "ok"
+    return 0
+  fi
+}
+
+check_acm_module()
+{
+  echo -n "  * checking for CDC-ACM support:     "
+  acm_found=`grep cdc_acm /proc/modules | wc -l`
+  if [ "x${acm_found}" = "x0" ]; then
+    echo "NOT LOADED"
+    return 1
+  else
+    echo "ok"
+    return 0
+  fi
+}
+
+check_acm_file()
+{
+  echo -n "  * checking for CDC-ACM node:        "
+  acm_found=`ls /dev/ttyACM* | wc -l`
+  if [ "x${acm_found}" = "x0" ]; then
+    echo "NOT FOUND"
+    return 1
+  else
+    echo "ok"
+    return 0
+  fi
+}
+
+check_cec_client_dev()
+{
+  echo -n "  * checking cec-client:              "
+  cec_client=`cec-client -l | grep 'Found devices' | awk '{print \$3}'`
+  if [ -z "${cec_client}" ]; then
+    echo "ERROR"
+  elif [ "x${cec_client}" = "xNONE" ]; then
+    echo "NO DEVICES FOUND"
+  else
+    echo "ok"
+  fi
+}
+
+check_poll_tv()
+{
+  echo -n "  * trying to poll the TV:            "
+  cec_client=`echo 'poll 0' | cec-client -t p -p 1 -d 1 -s | tail -n1 | grep 'POLL'`
+  if [ -z "${cec_client}" ]; then
+    echo "ERROR"
+  elif [ "x${cec_client}" = "xPOLL message sent" ]; then
+    echo "ok"
+  else
+    echo "COULD NOT POLL THE TV"
+  fi
+}
+
+check_tv_vendor()
+{
+  echo -n "  * vendor id of the TV:              "
+  cec_client=`echo 'ven 0' | cec-client -t p -p 1 -d 1 -s | tail -n1 | grep 'vendor' | awk '{print \$3}'`
+  if [ -z "${cec_client}" ]; then
+    echo "ERROR"
+  else
+    echo "${cec_client}"
+  fi
+}
+
+check_tv_power()
+{
+  echo -n "  * power status of the TV:           "
+  cec_client=`echo 'pow 0' | cec-client -t p -p 1 -d 1 -s | tail -n1 | grep 'power' | awk '{print \$3}'`
+  if [ -z "${cec_client}" ]; then
+    echo "ERROR"
+  else
+    echo "${cec_client}"
+  fi
+}
+
+check_tv_lang()
+{
+  echo -n "  * language of the TV:               "
+  cec_client=`echo 'lang 0' | cec-client -t p -p 1 -d 1 -s | tail -n1 | grep 'language' | awk '{print \$3}'`
+  if [ -z "${cec_client}" ]; then
+    echo "ERROR"
+  else
+    echo "${cec_client}"
+  fi
+}
+
+send_power_off()
+{
+  echo -n "  * powering off the TV:              "
+  cec_client=`echo 'standby 0' | cec-client -t p -p 1 -d 1 -s | tail -n1`
+  echo "ok"
+}
+
+echo "Pulse-Eight USB-CEC Adapter tester v0.1"
+echo ""
+
+check_lsusb
+check_acm_module
+check_acm_file
+check_cec_client_dev
+check_poll_tv
+check_tv_vendor
+check_tv_power
+check_tv_lang
+send_power_off
+