Resolve difference between method name in LibCECC.cpp and cecc.h.
+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:
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.
* 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.
+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:
[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("")]
// 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")]
[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("")];
// 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)];
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
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),
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),
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
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);
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);
while (!IsStopped())
{
+ ReplaceHandlers();
command.Clear();
msg.clear();
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);
}
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;
uint16_t iPhysicalAddress(0);
if (iBaseDevice > CECDEVICE_TV)
+ {
+ lock.Leave();
iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
+ lock.Lock();
+ }
if (iPhysicalAddress < 0xffff)
{
bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
{
+ CLockObject lock(&m_mutex);
if (m_logicalAddresses.primary != iLogicalAddress)
{
CStdString strLog;
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;
}
{
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;
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)
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);
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);
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);
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);
CMutex m_transmitMutex;
private:
+ void ReplaceHandlers(void);
void ScanCECBus(void);
bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
bool TryLogicalAddress(cec_logical_address address);
void ParseCommand(cec_command &command);
bool m_bStarted;
+ bool m_bInitialised;
uint8_t m_iHDMIPort;
cec_logical_address m_iBaseDevice;
cec_command m_currentframe;
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);
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);
//@{
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;
}
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();
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;
}
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)
}
}
-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);
}
}
- 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)
{
m_unsupportedFeatures.insert(opcode);
}
+
+bool CCECBusDevice::ActivateSource(void)
+{
+ CLockObject lock(&m_mutex);
+ return m_handler->ActivateSource();
+}
+
//@}
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);
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);
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);
virtual bool TransmitKeyRelease(bool bWait = true);
protected:
+ bool ReplaceHandler(bool bInitHandler = true);
+
bool RequestCecVersion(void);
bool RequestMenuLanguage(void);
bool RequestPowerStatus(void);
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;
cec_bus_device_status m_deviceStatus;
std::set<cec_opcode> m_unsupportedFeatures;
CMutex m_mutex;
+ CMutex m_handlerMutex;
};
};
CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
CCECCommandHandler(busDevice)
{
+ m_vendorId = CEC_VENDOR_SAMSUNG;
+ m_bOPTSendDeckStatusUpdateOnActiveSource = false;
}
bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
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);
};
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);
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);
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);
HandleRoutingInformation(command);
break;
case CEC_OPCODE_STANDBY:
- HandleStandby(command);
+ if (m_processor->IsInitialised())
+ HandleStandby(command);
break;
case CEC_OPCODE_ACTIVE_SOURCE:
HandleActiveSource(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;
}
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 */)
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)
{
}
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;
+}
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);
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);
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;
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;
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;
};
#include "../devices/CECPlaybackDevice.h"
#include "../CECProcessor.h"
#include "../platform/timeutils.h"
+#include "../platform/threads.h"
using namespace CEC;
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)
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);
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)
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)
}
}
-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);
}
-
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;
};
};
#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();
}
public:
CVLCommandHandler(CCECBusDevice *busDevice);
virtual ~CVLCommandHandler(void) {};
- virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_PANASONIC; };
+ virtual bool InitHandler(void);
};
};
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)
class CMutex
{
public:
- CMutex(void);
+ CMutex(bool bRecursive = true);
virtual ~CMutex(void);
bool TryLock(void);
--- /dev/null
+#!/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
+