From: Lars Op den Kamp Date: Tue, 3 Jan 2012 23:59:54 +0000 (+0100) Subject: Merge branch 'master' into release X-Git-Tag: upstream/2.2.0~1^2~42 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=2b2767288398d6cdcbe1201a8b52ef515a5f6591;hp=fe0cd8aa72091d860ad374abcbc0d8217f25ba69;p=deb_libcec.git Merge branch 'master' into release --- diff --git a/ChangeLog b/ChangeLog index 26e7662..7bd4547 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +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 Thu, 3 Jan 2012 22:48:00 +0100 + libcec (1.3-2) unstable; urgency=low * changed/added: diff --git a/README b/README index 5ef90e3..230054a 100644 --- 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. diff --git a/debian/changelog b/debian/changelog index 26e7662..7bd4547 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,29 @@ +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 Thu, 3 Jan 2012 22:48:00 +0100 + libcec (1.3-2) unstable; urgency=low * changed/added: diff --git a/project/libcec.rc b/project/libcec.rc index afac3b1..e18b9a3 100644 Binary files a/project/libcec.rc and b/project/libcec.rc differ diff --git a/project/testclient.rc b/project/testclient.rc index e21afdc..339801b 100644 Binary files a/project/testclient.rc and b/project/testclient.rc differ diff --git a/src/CecSharpTester/AssemblyInfo.cs b/src/CecSharpTester/AssemblyInfo.cs index 5bddf86..73ffc39 100644 --- a/src/CecSharpTester/AssemblyInfo.cs +++ b/src/CecSharpTester/AssemblyInfo.cs @@ -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.3.1.0")] -[assembly: AssemblyFileVersion("1.3.1.0")] +[assembly: AssemblyVersion("1.3.2.0")] +[assembly: AssemblyFileVersion("1.3.2.0")] diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp index 459ae9f..0624b82 100644 --- a/src/LibCecSharp/AssemblyInfo.cpp +++ b/src/LibCecSharp/AssemblyInfo.cpp @@ -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)]; diff --git a/src/lib/AdapterDetection.cpp b/src/lib/AdapterDetection.cpp index b304e43..de1da7c 100644 --- a/src/lib/AdapterDetection.cpp +++ b/src/lib/AdapterDetection.cpp @@ -50,8 +50,10 @@ static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; #elif defined(HAVE_LIBUDEV) #include -#include #include +extern "C" { +#include +} #endif #define CEC_VID 0x2548 diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 6af0664..5071ec6 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -170,22 +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_bInitialised = true; - m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true; - bReturn = m_busDevices[CECDEVICE_TV]->InitHandler(); - } - - if (bReturn) - { m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); } else @@ -239,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); @@ -349,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); } @@ -424,14 +497,12 @@ 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); + CLockObject lock(&m_mutex); - m_iBaseDevice = iBaseDevice; - m_iHDMIPort = iPort; - if (!m_bStarted && !bForce) - return true; - } + m_iBaseDevice = iBaseDevice; + m_iHDMIPort = iPort; + if (!m_bStarted && !bForce) + return true; CStdString strLog; strLog.Format("setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice); @@ -439,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) { @@ -524,19 +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; } @@ -1005,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) diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 13243ab..8c007b8 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -88,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); @@ -103,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); @@ -124,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); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index bd68dfc..9e9145c 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -176,11 +176,13 @@ bool CCECBusDevice::RequestCecVersion(void) 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; } @@ -213,14 +215,22 @@ bool CCECBusDevice::RequestMenuLanguage(void) 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(); @@ -255,10 +265,12 @@ bool CCECBusDevice::RequestOSDName(void) 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; } @@ -285,10 +297,12 @@ bool CCECBusDevice::RequestPhysicalAddress(void) 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; } @@ -317,10 +331,12 @@ bool CCECBusDevice::RequestPowerStatus(void) 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; } @@ -347,10 +363,14 @@ bool CCECBusDevice::RequestVendorId(void) 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; } @@ -493,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) @@ -600,42 +626,55 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) } } -bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */) +bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */) { CLockObject lock(&m_mutex); CLockObject handlerLock(&m_handlerMutex); if (m_vendor != m_handler->GetVendorId()) { - if (m_handler->InUse()) - return false; + 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; + } - delete m_handler; + strLog.Format("replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress()); + m_processor->AddLog(CEC_LOG_DEBUG, strLog); + delete m_handler; - switch (m_vendor) - { - case CEC_VENDOR_SAMSUNG: - m_handler = new CANCommandHandler(this); - break; - case CEC_VENDOR_LG: - m_handler = new CSLCommandHandler(this); - break; - case CEC_VENDOR_PANASONIC: - m_handler = new CVLCommandHandler(this); - break; - default: - m_handler = new CCECCommandHandler(this); - break; - } + switch (m_vendor) + { + case CEC_VENDOR_SAMSUNG: + m_handler = new CANCommandHandler(this); + break; + case CEC_VENDOR_LG: + m_handler = new CSLCommandHandler(this); + break; + case CEC_VENDOR_PANASONIC: + m_handler = new CVLCommandHandler(this); + break; + default: + m_handler = new CCECCommandHandler(this); + break; + } - if (bInitHandler && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised()) + m_handler->SetVendorId(m_vendor); m_handler->InitHandler(); + + if (bActivateSource && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised() && IsActiveSource()) + m_handler->ActivateSource(); + } } return true; } -bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */) +bool CCECBusDevice::SetVendorId(uint64_t iVendorId) { bool bVendorChanged(false); @@ -643,7 +682,6 @@ bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true CLockObject lock(&m_mutex); bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId); m_vendor = (cec_vendor_id)iVendorId; - ReplaceHandler(bInitHandler); } CStdString strLog; @@ -874,10 +912,10 @@ void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode) m_unsupportedFeatures.insert(opcode); } -bool CCECBusDevice::InitHandler(void) +bool CCECBusDevice::ActivateSource(void) { CLockObject lock(&m_mutex); - return m_handler->InitHandler(); + return m_handler->ActivateSource(); } //@} diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 30d8329..6157e0a 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -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,7 +81,7 @@ namespace CEC virtual void SetInactiveSource(void); virtual void SetActiveSource(void); virtual bool TryLogicalAddress(void); - virtual bool InitHandler(void); + virtual bool ActivateSource(void); virtual void SetDeviceStatus(const cec_bus_device_status newStatus); virtual void SetPhysicalAddress(uint16_t iNewAddress); @@ -89,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); diff --git a/src/lib/implementations/ANCommandHandler.cpp b/src/lib/implementations/ANCommandHandler.cpp index e9674ba..248a959 100644 --- a/src/lib/implementations/ANCommandHandler.cpp +++ b/src/lib/implementations/ANCommandHandler.cpp @@ -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) diff --git a/src/lib/implementations/ANCommandHandler.h b/src/lib/implementations/ANCommandHandler.h index 0207a63..8966c1a 100644 --- a/src/lib/implementations/ANCommandHandler.h +++ b/src/lib/implementations/ANCommandHandler.h @@ -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); }; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 74f7648..40b4f07 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -47,7 +47,9 @@ CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) : m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES), m_bHandlerInited(false), m_iUseCounter(0), - m_expectedResponse(CEC_OPCODE_NONE) + m_expectedResponse(CEC_OPCODE_NONE), + m_bOPTSendDeckStatusUpdateOnActiveSource(false), + m_vendorId(CEC_VENDOR_UNKNOWN) { } @@ -60,7 +62,7 @@ CCECCommandHandler::~CCECCommandHandler(void) bool CCECCommandHandler::HandleCommand(const cec_command &command) { - bool bHandled(true), bHandlerChanged(false); + bool bHandled(true); MarkBusy(); CStdString strLog; @@ -81,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); @@ -135,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); @@ -147,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); @@ -176,7 +192,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) break; } - if (bHandled && !bHandlerChanged) + if (bHandled) { CLockObject lock(&m_receiveMutex); if (m_expectedResponse == CEC_OPCODE_NONE || @@ -938,6 +954,7 @@ bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */, cec_opcode expectedResponse /* = CEC_OPCODE_NONE */) { bool bReturn(false); + MarkBusy(); command.transmit_timeout = m_iTransmitTimeout; { @@ -959,10 +976,11 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* --m_iUseCounter; } + MarkReady(); return bReturn; } -bool CCECCommandHandler::InitHandler(void) +bool CCECCommandHandler::ActivateSource(void) { if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) { diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index c99d569..0e3602d 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -48,11 +48,14 @@ 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 TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); @@ -84,6 +87,8 @@ namespace CEC 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); @@ -138,6 +143,8 @@ namespace CEC 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; }; diff --git a/src/lib/implementations/SLCommandHandler.cpp b/src/lib/implementations/SLCommandHandler.cpp index bc302aa..7a357d3 100644 --- a/src/lib/implementations/SLCommandHandler.cpp +++ b/src/lib/implementations/SLCommandHandler.cpp @@ -54,11 +54,12 @@ CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) : m_bSLEnabled(false), m_bPowerStateReset(false) { + m_vendorId = CEC_VENDOR_LG; CCECBusDevice *primary = m_processor->GetPrimaryDevice(); /* imitate LG devices */ if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) - primary->SetVendorId(CEC_VENDOR_LG, false); + primary->SetVendorId(CEC_VENDOR_LG); SetLGDeckStatus(); /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */ @@ -105,6 +106,14 @@ bool CSLCommandHandler::InitHandler(void) 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) diff --git a/src/lib/implementations/SLCommandHandler.h b/src/lib/implementations/SLCommandHandler.h index 48674cc..e398dc8 100644 --- a/src/lib/implementations/SLCommandHandler.h +++ b/src/lib/implementations/SLCommandHandler.h @@ -40,11 +40,12 @@ namespace CEC public: CSLCommandHandler(CCECBusDevice *busDevice); virtual ~CSLCommandHandler(void) {}; - virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_LG; }; virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool HandleReceiveFailed(void); + virtual bool InitHandler(void); + virtual bool ActivateSource(void); protected: virtual bool HandleActiveSource(const cec_command &command); diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index fbbfa29..f0d59db 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -32,11 +32,22 @@ #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(); } diff --git a/src/lib/implementations/VLCommandHandler.h b/src/lib/implementations/VLCommandHandler.h index 3959ad7..cff1da4 100644 --- a/src/lib/implementations/VLCommandHandler.h +++ b/src/lib/implementations/VLCommandHandler.h @@ -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); }; }; diff --git a/support/cec-test-device.sh b/support/cec-test-device.sh new file mode 100755 index 0000000..d00b483 --- /dev/null +++ b/support/cec-test-device.sh @@ -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 +