+libcec (1.6-4) unstable; urgency=low
+
+ * changed/added:
+ * serial port locking on linux
+ * cec-client: added -m/--monitor startup options, which will start a
+ monitor-only client. use 'mon 0' to switch to a normal client
+ * display an alert message when the firmware of the adapter can be upgraded
+ * added CEC 1.4 opcodes
+ * send a feature abort again for all unhandled commands
+ * refactored CLibCEC so a client registers itself within CCECProcessor,
+ which then allocates one or more logical addresses for it.
+
+ * interface changes:
+ * added a new setting, bMonitorOnly, which will start a monitor-only client
+
+ * fixed:
+ * ensure that we don't crash out when trying to stop a thread that hasn't
+ been started yet
+ * don't send a 'disconnected' alert when the close method is called
+ * use the correct source when transmitting an abort message as a reposonse
+ to a vendor command with id
+ * removed statics
+ * check the client version, not the server version in
+ libcec_configuration::operator==()
+ * cec-config: fix physical address detection
+ * LibCecSharp: fixed buffer overrun when copying libcec_configuration.
+ fixes crash when trying to save the configuration in the config gui.
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Mon, 14 May 2012 22:39:00 +0100
+
libcec (1.6-3) unstable; urgency=low
* changed/added:
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
+* liblockdev 1.0 or later
To compile libCEC on Linux, you'll need the following dependencies:
* autoconf 2.13 or later
* libtool
* udev development headers v151 or later
* gcc 4.2 or later
+* liblockdev 1.0 development headers
To compile, execute the following commands:
# autoreconf -vif
case "${host}" in
*-*-linux*)
PKG_CHECK_MODULES([UDEV],[libudev],,[has_libudev="no"]; AC_MSG_WARN("library 'udev' is missing - adapter detection will not be available"))
- LIBS+=" -lrt"
+ AC_CHECK_HEADER(lockdev.h,, AC_MSG_ERROR("required library 'liblockdev' is missing"))
+ LIBS+=" -lrt -llockdev"
;;
*-apple-darwin*)
has_libudev="no";
+libcec (1.6-4) unstable; urgency=low
+
+ * changed/added:
+ * serial port locking on linux
+ * cec-client: added -m/--monitor startup options, which will start a
+ monitor-only client. use 'mon 0' to switch to a normal client
+ * display an alert message when the firmware of the adapter can be upgraded
+ * added CEC 1.4 opcodes
+ * send a feature abort again for all unhandled commands
+ * refactored CLibCEC so a client registers itself within CCECProcessor,
+ which then allocates one or more logical addresses for it.
+
+ * interface changes:
+ * added a new setting, bMonitorOnly, which will start a monitor-only client
+
+ * fixed:
+ * ensure that we don't crash out when trying to stop a thread that hasn't
+ been started yet
+ * don't send a 'disconnected' alert when the close method is called
+ * use the correct source when transmitting an abort message as a reposonse
+ to a vendor command with id
+ * removed statics
+ * check the client version, not the server version in
+ libcec_configuration::operator==()
+ * cec-config: fix physical address detection
+ * LibCecSharp: fixed buffer overrun when copying libcec_configuration.
+ fixes crash when trying to save the configuration in the config gui.
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Mon, 14 May 2012 22:39:00 +0100
+
libcec (1.6-3) unstable; urgency=low
* changed/added:
Section: video
Priority: extra
Maintainer: Lars Op den Kamp <lars.opdenkamp@pulse-eight.com>
-Build-Depends: debhelper (>= 7), libudev-dev, mime-support, locales, gawk, autotools-dev, autoconf, automake, pkg-config
+Build-Depends: debhelper (>= 7), libudev-dev, mime-support, locales, gawk, autotools-dev, autoconf, automake, pkg-config, liblockdev1-dev
Standards-Version: 3.8.3
Homepage: http://www.pulse-eight.net/
Package: libcec
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
+Depends: ${shlibs:Depends}, ${misc:Depends}, liblockdev1
Description: Pulse-Eight CEC adapter control library
With this library you can access your Pulse-Eight CEC adapter.
#include "cectypes.h"
-#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_6_2
+#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_6_3
namespace CEC
{
CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70,
CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E,
CEC_OPCODE_SET_AUDIO_RATE = 0x9A,
+
+ /* CEC 1.4 */
+ CEC_OPCODE_START_ARC = 0xC0,
+ CEC_OPCODE_REPORT_ARC_STARTED = 0xC1,
+ CEC_OPCODE_REPORT_ARC_ENDED = 0xC2,
+ CEC_OPCODE_REQUEST_ARC_START = 0xC3,
+ CEC_OPCODE_REQUEST_ARC_END = 0xC4,
+ CEC_OPCODE_END_ARC = 0xC5,
+ CEC_OPCODE_CDC = 0xF8,
/* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */
CEC_OPCODE_NONE = 0xFD
} cec_opcode;
*/
void Clear(void)
{
- primary = CECDEVICE_UNKNOWN;
+ primary = CECDEVICE_UNREGISTERED;
for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
addresses[iPtr] = 0;
}
*/
bool IsEmpty(void) const
{
- return primary == CECDEVICE_UNKNOWN;
+ return primary == CECDEVICE_UNREGISTERED;
}
/*!
*/
void Set(cec_logical_address address)
{
- if (primary == CECDEVICE_UNKNOWN)
+ if (primary == CECDEVICE_UNREGISTERED)
primary = address;
addresses[(int) address] = 1;
* @brief Mark a logical address as 'unset'
* @param address The logical address to remove from this list.
*/
- void Unset(cec_logical_address address)
+ void Unset(const cec_logical_address address)
{
if (primary == address)
- primary = CECDEVICE_UNKNOWN;
+ primary = CECDEVICE_UNREGISTERED;
addresses[(int) address] = 0;
}
typedef enum libcec_alert
{
CEC_ALERT_SERVICE_DEVICE,
- CEC_ALERT_CONNECTION_LOST
+ CEC_ALERT_CONNECTION_LOST,
+ CEC_ALERT_PERMISSION_ERROR,
+ CEC_ALERT_PORT_BUSY
} libcec_alert;
typedef enum libcec_parameter_type
{
- CEC_PARAMETER_TYPE_STRING
+ CEC_PARAMETER_TYPE_STRING,
+ CEC_PARAMETER_TYPE_UNKOWN
} libcec_parameter_type;
struct libcec_parameter
CEC_CLIENT_VERSION_1_5_3 = 0x1503,
CEC_CLIENT_VERSION_1_6_0 = 0x1600,
CEC_CLIENT_VERSION_1_6_1 = 0x1601,
- CEC_CLIENT_VERSION_1_6_2 = 0x1602
+ CEC_CLIENT_VERSION_1_6_2 = 0x1602,
+ CEC_CLIENT_VERSION_1_6_3 = 0x1603
} cec_client_version;
typedef enum cec_server_version
CEC_SERVER_VERSION_1_5_3 = 0x1503,
CEC_SERVER_VERSION_1_6_0 = 0x1600,
CEC_SERVER_VERSION_1_6_1 = 0x1601,
- CEC_SERVER_VERSION_1_6_2 = 0x1602
+ CEC_SERVER_VERSION_1_6_2 = 0x1602,
+ CEC_SERVER_VERSION_1_6_3 = 0x1603
} cec_server_version;
typedef struct libcec_configuration
uint8_t bShutdownOnStandby; /*!< shutdown this PC when the TV is switched off. only used when bPowerOffOnStandby = 0. added in 1.6.0 */
char strDeviceLanguage[3]; /*!< the menu language used by the client. 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/ added in 1.6.2 */
uint32_t iFirmwareBuildDate; /*!< the build date of the firmware, in seconds since epoch. if not available, this value will be set to 0. added in 1.6.2 */
+ uint8_t bMonitorOnly; /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */
#ifdef __cplusplus
libcec_configuration(void) { Clear(); }
bPowerOffOnStandby == other.bPowerOffOnStandby &&
bSendInactiveSource == other.bSendInactiveSource &&
/* libcec 1.5.3+ */
- (other.serverVersion < CEC_SERVER_VERSION_1_5_3 || logicalAddresses == other.logicalAddresses) &&
+ (other.clientVersion < CEC_CLIENT_VERSION_1_5_3 || logicalAddresses == other.logicalAddresses) &&
/* libcec 1.6.0+ */
- (other.serverVersion < CEC_SERVER_VERSION_1_6_0 || iFirmwareVersion == other.iFirmwareVersion) &&
- (other.serverVersion < CEC_SERVER_VERSION_1_6_0 || bPowerOffDevicesOnStandby == other.bPowerOffDevicesOnStandby) &&
- (other.serverVersion < CEC_SERVER_VERSION_1_6_0 || bShutdownOnStandby == other.bShutdownOnStandby) &&
+ (other.clientVersion < CEC_CLIENT_VERSION_1_6_0 || iFirmwareVersion == other.iFirmwareVersion) &&
+ (other.clientVersion < CEC_CLIENT_VERSION_1_6_0 || bPowerOffDevicesOnStandby == other.bPowerOffDevicesOnStandby) &&
+ (other.clientVersion < CEC_CLIENT_VERSION_1_6_0 || bShutdownOnStandby == other.bShutdownOnStandby) &&
/* libcec 1.6.2+ */
- (other.serverVersion < CEC_SERVER_VERSION_1_6_2 || !strncmp(strDeviceLanguage, other.strDeviceLanguage, 3)) &&
- (other.serverVersion < CEC_SERVER_VERSION_1_6_2 || iFirmwareBuildDate == other.iFirmwareBuildDate));
+ (other.clientVersion < CEC_CLIENT_VERSION_1_6_2 || !strncmp(strDeviceLanguage, other.strDeviceLanguage, 3)) &&
+ (other.clientVersion < CEC_CLIENT_VERSION_1_6_2 || iFirmwareBuildDate == other.iFirmwareBuildDate) &&
+ /* libcec 1.6.3+ */
+ (other.clientVersion < CEC_CLIENT_VERSION_1_6_3 || bMonitorOnly == other.bMonitorOnly));
}
bool operator!=(const libcec_configuration &other) const
bPowerOffDevicesOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_DEVICES_STANDBY;
memcpy(strDeviceLanguage, CEC_DEFAULT_DEVICE_LANGUAGE, 3);
iFirmwareBuildDate = CEC_FW_BUILD_UNKNOWN;
+ bMonitorOnly = 0;
memset(strDeviceName, 0, 13);
deviceTypes.clear();
<ClInclude Include="..\src\lib\adapter\USBCECAdapterDetection.h" />
<ClInclude Include="..\src\lib\adapter\USBCECAdapterMessage.h" />
<ClInclude Include="..\src\lib\adapter\USBCECAdapterMessageQueue.h" />
+ <ClInclude Include="..\src\lib\CECClient.h" />
+ <ClInclude Include="..\src\lib\CECInputBuffer.h" />
<ClInclude Include="..\src\lib\CECProcessor.h" />
<ClInclude Include="..\src\lib\devices\CECAudioSystem.h" />
<ClInclude Include="..\src\lib\devices\CECBusDevice.h" />
+ <ClInclude Include="..\src\lib\devices\CECDeviceMap.h" />
<ClInclude Include="..\src\lib\devices\CECPlaybackDevice.h" />
<ClInclude Include="..\src\lib\devices\CECRecordingDevice.h" />
<ClInclude Include="..\src\lib\devices\CECTuner.h" />
<ClCompile Include="..\src\lib\adapter\USBCECAdapterDetection.cpp" />
<ClCompile Include="..\src\lib\adapter\USBCECAdapterMessage.cpp" />
<ClCompile Include="..\src\lib\adapter\USBCECAdapterMessageQueue.cpp" />
+ <ClCompile Include="..\src\lib\CECClient.cpp" />
<ClCompile Include="..\src\lib\CECProcessor.cpp" />
<ClCompile Include="..\src\lib\devices\CECAudioSystem.cpp" />
<ClCompile Include="..\src\lib\devices\CECBusDevice.cpp" />
+ <ClCompile Include="..\src\lib\devices\CECDeviceMap.cpp" />
<ClCompile Include="..\src\lib\devices\CECPlaybackDevice.cpp" />
<ClCompile Include="..\src\lib\devices\CECRecordingDevice.cpp" />
<ClCompile Include="..\src\lib\devices\CECTuner.cpp" />
<ClInclude Include="..\src\lib\adapter\USBCECAdapterMessageQueue.h">
<Filter>adapter</Filter>
</ClInclude>
+ <ClInclude Include="..\src\lib\CECClient.h" />
+ <ClInclude Include="..\src\lib\CECInputBuffer.h" />
+ <ClInclude Include="..\src\lib\devices\CECDeviceMap.h">
+ <Filter>devices</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\lib\CECProcessor.cpp" />
<ClCompile Include="..\src\lib\adapter\USBCECAdapterMessageQueue.cpp">
<Filter>adapter</Filter>
</ClCompile>
+ <ClCompile Include="..\src\lib\CECClient.cpp" />
+ <ClCompile Include="..\src\lib\devices\CECDeviceMap.cpp">
+ <Filter>devices</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="libcec.rc" />
// 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.6.2.0")]
-[assembly: AssemblyFileVersion("1.6.2.0")]
+[assembly: AssemblyVersion("1.6.3.0")]
+[assembly: AssemblyFileVersion("1.6.3.0")]
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
-[assembly:AssemblyVersionAttribute("1.6.2.0")];
+[assembly:AssemblyVersionAttribute("1.6.3.0")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
Version1_5_3 = 0x1503,
Version1_6_0 = 0x1600,
Version1_6_1 = 0x1601,
- Version1_6_2 = 0x1602
+ Version1_6_2 = 0x1602,
+ Version1_6_3 = 0x1603
};
public enum class CecServerVersion
Version1_5_3 = 0x1503,
Version1_6_0 = 0x1600,
Version1_6_1 = 0x1601,
- Version1_6_2 = 0x1602
+ Version1_6_2 = 0x1602,
+ Version1_6_3 = 0x1603
};
public ref class CecAdapter
if (ServerVersion >= CecServerVersion::Version1_6_2)
DeviceLanguage = gcnew System::String(config.strDeviceLanguage);
+
+ if (ServerVersion >= CecServerVersion::Version1_6_3)
+ MonitorOnlyClient = config.bMonitorOnly == 1;
}
property System::String ^ DeviceName;
property uint16_t FirmwareVersion;
property bool PowerOffDevicesOnStandby;
property bool ShutdownOnStandby;
+ property bool MonitorOnlyClient;
property System::String ^ DeviceLanguage;
property CecCallbackMethods ^ Callbacks;
};
{
config.Clear();
- _snprintf_s(config.strDeviceName, 13, context->marshal_as<const char*>(netConfig->DeviceName));
+ const char *strDeviceName = context->marshal_as<const char*>(netConfig->DeviceName);
+ memcpy_s(config.strDeviceName, 13, strDeviceName, 13);
for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr];
}
if (netConfig->ServerVersion >= CecServerVersion::Version1_6_2)
- _snprintf_s(config.strDeviceLanguage, 3, context->marshal_as<const char*>(netConfig->DeviceLanguage));
+ {
+ const char *strDeviceLanguage = context->marshal_as<const char*>(netConfig->DeviceLanguage);
+ memcpy_s(config.strDeviceLanguage, 3, strDeviceLanguage, 3);
+ }
+
+ if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3)
+ {
+ config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
+ }
config.callbacks = &g_cecCallbacks;
}
// 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.6.2.0")]
-[assembly: AssemblyFileVersion("1.6.2.0")]
+[assembly: AssemblyVersion("1.6.3.0")]
+[assembly: AssemblyFileVersion("1.6.3.0")]
ICECCallbacks g_callbacks;
libcec_configuration g_config;
ICECAdapter * g_parser;
-cec_logical_address g_primaryAddress;
inline void PrintToStdOut(const char *strFormat, ...)
{
return 0;
}
-void EnableCallbacks(ICECAdapter *adapter)
-{
- g_callbacks.CBCecLogMessage = &CecLogMessage;
- g_callbacks.CBCecKeyPress = &CecKeyPress;
- g_callbacks.CBCecCommand = &CecCommand;
- adapter->EnableCallbacks(NULL, &g_callbacks);
-}
-
-ICECAdapter *CreateParser(cec_device_type_list typeList)
-{
- ICECAdapter *parser = LibCecInit("ButtonConfig", typeList);
- if (!parser)
- {
- #ifdef __WINDOWS__
- PrintToStdOut("Cannot load libcec.dll");
- #else
- PrintToStdOut("Cannot load libcec.so");
- #endif
- return NULL;
- }
-
- PrintToStdOut("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor());
-
- return parser;
-}
-
bool ProcessConsoleCommand(string &input)
{
if (!input.empty())
g_config.Clear();
snprintf(g_config.strDeviceName, 13, "CEC-config");
g_config.callbackParam = NULL;
- g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_1_5_0;
+ g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_1_6_2;
g_callbacks.CBCecLogMessage = &CecLogMessage;
g_callbacks.CBCecKeyPress = &CecKeyPress;
g_callbacks.CBCecCommand = &CecCommand;
return false;
}
- cec_logical_addresses addr = g_parser->GetLogicalAddresses();
- g_primaryAddress = addr.primary;
+ g_parser->GetCurrentConfiguration(&g_config);
+ PrintToStdOut("CEC Parser created - libCEC version %s", g_parser->ToString((cec_server_version)g_config.serverVersion));
- PrintToStdOut("cec device opened. using logical address %X", g_primaryAddress);
return true;
}
cec_logical_address FindPhysicalAddressBaseDevice(void)
{
- PrintToStdOut("Press 1 if your CEC adapter is connected to your TV or\npress 2 if it's connected to an AVR, followed by <enter>. Anything else will cancel this wizard.");
+ PrintToStdOut("Press 1 if your CEC adapter is connected to your TV or\nPress 2 if it's connected to an AVR, followed by <enter>. Anything else will cancel this wizard.");
string input;
getline(cin, input);
PrintToStdOut("Failed. Please enter the address manually, or restart this wizard and use different settings.");
else
{
- iAddress = g_parser->GetDevicePhysicalAddress(g_primaryAddress);
+ g_parser->GetCurrentConfiguration(&g_config);
+ iAddress = g_parser->GetDevicePhysicalAddress(g_config.logicalAddresses.primary);
if (iAddress == 0 || iAddress == CEC_INVALID_PHYSICAL_ADDRESS)
PrintToStdOut("Failed. Please enter the address manually, or restart this wizard and use different settings.");
}
g_config.bActivateSource = (input == "y" || input == "Y") ? 1 : 0;
}
+ {
+ PrintToStdOut("Do you want to power on the TV when starting the application (y/n)?");
+ string input;
+ getline(cin, input);
+ cin.clear();
+ if (input == "y" || input == "Y")
+ g_config.wakeDevices.Set(CECDEVICE_TV);
+ }
+
{
PrintToStdOut("Do you want to power off CEC devices when closing the application (y/n)?");
string input;
getline(cin, input);
cin.clear();
if (input == "y" || input == "Y")
- g_config.powerOffDevices.Set(CECDEVICE_BROADCAST);
+ g_config.powerOffDevices.Set(CECDEVICE_TV);
}
{
PrintToStdOut("Physical address: %4X", g_config.iPhysicalAddress);
PrintToStdOut("Use the TV's language setting: %s", g_config.bUseTVMenuLanguage ? "yes" : "no");
PrintToStdOut("Make the adapter the active source when starting XBMC: %s", g_config.bActivateSource ? "yes" : "no");
+ PrintToStdOut("Power on the TV when starting XBMC: %s", g_config.wakeDevices.IsSet(CECDEVICE_BROADCAST) ? "yes" : "no");
PrintToStdOut("Power off devices when stopping XBMC: %s", g_config.powerOffDevices.IsSet(CECDEVICE_BROADCAST) ? "yes" : "no");
PrintToStdOut("Put devices in standby mode when activating screensaver: %s", g_config.bPowerOffScreensaver ? "yes" : "no");
PrintToStdOut("Put this PC in standby mode when the TV is switched off: %s", g_config.bPowerOffOnStandby ? "yes" : "no");
- PrintToStdOut("Seend an inactive source message when stopping XBMC: %s\n\n", g_config.bSendInactiveSource ? "yes" : "no");
+ PrintToStdOut("Send an inactive source message when stopping XBMC: %s\n\n", g_config.bSendInactiveSource ? "yes" : "no");
- if (g_parser->CanPersistConfiguration())
- {
- PrintToStdOut("Do you want to store these settings in the adapter (y/n)?");
- string input;
- getline(cin, input);
- cin.clear();
- if (input == "y" || input == "Y")
- {
- PrintToStdOut("Storing settings ...");
- if (g_parser->PersistConfiguration(&g_config))
- PrintToStdOut("Settings stored.");
- else
- PrintToStdOut("The settings could not be stored");
- }
- }
+ PrintToStdOut("Storing settings ...");
+ if (g_parser->PersistConfiguration(&g_config))
+ PrintToStdOut("Settings stored.");
else
- {
- PrintToStdOut("This adapter doesn't support settings persistence. Please set up these settings in your media player application.");
+ PrintToStdOut("The settings could not be stored");
- ofstream configOutput;
- configOutput.open("usb_2548_1001.xml");
- if (configOutput.is_open())
- {
- CStdString strWakeDevices;
- for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
- if (g_config.wakeDevices[iPtr])
- strWakeDevices.AppendFormat(" %d" + iPtr);
- CStdString strStandbyDevices;
- for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
- if (g_config.powerOffDevices[iPtr])
- strStandbyDevices.AppendFormat(" %d" + iPtr);
-
- configOutput <<
+ ofstream configOutput;
+ configOutput.open("usb_2548_1001.xml");
+ if (configOutput.is_open())
+ {
+ CStdString strWakeDevices;
+ for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+ if (g_config.wakeDevices[iPtr])
+ strWakeDevices.AppendFormat(" %d" + iPtr);
+ CStdString strStandbyDevices;
+ for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+ if (g_config.powerOffDevices[iPtr])
+ strStandbyDevices.AppendFormat(" %d" + iPtr);
+
+ configOutput <<
"<settings>\n" <<
"\t<setting id=\"enabled\" value=\"1\" />\n" <<
"\t<setting id=\"activate_source\" value=\"" << (int)g_config.bActivateSource << "\" />\n" <<
"\t<setting id=\"port\" value=\"\" />\n" <<
"\t<setting id=\"send_inactive_source\" value=\"" << (int)g_config.bSendInactiveSource << "\" />\n" <<
"</settings>";
- configOutput.close();
+ configOutput.close();
- PrintToStdOut("The configuration has been stored in 'usb_2548_1001.xml'. Copy this file to ~/.userdata/peripheral_data to use it in XBMC");
- }
+ PrintToStdOut("The configuration has been stored in 'usb_2548_1001.xml'. Copy this file to ~/.userdata/peripheral_data to use it in XBMC");
}
g_parser->StandbyDevices();
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "CECClient.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECAudioSystem.h"
+#include "devices/CECTV.h"
+
+using namespace CEC;
+using namespace PLATFORM;
+
+#define LIB_CEC m_processor->GetLib()
+#define ToString(x) LIB_CEC->ToString(x)
+
+CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &configuration) :
+ m_processor(processor),
+ m_bInitialised(false),
+ m_bRegistered(false),
+ m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+ m_buttontime(0)
+{
+ // set the initial configuration
+ SetConfiguration(configuration);
+}
+
+CCECClient::~CCECClient(void)
+{
+ // unregister the client
+ if (m_processor && IsRegistered())
+ m_processor->UnregisterClient(this);
+}
+
+bool CCECClient::IsInitialised(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bInitialised && m_processor;
+}
+
+void CCECClient::SetInitialised(bool bSetTo)
+{
+ CLockObject lock(m_mutex);
+ m_bInitialised = bSetTo;
+}
+
+bool CCECClient::IsRegistered(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bRegistered && m_processor;
+}
+
+void CCECClient::SetRegistered(bool bSetTo)
+{
+ CLockObject lock(m_mutex);
+ m_bRegistered = bSetTo;
+}
+
+bool CCECClient::OnRegister(void)
+{
+ // return false if already initialised
+ if (IsInitialised())
+ return true;
+
+ // get all device we control
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ // return false when no devices were found
+ if (devices.empty())
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "cannot find the primary device (logical address %x)", GetPrimaryLogicalAdddress());
+ return false;
+ }
+
+ // mark as initialised
+ SetInitialised(true);
+
+ // configure all devices
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // only set our OSD name for the primary device
+ if ((*it)->GetLogicalAddress() == GetPrimaryLogicalAdddress())
+ (*it)->SetOSDName(m_configuration.strDeviceName);
+
+ // set the default menu language for devices we control
+ (*it)->SetMenuLanguage(m_configuration.strDeviceLanguage);
+ }
+
+ // set the physical address
+ SetPhysicalAddress(m_configuration);
+
+ // ensure that we know the vendor id of the TV, so we are using the correct handler
+ m_processor->GetTV()->GetVendorId(GetPrimaryLogicalAdddress());
+
+ // make the primary device the active source if the option is set
+ if (m_configuration.bActivateSource == 1)
+ GetPrimaryDevice()->ActivateSource();
+
+ return true;
+}
+
+bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce /* = false */)
+{
+ bool bReturn(false);
+
+ // limit the HDMI port range to 1-15
+ if (iPort < CEC_MIN_HDMI_PORTNUMBER ||
+ iPort > CEC_MAX_HDMI_PORTNUMBER)
+ return bReturn;
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
+
+ // update the configuration
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.baseDevice = iBaseDevice;
+ m_configuration.iHDMIPort = iPort;
+ }
+
+ // don't continue if the connection isn't opened
+ if (!m_processor->CECInitialised() && !bForce)
+ return true;
+
+ // get the PA of the base device
+ uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
+ CCECBusDevice *baseDevice = m_processor->GetDevice(iBaseDevice);
+ if (baseDevice)
+ iPhysicalAddress = baseDevice->GetPhysicalAddress(GetPrimaryLogicalAdddress());
+
+ // add our port number
+ if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS)
+ {
+ if (iPhysicalAddress == 0)
+ iPhysicalAddress += 0x1000 * iPort;
+ else if (iPhysicalAddress % 0x1000 == 0)
+ iPhysicalAddress += 0x100 * iPort;
+ else if (iPhysicalAddress % 0x100 == 0)
+ iPhysicalAddress += 0x10 * iPort;
+ else if (iPhysicalAddress % 0x10 == 0)
+ iPhysicalAddress += iPort;
+
+ bReturn = true;
+ }
+
+ // set the default address when something went wrong
+ if (!bReturn)
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress, CEC_DEFAULT_PHYSICAL_ADDRESS);
+ iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
+ }
+
+ // and set the address
+ SetDevicePhysicalAddress(iPhysicalAddress);
+
+ ConfigurationChanged(m_configuration);
+
+ return bReturn;
+}
+
+void CCECClient::ResetPhysicalAddress(void)
+{
+ SetPhysicalAddress(m_configuration);
+}
+
+void CCECClient::SetPhysicalAddress(const libcec_configuration &configuration)
+{
+ // try to autodetect the address
+ bool bPASet(false);
+ if (m_processor->CECInitialised() && configuration.bAutodetectAddress == 1)
+ bPASet = AutodetectPhysicalAddress();
+
+ // try to use physical address setting
+ if (!bPASet && CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+ bPASet = SetPhysicalAddress(configuration.iPhysicalAddress);
+
+ // use the base device + hdmi port settings
+ if (!bPASet)
+ bPASet = SetHDMIPort(configuration.baseDevice, configuration.iHDMIPort);
+
+ // reset to defaults if something went wrong
+ if (!bPASet)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
+ m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+ m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
+ }
+}
+
+bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress)
+{
+ // update the configuration
+ {
+ CLockObject lock(m_mutex);
+ if (m_configuration.iPhysicalAddress == iPhysicalAddress)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address unchanged (%04X)", iPhysicalAddress);
+ return true;
+ }
+ else
+ {
+ m_configuration.iPhysicalAddress = iPhysicalAddress;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress);
+ }
+ }
+
+ // persist the new configuration
+ m_processor->PersistConfiguration(m_configuration);
+
+ // set the physical address for each device
+ SetDevicePhysicalAddress(iPhysicalAddress);
+
+ // and send back the updated configuration
+ ConfigurationChanged(m_configuration);
+
+ return true;
+}
+
+bool CCECClient::AllocateLogicalAddresses(void)
+{
+ // reset all previous LAs that were set
+ m_configuration.logicalAddresses.Clear();
+
+ // display an error if no device types are set
+ if (m_configuration.deviceTypes.IsEmpty())
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "no device types given");
+ return false;
+ }
+
+ // check each entry of the list
+ for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+ {
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+ continue;
+
+ // find an LA for this type
+ cec_logical_address address(CECDEVICE_UNKNOWN);
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ address = AllocateLogicalAddressRecordingDevice();
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
+ address = AllocateLogicalAddressTuner();
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
+ address = AllocateLogicalAddressPlaybackDevice();
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ address = AllocateLogicalAddressAudioSystem();
+
+ // display an error if no LA could be allocated
+ if (address == CECDEVICE_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]));
+ return false;
+ }
+
+ // display the registered LA
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]), address);
+ m_configuration.logicalAddresses.Set(address);
+ }
+
+ return true;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressRecordingDevice(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1))
+ retVal = CECDEVICE_RECORDINGDEVICE1;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2))
+ retVal = CECDEVICE_RECORDINGDEVICE2;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3))
+ retVal = CECDEVICE_RECORDINGDEVICE3;
+
+ return retVal;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressTuner(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_TUNER1))
+ retVal = CECDEVICE_TUNER1;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER2))
+ retVal = CECDEVICE_TUNER2;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER3))
+ retVal = CECDEVICE_TUNER3;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER4))
+ retVal = CECDEVICE_TUNER4;
+
+ return retVal;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressPlaybackDevice(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1))
+ retVal = CECDEVICE_PLAYBACKDEVICE1;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2))
+ retVal = CECDEVICE_PLAYBACKDEVICE2;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3))
+ retVal = CECDEVICE_PLAYBACKDEVICE3;
+
+ return retVal;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressAudioSystem(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audiosystem'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM))
+ retVal = CECDEVICE_AUDIOSYSTEM;
+
+ return retVal;
+}
+
+CCECBusDevice *CCECClient::GetDeviceByType(const cec_device_type type) const
+{
+ // get all devices that match our logical addresses
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ // filter the type we need
+ CCECDeviceMap::FilterType(type, devices);
+
+ return devices.empty() ?
+ NULL :
+ *devices.begin();
+}
+
+bool CCECClient::ChangeDeviceType(const cec_device_type from, const cec_device_type to)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
+
+ CLockObject lock(m_mutex);
+
+ // get the previous device that was allocated
+ CCECBusDevice *previousDevice = GetDeviceByType(from);
+ if (!previousDevice)
+ return false;
+
+ // change the type in the device type list
+ bool bChanged(false);
+ for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+ {
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+ continue;
+
+ if (m_configuration.deviceTypes.types[iPtr] == from)
+ {
+ bChanged = true;
+ m_configuration.deviceTypes.types[iPtr] = to;
+ }
+ else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged)
+ {
+ // ensure that dupes are removed
+ m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+ }
+ }
+
+ // re-register the client to set the new ackmask
+ if (!m_processor->RegisterClient(this))
+ return false;
+
+ return true;
+}
+
+bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress)
+{
+ CLockObject lock(m_mutex);
+ if (GetPrimaryLogicalAdddress() != iLogicalAddress)
+ {
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
+ m_configuration.logicalAddresses.primary = iLogicalAddress;
+ m_configuration.logicalAddresses.Set(iLogicalAddress);
+ }
+ return m_processor->RegisterClient(this);
+ }
+
+ return true;
+}
+
+bool CCECClient::Transmit(const cec_command &data)
+{
+ return m_processor ? m_processor->Transmit(data) : false;
+}
+
+bool CCECClient::SendPowerOnDevices(const cec_logical_address address /* = CECDEVICE_TV */)
+{
+ // if the broadcast address if set as destination and the client version >=1.5.0, read the wakeDevices setting
+ if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
+ {
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetWakeDevices(m_configuration, devices);
+ return m_processor->PowerOnDevices(GetPrimaryLogicalAdddress(), devices);
+ }
+
+ return m_processor->PowerOnDevice(GetPrimaryLogicalAdddress(), address);
+}
+
+bool CCECClient::SendStandbyDevices(const cec_logical_address address /* = CECDEVICE_BROADCAST */)
+{
+ // if the broadcast address if set as destination and the client version >=1.5.0, read the standbyDevices setting
+ if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
+ {
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetPowerOffDevices(m_configuration, devices);
+ return m_processor->StandbyDevices(GetPrimaryLogicalAdddress(), devices);
+ }
+
+ return m_processor->StandbyDevice(GetPrimaryLogicalAdddress(), address);
+}
+
+bool CCECClient::SendSetActiveSource(const cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
+{
+ // get the devices that are controlled by us
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ // filter out the device that matches the given type
+ if (type != CEC_DEVICE_TYPE_RESERVED)
+ CCECDeviceMap::FilterType(type, devices);
+
+ // no devices left, re-fetch the list of devices that are controlled by us
+ if (devices.empty())
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ if (!devices.empty())
+ {
+ // get the first device from the list
+ CCECBusDevice *device = *devices.begin();
+
+ // and activate it
+ if (!m_processor->CECInitialised())
+ device->MarkAsActiveSource();
+ else if (device->HasValidPhysicalAddress())
+ return device->ActivateSource();
+ }
+
+ return false;
+}
+
+CCECPlaybackDevice *CCECClient::GetPlaybackDevice(void)
+{
+ CCECPlaybackDevice *device(NULL);
+ CECDEVICEVEC devices;
+
+ // get the playback devices
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE, devices);
+
+ // no matches, get the recording devices
+ if (devices.empty())
+ {
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE, devices);
+ }
+
+ // get the first device that matches, and cast it to CCECPlaybackDevice
+ if (!devices.empty())
+ device = (*devices.begin())->AsPlaybackDevice();
+
+ return device;
+}
+
+cec_logical_address CCECClient::GetPrimaryLogicalAdddress(void)
+{
+ CLockObject lock(m_mutex);
+ return m_configuration.logicalAddresses.primary;
+}
+
+CCECBusDevice *CCECClient::GetPrimaryDevice(void)
+{
+ return m_processor->GetDevice(GetPrimaryLogicalAdddress());
+}
+
+bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode, bool bSendUpdate /* = true */)
+{
+ // find a playback device that we control
+ CCECPlaybackDevice *device = GetPlaybackDevice();
+ if (device)
+ {
+ // and set the deck control mode if there is a match
+ device->SetDeckControlMode(mode);
+ if (bSendUpdate)
+ return device->TransmitDeckStatus(CECDEVICE_TV);
+ return true;
+ }
+
+ // no match
+ return false;
+}
+
+bool CCECClient::SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate /* = true */)
+{
+ // find a playback device that we control
+ CCECPlaybackDevice *device = GetPlaybackDevice();
+ if (device)
+ {
+ // and set the deck status if there is a match
+ device->SetDeckStatus(info);
+ if (bSendUpdate)
+ return device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV);
+ return true;
+ }
+
+ // no match
+ return false;
+}
+
+bool CCECClient::SendSetMenuState(const cec_menu_state state, bool bSendUpdate /* = true */)
+{
+ CECDEVICEVEC devices;
+
+ // set the menu state for all devices that are controlled by us
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ (*it)->SetMenuState(state);
+ if (bSendUpdate)
+ (*it)->TransmitMenuState(CECDEVICE_TV);
+ }
+
+ return true;
+}
+
+bool CCECClient::SendSetInactiveView(void)
+{
+ CECDEVICEVEC devices;
+
+ // mark all devices that are controlled by us as inactive source
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if ((*it)->IsActiveSource())
+ {
+ (*it)->MarkAsInactiveSource();
+ return (*it)->TransmitInactiveSource();
+ }
+ }
+
+ return true;
+}
+
+bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress, const cec_display_control duration, const char *strMessage)
+{
+ CCECBusDevice *primary = GetPrimaryDevice();
+ if (primary)
+ return primary->TransmitOSDString(iLogicalAddress, duration, strMessage);
+
+ return false;
+}
+
+cec_version CCECClient::GetDeviceCecVersion(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetCecVersion(GetPrimaryLogicalAdddress());
+ return CEC_VERSION_UNKNOWN;
+}
+
+bool CCECClient::GetDeviceMenuLanguage(const cec_logical_address iAddress, cec_menu_language &language)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ {
+ language = device->GetMenuLanguage(GetPrimaryLogicalAdddress());
+ return (strcmp(language.language, "???") != 0);
+ }
+ return false;
+}
+
+cec_osd_name CCECClient::GetDeviceOSDName(const cec_logical_address iAddress)
+{
+ cec_osd_name retVal;
+ retVal.device = iAddress;
+ retVal.name[0] = 0;
+
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ {
+ CStdString strOSDName = device->GetOSDName(GetPrimaryLogicalAdddress());
+ snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
+ retVal.device = iAddress;
+ }
+
+ return retVal;
+}
+
+uint16_t CCECClient::GetDevicePhysicalAddress(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetPhysicalAddress(GetPrimaryLogicalAdddress());
+ return CEC_INVALID_PHYSICAL_ADDRESS;
+}
+
+cec_power_status CCECClient::GetDevicePowerStatus(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetPowerStatus(GetPrimaryLogicalAdddress());
+ return CEC_POWER_STATUS_UNKNOWN;
+}
+
+uint64_t CCECClient::GetDeviceVendorId(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetVendorId(GetPrimaryLogicalAdddress());
+ return CEC_VENDOR_UNKNOWN;
+}
+
+uint8_t CCECClient::SendVolumeUp(bool bSendRelease /* = true */)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+ return device && audio && audio->IsPresent() ?
+ audio->VolumeUp(device->GetLogicalAddress(), bSendRelease) :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CCECClient::SendVolumeDown(bool bSendRelease /* = true */)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+ return device && audio && audio->IsPresent() ?
+ audio->VolumeDown(device->GetLogicalAddress(), bSendRelease) :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CCECClient::SendMuteAudio(void)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+ return device && audio && audio->IsPresent() ?
+ audio->MuteAudio(device->GetLogicalAddress()) :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+bool CCECClient::SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait /* = true */)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECBusDevice *dest = m_processor->GetDevice(iDestination);
+
+ return device && dest ?
+ device->TransmitKeypress(GetPrimaryLogicalAdddress(), key, bWait) :
+ false;
+}
+
+bool CCECClient::SendKeyRelease(const cec_logical_address iDestination, bool bWait /* = true */)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECBusDevice *dest = m_processor->GetDevice(iDestination);
+
+ return device && dest ?
+ device->TransmitKeyRelease(GetPrimaryLogicalAdddress(), bWait) :
+ false;
+}
+
+bool CCECClient::GetCurrentConfiguration(libcec_configuration &configuration)
+{
+ CLockObject lock(m_mutex);
+
+ // client version 1.5.0
+ snprintf(configuration.strDeviceName, 13, "%s", m_configuration.strDeviceName);
+ configuration.deviceTypes = m_configuration.deviceTypes;
+ configuration.bAutodetectAddress = m_configuration.bAutodetectAddress;
+ configuration.iPhysicalAddress = m_configuration.iPhysicalAddress;
+ configuration.baseDevice = m_configuration.baseDevice;
+ configuration.iHDMIPort = m_configuration.iHDMIPort;
+ configuration.clientVersion = m_configuration.clientVersion;
+ configuration.serverVersion = m_configuration.serverVersion;
+ configuration.tvVendor = m_configuration.tvVendor;
+
+ configuration.bGetSettingsFromROM = m_configuration.bGetSettingsFromROM;
+ configuration.bUseTVMenuLanguage = m_configuration.bUseTVMenuLanguage;
+ configuration.bActivateSource = m_configuration.bActivateSource;
+ configuration.wakeDevices = m_configuration.wakeDevices;
+ configuration.powerOffDevices = m_configuration.powerOffDevices;
+ configuration.bPowerOffScreensaver = m_configuration.bPowerOffScreensaver;
+ configuration.bPowerOffOnStandby = m_configuration.bPowerOffOnStandby;
+
+ // client version 1.5.1
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_1)
+ configuration.bSendInactiveSource = m_configuration.bSendInactiveSource;
+
+ // client version 1.5.3
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_3)
+ configuration.logicalAddresses = m_configuration.logicalAddresses;
+
+ // client version 1.6.0
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0)
+ {
+ configuration.iFirmwareVersion = m_configuration.iFirmwareVersion;
+ configuration.bPowerOffDevicesOnStandby = m_configuration.bPowerOffDevicesOnStandby;
+ configuration.bShutdownOnStandby = m_configuration.bShutdownOnStandby;
+ }
+
+ // client version 1.6.2
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2)
+ {
+ memcpy(configuration.strDeviceLanguage, m_configuration.strDeviceLanguage, 3);
+ configuration.iFirmwareBuildDate = m_configuration.iFirmwareBuildDate;
+ }
+
+ // client version 1.6.3
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_3)
+ {
+ configuration.bMonitorOnly = m_configuration.bMonitorOnly;
+ }
+
+ return true;
+}
+
+bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
+{
+ bool bIsRunning(m_processor && m_processor->CECInitialised());
+ CCECBusDevice *primary = bIsRunning ? GetPrimaryDevice() : NULL;
+ uint16_t iPA = primary ? primary->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
+
+ // update the callbacks
+ if (configuration.callbacks)
+ EnableCallbacks(configuration.callbackParam, configuration.callbacks);
+
+ // update the client version
+ SetClientVersion((cec_client_version)configuration.clientVersion);
+
+ // update the OSD name
+ CStdString strOSDName(configuration.strDeviceName);
+ SetOSDName(strOSDName);
+
+ // update the TV vendor override
+ SetTVVendorOverride((cec_vendor_id)configuration.tvVendor);
+
+ // just copy these
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.bUseTVMenuLanguage = configuration.bUseTVMenuLanguage;
+ m_configuration.bActivateSource = configuration.bActivateSource;
+ m_configuration.bGetSettingsFromROM = configuration.bGetSettingsFromROM;
+ m_configuration.wakeDevices = configuration.wakeDevices;
+ m_configuration.powerOffDevices = configuration.powerOffDevices;
+ m_configuration.bPowerOffScreensaver = configuration.bPowerOffScreensaver;
+ m_configuration.bPowerOffOnStandby = configuration.bPowerOffOnStandby;
+
+ // client version 1.5.1
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_1)
+ m_configuration.bSendInactiveSource = configuration.bSendInactiveSource;
+
+ // client version 1.6.0
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0)
+ {
+ m_configuration.bPowerOffDevicesOnStandby = configuration.bPowerOffDevicesOnStandby;
+ m_configuration.bShutdownOnStandby = configuration.bShutdownOnStandby;
+ }
+
+ // client version 1.6.2
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2)
+ {
+ memcpy(m_configuration.strDeviceLanguage, configuration.strDeviceLanguage, 3);
+ }
+
+ // client version 1.6.3
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_3)
+ {
+ m_configuration.bMonitorOnly = configuration.bMonitorOnly;
+ }
+
+ // ensure that there is at least 1 device type set
+ if (m_configuration.deviceTypes.IsEmpty())
+ m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ }
+
+ bool bNeedReinit(false);
+
+ // device types
+ if (SetDeviceTypes(configuration.deviceTypes))
+ {
+ // the device type changed. just copy the rest, and re-register
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.iPhysicalAddress = configuration.iPhysicalAddress;
+ m_configuration.baseDevice = configuration.baseDevice;
+ m_configuration.iHDMIPort = configuration.iHDMIPort;
+ bNeedReinit = true;
+ }
+ }
+ else
+ {
+ // set the physical address
+ SetPhysicalAddress(configuration);
+ }
+
+ m_processor->PersistConfiguration(m_configuration);
+
+ if (!primary)
+ primary = GetPrimaryDevice();
+
+ if (bNeedReinit || !primary || primary->GetCurrentPhysicalAddress() != iPA)
+ {
+ // PA or device type changed
+ m_processor->RegisterClient(this);
+ }
+ else if (primary && configuration.bActivateSource == 1 && bIsRunning && !primary->IsActiveSource())
+ {
+ // activate the source if we're not already the active source
+ primary->ActivateSource();
+ }
+
+ return true;
+}
+
+void CCECClient::AddCommand(const cec_command &command)
+{
+ CLockObject lock(m_mutex);
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode);
+
+ if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand)
+ m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command);
+ else if (!m_commandBuffer.Push(command))
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "command buffer is full");
+}
+
+int CCECClient::MenuStateChanged(const cec_menu_state newState)
+{
+ CLockObject lock(m_mutex);
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST), ToString(newState));
+
+ if (m_configuration.callbacks &&
+ m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2 &&
+ m_configuration.callbacks->CBCecMenuStateChanged)
+ return m_configuration.callbacks->CBCecMenuStateChanged(m_configuration.callbackParam, newState);
+
+ return 0;
+}
+
+void CCECClient::Alert(const libcec_alert type, const libcec_parameter ¶m)
+{
+ CLockObject lock(m_mutex);
+
+ if (m_configuration.callbacks &&
+ m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0 &&
+ m_configuration.callbacks->CBCecAlert)
+ m_configuration.callbacks->CBCecAlert(m_configuration.callbackParam, type, param);
+}
+
+void CCECClient::AddLog(const cec_log_message &message)
+{
+ CLockObject lock(m_logMutex);
+ if (m_configuration.callbacks && m_configuration.callbacks->CBCecLogMessage)
+ m_configuration.callbacks->CBCecLogMessage(m_configuration.callbackParam, message);
+ else
+ m_logBuffer.Push(message);
+}
+
+void CCECClient::AddKey(void)
+{
+ CLockObject lock(m_mutex);
+
+ if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+ {
+ cec_keypress key;
+
+ key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
+ key.keycode = m_iCurrentButton;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode);
+
+ if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
+ m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
+ else
+ m_keyBuffer.Push(key);
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ }
+
+ m_buttontime = 0;
+}
+
+void CCECClient::AddKey(const cec_keypress &key)
+{
+ CLockObject lock(m_mutex);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
+
+ if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
+ m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
+ else
+ m_keyBuffer.Push(key);
+
+ m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode;
+ m_buttontime = key.duration > 0 ? 0 : GetTimeMs();
+}
+
+void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode)
+{
+ // push a keypress to the buffer with 0 duration and another with the duration set when released
+ cec_keypress key;
+ key.duration = 0;
+ key.keycode = iButtonCode;
+
+ AddKey(key);
+}
+
+void CCECClient::CheckKeypressTimeout(void)
+{
+ if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
+ {
+ AddKey();
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ }
+}
+
+void CCECClient::ConfigurationChanged(const libcec_configuration &config)
+{
+ CLockObject lock(m_mutex);
+
+ if (m_configuration.callbacks &&
+ m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0 &&
+ m_configuration.callbacks->CBCecConfigurationChanged &&
+ m_processor->CECInitialised())
+ m_configuration.callbacks->CBCecConfigurationChanged(m_configuration.callbackParam, config);
+}
+
+bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+{
+ CLockObject lock(m_mutex);
+ m_configuration.callbackParam = cbParam;
+ m_configuration.callbacks = callbacks;
+ return true;
+}
+
+bool CCECClient::PingAdapter(void)
+{
+ return m_processor ? m_processor->PingAdapter() : false;
+}
+
+bool CCECClient::GetNextLogMessage(cec_log_message *message)
+{
+ return (m_logBuffer.Pop(*message));
+}
+
+bool CCECClient::GetNextKeypress(cec_keypress *key)
+{
+ return m_keyBuffer.Pop(*key);
+}
+
+bool CCECClient::GetNextCommand(cec_command *command)
+{
+ return m_commandBuffer.Pop(*command);
+}
+
+CStdString CCECClient::GetConnectionInfo(void)
+{
+ CStdString strLog;
+ strLog.Format("libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version)m_configuration.serverVersion), ToString((cec_client_version)m_configuration.clientVersion), m_configuration.iFirmwareVersion);
+ if (m_configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
+ {
+ time_t buildTime = (time_t)m_configuration.iFirmwareBuildDate;
+ strLog.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime)));
+ strLog = strLog.Left((int)strLog.length() - 1); // strip \n added by asctime
+ strLog.append(" +0000");
+ }
+
+ // log the addresses that are being used
+ if (!m_configuration.logicalAddresses.IsEmpty())
+ {
+ strLog.append(", logical address(es) = ");
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ strLog.AppendFormat("%s (%X) ", (*it)->GetLogicalAddressName(), (*it)->GetLogicalAddress());
+ }
+
+ if (!CLibCEC::IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
+ strLog.AppendFormat(", base device: %s (%X), HDMI port number: %d", ToString(m_configuration.baseDevice), m_configuration.baseDevice, m_configuration.iHDMIPort);
+ else
+ strLog.AppendFormat(", physical address: %04x", m_configuration.iPhysicalAddress);
+
+ return strLog;
+}
+
+void CCECClient::SetTVVendorOverride(const cec_vendor_id id)
+{
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.tvVendor = id;
+ }
+
+ if (id != CEC_VENDOR_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString(id));
+
+ CCECBusDevice *tv = m_processor ? m_processor->GetTV() : NULL;
+ if (tv)
+ tv->SetVendorId((uint64_t)id);
+ }
+}
+
+cec_vendor_id CCECClient::GetTVVendorOverride(void)
+{
+ CLockObject lock(m_mutex);
+ return (cec_vendor_id)m_configuration.tvVendor;
+}
+
+void CCECClient::SetOSDName(const CStdString &strDeviceName)
+{
+ {
+ CLockObject lock(m_mutex);
+ snprintf(m_configuration.strDeviceName, 13, "%s", strDeviceName.c_str());
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, strDeviceName.c_str());
+
+ CCECBusDevice *primary = GetPrimaryDevice();
+ if (primary && !primary->GetCurrentOSDName().Equals(strDeviceName))
+ {
+ primary->SetOSDName(strDeviceName);
+ if (m_processor && m_processor->CECInitialised())
+ primary->TransmitOSDName(CECDEVICE_TV);
+ }
+}
+
+CStdString CCECClient::GetOSDName(void)
+{
+ CLockObject lock(m_mutex);
+ CStdString strOSDName(m_configuration.strDeviceName);
+ return strOSDName;
+}
+
+void CCECClient::SetWakeDevices(const cec_logical_addresses &addresses)
+{
+ CLockObject lock(m_mutex);
+ m_configuration.wakeDevices = addresses;
+}
+
+cec_logical_addresses CCECClient::GetWakeDevices(void)
+{
+ CLockObject lock(m_mutex);
+ return m_configuration.wakeDevices;
+}
+
+bool CCECClient::AutodetectPhysicalAddress(void)
+{
+ bool bPhysicalAutodetected(false);
+ uint16_t iPhysicalAddress = m_processor ? m_processor->GetDetectedPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
+
+ if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%04X'", __FUNCTION__, iPhysicalAddress);
+
+ CLockObject lock(m_mutex);
+ m_configuration.iPhysicalAddress = iPhysicalAddress;
+ m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
+ m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+ bPhysicalAutodetected = true;
+ }
+
+ SetDevicePhysicalAddress(iPhysicalAddress);
+
+ return bPhysicalAutodetected;
+}
+
+void CCECClient::SetClientVersion(const cec_client_version version)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, ToString(version));
+
+ CLockObject lock(m_mutex);
+ m_configuration.clientVersion = (uint32_t)version;
+}
+
+cec_client_version CCECClient::GetClientVersion(void)
+{
+ CLockObject lock(m_mutex);
+ return (cec_client_version)m_configuration.clientVersion;
+}
+
+bool CCECClient::SetDeviceTypes(const cec_device_type_list &deviceTypes)
+{
+ bool bNeedReinit(false);
+
+ {
+ CLockObject lock(m_mutex);
+ bNeedReinit = m_processor && m_processor->CECInitialised() &&
+ (m_configuration.deviceTypes != deviceTypes);
+ m_configuration.deviceTypes = deviceTypes;
+ }
+
+ if (bNeedReinit)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(deviceTypes[0]));
+
+ return bNeedReinit;
+}
+
+cec_device_type_list CCECClient::GetDeviceTypes(void)
+{
+ cec_device_type_list retVal;
+ CLockObject lock(m_mutex);
+ retVal = m_configuration.deviceTypes;
+ return retVal;
+}
+
+bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress)
+{
+ if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
+ return false;
+
+ // reconfigure all devices
+ cec_logical_address reactivateSource(CECDEVICE_UNKNOWN);
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // if this device was the active source, reactivate it afterwards
+ if ((*it)->IsActiveSource())
+ reactivateSource = (*it)->GetLogicalAddress();
+
+ // mark the device as inactive source
+ if (IsInitialised())
+ (*it)->MarkAsInactiveSource();
+
+ // set the new physical address
+ (*it)->SetPhysicalAddress(iPhysicalAddress);
+
+ // and transmit it
+ if (IsInitialised())
+ (*it)->TransmitPhysicalAddress();
+ }
+
+ // reactivate the previous active source
+ if (reactivateSource != CECDEVICE_UNKNOWN &&
+ m_processor->CECInitialised() &&
+ IsInitialised())
+ {
+ CCECBusDevice *device = m_processor->GetDevice(reactivateSource);
+ if (device)
+ device->ActivateSource();
+ }
+
+ return true;
+}
+
+bool CCECClient::SwitchMonitoring(bool bEnable)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
+
+ if (m_processor)
+ {
+ if (bEnable)
+ return m_processor->UnregisterClient(this);
+ else
+ {
+ m_configuration.bMonitorOnly = false;
+ return m_processor->RegisterClient(this);
+ }
+ }
+
+ return false;
+}
+
+bool CCECClient::PollDevice(const cec_logical_address iAddress)
+{
+ // try to find the primary device
+ CCECBusDevice *primary = GetPrimaryDevice();
+ // poll the destination, with the primary as source
+ if (primary)
+ return primary->TransmitPoll(iAddress);
+
+ return m_processor ? m_processor->PollDevice(iAddress) : false;
+}
+
+cec_logical_addresses CCECClient::GetActiveDevices(void)
+{
+ CECDEVICEVEC activeDevices;
+ if (m_processor)
+ m_processor->GetDevices()->GetActive(activeDevices);
+ return CCECDeviceMap::ToLogicalAddresses(activeDevices);
+}
+
+bool CCECClient::IsActiveDevice(const cec_logical_address iAddress)
+{
+ cec_logical_addresses activeDevices = GetActiveDevices();
+ return activeDevices.IsSet(iAddress);
+}
+
+bool CCECClient::IsActiveDeviceType(const cec_device_type type)
+{
+ CECDEVICEVEC activeDevices;
+ if (m_processor)
+ m_processor->GetDevices()->GetActive(activeDevices);
+ CCECDeviceMap::FilterType(type, activeDevices);
+ return !activeDevices.empty();
+}
+
+cec_logical_address CCECClient::GetActiveSource(void)
+{
+ return m_processor ? m_processor->GetActiveSource() : CECDEVICE_UNKNOWN;
+}
+
+bool CCECClient::IsActiveSource(const cec_logical_address iAddress)
+{
+ return m_processor ? m_processor->IsActiveSource(iAddress) : false;
+}
+
+bool CCECClient::SetStreamPath(const cec_logical_address iAddress)
+{
+ uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
+ if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS)
+ return SetStreamPath(iPhysicalAddress);
+ return false;
+}
+
+bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress)
+{
+ return m_processor ? m_processor->SetStreamPath(iPhysicalAddress) : false;
+}
+
+cec_logical_addresses CCECClient::GetLogicalAddresses(void)
+{
+ cec_logical_addresses addresses;
+ CLockObject lock(m_mutex);
+ addresses = m_configuration.logicalAddresses;
+ return addresses;
+}
+
+bool CCECClient::CanPersistConfiguration(void)
+{
+ return m_processor ? m_processor->CanPersistConfiguration() : false;
+}
+
+bool CCECClient::PersistConfiguration(const libcec_configuration &configuration)
+{
+ return m_processor ? m_processor->PersistConfiguration(configuration) : false;
+}
+
+void CCECClient::RescanActiveDevices(void)
+{
+ if (m_processor)
+ m_processor->RescanActiveDevices();
+}
+
+bool CCECClient::IsLibCECActiveSource(void)
+{
+ bool bReturn(false);
+ if (m_processor)
+ {
+ cec_logical_address activeSource = m_processor->GetActiveSource();
+ CCECBusDevice *device = m_processor->GetDevice(activeSource);
+ if (device)
+ bReturn = device->IsHandledByLibCEC();
+ }
+ return bReturn;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "../../include/cectypes.h"
+#include "platform/threads/mutex.h"
+#include "platform/util/buffer.h"
+
+#include "devices/CECBusDevice.h"
+
+namespace CEC
+{
+ class CCECProcessor;
+
+ class CCECClient
+ {
+ friend class CCECProcessor;
+
+ public:
+ CCECClient(CCECProcessor *processor, const libcec_configuration &configuration);
+ virtual ~CCECClient(void);
+
+ /*!
+ * @return True when initialised and registered, false otherwise.
+ */
+ virtual bool IsInitialised(void);
+
+ /*!
+ * @return True when registered in the processor, false otherwise.
+ */
+ virtual bool IsRegistered(void);
+
+ /*!
+ * @return The primary logical address that this client is controlling.
+ */
+ virtual cec_logical_address GetPrimaryLogicalAdddress(void);
+
+ /*!
+ * @return The primary device that this client is controlling, or NULL if none.
+ */
+ virtual CCECBusDevice *GetPrimaryDevice(void);
+
+ /*!
+ * @return Get the playback device or recording device that this client is controlling, or NULL if none.
+ */
+ virtual CCECPlaybackDevice *GetPlaybackDevice(void);
+
+ /*!
+ * @brief Change one of the device types that this client is controlling into another.
+ * @param from The type to change.
+ * @param to The new value.
+ * @return True when changed, false otherwise.
+ */
+ virtual bool ChangeDeviceType(const cec_device_type from, const cec_device_type to);
+
+ /*!
+ * @brief Get a device that this client is controlling, given it's type.
+ * @param type The type of the device to get.
+ * @return The requested device, or NULL if not found.
+ */
+ virtual CCECBusDevice *GetDeviceByType(const cec_device_type type) const;
+
+ /*!
+ * @brief Reset the physical address from the configuration.
+ */
+ virtual void ResetPhysicalAddress(void);
+
+ /*!
+ * @return A string that describes this client.
+ */
+ virtual CStdString GetConnectionInfo(void);
+
+ /*!
+ * @return The current value of the TV vendor override setting.
+ */
+ virtual cec_vendor_id GetTVVendorOverride(void);
+
+ /*!
+ * @return The current value of the OSD name setting.
+ */
+ virtual CStdString GetOSDName(void);
+
+ /*!
+ * @return Get the current value of the wake device setting.
+ */
+ virtual cec_logical_addresses GetWakeDevices(void);
+
+ /*!
+ * @return The version of this client.
+ */
+ virtual cec_client_version GetClientVersion(void);
+
+ /*!
+ * @return The device types that this client is controlling.
+ */
+ virtual cec_device_type_list GetDeviceTypes(void);
+
+ // client-specific part of ICECAdapter
+ virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks);
+ virtual bool PingAdapter(void);
+ virtual bool GetNextLogMessage(cec_log_message *message); /**< @deprecated will be removed in v2.0 */
+ virtual bool GetNextKeypress(cec_keypress *key); /**< @deprecated will be removed in v2.0 */
+ virtual bool GetNextCommand(cec_command *command); /**< @deprecated will be removed in v2.0 */
+ virtual bool Transmit(const cec_command &data);
+ virtual bool SetLogicalAddress(const cec_logical_address iLogicalAddress);
+ virtual bool SetPhysicalAddress(const uint16_t iPhysicalAddress);
+ virtual bool SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce = false);
+ virtual bool SendPowerOnDevices(const cec_logical_address address = CECDEVICE_TV);
+ virtual bool SendStandbyDevices(const cec_logical_address address = CECDEVICE_BROADCAST);
+ virtual bool SendSetActiveSource(const cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
+ virtual bool SendSetDeckControlMode(const cec_deck_control_mode mode, bool bSendUpdate = true);
+ virtual bool SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate = true);
+ virtual bool SendSetInactiveView(void);
+ virtual bool SendSetMenuState(const cec_menu_state state, bool bSendUpdate = true);
+ virtual bool SendSetOSDString(const cec_logical_address iLogicalAddress, const cec_display_control duration, const char *strMessage);
+ virtual bool SwitchMonitoring(bool bEnable);
+ virtual cec_version GetDeviceCecVersion(const cec_logical_address iAddress);
+ virtual bool GetDeviceMenuLanguage(const cec_logical_address iAddress, cec_menu_language &language);
+ virtual uint64_t GetDeviceVendorId(const cec_logical_address iAddress);
+ virtual cec_power_status GetDevicePowerStatus(const cec_logical_address iAddress);
+ virtual uint16_t GetDevicePhysicalAddress(const cec_logical_address iAddress);
+ virtual bool PollDevice(const cec_logical_address iAddress);
+ virtual cec_logical_addresses GetActiveDevices(void);
+ virtual bool IsActiveDevice(const cec_logical_address iAddress);
+ virtual bool IsActiveDeviceType(const cec_device_type type);
+ virtual uint8_t SendVolumeUp(bool bSendRelease = true);
+ virtual uint8_t SendVolumeDown(bool bSendRelease = true);
+ virtual uint8_t SendMuteAudio(void);
+ virtual bool SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait = true);
+ virtual bool SendKeyRelease(const cec_logical_address iDestination, bool bWait = true);
+ virtual cec_osd_name GetDeviceOSDName(const cec_logical_address iAddress);
+ virtual cec_logical_address GetActiveSource(void);
+ virtual bool IsActiveSource(const cec_logical_address iAddress);
+ virtual bool SetStreamPath(const cec_logical_address iAddress);
+ virtual bool SetStreamPath(const uint16_t iPhysicalAddress);
+ virtual cec_logical_addresses GetLogicalAddresses(void);
+ virtual void RescanActiveDevices(void);
+ virtual bool IsLibCECActiveSource(void);
+
+ // configuration
+ virtual bool GetCurrentConfiguration(libcec_configuration &configuration);
+ virtual bool SetConfiguration(const libcec_configuration &configuration);
+ virtual bool CanPersistConfiguration(void);
+ virtual bool PersistConfiguration(const libcec_configuration &configuration);
+ virtual void SetPhysicalAddress(const libcec_configuration &configuration);
+
+ // callbacks
+ virtual void AddCommand(const cec_command &command);
+ virtual int MenuStateChanged(const cec_menu_state newState);
+ virtual void Alert(const libcec_alert type, const libcec_parameter ¶m);
+ virtual void AddLog(const cec_log_message &message);
+ virtual void AddKey(void);
+ virtual void AddKey(const cec_keypress &key);
+ virtual void SetCurrentButton(const cec_user_control_code iButtonCode);
+ virtual void CheckKeypressTimeout(void);
+
+ protected:
+ /*!
+ * @brief Register this client in the processor
+ * @return True when registered, false otherwise.
+ */
+ virtual bool OnRegister(void);
+
+ /*!
+ * @brief Called by the processor when this client is unregistered
+ */
+ virtual void OnUnregister(void) { SetRegistered(false); SetInitialised(false); }
+
+ /*!
+ * @brief Set the registered state of this client.
+ * @param bSetTo The new value.
+ */
+ virtual void SetRegistered(bool bSetTo);
+
+ /*!
+ * @brief Set the initialised state of this client.
+ * @param bSetTo The new value
+ */
+ virtual void SetInitialised(bool bSetTo);
+
+ /*!
+ * @brief Change the TV vendor id override setting.
+ * @param id The new value.
+ */
+ virtual void SetTVVendorOverride(const cec_vendor_id id);
+
+ /*!
+ * @brief Change the OSD name of the primary device that this client is controlling.
+ * @param strDeviceName The new value.
+ */
+ virtual void SetOSDName(const CStdString &strDeviceName);
+
+ /*!
+ * @brief Change the value of the devices to wake.
+ * @param addresses The new value.
+ */
+ virtual void SetWakeDevices(const cec_logical_addresses &addresses);
+
+ /*!
+ * @brief Change the value of the client version setting.
+ * @param version The new version setting.
+ */
+ virtual void SetClientVersion(const cec_client_version version);
+
+ /*!
+ * @brief Change the device types that this client is controlling.
+ * @param deviceTypes The new types.
+ * @return True when the client needs to be re-registered to pick up the new setting, false otherwise.
+ */
+ virtual bool SetDeviceTypes(const cec_device_type_list &deviceTypes);
+
+ /*!
+ * @return A pointer to the current configuration of this client.
+ */
+ virtual libcec_configuration *GetConfiguration(void) { return &m_configuration; }
+
+ /*!
+ * @brief Called by the processor when registering this client to allocate the logical addresses.
+ * @return True when the addresses for all types were allocated, false otherwise.
+ */
+ virtual bool AllocateLogicalAddresses(void);
+
+ /*!
+ * @brief Try to allocate a logical address for a recording device controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressRecordingDevice(void);
+
+ /*!
+ * @brief Try to allocate a logical address for a tuner controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressTuner(void);
+
+ /*!
+ * @brief Try to allocate a logical address for a playback device controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressPlaybackDevice(void);
+
+ /*!
+ * @brief Try to allocate a logical address for an audiosystem controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressAudioSystem(void);
+
+ /*!
+ * @brief Change the physical address of the devices controlled by this client.
+ * @param iPhysicalAddress The new physical address.
+ * @return True when changed, false otherwise.
+ */
+ virtual bool SetDevicePhysicalAddress(const uint16_t iPhysicalAddress);
+
+ /*!
+ * @brief Called when the configuration changed and needs to be sent back to the client.
+ * @param config The new configuration.
+ */
+ virtual void ConfigurationChanged(const libcec_configuration &config);
+
+ /*!
+ * @brief Try to autodetect the physical address.
+ * @return True when autodetected (and set in m_configuration), false otherwise.
+ */
+ virtual bool AutodetectPhysicalAddress(void);
+
+ CCECProcessor * m_processor; /**< a pointer to the processor */
+ libcec_configuration m_configuration; /**< the configuration of this client */
+ bool m_bInitialised; /**< true when initialised, false otherwise */
+ bool m_bRegistered; /**< true when registered in the processor, false otherwise */
+ PLATFORM::CMutex m_mutex; /**< mutex for changes to this instance */
+ PLATFORM::CMutex m_logMutex; /**< mutex that is held when sending a log message back to the client */
+ cec_user_control_code m_iCurrentButton; /**< the control code of the button that's currently held down (if any) */
+ int64_t m_buttontime; /**< the timestamp when the button was pressed (in seconds since epoch), or 0 if none was pressed. */
+ PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer; /**< @deprecated will be removed in v2.0. buffer for log messages */
+ PLATFORM::SyncedBuffer<cec_keypress> m_keyBuffer; /**< @deprecated will be removed in v2.0. buffer for keypresses */
+ PLATFORM::SyncedBuffer<cec_command> m_commandBuffer; /**< @deprecated will be removed in v2.0. buffer for commands */
+ };
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "../../include/cectypes.h"
+#include "platform/threads/mutex.h"
+#include "platform/util/buffer.h"
+
+namespace CEC
+{
+ // a buffer that priotises the input from the TV.
+ // if we need more than this, we'll have to change it into a priority_queue
+ class CCECInputBuffer
+ {
+ public:
+ CCECInputBuffer(void) : m_bHasData(false) {}
+ virtual ~CCECInputBuffer(void)
+ {
+ m_condition.Broadcast();
+ }
+
+ bool Push(const cec_command &command)
+ {
+ bool bReturn(false);
+ PLATFORM::CLockObject lock(m_mutex);
+ if (command.initiator == CECDEVICE_TV)
+ bReturn = m_tvInBuffer.Push(command);
+ else
+ bReturn = m_inBuffer.Push(command);
+
+ m_bHasData |= bReturn;
+ if (m_bHasData)
+ m_condition.Signal();
+
+ return bReturn;
+ }
+
+ bool Pop(cec_command &command, uint16_t iTimeout)
+ {
+ bool bReturn(false);
+ PLATFORM::CLockObject lock(m_mutex);
+ if (m_tvInBuffer.IsEmpty() && m_inBuffer.IsEmpty() &&
+ !m_condition.Wait(m_mutex, m_bHasData, iTimeout))
+ return bReturn;
+
+ if (m_tvInBuffer.Pop(command))
+ bReturn = true;
+ else if (m_inBuffer.Pop(command))
+ bReturn = true;
+
+ m_bHasData = !m_tvInBuffer.IsEmpty() || !m_inBuffer.IsEmpty();
+ return bReturn;
+ }
+
+ private:
+ PLATFORM::CMutex m_mutex;
+ PLATFORM::CCondition<volatile bool> m_condition;
+ volatile bool m_bHasData;
+ PLATFORM::SyncedBuffer<cec_command> m_tvInBuffer;
+ PLATFORM::SyncedBuffer<cec_command> m_inBuffer;
+ };
+};
#include "devices/CECTV.h"
#include "implementations/CECCommandHandler.h"
#include "LibCEC.h"
+#include "CECClient.h"
#include "platform/util/timeutils.h"
using namespace CEC;
#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
-CCECProcessor::CCECProcessor(CLibCEC *controller, libcec_configuration *configuration) :
- m_bConnectionOpened(false),
+#define ToString(x) m_libcec->ToString(x)
+
+CCECProcessor::CCECProcessor(CLibCEC *libcec) :
m_bInitialised(false),
m_communication(NULL),
- m_controller(controller),
- m_bMonitor(false),
+ m_libcec(libcec),
m_iStandardLineTimeout(3),
m_iRetryLineTimeout(3),
m_iLastTransmission(0)
{
- CreateBusDevices();
- m_configuration.Clear();
- m_configuration.serverVersion = LIBCEC_VERSION_CURRENT;
- SetConfiguration(configuration);
-
- if (m_configuration.tvVendor != CEC_VENDOR_UNKNOWN)
- m_busDevices[CECDEVICE_TV]->ReplaceHandler(false);
+ m_busDevices = new CCECDeviceMap(this);
}
-CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types, uint16_t iPhysicalAddress) :
- m_bConnectionOpened(false),
- m_bInitialised(false),
- m_communication(NULL),
- m_controller(controller),
- m_bMonitor(false),
- m_iStandardLineTimeout(3),
- m_iRetryLineTimeout(3),
- m_iLastTransmission(0)
+CCECProcessor::~CCECProcessor(void)
{
- m_configuration.Clear();
- m_configuration.serverVersion = LIBCEC_VERSION_CURRENT;
-
- // client version < 1.5.0
- m_configuration.clientVersion = (uint32_t)CEC_CLIENT_VERSION_PRE_1_5;
- snprintf(m_configuration.strDeviceName, 13, "%s", strDeviceName);
- m_configuration.deviceTypes = types;
- m_configuration.iPhysicalAddress = iPhysicalAddress;
- m_configuration.baseDevice = (cec_logical_address)CEC_DEFAULT_BASE_DEVICE;
- m_configuration.iHDMIPort = CEC_DEFAULT_HDMI_PORT;
-
- if (m_configuration.deviceTypes.IsEmpty())
- m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
- CreateBusDevices();
+ Close();
+ delete m_busDevices;
}
-void CCECProcessor::CreateBusDevices(void)
+bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
{
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+ CLockObject lock(m_mutex);
+ // open a connection
+ if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
+ return false;
+
+ // create the processor thread
+ if (!IsRunning())
{
- switch(iPtr)
+ if (!CreateThread())
{
- case CECDEVICE_AUDIOSYSTEM:
- m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr);
- break;
- case CECDEVICE_PLAYBACKDEVICE1:
- case CECDEVICE_PLAYBACKDEVICE2:
- case CECDEVICE_PLAYBACKDEVICE3:
- m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr);
- break;
- case CECDEVICE_RECORDINGDEVICE1:
- case CECDEVICE_RECORDINGDEVICE2:
- case CECDEVICE_RECORDINGDEVICE3:
- m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr);
- break;
- case CECDEVICE_TUNER1:
- case CECDEVICE_TUNER2:
- case CECDEVICE_TUNER3:
- case CECDEVICE_TUNER4:
- m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr);
- break;
- case CECDEVICE_TV:
- m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr);
- break;
- default:
- m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr);
- break;
+ m_libcec->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+ return false;
}
}
-}
-CCECProcessor::~CCECProcessor(void)
-{
- Close();
-
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
- {
- delete m_busDevices[iPtr];
- m_busDevices[iPtr] = NULL;
- }
+ return true;
}
void CCECProcessor::Close(void)
{
- StopThread(false);
- SetInitialised(false);
+ // mark as uninitialised
+ SetCECInitialised(false);
+
+ // stop the processor
StopThread();
- bool bClose(false);
+ // close the connection
+ if (m_communication)
{
- CLockObject lock(m_mutex);
- bClose = m_bConnectionOpened;
- m_bConnectionOpened = false;
+ delete m_communication;
+ m_communication = NULL;
}
+}
- if (bClose && m_communication)
+void CCECProcessor::ResetMembers(void)
+{
+ // close the connection
+ if (m_communication)
{
delete m_communication;
m_communication = NULL;
}
+
+ // reset the other members to the initial state
+ m_iStandardLineTimeout = 3;
+ m_iRetryLineTimeout = 3;
+ m_iLastTransmission = 0;
+ m_busDevices->ResetDeviceStatus();
}
bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening /* = true */)
{
bool bReturn(false);
+ CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
+
+ // ensure that a previous connection is closed
Close();
+ // reset all member to the initial state
+ ResetMembers();
+
+ // check whether the Close() method deleted any previous connection
+ if (m_communication)
{
- CLockObject lock(m_mutex);
- if (m_bConnectionOpened)
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "connection already opened");
- return false;
- }
- m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
- m_bConnectionOpened = (m_communication != NULL);
+ m_libcec->AddLog(CEC_LOG_ERROR, "previous connection could not be closed");
+ return bReturn;
}
- CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
+ // create a new connection
+ m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
- /* open a new connection */
+ // open a new connection
unsigned iConnectTry(0);
while (timeout.TimeLeft() > 0 && (bReturn = m_communication->Open((timeout.TimeLeft() / CEC_CONNECT_TRIES), false, bStartListening)) == false)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+ m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
m_communication->Close();
CEvent::Sleep(CEC_DEFAULT_CONNECT_RETRY_WAIT);
}
- if (bReturn)
- {
- m_configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
- m_configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
- CStdString strLog;
- strLog.Format("connected to the CEC adapter. libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version)m_configuration.serverVersion), ToString((cec_client_version)m_configuration.clientVersion), m_configuration.iFirmwareVersion);
- if (m_configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
- {
- time_t buildTime = (time_t)m_configuration.iFirmwareBuildDate;
- strLog.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime)));
- strLog = strLog.Left((int)strLog.length() - 1); // strip \n added by asctime
- strLog.append(" +0000");
- }
- CLibCEC::AddLog(CEC_LOG_NOTICE, strLog);
- }
+ m_libcec->AddLog(CEC_LOG_NOTICE, "connection opened");
- if (m_configuration.bGetSettingsFromROM == 1)
- {
- libcec_configuration config;
- config.Clear();
- m_communication->GetConfiguration(&config);
+ // always start by setting the ackmask to 0, to clear previous values
+ SetAckMask(0);
- CLockObject lock(m_mutex);
- if (!config.deviceTypes.IsEmpty())
- m_configuration.deviceTypes = config.deviceTypes;
- if (IsValidPhysicalAddress(config.iPhysicalAddress))
- m_configuration.iPhysicalAddress = config.iPhysicalAddress;
- snprintf(m_configuration.strDeviceName, 13, "%s", config.strDeviceName);
- }
+ // mark as initialised
+ SetCECInitialised(true);
return bReturn;
}
-bool CCECProcessor::IsInitialised(void)
+bool CCECProcessor::CECInitialised(void)
{
CLockObject lock(m_threadMutex);
return m_bInitialised;
}
-void CCECProcessor::SetInitialised(bool bSetTo /* = true */)
+void CCECProcessor::SetCECInitialised(bool bSetTo /* = true */)
{
- CLockObject lock(m_mutex);
- m_bInitialised = bSetTo;
-}
-
-bool CCECProcessor::Initialise(void)
-{
- bool bReturn(false);
{
CLockObject lock(m_mutex);
- if (!m_configuration.logicalAddresses.IsEmpty())
- m_configuration.logicalAddresses.Clear();
-
- if (!FindLogicalAddresses())
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
- return bReturn;
- }
-
- /* only set our OSD name for the primary device */
- m_busDevices[m_configuration.logicalAddresses.primary]->m_strDeviceName = m_configuration.strDeviceName;
-
- /* make the primary device the active source if the option is set */
- if (m_configuration.bActivateSource == 1)
- m_busDevices[m_configuration.logicalAddresses.primary]->m_bActiveSource = true;
-
- /* set the default menu language for devices we control */
- cec_menu_language language;
- language.device = m_configuration.logicalAddresses.primary;
- memcpy(language.language, m_configuration.strDeviceLanguage, 3);
- language.language[3] = 0;
-
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_configuration.logicalAddresses[iPtr])
- {
- language.device = (cec_logical_address) iPtr;
- m_busDevices[iPtr]->SetMenuLanguage(language);
- }
- }
- }
-
- /* get the vendor id from the TV, so we are using the correct handler */
- m_busDevices[CECDEVICE_TV]->GetVendorId();
-
- if (IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
- {
- CLibCEC::AddLog(CEC_LOG_NOTICE, "setting the physical address to %04X", m_configuration.iPhysicalAddress);
- m_busDevices[m_configuration.logicalAddresses.primary]->m_iPhysicalAddress = m_configuration.iPhysicalAddress;
- if ((bReturn = m_busDevices[m_configuration.logicalAddresses.primary]->TransmitPhysicalAddress()) == false)
- CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set the physical address to %04X", m_configuration.iPhysicalAddress);
- }
- else
- {
- if (!SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort, true))
- CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set HDMI port %d on %s (%x)", m_configuration.iHDMIPort, ToString(m_configuration.baseDevice), (uint8_t)m_configuration.baseDevice);
- bReturn = true;
- }
-
- if (bReturn && m_configuration.bActivateSource == 1)
- m_busDevices[m_configuration.logicalAddresses.primary]->ActivateSource();
-
- SetInitialised(bReturn);
- if (bReturn)
- CLibCEC::ConfigurationChanged(m_configuration);
-
- return bReturn;
-}
-
-bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
-{
- bool bReturn(false);
-
- {
- CLockObject lock(m_mutex);
- if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
- return bReturn;
-
- /* create the processor thread */
- if (!CreateThread())
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
- return bReturn;
- }
- }
-
- if ((bReturn = Initialise()) == false)
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
- StopThread(true);
+ m_bInitialised = bSetTo;
}
- else
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
- }
-
- return bReturn;
+ if (!bSetTo)
+ UnregisterClients();
}
bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
{
- if (m_busDevices[address]->TryLogicalAddress())
- {
- m_configuration.logicalAddresses.Set(address);
- return true;
- }
-
- return false;
-}
-
-bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
-{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
- return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1) ||
- TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2) ||
- TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3);
-}
-
-bool CCECProcessor::FindLogicalAddressTuner(void)
-{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
- return TryLogicalAddress(CECDEVICE_TUNER1) ||
- TryLogicalAddress(CECDEVICE_TUNER2) ||
- TryLogicalAddress(CECDEVICE_TUNER3) ||
- TryLogicalAddress(CECDEVICE_TUNER4);
-}
-
-bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
-{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
- return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1) ||
- TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2) ||
- TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3);
-}
-
-bool CCECProcessor::FindLogicalAddressAudioSystem(void)
-{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
- return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
-}
-
-bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
-{
- bool bChanged(false);
-
- CLibCEC::AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
-
- CLockObject lock(m_mutex);
- CCECBusDevice *previousDevice = GetDeviceByType(from);
- m_configuration.logicalAddresses.primary = CECDEVICE_UNKNOWN;
-
- for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
- {
- if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
- continue;
-
- if (m_configuration.deviceTypes.types[iPtr] == from)
- {
- bChanged = true;
- m_configuration.deviceTypes.types[iPtr] = to;
- }
- else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged)
- {
- m_configuration.deviceTypes.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_NOT_PRESENT);
-
- newDevice->SetCecVersion(previousDevice->GetCecVersion(false));
- previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN);
-
- newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false));
-
- newDevice->SetMenuState(previousDevice->GetMenuState());
- previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
-
- newDevice->SetOSDName(previousDevice->GetOSDName(false));
- previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress()));
-
- newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress());
- previousDevice->SetPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
-
- 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);
- m_configuration.logicalAddresses.Clear();
-
- if (m_configuration.deviceTypes.IsEmpty())
+ // find the device
+ CCECBusDevice *device = m_busDevices->At(address);
+ if (device)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "no device types set");
- return false;
- }
+ // check if it's already marked as present or used
+ if (device->IsPresent() || device->IsHandledByLibCEC())
+ return false;
- for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
- {
- if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
- continue;
-
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - device %d: type %d", __FUNCTION__, iPtr, m_configuration.deviceTypes.types[iPtr]);
-
- if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
- bReturn &= FindLogicalAddressRecordingDevice();
- if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
- bReturn &= FindLogicalAddressTuner();
- if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
- bReturn &= FindLogicalAddressPlaybackDevice();
- if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
- bReturn &= FindLogicalAddressAudioSystem();
+ // poll the LA if not
+ SetAckMask(0);
+ return device->TryLogicalAddress();
}
- if (bReturn)
- SetAckMask(m_configuration.logicalAddresses.AckMask());
-
- return bReturn;
+ return false;
}
void CCECProcessor::ReplaceHandlers(void)
{
- if (!IsInitialised())
+ if (!CECInitialised())
return;
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
- m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
+
+ // check each device
+ for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+ it->second->ReplaceHandler(true);
}
bool CCECProcessor::OnCommandReceived(const cec_command &command)
void *CCECProcessor::Process(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
+ m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
cec_command command;
- command.Clear();
+ // as long as we're not being stopped and the connection is open
while (!IsStopped() && m_communication->IsOpen())
{
+ // wait for a new incoming command, and process it
if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME))
- ParseCommand(command);
+ ProcessCommand(command);
- if (IsInitialised())
+ if (CECInitialised())
{
- ReplaceHandlers();
+ // check clients for keypress timeouts
+ m_libcec->CheckKeypressTimeout();
- m_controller->CheckKeypressTimeout();
+ // check if we need to replace handlers
+ ReplaceHandlers();
}
}
return NULL;
}
-bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
+bool CCECProcessor::ActivateSource(uint16_t iStreamPath)
{
bool bReturn(false);
- if (!IsRunning())
- return bReturn;
-
- cec_logical_address addr = m_configuration.logicalAddresses.primary;
-
- if (type != CEC_DEVICE_TYPE_RESERVED)
- {
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
- {
- if (m_configuration.logicalAddresses[iPtr] && m_busDevices[iPtr]->m_type == type)
- {
- addr = (cec_logical_address) iPtr;
- break;
- }
- }
- }
-
- m_busDevices[addr]->SetActiveSource();
- if (IsValidPhysicalAddress(m_busDevices[addr]->GetPhysicalAddress()))
- bReturn = m_busDevices[addr]->ActivateSource();
-
- return bReturn;
-}
-
-bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
-{
- bool bReturn(false);
-
- // suppress polls when searching for a device
+ // find the device with the given PA
CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
+ // and make it the active source when found
if (device)
- {
- device->SetActiveSource();
- bReturn = true;
- }
+ bReturn = device->ActivateSource();
else
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath);
- }
+ m_libcec->AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath);
return bReturn;
}
void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
{
- CLockObject lock(m_mutex);
- m_iStandardLineTimeout = iTimeout;
-}
-
-void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
-{
- CLockObject lock(m_mutex);
- m_iRetryLineTimeout = iTimeout;
-}
-
-bool CCECProcessor::SetActiveView(void)
-{
- CLibCEC::AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
- return SetActiveSource(m_configuration.deviceTypes.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_configuration.deviceTypes[0]);
-}
-
-bool CCECProcessor::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
-{
- bool bReturn(false);
-
- CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
- if (device)
- {
- ((CCECPlaybackDevice *) device)->SetDeckControlMode(mode);
- if (bSendUpdate)
- ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
- bReturn = true;
- }
-
- return bReturn;
-}
-
-bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
-{
- bool bReturn(false);
-
- CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
- if (device)
- {
- ((CCECPlaybackDevice *) device)->SetDeckStatus(info);
- if (bSendUpdate)
- ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
- bReturn = true;
- }
-
- return bReturn;
-}
-
-bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
-{
- bool bReturn(false);
-
- // limit the HDMI port range to 1-15
- if (iPort < CEC_MIN_HDMI_PORTNUMBER ||
- iPort > CEC_MAX_HDMI_PORTNUMBER)
- return bReturn;
-
- {
- CLockObject lock(m_mutex);
- m_configuration.baseDevice = iBaseDevice;
- m_configuration.iHDMIPort = iPort;
- }
-
- if (!IsRunning() && !bForce)
- return true;
-
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
-
- uint16_t iPhysicalAddress(0);
- if (iBaseDevice > CECDEVICE_TV)
- iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress(false);
-
- if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS)
- {
- if (iPhysicalAddress == 0)
- iPhysicalAddress += 0x1000 * iPort;
- else if (iPhysicalAddress % 0x1000 == 0)
- iPhysicalAddress += 0x100 * iPort;
- else if (iPhysicalAddress % 0x100 == 0)
- iPhysicalAddress += 0x10 * iPort;
- else if (iPhysicalAddress % 0x10 == 0)
- iPhysicalAddress += iPort;
-
- bReturn = true;
- }
-
- if (!bReturn)
- {
- CLibCEC::AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress, CEC_DEFAULT_PHYSICAL_ADDRESS);
- iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
- }
-
- SetPhysicalAddress(iPhysicalAddress);
-
- return bReturn;
-}
-
-bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
-{
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress)
- return true;
- }
- return false;
-}
-
-bool CCECProcessor::TransmitInactiveSource(void)
-{
- if (!IsRunning())
- return false;
-
- if (!m_configuration.logicalAddresses.IsEmpty() && m_busDevices[m_configuration.logicalAddresses.primary])
- return m_busDevices[m_configuration.logicalAddresses.primary]->TransmitInactiveSource();
- return false;
-}
-
-void CCECProcessor::LogOutput(const cec_command &data)
-{
- CStdString strTx;
- strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
- if (data.opcode_set)
- strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
-
- for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
- strTx.AppendFormat(":%02x", data.parameters[iPtr]);
- CLibCEC::AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
-}
-
-bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
-{
- CLockObject lock(m_mutex);
- if (m_configuration.logicalAddresses.primary != iLogicalAddress)
- {
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
- m_configuration.logicalAddresses.primary = iLogicalAddress;
- m_configuration.logicalAddresses.Set(iLogicalAddress);
- return SetAckMask(m_configuration.logicalAddresses.AckMask());
- }
-
- return true;
-}
-
-bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
-{
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_configuration.logicalAddresses[iPtr])
- m_busDevices[iPtr]->SetMenuState(state);
- }
-
- if (bSendUpdate)
- m_busDevices[m_configuration.logicalAddresses.primary]->TransmitMenuState(CECDEVICE_TV);
-
- return true;
-}
-
-bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate /* = true */)
-{
- bool bSendActiveView(false);
- bool bReturn(false);
- cec_logical_addresses sendUpdatesTo;
- sendUpdatesTo.Clear();
-
- {
- CLockObject lock(m_mutex);
- m_configuration.iPhysicalAddress = iPhysicalAddress;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress);
-
- if (!m_configuration.logicalAddresses.IsEmpty())
- {
- bool bWasActiveSource(false);
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- if (m_configuration.logicalAddresses[iPtr])
- {
- bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource();
- m_busDevices[iPtr]->SetInactiveSource();
- m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
- if (bSendUpdate)
- sendUpdatesTo.Set((cec_logical_address)iPtr);
- }
-
- bSendActiveView = bWasActiveSource && bSendUpdate;
- bReturn = true;
- }
- }
-
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- if (sendUpdatesTo[iPtr])
- m_busDevices[iPtr]->TransmitPhysicalAddress();
-
- if (bSendActiveView)
- SetActiveView();
-
- if (bReturn)
- {
- libcec_configuration config;
- {
- CLockObject lock(m_mutex);
- config = m_configuration;
- }
-
- PersistConfiguration(&config);
- CLibCEC::ConfigurationChanged(config);
- }
-
- return bReturn;
-}
-
-bool CCECProcessor::SwitchMonitoring(bool bEnable)
-{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
-
- {
- CLockObject lock(m_mutex);
- m_bMonitor = bEnable;
- }
-
- if (bEnable)
- return SetAckMask(0);
- else
- return SetAckMask(m_configuration.logicalAddresses.AckMask());
-}
-
-bool CCECProcessor::PollDevice(cec_logical_address iAddress)
-{
- if (iAddress != CECDEVICE_UNKNOWN && m_busDevices[iAddress])
- {
- return m_configuration.logicalAddresses.primary == CECDEVICE_UNKNOWN ?
- m_busDevices[iAddress]->TransmitPoll(iAddress) :
- m_busDevices[m_configuration.logicalAddresses.primary]->TransmitPoll(iAddress);
- }
- return false;
-}
-
-uint8_t CCECProcessor::VolumeUp(bool bSendRelease /* = true */)
-{
- uint8_t status(CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
- if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
- status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bSendRelease);
-
- return status;
-}
-
-uint8_t CCECProcessor::VolumeDown(bool bSendRelease /* = true */)
-{
- uint8_t status(CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
- if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
- status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bSendRelease);
-
- return status;
-}
-
-uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
-{
- uint8_t status(CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
- if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
- status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bSendRelease);
-
- return status;
-}
-
-CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
-{
- CCECBusDevice *device(NULL);
-
- // check each device until we found a match
- for (uint8_t iPtr = CECDEVICE_TV; !device && iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_busDevices[iPtr]->GetPhysicalAddress(bSuppressUpdate) == iPhysicalAddress)
- device = m_busDevices[iPtr];
- }
-
- return device;
-}
-
-CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const
-{
- CCECBusDevice *device = NULL;
-
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_busDevices[iPtr]->m_type == type && m_configuration.logicalAddresses[iPtr])
- {
- device = m_busDevices[iPtr];
- break;
- }
- }
-
- return device;
+ CLockObject lock(m_mutex);
+ m_iStandardLineTimeout = iTimeout;
}
-CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const
+uint8_t CCECProcessor::GetStandardLineTimeout(void)
{
- CCECBusDevice *device(NULL);
- cec_logical_address primary = m_configuration.logicalAddresses.primary;
- if (primary != CECDEVICE_UNKNOWN)
- device = m_busDevices[primary];
- return device;
+ CLockObject lock(m_mutex);
+ return m_iStandardLineTimeout;
}
-cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
+void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
{
- return m_busDevices[iAddress]->GetCecVersion();
+ CLockObject lock(m_mutex);
+ m_iRetryLineTimeout = iTimeout;
}
-cec_osd_name CCECProcessor::GetDeviceOSDName(cec_logical_address iAddress)
+uint8_t CCECProcessor::GetRetryLineTimeout(void)
{
- CStdString strOSDName = m_busDevices[iAddress]->GetOSDName();
- cec_osd_name retVal;
-
- snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
- retVal.device = iAddress;
-
- return retVal;
+ CLockObject lock(m_mutex);
+ return m_iRetryLineTimeout;
}
-bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
+bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
{
- if (m_busDevices[iAddress])
- {
- *language = m_busDevices[iAddress]->GetMenuLanguage();
- return (strcmp(language->language, "???") != 0);
- }
- return false;
+ CCECBusDevice *device = GetDeviceByPhysicalAddress(iPhysicalAddress);
+ return device != NULL;
}
-CStdString CCECProcessor::GetDeviceName(void) const
+void CCECProcessor::LogOutput(const cec_command &data)
{
- CStdString strName;
- strName = m_configuration.strDeviceName;
- return strName;
+ CStdString strTx;
+
+ // initiator and destination
+ strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
+
+ // append the opcode
+ if (data.opcode_set)
+ strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
+
+ // append the parameters
+ for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
+ strTx.AppendFormat(":%02x", data.parameters[iPtr]);
+
+ // and log it
+ m_libcec->AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
}
-uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
+bool CCECProcessor::PollDevice(cec_logical_address iAddress)
{
- if (m_busDevices[iAddress])
- return m_busDevices[iAddress]->GetVendorId();
+ // try to find the primary device
+ CCECBusDevice *primary = GetPrimaryDevice();
+ // poll the destination, with the primary as source
+ if (primary)
+ return primary->TransmitPoll(iAddress);
+
+ // try to find the destination
+ CCECBusDevice *device = m_busDevices->At(iAddress);
+ // and poll the destination, with the same LA as source
+ if (device)
+ return device->TransmitPoll(iAddress);
+
return false;
}
-uint16_t CCECProcessor::GetDevicePhysicalAddress(cec_logical_address iAddress)
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
{
- if (m_busDevices[iAddress])
- return m_busDevices[iAddress]->GetPhysicalAddress(false);
- return false;
+ return m_busDevices ?
+ m_busDevices->GetDeviceByPhysicalAddress(iPhysicalAddress, bSuppressUpdate) :
+ NULL;
}
-cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddress)
+CCECBusDevice *CCECProcessor::GetDevice(cec_logical_address address) const
{
- if (m_busDevices[iAddress])
- return m_busDevices[iAddress]->GetPowerStatus();
- return CEC_POWER_STATUS_UNKNOWN;
+ return m_busDevices ?
+ m_busDevices->At(address) :
+ NULL;
}
cec_logical_address CCECProcessor::GetActiveSource(bool bRequestActiveSource /* = true */)
{
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
- {
- if (m_busDevices[iPtr]->IsActiveSource())
- return (cec_logical_address)iPtr;
- }
+ // get the device that is marked as active source from the device map
+ CCECBusDevice *activeSource = m_busDevices->GetActiveSource();
+ if (activeSource)
+ return activeSource->GetLogicalAddress();
- if (bRequestActiveSource && m_configuration.logicalAddresses.primary != CECDEVICE_UNKNOWN)
+ if (bRequestActiveSource)
{
- CCECBusDevice *primary = m_busDevices[m_configuration.logicalAddresses.primary];
+ // request the active source from the bus
+ CCECBusDevice *primary = GetPrimaryDevice();
if (primary)
+ {
primary->RequestActiveSource();
-
- return GetActiveSource(false);
+ return GetActiveSource(false);
+ }
}
+ // unknown or none
return CECDEVICE_UNKNOWN;
}
bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
{
- return iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST ?
- m_busDevices[iAddress]->IsActiveSource() :
- false;
+ CCECBusDevice *device = m_busDevices->At(iAddress);
+ return device && device->IsActiveSource();
}
bool CCECProcessor::Transmit(const cec_command &data)
{
- if (m_configuration.logicalAddresses[(uint8_t)data.destination])
+ uint8_t iMaxTries(0);
+ bool bRetry(true);
+ uint8_t iTries(0);
+
+ // get the current timeout setting
+ uint8_t iLineTimeout(GetStandardLineTimeout());
+
+ // reset the state of this message to 'unknown'
+ cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;
+
+ LogOutput(data);
+
+ // find the initiator device
+ CCECBusDevice *initiator = m_busDevices->At(data.initiator);
+ if (!initiator)
{
- CLibCEC::AddLog(CEC_LOG_WARNING, "not sending data to myself!");
+ m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator");
return false;
}
- uint8_t iMaxTries(0);
+ // find the destination device, if it's not the broadcast address
+ if (data.destination != CECDEVICE_BROADCAST)
{
- CLockObject lock(m_mutex);
- if (IsStopped())
- return false;
- LogOutput(data);
- m_iLastTransmission = GetTimeMs();
- if (!m_communication || !m_communication->IsOpen())
+ // check if the device is marked as handled by libCEC
+ CCECBusDevice *destination = m_busDevices->At(data.destination);
+ if (destination && destination->IsHandledByLibCEC())
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "cannot transmit command: connection closed");
+ // and reject the command if it's trying to send data to a device that is handled by libCEC
+ m_libcec->AddLog(CEC_LOG_WARNING, "not sending data to myself!");
return false;
}
- iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
}
- bool bRetry(true);
- uint8_t iTries(0);
- uint8_t iLineTimeout = m_iStandardLineTimeout;
- cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;
+ {
+ CLockObject lock(m_mutex);
+ m_iLastTransmission = GetTimeMs();
+ // set the number of tries
+ iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
+ }
+ // and try to send the command
while (bRetry && ++iTries < iMaxTries)
{
- if (m_busDevices[data.initiator]->IsUnsupportedFeature(data.opcode))
+ if (initiator->IsUnsupportedFeature(data.opcode))
return false;
- adapterState = m_communication->Write(data, bRetry, iLineTimeout);
+ adapterState = !IsStopped() && m_communication && m_communication->IsOpen() ?
+ m_communication->Write(data, bRetry, iLineTimeout) :
+ ADAPTER_MESSAGE_STATE_ERROR;
iLineTimeout = m_iRetryLineTimeout;
}
return adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
}
-void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
+void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
+ m_libcec->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
cec_command command;
- // TODO
- cec_command::Format(command, m_configuration.logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
+ cec_command::Format(command, source, destination, CEC_OPCODE_FEATURE_ABORT);
command.parameters.PushBack((uint8_t)opcode);
command.parameters.PushBack((uint8_t)reason);
Transmit(command);
}
-void CCECProcessor::ParseCommand(const cec_command &command)
+void CCECProcessor::ProcessCommand(const cec_command &command)
{
+ // log the command
CStdString dataStr;
dataStr.Format(">> %1x%1x", command.initiator, command.destination);
if (command.opcode_set == 1)
dataStr.AppendFormat(":%02x", command.opcode);
for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]);
- CLibCEC::AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
+ m_libcec->AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
- if (!m_bMonitor && command.initiator >= CECDEVICE_TV && command.initiator <= CECDEVICE_BROADCAST)
- m_busDevices[(uint8_t)command.initiator]->HandleCommand(command);
-}
+ // find the initiator
+ CCECBusDevice *device = m_busDevices->At(command.initiator);
-cec_logical_addresses CCECProcessor::GetActiveDevices(void)
-{
- cec_logical_addresses addresses;
- addresses.Clear();
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
- addresses.Set((cec_logical_address) iPtr);
- }
- return addresses;
+ if (device)
+ device->HandleCommand(command);
}
bool CCECProcessor::IsPresentDevice(cec_logical_address address)
{
- return m_busDevices[address]->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
+ CCECBusDevice *device = m_busDevices->At(address);
+ return device && device->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
}
bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
{
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_busDevices[iPtr]->GetType() == type && m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
- return true;
- }
-
- return false;
+ CECDEVICEVEC devices;
+ m_busDevices->GetByType(type, devices);
+ CCECDeviceMap::FilterActive(devices);
+ return !devices.empty();
}
-uint16_t CCECProcessor::GetPhysicalAddress(void) const
+uint16_t CCECProcessor::GetDetectedPhysicalAddress(void) const
{
- if (!m_configuration.logicalAddresses.IsEmpty() && m_busDevices[m_configuration.logicalAddresses.primary])
- return m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress();
- return false;
+ return m_communication ? m_communication->GetPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
}
bool CCECProcessor::SetAckMask(uint16_t iMask)
return m_communication ? m_communication->SetAckMask(iMask) : false;
}
-bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
+bool CCECProcessor::StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
{
- return m_busDevices[iDestination]->TransmitKeypress(key, bWait);
+ bool bReturn(true);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ bReturn &= (*it)->Standby(initiator);
+ return bReturn;
}
-bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
+bool CCECProcessor::StandbyDevice(const cec_logical_address initiator, cec_logical_address address)
{
- return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
+ CCECBusDevice *device = m_busDevices->At(address);
+ return device ? device->Standby(initiator) : false;
}
-bool CCECProcessor::EnablePhysicalAddressDetection(void)
+bool CCECProcessor::PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
{
- CLibCEC::AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
- uint16_t iPhysicalAddress = m_communication->GetPhysicalAddress();
- if (IsValidPhysicalAddress(iPhysicalAddress))
- {
- m_configuration.bAutodetectAddress = 1;
- m_configuration.iPhysicalAddress = iPhysicalAddress;
- m_configuration.baseDevice = CECDEVICE_UNKNOWN;
- m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
- return SetPhysicalAddress(iPhysicalAddress);
- }
- return false;
+ bool bReturn(true);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ bReturn &= (*it)->PowerOn(initiator);
+ return bReturn;
}
-bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CCECProcessor::PowerOnDevice(const cec_logical_address initiator, cec_logical_address address)
{
- if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
- {
- bool bReturn(true);
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
- {
- if (m_configuration.powerOffDevices[iPtr])
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - putting '%s' in standby mode", __FUNCTION__, ToString((cec_logical_address)iPtr));
- bReturn &= m_busDevices[iPtr]->Standby();
- }
- }
- return bReturn;
- }
-
- return m_busDevices[address]->Standby();
+ CCECBusDevice *device = m_busDevices->At(address);
+ return device ? device->PowerOn(initiator) : false;
}
-bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
{
- if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
+ bool bReturn(false);
+ // open a connection if no connection has been opened
+ if (!m_communication && strPort)
{
- bool bReturn(true);
- for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+ IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort);
+ CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
+ int iConnectTry(0);
+ while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+ comm->Close();
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+ }
+ if (comm->IsOpen())
{
- if (m_configuration.wakeDevices[iPtr])
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - powering on '%s'", __FUNCTION__, ToString((cec_logical_address)iPtr));
- bReturn &= m_busDevices[iPtr]->PowerOn();
- }
+ bReturn = comm->StartBootloader();
+ delete comm;
}
return bReturn;
}
-
- return m_busDevices[address]->PowerOn();
-}
-
-const char *CCECProcessor::ToString(const cec_device_type type)
-{
- switch (type)
+ else
{
- 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";
+ m_communication->StartBootloader();
+ Close();
+ bReturn = true;
}
-}
-const char *CCECProcessor::ToString(const cec_menu_state state)
-{
- switch (state)
- {
- case CEC_MENU_STATE_ACTIVATED:
- return "activated";
- case CEC_MENU_STATE_DEACTIVATED:
- return "deactivated";
- default:
- return "unknown";
- }
+ return bReturn;
}
-const char *CCECProcessor::ToString(const cec_version version)
+bool CCECProcessor::PingAdapter(void)
{
- switch (version)
- {
- case CEC_VERSION_1_2:
- return "1.2";
- case CEC_VERSION_1_2A:
- return "1.2a";
- case CEC_VERSION_1_3:
- return "1.3";
- case CEC_VERSION_1_3A:
- return "1.3a";
- case CEC_VERSION_1_4:
- return "1.4";
- default:
- return "unknown";
- }
+ return m_communication->PingAdapter();
}
-const char *CCECProcessor::ToString(const cec_power_status status)
+void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
{
- switch (status)
- {
- case CEC_POWER_STATUS_ON:
- return "on";
- case CEC_POWER_STATUS_STANDBY:
- return "standby";
- case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
- return "in transition from on to standby";
- case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
- return "in transition from standby to on";
- default:
- return "unknown";
- }
+ CCECBusDevice *device = m_busDevices->At(destination);
+ if (device)
+ device->HandlePollFrom(initiator);
}
-const char *CCECProcessor::ToString(const cec_logical_address address)
+bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
{
- switch(address)
- {
- case CECDEVICE_AUDIOSYSTEM:
- return "Audio";
- case CECDEVICE_BROADCAST:
- return "Broadcast";
- case CECDEVICE_FREEUSE:
- return "Free use";
- case CECDEVICE_PLAYBACKDEVICE1:
- return "Playback 1";
- case CECDEVICE_PLAYBACKDEVICE2:
- return "Playback 2";
- case CECDEVICE_PLAYBACKDEVICE3:
- return "Playback 3";
- case CECDEVICE_RECORDINGDEVICE1:
- return "Recorder 1";
- case CECDEVICE_RECORDINGDEVICE2:
- return "Recorder 2";
- case CECDEVICE_RECORDINGDEVICE3:
- return "Recorder 3";
- case CECDEVICE_RESERVED1:
- return "Reserved 1";
- case CECDEVICE_RESERVED2:
- return "Reserved 2";
- case CECDEVICE_TUNER1:
- return "Tuner 1";
- case CECDEVICE_TUNER2:
- return "Tuner 2";
- case CECDEVICE_TUNER3:
- return "Tuner 3";
- case CECDEVICE_TUNER4:
- return "Tuner 4";
- case CECDEVICE_TV:
- return "TV";
- default:
- return "unknown";
- }
+ CCECBusDevice *device = m_busDevices->At(initiator);
+ return !device || !device->HandleReceiveFailed();
}
-const char *CCECProcessor::ToString(const cec_deck_control_mode mode)
+bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
{
- switch (mode)
- {
- case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
- return "skip forward wind";
- case CEC_DECK_CONTROL_MODE_EJECT:
- return "eject";
- case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
- return "reverse rewind";
- case CEC_DECK_CONTROL_MODE_STOP:
- return "stop";
- default:
- return "unknown";
- }
+ // stream path changes are sent by the TV
+ return GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
}
-const char *CCECProcessor::ToString(const cec_deck_info status)
+bool CCECProcessor::CanPersistConfiguration(void)
{
- switch (status)
- {
- case CEC_DECK_INFO_PLAY:
- return "play";
- case CEC_DECK_INFO_RECORD:
- return "record";
- case CEC_DECK_INFO_PLAY_REVERSE:
- return "play reverse";
- case CEC_DECK_INFO_STILL:
- return "still";
- case CEC_DECK_INFO_SLOW:
- return "slow";
- case CEC_DECK_INFO_SLOW_REVERSE:
- return "slow reverse";
- case CEC_DECK_INFO_FAST_FORWARD:
- return "fast forward";
- case CEC_DECK_INFO_FAST_REVERSE:
- return "fast reverse";
- case CEC_DECK_INFO_NO_MEDIA:
- return "no media";
- case CEC_DECK_INFO_STOP:
- return "stop";
- case CEC_DECK_INFO_SKIP_FORWARD_WIND:
- return "info skip forward wind";
- case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
- return "info skip reverse rewind";
- case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
- return "info index search forward";
- case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
- return "info index search reverse";
- case CEC_DECK_INFO_OTHER_STATUS:
- return "other";
- case CEC_DECK_INFO_OTHER_STATUS_LG:
- return "LG other";
- default:
- return "unknown";
- }
+ return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
}
-const char *CCECProcessor::ToString(const cec_opcode opcode)
+bool CCECProcessor::PersistConfiguration(const libcec_configuration &configuration)
{
- switch (opcode)
- {
- case CEC_OPCODE_ACTIVE_SOURCE:
- return "active source";
- case CEC_OPCODE_IMAGE_VIEW_ON:
- return "image view on";
- case CEC_OPCODE_TEXT_VIEW_ON:
- return "text view on";
- case CEC_OPCODE_INACTIVE_SOURCE:
- return "inactive source";
- case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
- return "request active source";
- case CEC_OPCODE_ROUTING_CHANGE:
- return "routing change";
- case CEC_OPCODE_ROUTING_INFORMATION:
- return "routing information";
- case CEC_OPCODE_SET_STREAM_PATH:
- return "set stream path";
- case CEC_OPCODE_STANDBY:
- return "standby";
- case CEC_OPCODE_RECORD_OFF:
- return "record off";
- case CEC_OPCODE_RECORD_ON:
- return "record on";
- case CEC_OPCODE_RECORD_STATUS:
- return "record status";
- case CEC_OPCODE_RECORD_TV_SCREEN:
- return "record tv screen";
- case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
- return "clear analogue timer";
- case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
- return "clear digital timer";
- case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
- return "clear external timer";
- case CEC_OPCODE_SET_ANALOGUE_TIMER:
- return "set analogue timer";
- case CEC_OPCODE_SET_DIGITAL_TIMER:
- return "set digital timer";
- case CEC_OPCODE_SET_EXTERNAL_TIMER:
- return "set external timer";
- case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
- return "set timer program title";
- case CEC_OPCODE_TIMER_CLEARED_STATUS:
- return "timer cleared status";
- case CEC_OPCODE_TIMER_STATUS:
- return "timer status";
- case CEC_OPCODE_CEC_VERSION:
- return "cec version";
- case CEC_OPCODE_GET_CEC_VERSION:
- return "get cec version";
- case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
- return "give physical address";
- case CEC_OPCODE_GET_MENU_LANGUAGE:
- return "get menu language";
- case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
- return "report physical address";
- case CEC_OPCODE_SET_MENU_LANGUAGE:
- return "set menu language";
- case CEC_OPCODE_DECK_CONTROL:
- return "deck control";
- case CEC_OPCODE_DECK_STATUS:
- return "deck status";
- case CEC_OPCODE_GIVE_DECK_STATUS:
- return "give deck status";
- case CEC_OPCODE_PLAY:
- return "play";
- case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
- return "give tuner status";
- case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
- return "select analogue service";
- case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
- return "set digital service";
- case CEC_OPCODE_TUNER_DEVICE_STATUS:
- return "tuner device status";
- case CEC_OPCODE_TUNER_STEP_DECREMENT:
- return "tuner step decrement";
- case CEC_OPCODE_TUNER_STEP_INCREMENT:
- return "tuner step increment";
- case CEC_OPCODE_DEVICE_VENDOR_ID:
- return "device vendor id";
- case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
- return "give device vendor id";
- case CEC_OPCODE_VENDOR_COMMAND:
- return "vendor command";
- case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
- return "vendor command with id";
- case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
- return "vendor remote button down";
- case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
- return "vendor remote button up";
- case CEC_OPCODE_SET_OSD_STRING:
- return "set osd string";
- case CEC_OPCODE_GIVE_OSD_NAME:
- return "give osd name";
- case CEC_OPCODE_SET_OSD_NAME:
- return "set osd name";
- case CEC_OPCODE_MENU_REQUEST:
- return "menu request";
- case CEC_OPCODE_MENU_STATUS:
- return "menu status";
- case CEC_OPCODE_USER_CONTROL_PRESSED:
- return "user control pressed";
- case CEC_OPCODE_USER_CONTROL_RELEASE:
- return "user control release";
- case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
- return "give device power status";
- case CEC_OPCODE_REPORT_POWER_STATUS:
- return "report power status";
- case CEC_OPCODE_FEATURE_ABORT:
- return "feature abort";
- case CEC_OPCODE_ABORT:
- return "abort";
- case CEC_OPCODE_GIVE_AUDIO_STATUS:
- return "give audio status";
- case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
- return "give audio mode status";
- case CEC_OPCODE_REPORT_AUDIO_STATUS:
- return "report audio status";
- case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
- return "set system audio mode";
- case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
- return "system audio mode request";
- case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
- return "system audio mode status";
- case CEC_OPCODE_SET_AUDIO_RATE:
- return "set audio rate";
- case CEC_OPCODE_NONE:
- return "poll";
- default:
- return "UNKNOWN";
- }
+ return m_communication ? m_communication->PersistConfiguration(configuration) : false;
}
-const char *CCECProcessor::ToString(const cec_system_audio_status mode)
+void CCECProcessor::RescanActiveDevices(void)
{
- switch(mode)
- {
- case CEC_SYSTEM_AUDIO_STATUS_ON:
- return "on";
- case CEC_SYSTEM_AUDIO_STATUS_OFF:
- return "off";
- default:
- return "unknown";
- }
+ for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+ it->second->GetStatus(true);
}
-const char *CCECProcessor::ToString(const cec_audio_status UNUSED(status))
+bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
{
- // TODO this is a mask
- return "TODO";
-}
+ if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false))
+ return false;
-const char *CCECProcessor::ToString(const cec_vendor_id vendor)
-{
- switch (vendor)
- {
- case CEC_VENDOR_SAMSUNG:
- return "Samsung";
- case CEC_VENDOR_LG:
- return "LG";
- case CEC_VENDOR_PANASONIC:
- return "Panasonic";
- case CEC_VENDOR_PIONEER:
- return "Pioneer";
- case CEC_VENDOR_ONKYO:
- return "Onkyo";
- case CEC_VENDOR_YAMAHA:
- return "Yamaha";
- case CEC_VENDOR_PHILIPS:
- return "Philips";
- case CEC_VENDOR_SONY:
- return "Sony";
- case CEC_VENDOR_TOSHIBA:
- return "Toshiba";
- default:
- return "Unknown";
- }
-}
+ config->iFirmwareVersion = m_communication->GetFirmwareVersion();
+ config->iPhysicalAddress = m_communication->GetPhysicalAddress();
+ config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
-const char *CCECProcessor::ToString(const cec_client_version version)
-{
- switch (version)
- {
- case CEC_CLIENT_VERSION_PRE_1_5:
- return "pre-1.5";
- case CEC_CLIENT_VERSION_1_5_0:
- return "1.5.0";
- case CEC_CLIENT_VERSION_1_5_1:
- return "1.5.1";
- case CEC_CLIENT_VERSION_1_5_2:
- return "1.5.2";
- case CEC_CLIENT_VERSION_1_5_3:
- return "1.5.3";
- case CEC_CLIENT_VERSION_1_6_0:
- return "1.6.0";
- case CEC_CLIENT_VERSION_1_6_1:
- return "1.6.1";
- case CEC_CLIENT_VERSION_1_6_2:
- return "1.6.2";
- default:
- return "Unknown";
- }
+ return true;
}
-const char *CCECProcessor::ToString(const cec_server_version version)
+bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
{
- switch (version)
- {
- case CEC_SERVER_VERSION_PRE_1_5:
- return "pre-1.5";
- case CEC_SERVER_VERSION_1_5_0:
- return "1.5.0";
- case CEC_SERVER_VERSION_1_5_1:
- return "1.5.1";
- case CEC_SERVER_VERSION_1_5_2:
- return "1.5.2";
- case CEC_SERVER_VERSION_1_5_3:
- return "1.5.3";
- case CEC_SERVER_VERSION_1_6_0:
- return "1.6.0";
- case CEC_SERVER_VERSION_1_6_1:
- return "1.6.1";
- case CEC_SERVER_VERSION_1_6_2:
- return "1.6.2";
- default:
- return "Unknown";
- }
+ bool bReturn(true);
+ for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+ bReturn &= it->second->TransmitPendingActiveSourceCommands();
+ return bReturn;
}
-bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
+CCECTV *CCECProcessor::GetTV(void) const
{
- bool bReturn(false);
- if (!m_communication && strPort)
- {
- IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort);
- CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
- int iConnectTry(0);
- while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
- {
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
- comm->Close();
- Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
- }
- if (comm->IsOpen())
- {
- bReturn = comm->StartBootloader();
- delete comm;
- }
- return bReturn;
- }
- else
- {
- m_communication->StartBootloader();
- Close();
- bReturn = true;
- }
-
- return bReturn;
+ return CCECBusDevice::AsTV(m_busDevices->At(CECDEVICE_TV));
}
-bool CCECProcessor::PingAdapter(void)
+CCECAudioSystem *CCECProcessor::GetAudioSystem(void) const
{
- return m_communication->PingAdapter();
+ return CCECBusDevice::AsAudioSystem(m_busDevices->At(CECDEVICE_AUDIOSYSTEM));
}
-void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
+CCECPlaybackDevice *CCECProcessor::GetPlaybackDevice(cec_logical_address address) const
{
- if (destination < CECDEVICE_BROADCAST)
- m_busDevices[destination]->HandlePollFrom(initiator);
+ return CCECBusDevice::AsPlaybackDevice(m_busDevices->At(address));
}
-bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
+CCECRecordingDevice *CCECProcessor::GetRecordingDevice(cec_logical_address address) const
{
- return !m_busDevices[initiator]->HandleReceiveFailed();
+ return CCECBusDevice::AsRecordingDevice(m_busDevices->At(address));
}
-bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
+CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const
{
- // stream path changes are sent by the TV
- return m_busDevices[CECDEVICE_TV]->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
+ return CCECBusDevice::AsTuner(m_busDevices->At(address));
}
-bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
+bool CCECProcessor::RegisterClient(CCECClient *client)
{
- bool bReinit(false);
- CCECBusDevice *primary = IsRunning() ? GetPrimaryDevice() : NULL;
- cec_device_type oldPrimaryType = primary ? primary->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE;
- m_configuration.clientVersion = configuration->clientVersion;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, ToString((cec_client_version)configuration->clientVersion));
-
- // client version 1.5.0
+ if (!client)
+ return false;
- // device types
- bool bDeviceTypeChanged = IsRunning () && m_configuration.deviceTypes != configuration->deviceTypes;
- m_configuration.deviceTypes = configuration->deviceTypes;
- if (bDeviceTypeChanged)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(configuration->deviceTypes[0]));
+ libcec_configuration &configuration = *client->GetConfiguration();
- bool bPhysicalAddressChanged(false);
+ if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_3 && configuration.bMonitorOnly == 1)
+ return true;
- // autodetect address
- bool bPhysicalAutodetected(false);
- if (IsRunning() && configuration->bAutodetectAddress == 1)
+ if (!CECInitialised())
{
- uint16_t iPhysicalAddress = m_communication->GetPhysicalAddress();
- if (IsValidPhysicalAddress(iPhysicalAddress))
- {
- if (IsRunning())
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%04X'", __FUNCTION__, iPhysicalAddress);
- else
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using physical address '%04X'", __FUNCTION__, iPhysicalAddress);
- bPhysicalAddressChanged = (m_configuration.iPhysicalAddress != iPhysicalAddress);
- m_configuration.iPhysicalAddress = iPhysicalAddress;
- m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
- m_configuration.baseDevice = CECDEVICE_UNKNOWN;
- bPhysicalAutodetected = true;
- }
+ m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: CEC processor is not initialised");
+ return false;
}
- // physical address
- if (!bPhysicalAutodetected)
- {
- uint16_t iPhysicalAddress(IsValidPhysicalAddress(configuration->iPhysicalAddress) ? configuration->iPhysicalAddress : CEC_PHYSICAL_ADDRESS_TV);
- bPhysicalAddressChanged = IsRunning() && m_configuration.iPhysicalAddress != iPhysicalAddress;
- if (bPhysicalAddressChanged)
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - physical address '%04X'", __FUNCTION__, iPhysicalAddress);
- m_configuration.iPhysicalAddress = iPhysicalAddress;
- }
- }
+ // unregister the client first if it's already been marked as registered
+ if (client->IsRegistered())
+ UnregisterClient(client);
- bool bHdmiPortChanged(false);
- if (!bPhysicalAutodetected && !IsValidPhysicalAddress(configuration->iPhysicalAddress))
- {
- // base device
- bHdmiPortChanged = IsRunning() && m_configuration.baseDevice != configuration->baseDevice;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using base device '%x'", __FUNCTION__, (int)configuration->baseDevice);
- m_configuration.baseDevice = configuration->baseDevice;
-
- // hdmi port
- bHdmiPortChanged |= IsRunning() && m_configuration.iHDMIPort != configuration->iHDMIPort;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using HDMI port '%d'", __FUNCTION__, configuration->iHDMIPort);
- m_configuration.iHDMIPort = configuration->iHDMIPort;
- }
- else
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
- m_configuration.baseDevice = CECDEVICE_UNKNOWN;
- m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
- }
+ // get the configuration from the client
+ m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion));
- bReinit = bPhysicalAddressChanged || bHdmiPortChanged || bDeviceTypeChanged;
+ // mark as uninitialised and unregistered
+ client->SetRegistered(false);
+ client->SetInitialised(false);
- // device name
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, configuration->strDeviceName);
- snprintf(m_configuration.strDeviceName, 13, "%s", configuration->strDeviceName);
- if (primary && !primary->GetOSDName().Equals(m_configuration.strDeviceName))
+ // get the current ackmask, so we can restore it if polling fails
+ uint16_t iPreviousMask(m_communication->GetAckMask());
+
+ // find logical addresses for this client
+ if (!client->AllocateLogicalAddresses())
{
- primary->SetOSDName(m_configuration.strDeviceName);
- if (!bReinit && IsRunning())
- primary->TransmitOSDName(CECDEVICE_TV);
+ m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types");
+ SetAckMask(iPreviousMask);
+ return false;
}
- // tv vendor id override
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString((cec_vendor_id)configuration->tvVendor));
- if (m_configuration.tvVendor != configuration->tvVendor)
+ // register this client on the new addresses
+ CECDEVICEVEC devices;
+ m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
{
- m_configuration.tvVendor= configuration->tvVendor;
- m_busDevices[CECDEVICE_TV]->SetVendorId((uint64_t)m_configuration.tvVendor);
+ // replace a previous client
+ CLockObject lock(m_mutex);
+ m_clients.erase((*it)->GetLogicalAddress());
+ m_clients.insert(make_pair<cec_logical_address, CCECClient *>((*it)->GetLogicalAddress(), client));
}
- // wake CEC devices
- if (m_configuration.wakeDevices != configuration->wakeDevices)
+ // get the settings from the rom
+ if (configuration.bGetSettingsFromROM == 1)
{
- m_configuration.wakeDevices = configuration->wakeDevices;
- if (!bReinit && IsRunning())
- PowerOnDevices();
- }
+ libcec_configuration config;
+ m_communication->GetConfiguration(config);
- // just copy these
- m_configuration.bUseTVMenuLanguage = configuration->bUseTVMenuLanguage;
- m_configuration.bActivateSource = configuration->bActivateSource;
- m_configuration.bGetSettingsFromROM = configuration->bGetSettingsFromROM;
- m_configuration.powerOffDevices = configuration->powerOffDevices;
- m_configuration.bPowerOffScreensaver = configuration->bPowerOffScreensaver;
- m_configuration.bPowerOffOnStandby = configuration->bPowerOffOnStandby;
+ CLockObject lock(m_mutex);
+ if (!config.deviceTypes.IsEmpty())
+ configuration.deviceTypes = config.deviceTypes;
+ if (CLibCEC::IsValidPhysicalAddress(config.iPhysicalAddress))
+ configuration.iPhysicalAddress = config.iPhysicalAddress;
+ snprintf(configuration.strDeviceName, 13, "%s", config.strDeviceName);
+ }
- // client version 1.5.1
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_1)
- m_configuration.bSendInactiveSource = configuration->bSendInactiveSource;
+ // set the firmware version and build date
+ configuration.serverVersion = LIBCEC_VERSION_CURRENT;
+ configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
+ configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
- // client version 1.6.0
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_0)
- {
- m_configuration.bPowerOffDevicesOnStandby = configuration->bPowerOffDevicesOnStandby;
- m_configuration.bShutdownOnStandby = configuration->bShutdownOnStandby;
- }
+ // mark the client as registered
+ client->SetRegistered(true);
- // client version 1.6.2
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2)
- {
- memcpy(m_configuration.strDeviceLanguage, configuration->strDeviceLanguage, 3);
- }
+ // set the new ack mask
+ bool bReturn = SetAckMask(GetLogicalAddresses().AckMask()) &&
+ // and initialise the client
+ client->OnRegister();
- // ensure that there is at least 1 device type set
- if (m_configuration.deviceTypes.IsEmpty())
- m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ // log the new registration
+ CStdString strLog;
+ strLog.Format("%s: %s", bReturn ? "CEC client registered" : "failed to register the CEC client", client->GetConnectionInfo().c_str());
+ m_libcec->AddLog(bReturn ? CEC_LOG_NOTICE : CEC_LOG_ERROR, strLog);
- bool bReturn(true);
- if (bReinit || m_configuration.logicalAddresses.IsEmpty())
- {
- if (bDeviceTypeChanged)
- bReturn = ChangeDeviceType(oldPrimaryType, m_configuration.deviceTypes[0]);
- else if (IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
- bReturn = SetPhysicalAddress(m_configuration.iPhysicalAddress);
- else if (m_configuration.baseDevice != CECDEVICE_UNKNOWN && m_configuration.iHDMIPort != CEC_HDMI_PORTNUMBER_NONE)
- bReturn = SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort);
- }
- else if (m_configuration.bActivateSource == 1 && IsRunning() && !IsActiveSource(m_configuration.logicalAddresses.primary))
+ // display a warning if the firmware can be upgraded
+ if (bReturn && !IsRunningLatestFirmware())
{
- // activate the source if we're not already the active source
- SetActiveSource(m_configuration.deviceTypes.types[0]);
+ const char *strUpgradeMessage = "The firmware of this adapter can be upgraded. Please visit http://blog.pulse-eight.com/ for more information.";
+ m_libcec->AddLog(CEC_LOG_WARNING, strUpgradeMessage);
+ libcec_parameter param;
+ param.paramData = (void*)strUpgradeMessage; param.paramType = CEC_PARAMETER_TYPE_STRING;
+ client->Alert(CEC_ALERT_SERVICE_DEVICE, param);
}
- // persist the configuration
- if (IsRunning())
- m_communication->PersistConfiguration(&m_configuration);
-
return bReturn;
}
-bool CCECProcessor::GetCurrentConfiguration(libcec_configuration *configuration)
+bool CCECProcessor::UnregisterClient(CCECClient *client)
{
- // client version 1.5.0
- snprintf(configuration->strDeviceName, 13, "%s", m_configuration.strDeviceName);
- configuration->deviceTypes = m_configuration.deviceTypes;
- configuration->bAutodetectAddress = m_configuration.bAutodetectAddress;
- configuration->iPhysicalAddress = m_configuration.iPhysicalAddress;
- configuration->baseDevice = m_configuration.baseDevice;
- configuration->iHDMIPort = m_configuration.iHDMIPort;
- configuration->clientVersion = m_configuration.clientVersion;
- configuration->serverVersion = m_configuration.serverVersion;
- configuration->tvVendor = m_configuration.tvVendor;
-
- configuration->bGetSettingsFromROM = m_configuration.bGetSettingsFromROM;
- configuration->bUseTVMenuLanguage = m_configuration.bUseTVMenuLanguage;
- configuration->bActivateSource = m_configuration.bActivateSource;
- configuration->wakeDevices = m_configuration.wakeDevices;
- configuration->powerOffDevices = m_configuration.powerOffDevices;
- configuration->bPowerOffScreensaver = m_configuration.bPowerOffScreensaver;
- configuration->bPowerOffOnStandby = m_configuration.bPowerOffOnStandby;
-
- // client version 1.5.1
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_1)
- configuration->bSendInactiveSource = m_configuration.bSendInactiveSource;
-
- // client version 1.5.3
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_3)
- configuration->logicalAddresses = m_configuration.logicalAddresses;
-
- // client version 1.6.0
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_0)
- {
- configuration->iFirmwareVersion = m_configuration.iFirmwareVersion;
- configuration->bPowerOffDevicesOnStandby = m_configuration.bPowerOffDevicesOnStandby;
- configuration->bShutdownOnStandby = m_configuration.bShutdownOnStandby;
- }
+ if (!client)
+ return false;
+
+ if (client->IsRegistered())
+ m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering client: %s", client->GetConnectionInfo().c_str());
+
+ // notify the client that it will be unregistered
+ client->OnUnregister();
- // client version 1.6.2
- if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2)
{
- memcpy(configuration->strDeviceLanguage, m_configuration.strDeviceLanguage, 3);
- configuration->iFirmwareBuildDate = m_configuration.iFirmwareBuildDate;
+ CLockObject lock(m_mutex);
+ // find all devices that match the LA's of this client
+ CECDEVICEVEC devices;
+ m_busDevices->GetByLogicalAddresses(devices, client->GetConfiguration()->logicalAddresses);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // find the client
+ map<cec_logical_address, CCECClient *>::iterator entry = m_clients.find((*it)->GetLogicalAddress());
+ // unregister the client
+ if (entry != m_clients.end())
+ m_clients.erase(entry);
+
+ // reset the device status
+ (*it)->ResetDeviceStatus();
+ }
}
- return true;
+
+ // set the new ackmask
+ return SetAckMask(GetLogicalAddresses().AckMask());
}
-bool CCECProcessor::CanPersistConfiguration(void)
+void CCECProcessor::UnregisterClients(void)
{
- return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
+ m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering all CEC clients");
+
+ vector<CCECClient *> clients = m_libcec->GetClients();
+ for (vector<CCECClient *>::iterator client = clients.begin(); client != clients.end(); client++)
+ UnregisterClient(*client);
+
+ CLockObject lock(m_mutex);
+ m_clients.clear();
}
-bool CCECProcessor::PersistConfiguration(libcec_configuration *configuration)
+CCECClient *CCECProcessor::GetClient(const cec_logical_address address)
{
- return m_communication ? m_communication->PersistConfiguration(configuration) : false;
+ CLockObject lock(m_mutex);
+ map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.find(address);
+ if (client != m_clients.end())
+ return client->second;
+ return NULL;
}
-void CCECProcessor::RescanActiveDevices(void)
+CCECClient *CCECProcessor::GetPrimaryClient(void)
{
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- m_busDevices[iPtr]->GetStatus(true);
+ CLockObject lock(m_mutex);
+ map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.begin();
+ if (client != m_clients.end())
+ return client->second;
+ return NULL;
}
-bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+CCECBusDevice *CCECProcessor::GetPrimaryDevice(void)
{
- if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false))
- return false;
+ return m_busDevices->At(GetLogicalAddress());
+}
- config->iFirmwareVersion = m_communication->GetFirmwareVersion();
- config->iPhysicalAddress = m_communication->GetPhysicalAddress();
- config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+cec_logical_address CCECProcessor::GetLogicalAddress(void)
+{
+ cec_logical_addresses addresses = GetLogicalAddresses();
+ return addresses.primary;
+}
- return true;
+cec_logical_addresses CCECProcessor::GetLogicalAddresses(void)
+{
+ CLockObject lock(m_mutex);
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ for (map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.begin(); client != m_clients.end(); client++)
+ addresses.Set(client->first);
+
+ return addresses;
}
-bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
+bool CCECProcessor::IsHandledByLibCEC(const cec_logical_address address) const
{
- bool bReturn(true);
- for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
- bReturn &= m_busDevices[iPtr]->TransmitPendingActiveSourceCommands();
- return bReturn;
+ CCECBusDevice *device = GetDevice(address);
+ return device && device->IsHandledByLibCEC();
}
-bool CCECProcessor::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
+bool CCECProcessor::IsRunningLatestFirmware(void)
{
- return iPhysicalAddress >= CEC_MIN_PHYSICAL_ADDRESS &&
- iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
+ return m_communication && m_communication->IsOpen() ?
+ m_communication->IsRunningLatestFirmware() :
+ true;
}
#include <string>
#include "../../include/cectypes.h"
+
#include "platform/threads/threads.h"
#include "platform/util/buffer.h"
+
#include "adapter/AdapterCommunication.h"
+#include "devices/CECDeviceMap.h"
+#include "CECInputBuffer.h"
namespace CEC
{
class CLibCEC;
class IAdapterCommunication;
class CCECBusDevice;
-
- // a buffer that priotises the input from the TV.
- // if we need more than this, we'll have to change it into a priority_queue
- class CCECInputBuffer
- {
- public:
- CCECInputBuffer(void) : m_bHasData(false) {}
- virtual ~CCECInputBuffer(void)
- {
- m_condition.Broadcast();
- }
-
- bool Push(const cec_command &command)
- {
- bool bReturn(false);
- PLATFORM::CLockObject lock(m_mutex);
- if (command.initiator == CECDEVICE_TV)
- bReturn = m_tvInBuffer.Push(command);
- else
- bReturn = m_inBuffer.Push(command);
-
- m_bHasData |= bReturn;
- if (m_bHasData)
- m_condition.Signal();
-
- return bReturn;
- }
-
- bool Pop(cec_command &command, uint16_t iTimeout)
- {
- bool bReturn(false);
- PLATFORM::CLockObject lock(m_mutex);
- if (m_tvInBuffer.IsEmpty() && m_inBuffer.IsEmpty() &&
- !m_condition.Wait(m_mutex, m_bHasData, iTimeout))
- return bReturn;
-
- if (m_tvInBuffer.Pop(command))
- bReturn = true;
- else if (m_inBuffer.Pop(command))
- bReturn = true;
-
- m_bHasData = !m_tvInBuffer.IsEmpty() || !m_inBuffer.IsEmpty();
- return bReturn;
- }
-
- private:
- PLATFORM::CMutex m_mutex;
- PLATFORM::CCondition<volatile bool> m_condition;
- volatile bool m_bHasData;
- PLATFORM::SyncedBuffer<cec_command> m_tvInBuffer;
- PLATFORM::SyncedBuffer<cec_command> m_inBuffer;
- };
+ class CCECAudioSystem;
+ class CCECPlaybackDevice;
+ class CCECRecordingDevice;
+ class CCECTuner;
+ class CCECTV;
+ class CCECClient;
class CCECProcessor : public PLATFORM::CThread, public IAdapterCommunicationCallback
{
public:
- CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types, uint16_t iPhysicalAddress);
- CCECProcessor(CLibCEC *controller, libcec_configuration *configuration);
+ CCECProcessor(CLibCEC *libcec);
virtual ~CCECProcessor(void);
bool Start(const char *strPort, uint16_t iBaudRate = CEC_SERIAL_DEFAULT_BAUDRATE, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
void *Process(void);
void Close(void);
+ bool RegisterClient(CCECClient *client);
+ bool UnregisterClient(CCECClient *client);
+ void UnregisterClients(void);
+ CCECClient *GetPrimaryClient(void);
+ CCECClient *GetClient(const cec_logical_address address);
+
bool OnCommandReceived(const cec_command &command);
- bool IsMonitoring(void) const { return m_bMonitor; }
+ CCECBusDevice * GetDevice(cec_logical_address address) const;
+ CCECAudioSystem * GetAudioSystem(void) const;
+ CCECPlaybackDevice * GetPlaybackDevice(cec_logical_address address) const;
+ CCECRecordingDevice * GetRecordingDevice(cec_logical_address address) const;
+ CCECTuner * GetTuner(cec_logical_address address) const;
+ CCECTV * GetTV(void) const;
+
CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate = true);
- CCECBusDevice * GetDeviceByType(cec_device_type type) const;
- CCECBusDevice * GetPrimaryDevice(void) const;
- cec_version GetDeviceCecVersion(cec_logical_address iAddress);
- bool GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
- CStdString GetDeviceName(void) const;
- cec_osd_name GetDeviceOSDName(cec_logical_address iAddress);
- uint64_t GetDeviceVendorId(cec_logical_address iAddress);
- cec_power_status GetDevicePowerStatus(cec_logical_address iAddress);
- cec_logical_address GetLogicalAddress(void) const { return m_configuration.logicalAddresses.primary; }
- cec_logical_addresses GetLogicalAddresses(void) const { return m_configuration.logicalAddresses; }
- cec_logical_addresses GetActiveDevices(void);
- uint16_t GetDevicePhysicalAddress(cec_logical_address iAddress);
- bool HasLogicalAddress(cec_logical_address address) const { return m_configuration.logicalAddresses.IsSet(address); }
+ CCECBusDevice * GetPrimaryDevice(void);
+ cec_logical_address GetLogicalAddress(void);
+ cec_logical_addresses GetLogicalAddresses(void);
bool IsPresentDevice(cec_logical_address address);
bool IsPresentDeviceType(cec_device_type type);
- uint16_t GetPhysicalAddress(void) const;
+ uint16_t GetDetectedPhysicalAddress(void) const;
uint64_t GetLastTransmission(void) const { return m_iLastTransmission; }
cec_logical_address GetActiveSource(bool bRequestActiveSource = true);
bool IsActiveSource(cec_logical_address iAddress);
- bool IsInitialised(void);
+ bool CECInitialised(void);
bool SetStreamPath(uint16_t iPhysicalAddress);
- cec_client_version GetClientVersion(void) const { return (cec_client_version)m_configuration.clientVersion; };
- bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
- bool PowerOnDevices(cec_logical_address address = CECDEVICE_BROADCAST);
- bool SetActiveView(void);
- bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
- bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true);
+ bool StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices);
+ bool StandbyDevice(const cec_logical_address initiator, cec_logical_address address);
+ bool PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices);
+ bool PowerOnDevice(const cec_logical_address initiator, cec_logical_address address);
+
bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
- bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce = false);
- bool TransmitInactiveSource(void);
- bool SetLogicalAddress(cec_logical_address iLogicalAddress);
- bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
- bool SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate = true);
- bool SetActiveSource(uint16_t iStreamPath);
- bool SwitchMonitoring(bool bEnable);
+ bool ActivateSource(uint16_t iStreamPath);
bool PollDevice(cec_logical_address iAddress);
- uint8_t VolumeUp(bool bSendRelease = true);
- uint8_t VolumeDown(bool bSendRelease = true);
- uint8_t MuteAudio(bool bSendRelease = true);
- bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
- bool TransmitKeyRelease(cec_logical_address iDestination, bool bWait = true);
- bool EnablePhysicalAddressDetection(void);
void SetStandardLineTimeout(uint8_t iTimeout);
+ uint8_t GetStandardLineTimeout(void);
void SetRetryLineTimeout(uint8_t iTimeout);
- bool GetCurrentConfiguration(libcec_configuration *configuration);
- bool SetConfiguration(const libcec_configuration *configuration);
+ uint8_t GetRetryLineTimeout(void);
bool CanPersistConfiguration(void);
- bool PersistConfiguration(libcec_configuration *configuration);
+ bool PersistConfiguration(const libcec_configuration &configuration);
void RescanActiveDevices(void);
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);
- const char *ToString(const cec_logical_address address);
- const char *ToString(const cec_deck_control_mode mode);
- const char *ToString(const cec_deck_info status);
- const char *ToString(const cec_opcode opcode);
- const char *ToString(const cec_system_audio_status mode);
- const char *ToString(const cec_audio_status status);
- const char *ToString(const cec_vendor_id vendor);
- const char *ToString(const cec_client_version version);
- const char *ToString(const cec_server_version version);
-
- static bool IsValidPhysicalAddress(uint16_t iPhysicalAddress);
-
bool Transmit(const cec_command &data);
- void TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
-
- bool ChangeDeviceType(cec_device_type from, cec_device_type to);
- bool FindLogicalAddresses(void);
- bool SetAckMask(uint16_t iMask);
+ void TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
bool StartBootloader(const char *strPort = NULL);
bool PingAdapter(void);
bool TransmitPendingActiveSourceCommands(void);
- CCECBusDevice * m_busDevices[16];
+ CCECDeviceMap *GetDevices(void) const { return m_busDevices; }
+ CLibCEC *GetLib(void) const { return m_libcec; }
+
+ bool IsHandledByLibCEC(const cec_logical_address address) const;
+ bool TryLogicalAddress(cec_logical_address address);
+
+ bool IsRunningLatestFirmware(void);
private:
bool OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening = true);
- bool Initialise(void);
- void SetInitialised(bool bSetTo = true);
- void CreateBusDevices(void);
+ void SetCECInitialised(bool bSetTo = true);
void ReplaceHandlers(void);
bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
- bool TryLogicalAddress(cec_logical_address address);
- bool FindLogicalAddressRecordingDevice(void);
- bool FindLogicalAddressTuner(void);
- bool FindLogicalAddressPlaybackDevice(void);
- bool FindLogicalAddressAudioSystem(void);
+ bool SetAckMask(uint16_t iMask);
void LogOutput(const cec_command &data);
- void ParseCommand(const cec_command &command);
-
- bool m_bConnectionOpened;
- bool m_bInitialised;
- PLATFORM::CMutex m_mutex;
- IAdapterCommunication * m_communication;
- CLibCEC* m_controller;
- bool m_bMonitor;
- cec_keypress m_previousKey;
- PLATFORM::CThread * m_busScan;
- uint8_t m_iStandardLineTimeout;
- uint8_t m_iRetryLineTimeout;
- uint64_t m_iLastTransmission;
- CCECInputBuffer m_inBuffer;
- libcec_configuration m_configuration;
+ void ProcessCommand(const cec_command &command);
+
+ void ResetMembers(void);
+
+ bool m_bInitialised;
+ PLATFORM::CMutex m_mutex;
+ IAdapterCommunication * m_communication;
+ CLibCEC* m_libcec;
+ uint8_t m_iStandardLineTimeout;
+ uint8_t m_iRetryLineTimeout;
+ uint64_t m_iLastTransmission;
+ CCECInputBuffer m_inBuffer;
+ CCECDeviceMap * m_busDevices;
+ std::map<cec_logical_address, CCECClient *> m_clients;
};
};
#include "adapter/USBCECAdapterDetection.h"
#include "adapter/USBCECAdapterCommunication.h"
#include "CECProcessor.h"
+#include "devices/CECAudioSystem.h"
#include "devices/CECBusDevice.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECTV.h"
#include "platform/util/timeutils.h"
#include "platform/util/StdString.h"
+#include "CECClient.h"
+
using namespace std;
using namespace CEC;
using namespace PLATFORM;
-CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */) :
+CLibCEC::CLibCEC(const char *UNUSED(strDeviceName), cec_device_type_list UNUSED(types), uint16_t UNUSED(iPhysicalAddress) /* = 0 */) :
m_iStartTime(GetTimeMs()),
- m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
- m_buttontime(0),
- m_callbacks(NULL),
- m_cbParam(NULL)
+ m_client(NULL)
{
- m_cec = new CCECProcessor(this, strDeviceName, types, iPhysicalAddress);
+ m_cec = new CCECProcessor(this);
}
-CLibCEC::CLibCEC(libcec_configuration *configuration) :
+CLibCEC::CLibCEC(libcec_configuration *UNUSED(configuration)) :
m_iStartTime(GetTimeMs()),
- m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
- m_buttontime(0),
- m_callbacks(configuration->callbacks),
- m_cbParam(configuration->callbackParam)
+ m_client(NULL)
{
- m_cec = new CCECProcessor(this, configuration);
+ m_cec = new CCECProcessor(this);
}
CLibCEC::~CLibCEC(void)
{
+ // unregister all clients client
+ UnregisterClients();
+
+ // delete the adapter connection
delete m_cec;
+ m_cec = NULL;
}
bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
{
- if (m_cec->IsRunning())
- {
- AddLog(CEC_LOG_ERROR, "connection already open");
+ if (!m_cec || !strPort)
return false;
- }
+ // open a new connection
if (!m_cec->Start(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs))
{
AddLog(CEC_LOG_ERROR, "could not start CEC communications");
return false;
}
+ // register all clients
+ for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ {
+ if (!m_cec->RegisterClient(*it))
+ {
+ AddLog(CEC_LOG_ERROR, "failed to register a CEC client");
+ return false;
+ }
+ }
+
return true;
}
void CLibCEC::Close(void)
{
+ // unregister all clients
+ UnregisterClients();
+
+ // close the connection
if (m_cec)
m_cec->Close();
}
-bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
{
- CLockObject lock(m_mutex);
- if (m_cec)
- {
- m_cbParam = cbParam;
- m_callbacks = callbacks;
- }
- return false;
+ return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
}
-int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+bool CLibCEC::StartBootloader(void)
{
- CStdString strDebug;
- if (strDevicePath)
- strDebug.Format("trying to autodetect the com port for device path '%s'", strDevicePath);
- else
- strDebug.Format("trying to autodetect all CEC adapters");
- AddLog(CEC_LOG_DEBUG, strDebug);
-
- return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
+ return m_cec ? m_cec->StartBootloader() : false;
}
bool CLibCEC::PingAdapter(void)
{
- return m_cec ? m_cec->PingAdapter() : false;
+ return m_client ? m_client->PingAdapter() : false;
}
-bool CLibCEC::StartBootloader(void)
+bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
{
- return m_cec ? m_cec->StartBootloader() : false;
+ return m_client ? m_client->EnableCallbacks(cbParam, callbacks) : false;
}
-bool CLibCEC::GetNextLogMessage(cec_log_message *message)
+bool CLibCEC::GetCurrentConfiguration(libcec_configuration *configuration)
{
- return (m_logBuffer.Pop(*message));
+ return m_client ? m_client->GetCurrentConfiguration(*configuration) : false;
}
-bool CLibCEC::GetNextKeypress(cec_keypress *key)
+bool CLibCEC::SetConfiguration(const libcec_configuration *configuration)
{
- return m_keyBuffer.Pop(*key);
+ return m_client ? m_client->SetConfiguration(*configuration) : false;
}
-bool CLibCEC::GetNextCommand(cec_command *command)
+bool CLibCEC::CanPersistConfiguration(void)
+{
+ return m_client ? m_client->CanPersistConfiguration() : false;
+}
+
+bool CLibCEC::PersistConfiguration(libcec_configuration *configuration)
+{
+ return m_client ? m_client->PersistConfiguration(*configuration) : false;
+}
+
+void CLibCEC::RescanActiveDevices(void)
+{
+ if (m_client)
+ m_client->RescanActiveDevices();
+}
+
+bool CLibCEC::IsLibCECActiveSource(void)
{
- return m_commandBuffer.Pop(*command);
+ return m_client ? m_client->IsLibCECActiveSource() : false;
}
bool CLibCEC::Transmit(const cec_command &data)
{
- return m_cec ? m_cec->Transmit(data) : false;
+ return m_client ? m_client->Transmit(data) : false;
}
bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
{
- return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false;
+ return m_client ? m_client->SetLogicalAddress(iLogicalAddress) : false;
}
bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
{
- return m_cec ? m_cec->SetPhysicalAddress(iPhysicalAddress) : false;
+ return m_client ? m_client->SetPhysicalAddress(iPhysicalAddress) : false;
}
bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
{
- return m_cec ? m_cec->SetHDMIPort(iBaseDevice, iPort) : false;
-}
-
-bool CLibCEC::EnablePhysicalAddressDetection(void)
-{
- return m_cec ? m_cec->EnablePhysicalAddressDetection() : false;
+ return m_client ? m_client->SetHDMIPort(iBaseDevice, iPort) : false;
}
bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
{
- return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->PowerOnDevices(address) : false;
+ return m_client ? m_client->SendPowerOnDevices(address) : false;
}
bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
{
- return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->StandbyDevices(address) : false;
+ return m_client ? m_client->SendStandbyDevices(address) : false;
}
bool CLibCEC::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
{
- return m_cec ? m_cec->SetActiveSource(type) : false;
-}
-
-bool CLibCEC::SetActiveView(void)
-{
- return m_cec ? m_cec->SetActiveView() : false;
+ return m_client ? m_client->SendSetActiveSource(type) : false;
}
bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
{
- return m_cec ? m_cec->SetDeckControlMode(mode, bSendUpdate) : false;
+ return m_client ? m_client->SendSetDeckControlMode(mode, bSendUpdate) : false;
}
bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
{
- return m_cec ? m_cec->SetDeckInfo(info, bSendUpdate) : false;
+ return m_client ? m_client->SendSetDeckInfo(info, bSendUpdate) : false;
}
bool CLibCEC::SetInactiveView(void)
{
- return m_cec ? m_cec->TransmitInactiveSource() : false;
+ return m_client ? m_client->SendSetInactiveView() : false;
}
bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
{
- return m_cec ? m_cec->SetMenuState(state, bSendUpdate) : false;
+ return m_client ? m_client->SendSetMenuState(state, bSendUpdate) : false;
}
bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
{
- return m_cec && iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST ?
- m_cec->m_busDevices[m_cec->GetLogicalAddress()]->TransmitOSDString(iLogicalAddress, duration, strMessage) :
- false;
+ return m_client ? m_client->SendSetOSDString(iLogicalAddress, duration, strMessage) : false;
}
bool CLibCEC::SwitchMonitoring(bool bEnable)
{
- return m_cec ? m_cec->SwitchMonitoring(bEnable) : false;
+ return m_client ? m_client->SwitchMonitoring(bEnable) : false;
}
cec_version CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->GetDeviceCecVersion(iAddress);
- return CEC_VERSION_UNKNOWN;
+ return m_client ? m_client->GetDeviceCecVersion(iAddress) : CEC_VERSION_UNKNOWN;
}
bool CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->GetDeviceMenuLanguage(iAddress, language);
- return false;
+ return m_client ? m_client->GetDeviceMenuLanguage(iAddress, *language) : false;
}
uint64_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->GetDeviceVendorId(iAddress);
- return 0;
+ return m_client ? m_client->GetDeviceVendorId(iAddress) : (uint64_t)CEC_VENDOR_UNKNOWN;
}
uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->GetDevicePhysicalAddress(iAddress);
- return 0;
-}
-
-cec_logical_address CLibCEC::GetActiveSource(void)
-{
- return m_cec ? m_cec->GetActiveSource() : CECDEVICE_UNKNOWN;
-}
-
-bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
-{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->IsActiveSource(iAddress);
- return false;
+ return m_client ? m_client->GetDevicePhysicalAddress(iAddress) : CEC_INVALID_PHYSICAL_ADDRESS;
}
cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->GetDevicePowerStatus(iAddress);
- return CEC_POWER_STATUS_UNKNOWN;
+ return m_client ? m_client->GetDevicePowerStatus(iAddress) : CEC_POWER_STATUS_UNKNOWN;
}
bool CLibCEC::PollDevice(cec_logical_address iAddress)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->PollDevice(iAddress);
- return false;
+ return m_client ? m_client->PollDevice(iAddress) : false;
}
cec_logical_addresses CLibCEC::GetActiveDevices(void)
{
cec_logical_addresses addresses;
addresses.Clear();
- if (m_cec)
- addresses = m_cec->GetActiveDevices();
+ if (m_client)
+ addresses = m_client->GetActiveDevices();
return addresses;
}
bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
{
- if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
- return m_cec->IsPresentDevice(iAddress);
- return false;
+ return m_client ? m_client->IsActiveDevice(iAddress) : false;
}
bool CLibCEC::IsActiveDeviceType(cec_device_type type)
{
- if (m_cec && type >= CEC_DEVICE_TYPE_TV && type <= CEC_DEVICE_TYPE_AUDIO_SYSTEM)
- return m_cec->IsPresentDeviceType(type);
- return false;
+ return m_client ? m_client->IsActiveDeviceType(type) : false;
}
uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
{
- if (m_cec)
- return m_cec->VolumeUp(bSendRelease);
- return 0;
+ return m_client ? m_client->SendVolumeUp(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
}
uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
{
- if (m_cec)
- return m_cec->VolumeDown(bSendRelease);
- return 0;
+ return m_client ? m_client->SendVolumeDown(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
}
-
-uint8_t CLibCEC::MuteAudio(bool bSendRelease /* = true */)
+uint8_t CLibCEC::MuteAudio(bool UNUSED(bSendRelease) /* = true */)
{
- if (m_cec)
- return m_cec->MuteAudio(bSendRelease);
- return 0;
+ return m_client ? m_client->SendMuteAudio() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
}
bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
{
- if (m_cec)
- return m_cec->TransmitKeypress(iDestination, key, bWait);
- return false;
+ return m_client ? m_client->SendKeypress(iDestination, key, bWait) : false;
}
bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
{
- if (m_cec)
- return m_cec->TransmitKeyRelease(iDestination, bWait);
- return false;
+ return m_client ? m_client->SendKeyRelease(iDestination, bWait) : false;
}
cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
{
cec_osd_name retVal;
- retVal.device = iAddress;
- retVal.name[0] = 0;
-
- if (m_cec)
- retVal = m_cec->GetDeviceOSDName(iAddress);
+ retVal.device = CECDEVICE_UNKNOWN;
+ memset(retVal.name, 0, 14);
+ if (m_client)
+ retVal = m_client->GetDeviceOSDName(iAddress);
return retVal;
}
-void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
-{
- CStdString strLog;
-
- va_list argList;
- va_start(argList, strFormat);
- strLog.FormatV(strFormat, argList);
- va_end(argList);
-
- CLibCEC *instance = CLibCEC::GetInstance();
- if (!instance)
- return;
- CLockObject lock(instance->m_logMutex);
-
- cec_log_message message;
- message.level = level;
- message.time = GetTimeMs() - instance->m_iStartTime;
- snprintf(message.message, sizeof(message.message), "%s", strLog.c_str());
-
- if (instance->m_callbacks && instance->m_callbacks->CBCecLogMessage)
- instance->m_callbacks->CBCecLogMessage(instance->m_cbParam, message);
- else
- instance->m_logBuffer.Push(message);
-}
-
-void CLibCEC::AddKey(const cec_keypress &key)
-{
- CLibCEC *instance = CLibCEC::GetInstance();
- if (!instance)
- return;
- CLockObject lock(instance->m_mutex);
-
- AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
-
- if (instance->m_callbacks && instance->m_callbacks->CBCecKeyPress)
- instance->m_callbacks->CBCecKeyPress(instance->m_cbParam, key);
- else
- instance->m_keyBuffer.Push(key);
-
- instance->m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode;
- instance->m_buttontime = key.duration > 0 ? 0 : GetTimeMs();
-}
-
-void CLibCEC::ConfigurationChanged(const libcec_configuration &config)
-{
- CLibCEC *instance = CLibCEC::GetInstance();
- CLockObject lock(instance->m_mutex);
-
- if (instance->m_callbacks &&
- config.clientVersion >= CEC_CLIENT_VERSION_1_5_0 &&
- instance->m_callbacks->CBCecConfigurationChanged &&
- instance->m_cec->IsInitialised())
- instance->m_callbacks->CBCecConfigurationChanged(instance->m_cbParam, config);
-}
-
-void CLibCEC::SetCurrentButton(cec_user_control_code iButtonCode)
-{
- /* push keypress to the keybuffer with 0 duration.
- push another press to the keybuffer with the duration set when the button is released */
- cec_keypress key;
- key.duration = 0;
- key.keycode = iButtonCode;
-
- AddKey(key);
-}
-
-void CLibCEC::AddKey(void)
-{
- CLibCEC *instance = CLibCEC::GetInstance();
- if (!instance)
- return;
- CLockObject lock(instance->m_mutex);
-
- if (instance->m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
- {
- cec_keypress key;
-
- key.duration = (unsigned int) (GetTimeMs() - instance->m_buttontime);
- key.keycode = instance->m_iCurrentButton;
- AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode);
-
- if (instance->m_callbacks && instance->m_callbacks->CBCecKeyPress)
- instance->m_callbacks->CBCecKeyPress(instance->m_cbParam, key);
- else
- instance->m_keyBuffer.Push(key);
- instance->m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
- }
- instance->m_buttontime = 0;
-}
-
-void CLibCEC::AddCommand(const cec_command &command)
-{
- CLibCEC *instance = CLibCEC::GetInstance();
- if (!instance)
- return;
- CLockObject lock(instance->m_mutex);
-
- AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", instance->m_cec->ToString(command.initiator), command.initiator, instance->m_cec->ToString(command.destination), command.destination, instance->m_cec->ToString(command.opcode), command.opcode);
-
- if (instance->m_callbacks && instance->m_callbacks->CBCecCommand)
- instance->m_callbacks->CBCecCommand(instance->m_cbParam, command);
- else if (!instance->m_commandBuffer.Push(command))
- AddLog(CEC_LOG_WARNING, "command buffer is full");
-}
-
-void CLibCEC::Alert(const libcec_alert type, const libcec_parameter ¶m)
-{
- CLibCEC *instance = CLibCEC::GetInstance();
- if (!instance)
- return;
- CLockObject lock(instance->m_mutex);
-
- libcec_configuration config;
- instance->GetCurrentConfiguration(&config);
-
- if (instance->m_callbacks &&
- config.clientVersion >= CEC_CLIENT_VERSION_1_6_0 &&
- instance->m_cec->IsInitialised() &&
- instance->m_callbacks->CBCecAlert)
- instance->m_callbacks->CBCecAlert(instance->m_cbParam, type, param);
-
- if (type == CEC_ALERT_CONNECTION_LOST)
- instance->Close();
-}
-
-void CLibCEC::CheckKeypressTimeout(void)
+cec_logical_address CLibCEC::GetActiveSource(void)
{
- if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
- {
- AddKey();
- m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
- }
+ return m_client ? m_client->GetActiveSource() : CECDEVICE_UNKNOWN;
}
-int CLibCEC::MenuStateChanged(const cec_menu_state newState)
+bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
{
- int iReturn(0);
-
- CLibCEC *instance = CLibCEC::GetInstance();
- if (!instance)
- return iReturn;
- CLockObject lock(instance->m_mutex);
-
- AddLog(CEC_LOG_NOTICE, ">> %s: %s", instance->m_cec->ToString(CEC_OPCODE_MENU_REQUEST), instance->m_cec->ToString(newState));
-
- libcec_configuration config;
- instance->GetCurrentConfiguration(&config);
-
- if (instance->m_callbacks &&
- config.clientVersion >= CEC_CLIENT_VERSION_1_6_2 &&
- instance->m_callbacks->CBCecMenuStateChanged)
- iReturn = instance->m_callbacks->CBCecMenuStateChanged(instance->m_cbParam, newState);
-
- return iReturn;
+ return m_client ? m_client->IsActiveSource(iAddress) : false;
}
-
bool CLibCEC::SetStreamPath(cec_logical_address iAddress)
{
- uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
- if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS)
- return SetStreamPath(iPhysicalAddress);
- return false;
+ return m_client ? m_client->SetStreamPath(iAddress) : false;
}
bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress)
{
- return m_cec->SetStreamPath(iPhysicalAddress);
+ return m_client ? m_client->SetStreamPath(iPhysicalAddress) : false;
}
cec_logical_addresses CLibCEC::GetLogicalAddresses(void)
{
- cec_logical_addresses addr = m_cec->GetLogicalAddresses();
- return addr;
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ if (m_client)
+ m_client->GetLogicalAddresses();
+ return addresses;
}
-static CLibCEC *g_libCEC_instance(NULL);
-CLibCEC *CLibCEC::GetInstance(void)
+bool CLibCEC::GetNextLogMessage(cec_log_message *message)
{
- return g_libCEC_instance;
+ return m_client ? m_client->GetNextLogMessage(message) : false;
}
-void CLibCEC::SetInstance(CLibCEC *instance)
+bool CLibCEC::GetNextKeypress(cec_keypress *key)
{
- if (g_libCEC_instance)
- delete g_libCEC_instance;
- g_libCEC_instance = instance;
+ return m_client ? m_client->GetNextKeypress(key) : false;
}
-void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t UNUSED(iPhysicalAddress) /* = 0 */)
+bool CLibCEC::GetNextCommand(cec_command *command)
{
- CLibCEC *lib = new CLibCEC(strDeviceName, types);
- CLibCEC::SetInstance(lib);
- return static_cast< void* > (lib);
+ return m_client ? m_client->GetNextCommand(command) : false;
}
-void * CECInitialise(libcec_configuration *configuration)
+cec_device_type CLibCEC::GetType(cec_logical_address address)
{
- CLibCEC *lib = new CLibCEC(configuration);
- CLibCEC::SetInstance(lib);
- lib->GetCurrentConfiguration(configuration);
- return static_cast< void* > (lib);
+ switch (address)
+ {
+ case CECDEVICE_AUDIOSYSTEM:
+ return CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_PLAYBACKDEVICE2:
+ case CECDEVICE_PLAYBACKDEVICE3:
+ return CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE2:
+ case CECDEVICE_RECORDINGDEVICE3:
+ return CEC_DEVICE_TYPE_RECORDING_DEVICE;
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TUNER2:
+ case CECDEVICE_TUNER3:
+ case CECDEVICE_TUNER4:
+ return CEC_DEVICE_TYPE_TUNER;
+ case CECDEVICE_TV:
+ return CEC_DEVICE_TYPE_TV;
+ default:
+ return CEC_DEVICE_TYPE_RESERVED;
+ }
}
-bool CECStartBootloader(void)
+uint16_t CLibCEC::GetMaskForType(cec_logical_address address)
{
- bool bReturn(false);
- cec_adapter deviceList[1];
- if (CUSBCECAdapterDetection::FindAdapters(deviceList, 1) > 0)
+ return GetMaskForType(GetType(address));
+}
+
+uint16_t CLibCEC::GetMaskForType(cec_device_type type)
+{
+ switch (type)
{
- CUSBCECAdapterCommunication comm(NULL, deviceList[0].comm);
- CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
- while (timeout.TimeLeft() > 0 && (bReturn = comm.Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
+ case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
{
- comm.Close();
- CEvent::Sleep(500);
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_AUDIOSYSTEM);
+ return addr.AckMask();
}
- if (comm.IsOpen())
- bReturn = comm.StartBootloader();
+ case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_PLAYBACKDEVICE1);
+ addr.Set(CECDEVICE_PLAYBACKDEVICE2);
+ addr.Set(CECDEVICE_PLAYBACKDEVICE3);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_RECORDING_DEVICE:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_RECORDINGDEVICE1);
+ addr.Set(CECDEVICE_RECORDINGDEVICE2);
+ addr.Set(CECDEVICE_RECORDINGDEVICE3);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_TUNER:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_TUNER1);
+ addr.Set(CECDEVICE_TUNER2);
+ addr.Set(CECDEVICE_TUNER3);
+ addr.Set(CECDEVICE_TUNER4);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_TV:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_TV);
+ return addr.AckMask();
+ }
+ default:
+ return 0;
}
+}
- return bReturn;
+bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
+{
+ return iPhysicalAddress >= CEC_MIN_PHYSICAL_ADDRESS &&
+ iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
}
-void CECDestroy(CEC::ICECAdapter *UNUSED(instance))
+const char *CLibCEC::ToString(const cec_device_type type)
{
- CLibCEC::SetInstance(NULL);
+ 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 *CLibCEC::ToString(const cec_menu_state state)
{
- return m_cec->ToString(state);
+ switch (state)
+ {
+ case CEC_MENU_STATE_ACTIVATED:
+ return "activated";
+ case CEC_MENU_STATE_DEACTIVATED:
+ return "deactivated";
+ default:
+ return "unknown";
+ }
}
const char *CLibCEC::ToString(const cec_version version)
{
- return m_cec->ToString(version);
+ switch (version)
+ {
+ case CEC_VERSION_1_2:
+ return "1.2";
+ case CEC_VERSION_1_2A:
+ return "1.2a";
+ case CEC_VERSION_1_3:
+ return "1.3";
+ case CEC_VERSION_1_3A:
+ return "1.3a";
+ case CEC_VERSION_1_4:
+ return "1.4";
+ default:
+ return "unknown";
+ }
}
const char *CLibCEC::ToString(const cec_power_status status)
{
- return m_cec->ToString(status);
+ switch (status)
+ {
+ case CEC_POWER_STATUS_ON:
+ return "on";
+ case CEC_POWER_STATUS_STANDBY:
+ return "standby";
+ case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
+ return "in transition from on to standby";
+ case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
+ return "in transition from standby to on";
+ default:
+ return "unknown";
+ }
}
const char *CLibCEC::ToString(const cec_logical_address address)
{
- return m_cec->ToString(address);
+ switch(address)
+ {
+ case CECDEVICE_AUDIOSYSTEM:
+ return "Audio";
+ case CECDEVICE_BROADCAST:
+ return "Broadcast";
+ case CECDEVICE_FREEUSE:
+ return "Free use";
+ case CECDEVICE_PLAYBACKDEVICE1:
+ return "Playback 1";
+ case CECDEVICE_PLAYBACKDEVICE2:
+ return "Playback 2";
+ case CECDEVICE_PLAYBACKDEVICE3:
+ return "Playback 3";
+ case CECDEVICE_RECORDINGDEVICE1:
+ return "Recorder 1";
+ case CECDEVICE_RECORDINGDEVICE2:
+ return "Recorder 2";
+ case CECDEVICE_RECORDINGDEVICE3:
+ return "Recorder 3";
+ case CECDEVICE_RESERVED1:
+ return "Reserved 1";
+ case CECDEVICE_RESERVED2:
+ return "Reserved 2";
+ case CECDEVICE_TUNER1:
+ return "Tuner 1";
+ case CECDEVICE_TUNER2:
+ return "Tuner 2";
+ case CECDEVICE_TUNER3:
+ return "Tuner 3";
+ case CECDEVICE_TUNER4:
+ return "Tuner 4";
+ case CECDEVICE_TV:
+ return "TV";
+ default:
+ return "unknown";
+ }
}
const char *CLibCEC::ToString(const cec_deck_control_mode mode)
{
- return m_cec->ToString(mode);
+ switch (mode)
+ {
+ case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
+ return "skip forward wind";
+ case CEC_DECK_CONTROL_MODE_EJECT:
+ return "eject";
+ case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
+ return "reverse rewind";
+ case CEC_DECK_CONTROL_MODE_STOP:
+ return "stop";
+ default:
+ return "unknown";
+ }
}
const char *CLibCEC::ToString(const cec_deck_info status)
{
- return m_cec->ToString(status);
+ switch (status)
+ {
+ case CEC_DECK_INFO_PLAY:
+ return "play";
+ case CEC_DECK_INFO_RECORD:
+ return "record";
+ case CEC_DECK_INFO_PLAY_REVERSE:
+ return "play reverse";
+ case CEC_DECK_INFO_STILL:
+ return "still";
+ case CEC_DECK_INFO_SLOW:
+ return "slow";
+ case CEC_DECK_INFO_SLOW_REVERSE:
+ return "slow reverse";
+ case CEC_DECK_INFO_FAST_FORWARD:
+ return "fast forward";
+ case CEC_DECK_INFO_FAST_REVERSE:
+ return "fast reverse";
+ case CEC_DECK_INFO_NO_MEDIA:
+ return "no media";
+ case CEC_DECK_INFO_STOP:
+ return "stop";
+ case CEC_DECK_INFO_SKIP_FORWARD_WIND:
+ return "info skip forward wind";
+ case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
+ return "info skip reverse rewind";
+ case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
+ return "info index search forward";
+ case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
+ return "info index search reverse";
+ case CEC_DECK_INFO_OTHER_STATUS:
+ return "other";
+ case CEC_DECK_INFO_OTHER_STATUS_LG:
+ return "LG other";
+ default:
+ return "unknown";
+ }
}
const char *CLibCEC::ToString(const cec_opcode opcode)
{
- return m_cec->ToString(opcode);
+ switch (opcode)
+ {
+ case CEC_OPCODE_ACTIVE_SOURCE:
+ return "active source";
+ case CEC_OPCODE_IMAGE_VIEW_ON:
+ return "image view on";
+ case CEC_OPCODE_TEXT_VIEW_ON:
+ return "text view on";
+ case CEC_OPCODE_INACTIVE_SOURCE:
+ return "inactive source";
+ case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+ return "request active source";
+ case CEC_OPCODE_ROUTING_CHANGE:
+ return "routing change";
+ case CEC_OPCODE_ROUTING_INFORMATION:
+ return "routing information";
+ case CEC_OPCODE_SET_STREAM_PATH:
+ return "set stream path";
+ case CEC_OPCODE_STANDBY:
+ return "standby";
+ case CEC_OPCODE_RECORD_OFF:
+ return "record off";
+ case CEC_OPCODE_RECORD_ON:
+ return "record on";
+ case CEC_OPCODE_RECORD_STATUS:
+ return "record status";
+ case CEC_OPCODE_RECORD_TV_SCREEN:
+ return "record tv screen";
+ case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
+ return "clear analogue timer";
+ case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
+ return "clear digital timer";
+ case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
+ return "clear external timer";
+ case CEC_OPCODE_SET_ANALOGUE_TIMER:
+ return "set analogue timer";
+ case CEC_OPCODE_SET_DIGITAL_TIMER:
+ return "set digital timer";
+ case CEC_OPCODE_SET_EXTERNAL_TIMER:
+ return "set external timer";
+ case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
+ return "set timer program title";
+ case CEC_OPCODE_TIMER_CLEARED_STATUS:
+ return "timer cleared status";
+ case CEC_OPCODE_TIMER_STATUS:
+ return "timer status";
+ case CEC_OPCODE_CEC_VERSION:
+ return "cec version";
+ case CEC_OPCODE_GET_CEC_VERSION:
+ return "get cec version";
+ case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+ return "give physical address";
+ case CEC_OPCODE_GET_MENU_LANGUAGE:
+ return "get menu language";
+ case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
+ return "report physical address";
+ case CEC_OPCODE_SET_MENU_LANGUAGE:
+ return "set menu language";
+ case CEC_OPCODE_DECK_CONTROL:
+ return "deck control";
+ case CEC_OPCODE_DECK_STATUS:
+ return "deck status";
+ case CEC_OPCODE_GIVE_DECK_STATUS:
+ return "give deck status";
+ case CEC_OPCODE_PLAY:
+ return "play";
+ case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
+ return "give tuner status";
+ case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
+ return "select analogue service";
+ case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
+ return "set digital service";
+ case CEC_OPCODE_TUNER_DEVICE_STATUS:
+ return "tuner device status";
+ case CEC_OPCODE_TUNER_STEP_DECREMENT:
+ return "tuner step decrement";
+ case CEC_OPCODE_TUNER_STEP_INCREMENT:
+ return "tuner step increment";
+ case CEC_OPCODE_DEVICE_VENDOR_ID:
+ return "device vendor id";
+ case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+ return "give device vendor id";
+ case CEC_OPCODE_VENDOR_COMMAND:
+ return "vendor command";
+ case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
+ return "vendor command with id";
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
+ return "vendor remote button down";
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
+ return "vendor remote button up";
+ case CEC_OPCODE_SET_OSD_STRING:
+ return "set osd string";
+ case CEC_OPCODE_GIVE_OSD_NAME:
+ return "give osd name";
+ case CEC_OPCODE_SET_OSD_NAME:
+ return "set osd name";
+ case CEC_OPCODE_MENU_REQUEST:
+ return "menu request";
+ case CEC_OPCODE_MENU_STATUS:
+ return "menu status";
+ case CEC_OPCODE_USER_CONTROL_PRESSED:
+ return "user control pressed";
+ case CEC_OPCODE_USER_CONTROL_RELEASE:
+ return "user control release";
+ case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+ return "give device power status";
+ case CEC_OPCODE_REPORT_POWER_STATUS:
+ return "report power status";
+ case CEC_OPCODE_FEATURE_ABORT:
+ return "feature abort";
+ case CEC_OPCODE_ABORT:
+ return "abort";
+ case CEC_OPCODE_GIVE_AUDIO_STATUS:
+ return "give audio status";
+ case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
+ return "give audio mode status";
+ case CEC_OPCODE_REPORT_AUDIO_STATUS:
+ return "report audio status";
+ case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
+ return "set system audio mode";
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
+ return "system audio mode request";
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
+ return "system audio mode status";
+ case CEC_OPCODE_SET_AUDIO_RATE:
+ return "set audio rate";
+ case CEC_OPCODE_START_ARC:
+ return "start ARC";
+ case CEC_OPCODE_REPORT_ARC_STARTED:
+ return "report ARC started";
+ case CEC_OPCODE_REPORT_ARC_ENDED:
+ return "report ARC ended";
+ case CEC_OPCODE_REQUEST_ARC_START:
+ return "request ARC start";
+ case CEC_OPCODE_REQUEST_ARC_END:
+ return "request ARC end";
+ case CEC_OPCODE_END_ARC:
+ return "end ARC";
+ case CEC_OPCODE_CDC:
+ return "CDC";
+ case CEC_OPCODE_NONE:
+ return "poll";
+ default:
+ return "UNKNOWN";
+ }
}
const char *CLibCEC::ToString(const cec_system_audio_status mode)
{
- return m_cec->ToString(mode);
+ switch(mode)
+ {
+ case CEC_SYSTEM_AUDIO_STATUS_ON:
+ return "on";
+ case CEC_SYSTEM_AUDIO_STATUS_OFF:
+ return "off";
+ default:
+ return "unknown";
+ }
}
-const char *CLibCEC::ToString(const cec_audio_status status)
+const char *CLibCEC::ToString(const cec_audio_status UNUSED(status))
{
- return m_cec->ToString(status);
+ // TODO this is a mask
+ return "TODO";
}
const char *CLibCEC::ToString(const cec_vendor_id vendor)
{
- return m_cec->ToString(vendor);
+ switch (vendor)
+ {
+ case CEC_VENDOR_SAMSUNG:
+ return "Samsung";
+ case CEC_VENDOR_LG:
+ return "LG";
+ case CEC_VENDOR_PANASONIC:
+ return "Panasonic";
+ case CEC_VENDOR_PIONEER:
+ return "Pioneer";
+ case CEC_VENDOR_ONKYO:
+ return "Onkyo";
+ case CEC_VENDOR_YAMAHA:
+ return "Yamaha";
+ case CEC_VENDOR_PHILIPS:
+ return "Philips";
+ case CEC_VENDOR_SONY:
+ return "Sony";
+ case CEC_VENDOR_TOSHIBA:
+ return "Toshiba";
+ default:
+ return "Unknown";
+ }
}
const char *CLibCEC::ToString(const cec_client_version version)
{
- return m_cec->ToString(version);
+ switch (version)
+ {
+ case CEC_CLIENT_VERSION_PRE_1_5:
+ return "pre-1.5";
+ case CEC_CLIENT_VERSION_1_5_0:
+ return "1.5.0";
+ case CEC_CLIENT_VERSION_1_5_1:
+ return "1.5.1";
+ case CEC_CLIENT_VERSION_1_5_2:
+ return "1.5.2";
+ case CEC_CLIENT_VERSION_1_5_3:
+ return "1.5.3";
+ case CEC_CLIENT_VERSION_1_6_0:
+ return "1.6.0";
+ case CEC_CLIENT_VERSION_1_6_1:
+ return "1.6.1";
+ case CEC_CLIENT_VERSION_1_6_2:
+ return "1.6.2";
+ case CEC_CLIENT_VERSION_1_6_3:
+ return "1.6.3";
+ default:
+ return "Unknown";
+ }
}
const char *CLibCEC::ToString(const cec_server_version version)
{
- return m_cec->ToString(version);
+ switch (version)
+ {
+ case CEC_SERVER_VERSION_PRE_1_5:
+ return "pre-1.5";
+ case CEC_SERVER_VERSION_1_5_0:
+ return "1.5.0";
+ case CEC_SERVER_VERSION_1_5_1:
+ return "1.5.1";
+ case CEC_SERVER_VERSION_1_5_2:
+ return "1.5.2";
+ case CEC_SERVER_VERSION_1_5_3:
+ return "1.5.3";
+ case CEC_SERVER_VERSION_1_6_0:
+ return "1.6.0";
+ case CEC_SERVER_VERSION_1_6_1:
+ return "1.6.1";
+ case CEC_SERVER_VERSION_1_6_2:
+ return "1.6.2";
+ case CEC_SERVER_VERSION_1_6_3:
+ return "1.6.3";
+ default:
+ return "Unknown";
+ }
}
-const char *CLibCEC::ToString(const cec_device_type type)
+void CLibCEC::CheckKeypressTimeout(void)
{
- return m_cec->ToString(type);
+ // check all clients
+ for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->CheckKeypressTimeout();
}
-bool CLibCEC::GetCurrentConfiguration(libcec_configuration *configuration)
+void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
{
- return m_cec->GetCurrentConfiguration(configuration);
+ CStdString strLog;
+
+ // format the message
+ va_list argList;
+ va_start(argList, strFormat);
+ strLog.FormatV(strFormat, argList);
+ va_end(argList);
+
+ cec_log_message message;
+ message.level = level;
+ message.time = GetTimeMs() - m_iStartTime;
+ snprintf(message.message, sizeof(message.message), "%s", strLog.c_str());
+
+ // send the message to all clients
+ for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->AddLog(message);
}
-bool CLibCEC::SetConfiguration(const libcec_configuration *configuration)
+void CLibCEC::Alert(const libcec_alert type, const libcec_parameter ¶m)
{
- return m_cec->SetConfiguration(configuration);
+ // send the alert to all clients
+ for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->Alert(type, param);
}
-bool CLibCEC::CanPersistConfiguration(void)
+bool CLibCEC::SetActiveView(void)
{
- return m_cec->CanPersistConfiguration();
+ AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
+ return SetActiveSource();
}
-bool CLibCEC::PersistConfiguration(libcec_configuration *configuration)
+bool CLibCEC::EnablePhysicalAddressDetection(void)
{
- return m_cec->PersistConfiguration(configuration);
+ AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
+ return true;
}
-void CLibCEC::RescanActiveDevices(void)
+CCECClient *CLibCEC::RegisterClient(libcec_configuration &configuration)
{
- return m_cec->RescanActiveDevices();
+ if (!m_cec)
+ return NULL;
+
+ // create a new client instance
+ CCECClient *newClient = new CCECClient(m_cec, configuration);
+ if (!newClient)
+ return NULL;
+ m_clients.push_back(newClient);
+
+ // if the default client isn't set, set it
+ if (!m_client)
+ m_client = newClient;
+
+ // register the new client
+ if (m_cec->CECInitialised())
+ m_cec->RegisterClient(newClient);
+
+ return newClient;
}
-bool CLibCEC::IsLibCECActiveSource(void)
+void CLibCEC::UnregisterClients(void)
{
- bool bReturn(false);
if (m_cec)
- {
- cec_logical_address activeSource = m_cec->GetActiveSource();
- if (activeSource != CECDEVICE_UNKNOWN)
- bReturn = m_cec->m_busDevices[activeSource]->GetStatus(false) == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
- }
- return bReturn;
+ m_cec->UnregisterClients();
+
+ m_clients.clear();
+
+ delete m_client;
+ m_client = NULL;
}
-cec_device_type CLibCEC::GetType(cec_logical_address address)
+void * CECInitialise(libcec_configuration *configuration)
{
- switch (address)
- {
- case CECDEVICE_AUDIOSYSTEM:
- return CEC_DEVICE_TYPE_AUDIO_SYSTEM;
- case CECDEVICE_PLAYBACKDEVICE1:
- case CECDEVICE_PLAYBACKDEVICE2:
- case CECDEVICE_PLAYBACKDEVICE3:
- return CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
- case CECDEVICE_RECORDINGDEVICE1:
- case CECDEVICE_RECORDINGDEVICE2:
- case CECDEVICE_RECORDINGDEVICE3:
- return CEC_DEVICE_TYPE_RECORDING_DEVICE;
- case CECDEVICE_TUNER1:
- case CECDEVICE_TUNER2:
- case CECDEVICE_TUNER3:
- case CECDEVICE_TUNER4:
- return CEC_DEVICE_TYPE_TUNER;
- case CECDEVICE_TV:
- return CEC_DEVICE_TYPE_TV;
- default:
- return CEC_DEVICE_TYPE_RESERVED;
- }
+ if (!configuration)
+ return NULL;
+
+ // create a new libCEC instance
+ CLibCEC *lib = new CLibCEC(NULL);
+
+ // register a new client
+ CCECClient *client(NULL);
+ if (lib && configuration)
+ client = lib->RegisterClient(*configuration);
+
+ // update the current configuration
+ if (client)
+ client->GetCurrentConfiguration(*configuration);
+
+ // ensure that the correct server version is set
+ configuration->serverVersion = LIBCEC_VERSION_CURRENT;
+
+ return static_cast< void* > (lib);
}
-uint16_t CLibCEC::GetMaskForType(cec_logical_address address)
+void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */)
{
- return GetMaskForType(GetType(address));
+ libcec_configuration configuration;
+
+ // client version < 1.5.0
+ snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
+ configuration.deviceTypes = types;
+ configuration.iPhysicalAddress = iPhysicalAddress;
+
+ if (configuration.deviceTypes.IsEmpty())
+ configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+
+ return CECInitialise(&configuration);
}
-uint16_t CLibCEC::GetMaskForType(cec_device_type type)
+bool CECStartBootloader(void)
{
- switch (type)
+ bool bReturn(false);
+ cec_adapter deviceList[1];
+ if (CUSBCECAdapterDetection::FindAdapters(deviceList, 1) > 0)
{
- case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
- {
- cec_logical_addresses addr;
- addr.Clear();
- addr.Set(CECDEVICE_AUDIOSYSTEM);
- return addr.AckMask();
- }
- case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
- {
- cec_logical_addresses addr;
- addr.Clear();
- addr.Set(CECDEVICE_PLAYBACKDEVICE1);
- addr.Set(CECDEVICE_PLAYBACKDEVICE2);
- addr.Set(CECDEVICE_PLAYBACKDEVICE3);
- return addr.AckMask();
- }
- case CEC_DEVICE_TYPE_RECORDING_DEVICE:
- {
- cec_logical_addresses addr;
- addr.Clear();
- addr.Set(CECDEVICE_RECORDINGDEVICE1);
- addr.Set(CECDEVICE_RECORDINGDEVICE2);
- addr.Set(CECDEVICE_RECORDINGDEVICE3);
- return addr.AckMask();
- }
- case CEC_DEVICE_TYPE_TUNER:
- {
- cec_logical_addresses addr;
- addr.Clear();
- addr.Set(CECDEVICE_TUNER1);
- addr.Set(CECDEVICE_TUNER2);
- addr.Set(CECDEVICE_TUNER3);
- addr.Set(CECDEVICE_TUNER4);
- return addr.AckMask();
- }
- case CEC_DEVICE_TYPE_TV:
+ CUSBCECAdapterCommunication comm(NULL, deviceList[0].comm);
+ CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
+ while (timeout.TimeLeft() > 0 && (bReturn = comm.Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
{
- cec_logical_addresses addr;
- addr.Clear();
- addr.Set(CECDEVICE_TV);
- return addr.AckMask();
+ comm.Close();
+ CEvent::Sleep(500);
}
- default:
- return 0;
+ if (comm.IsOpen())
+ bReturn = comm.StartBootloader();
}
+
+ return bReturn;
+}
+
+void CECDestroy(CEC::ICECAdapter *instance)
+{
+ delete instance;
}
bool CLibCEC::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
{
if (m_cec->IsRunning())
return false;
-
+
return m_cec->GetDeviceInformation(strPort, config, iTimeoutMs);
}
+
+// no longer being used
+void CLibCEC::AddKey(const cec_keypress &UNUSED(key)) {}
+void CLibCEC::AddCommand(const cec_command &UNUSED(command)) {}
+void CLibCEC::ConfigurationChanged(const libcec_configuration &UNUSED(config)) {}
+void CLibCEC::SetCurrentButton(cec_user_control_code UNUSED(iButtonCode)) {}
+CLibCEC *CLibCEC::GetInstance(void) { return NULL; }
+void CLibCEC::SetInstance(CLibCEC *UNUSED(instance)) {}
{
class CAdapterCommunication;
class CCECProcessor;
+ class CCECClient;
class CLibCEC : public ICECAdapter
{
public:
- /*!
- * ICECAdapter implementation
- */
- //@{
CLibCEC(const char *strDeviceName, cec_device_type_list types, uint16_t iPhysicalAddress = 0);
CLibCEC(libcec_configuration *configuration);
virtual ~CLibCEC(void);
+ /*!
+ * ICECAdapter implementation
+ */
+ //@{
bool Open(const char *strPort, uint32_t iTimeout = CEC_DEFAULT_CONNECT_TIMEOUT);
void Close(void);
bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks);
bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
//@}
- static void AddLog(const cec_log_level level, const char *strFormat, ...);
- static void AddKey(void);
- static void AddKey(const cec_keypress &key);
- static void AddCommand(const cec_command &command);
- static void ConfigurationChanged(const libcec_configuration &config);
- static void SetCurrentButton(cec_user_control_code iButtonCode);
+ void AddLog(const cec_log_level level, const char *strFormat, ...);
+ static void AddKey(void) {} //UNUSED
+ static void AddKey(const cec_keypress &key); //UNUSED
+ static void AddCommand(const cec_command &command); //UNUSED
+ static void ConfigurationChanged(const libcec_configuration &config); //UNUSED
+ static void SetCurrentButton(cec_user_control_code iButtonCode); //UNUSED
void CheckKeypressTimeout(void);
- static int MenuStateChanged(const cec_menu_state newState);
- static void Alert(const libcec_alert type, const libcec_parameter ¶m);
+ void Alert(const libcec_alert type, const libcec_parameter ¶m);
+ static CLibCEC *GetInstance(void); //UNUSED
+ static void SetInstance(CLibCEC *instance); //UNUSED
- static CLibCEC *GetInstance(void);
- static void SetInstance(CLibCEC *instance);
+ static bool IsValidPhysicalAddress(uint16_t iPhysicalAddress);
+ CCECClient *RegisterClient(libcec_configuration &configuration);
+ void UnregisterClients(void);
+ std::vector<CCECClient *> GetClients(void) { return m_clients; };
+
+ CCECProcessor * m_cec;
- CCECProcessor * m_cec;
protected:
int64_t m_iStartTime;
- cec_user_control_code m_iCurrentButton;
- int64_t m_buttontime;
- PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer;
- PLATFORM::SyncedBuffer<cec_keypress> m_keyBuffer;
- PLATFORM::SyncedBuffer<cec_command> m_commandBuffer;
- ICECCallbacks * m_callbacks;
- void * m_cbParam;
+ cec_user_control_code m_iCurrentButton; //UNUSED
+ int64_t m_buttontime; //UNUSED
+ PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer; //UNUSED
+ PLATFORM::SyncedBuffer<cec_keypress> m_keyBuffer; //UNUSED
+ PLATFORM::SyncedBuffer<cec_command> m_commandBuffer; //UNUSED
+ ICECCallbacks * m_callbacks; //UNUSED
+ void * m_cbParam; //UNUSED
PLATFORM::CMutex m_mutex;
- PLATFORM::CMutex m_logMutex;
+ PLATFORM::CMutex m_logMutex; //UNUSED
+
+ CCECClient * m_client;
+ std::vector<CCECClient *> m_clients;
};
};
libcec_la_SOURCES = CECProcessor.cpp \
LibCEC.cpp \
LibCECC.cpp \
+ CECClient.cpp \
adapter/USBCECAdapterCommands.cpp \
adapter/USBCECAdapterCommunication.cpp \
adapter/USBCECAdapterDetection.cpp \
adapter/USBCECAdapterMessageQueue.cpp \
devices/CECAudioSystem.cpp \
devices/CECBusDevice.cpp \
+ devices/CECDeviceMap.cpp \
devices/CECPlaybackDevice.cpp \
devices/CECRecordingDevice.cpp \
devices/CECTuner.cpp \
namespace CEC
{
+ class CLibCEC;
+
class IAdapterCommunicationCallback
{
public:
* @return True when this is an error, false otherwise.
*/
virtual bool HandleReceiveFailed(cec_logical_address initiator) = 0;
+
+ virtual CLibCEC *GetLib(void) const = 0;
};
class IAdapterCommunication
* @return True when set, false otherwise.
*/
virtual bool SetAckMask(uint16_t iMask) = 0;
+ virtual uint16_t GetAckMask(void) = 0;
/*!
* @brief Check whether the CEC adapter responds
*/
virtual uint32_t GetFirmwareBuildDate(void) = 0;
+ /*!
+ * @return True when this adapter is using the latest firmware build, or when the latest firmware build for this adapter type is unknown. False otherwise.
+ */
+ virtual bool IsRunningLatestFirmware(void) = 0;
+
/*!
* @return True when the control mode has been set, false otherwise.
*/
* @brief The configuration to store.
* @return True when the configuration was persisted, false otherwise.
*/
- virtual bool PersistConfiguration(libcec_configuration *configuration) = 0;
+ virtual bool PersistConfiguration(const libcec_configuration &configuration) = 0;
/*!
* @brief Get the persisted configuration from the adapter (if supported)
* @param configuration The updated configuration.
* @return True when the configuration was updated, false otherwise.
*/
- virtual bool GetConfiguration(libcec_configuration *configuration) = 0;
+ virtual bool GetConfiguration(libcec_configuration &configuration) = 0;
/*!
* @return The name of the port
*/
virtual uint16_t GetPhysicalAddress(void) = 0;
- protected:
IAdapterCommunicationCallback *m_callback;
};
};
using namespace CEC;
using namespace PLATFORM;
+#define LIB_CEC m_comm->m_callback->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
CUSBCECAdapterCommands::CUSBCECAdapterCommands(CUSBCECAdapterCommunication *comm) :
m_comm(comm),
m_bSettingsRetrieved(false),
while (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN && iFwVersionTry++ < 3)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
cec_datapacket response = RequestSetting(MSGCODE_FIRMWARE_VERSION);
if (response.size == 2)
m_persistedConfiguration.iFirmwareVersion = (response[0] << 8 | response[1]);
else
{
- CLibCEC::AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", iFwVersionTry);
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", iFwVersionTry);
CEvent::Sleep(500);
}
}
if (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1");
m_persistedConfiguration.iFirmwareVersion = 1;
}
bool CUSBCECAdapterCommands::RequestSettingAutoEnabled(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting");
cec_datapacket response = RequestSetting(MSGCODE_GET_AUTO_ENABLED);
if (response.size == 1)
{
m_bSettingAutoEnabled = response[0] == 1;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted autonomous mode setting: '%s'", m_bSettingAutoEnabled ? "enabled" : "disabled");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted autonomous mode setting: '%s'", m_bSettingAutoEnabled ? "enabled" : "disabled");
return true;
}
return false;
bool CUSBCECAdapterCommands::RequestSettingCECVersion(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting CEC version setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting CEC version setting");
cec_datapacket response = RequestSetting(MSGCODE_GET_HDMI_VERSION);
if (response.size == 1)
{
m_settingCecVersion = (cec_version)response[0];
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted CEC version setting: '%s'", CLibCEC::GetInstance()->ToString(m_settingCecVersion));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted CEC version setting: '%s'", ToString(m_settingCecVersion));
return true;
}
return false;
{
if (m_iBuildDate == CEC_FW_BUILD_UNKNOWN)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting firmware build date");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting firmware build date");
cec_datapacket response = RequestSetting(MSGCODE_GET_BUILDDATE);
if (response.size == 4)
bool CUSBCECAdapterCommands::RequestSettingDefaultLogicalAddress(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting default logical address setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting default logical address setting");
cec_datapacket response = RequestSetting(MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS);
if (response.size == 1)
{
m_persistedConfiguration.logicalAddresses.primary = (cec_logical_address)response[0];
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted logical address setting: '%s'", CLibCEC::GetInstance()->ToString(m_persistedConfiguration.logicalAddresses.primary));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted logical address setting: '%s'", ToString(m_persistedConfiguration.logicalAddresses.primary));
return true;
}
return false;
bool CUSBCECAdapterCommands::RequestSettingDeviceType(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting device type setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting device type setting");
m_persistedConfiguration.deviceTypes.Clear();
cec_datapacket response = RequestSetting(MSGCODE_GET_DEVICE_TYPE);
if (response.size == 1)
{
m_persistedConfiguration.deviceTypes.Add((cec_device_type)response[0]);
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted device type setting: '%s'", CLibCEC::GetInstance()->ToString((cec_device_type)response[0]));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted device type setting: '%s'", ToString((cec_device_type)response[0]));
return true;
}
- CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted device type setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted device type setting");
return false;
}
bool CUSBCECAdapterCommands::RequestSettingLogicalAddressMask(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting");
cec_datapacket response = RequestSetting(MSGCODE_GET_LOGICAL_ADDRESS_MASK);
if (response.size == 2)
{
m_iSettingLAMask = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]);
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted logical address mask setting: '%x'", m_iSettingLAMask);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted logical address mask setting: '%x'", m_iSettingLAMask);
return true;
}
return false;
bool CUSBCECAdapterCommands::RequestSettingOSDName(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting OSD name setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting OSD name setting");
memset(m_persistedConfiguration.strDeviceName, 0, 13);
cec_datapacket response = RequestSetting(MSGCODE_GET_OSD_NAME);
if (response.size == 0)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted device name setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted device name setting");
return false;
}
buf[response.size] = 0;
snprintf(m_persistedConfiguration.strDeviceName, 13, "%s", buf);
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted device name setting: '%s'", buf);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted device name setting: '%s'", buf);
return true;
}
bool CUSBCECAdapterCommands::RequestSettingPhysicalAddress(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting physical address setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting physical address setting");
cec_datapacket response = RequestSetting(MSGCODE_GET_PHYSICAL_ADDRESS);
if (response.size == 2)
{
m_persistedConfiguration.iPhysicalAddress = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]);
- CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted physical address setting: '%4x'", m_persistedConfiguration.iPhysicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted physical address setting: '%4x'", m_persistedConfiguration.iPhysicalAddress);
return true;
}
- CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted physical address setting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted physical address setting");
return false;
}
/* check whether this value was changed */
if (m_bSettingAutoEnabled == enabled)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "autonomous mode setting unchanged (%s)", enabled ? "on" : "off");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "autonomous mode setting unchanged (%s)", enabled ? "on" : "off");
return bReturn;
}
m_bNeedsWrite = true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off");
CCECAdapterMessage params;
params.PushEscaped(enabled ? 1 : 0);
/* check whether this value was changed */
if (m_persistedConfiguration.deviceTypes.types[0] == type)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device type setting unchanged (%X)", (uint8_t)type);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "device type setting unchanged (%X)", (uint8_t)type);
return bReturn;
}
m_bNeedsWrite = true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the device type to %X (previous: %X)", (uint8_t)type, (uint8_t)m_persistedConfiguration.deviceTypes.types[0]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the device type to %X (previous: %X)", (uint8_t)type, (uint8_t)m_persistedConfiguration.deviceTypes.types[0]);
CCECAdapterMessage params;
params.PushEscaped((uint8_t)type);
/* check whether this value was changed */
if (m_persistedConfiguration.logicalAddresses.primary == address)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address setting unchanged (%X)", (uint8_t)address);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address setting unchanged (%X)", (uint8_t)address);
return bReturn;
}
m_bNeedsWrite = true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the default logical address to %X (previous: %X)", (uint8_t)address, (uint8_t)m_persistedConfiguration.logicalAddresses.primary);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the default logical address to %X (previous: %X)", (uint8_t)address, (uint8_t)m_persistedConfiguration.logicalAddresses.primary);
CCECAdapterMessage params;
params.PushEscaped((uint8_t)address);
/* check whether this value was changed */
if (m_iSettingLAMask == iMask)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address mask setting unchanged (%2X)", iMask);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address mask setting unchanged (%2X)", iMask);
return bReturn;
}
m_bNeedsWrite = true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X (previous: %2X)", iMask, m_iSettingLAMask);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X (previous: %2X)", iMask, m_iSettingLAMask);
CCECAdapterMessage params;
params.PushEscaped(iMask >> 8);
/* check whether this value was changed */
if (m_persistedConfiguration.iPhysicalAddress == iPhysicalAddress)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "physical address setting unchanged (%04X)", iPhysicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address setting unchanged (%04X)", iPhysicalAddress);
return bReturn;
}
m_bNeedsWrite = true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X (previous: %04X)", iPhysicalAddress, m_persistedConfiguration.iPhysicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X (previous: %04X)", iPhysicalAddress, m_persistedConfiguration.iPhysicalAddress);
CCECAdapterMessage params;
params.PushEscaped(iPhysicalAddress >> 8);
/* check whether this value was changed */
if (m_settingCecVersion == version)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "CEC version setting unchanged (%s)", CLibCEC::GetInstance()->ToString(version));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "CEC version setting unchanged (%s)", ToString(version));
return bReturn;
}
m_bNeedsWrite = true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s (previous: %s)", CLibCEC::GetInstance()->ToString(version), CLibCEC::GetInstance()->ToString(m_settingCecVersion));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s (previous: %s)", ToString(version), ToString(m_settingCecVersion));
CCECAdapterMessage params;
params.PushEscaped((uint8_t)version);
/* check whether this value was changed */
if (!strcmp(m_persistedConfiguration.strDeviceName, strOSDName))
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "OSD name setting unchanged (%s)", strOSDName);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "OSD name setting unchanged (%s)", strOSDName);
return bReturn;
}
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s (previous: %s)", strOSDName, m_persistedConfiguration.strDeviceName);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s (previous: %s)", strOSDName, m_persistedConfiguration.strDeviceName);
CCECAdapterMessage params;
for (size_t iPtr = 0; iPtr < strlen(strOSDName); iPtr++)
if (!m_bNeedsWrite)
return true;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM");
CCECAdapterMessage params;
CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_WRITE_EEPROM, params);
return m_bNeedsWrite;
}
-bool CUSBCECAdapterCommands::PersistConfiguration(libcec_configuration *configuration)
+bool CUSBCECAdapterCommands::PersistConfiguration(const libcec_configuration &configuration)
{
if (m_persistedConfiguration.iFirmwareVersion < 2)
return false;
bool bReturn(true);
bReturn &= SetSettingAutoEnabled(true);
- bReturn &= SetSettingDeviceType(CLibCEC::GetType(configuration->logicalAddresses.primary));
- bReturn &= SetSettingDefaultLogicalAddress(configuration->logicalAddresses.primary);
- bReturn &= SetSettingLogicalAddressMask(CLibCEC::GetMaskForType(configuration->logicalAddresses.primary));
- bReturn &= SetSettingPhysicalAddress(configuration->iPhysicalAddress);
+ bReturn &= SetSettingDeviceType(CLibCEC::GetType(configuration.logicalAddresses.primary));
+ bReturn &= SetSettingDefaultLogicalAddress(configuration.logicalAddresses.primary);
+ bReturn &= SetSettingLogicalAddressMask(CLibCEC::GetMaskForType(configuration.logicalAddresses.primary));
+ bReturn &= SetSettingPhysicalAddress(configuration.iPhysicalAddress);
bReturn &= SetSettingCECVersion(CEC_VERSION_1_3A);
- bReturn &= SetSettingOSDName(configuration->strDeviceName);
+ bReturn &= SetSettingOSDName(configuration.strDeviceName);
bReturn &= WriteEEPROM();
return bReturn;
}
{
if (m_persistedConfiguration.iFirmwareVersion < 2)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - firmware version %d does not have any eeprom settings", __FUNCTION__, m_persistedConfiguration.iFirmwareVersion);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - firmware version %d does not have any eeprom settings", __FUNCTION__, m_persistedConfiguration.iFirmwareVersion);
// settings can only be persisted with firmware v2+
return false;
}
return bReturn;
}
-bool CUSBCECAdapterCommands::GetConfiguration(libcec_configuration *configuration)
+bool CUSBCECAdapterCommands::GetConfiguration(libcec_configuration &configuration)
{
// get the settings from the eeprom if needed
if (!RequestSettings())
return false;
// copy the settings
- configuration->iFirmwareVersion = m_persistedConfiguration.iFirmwareVersion;
- configuration->deviceTypes = m_persistedConfiguration.deviceTypes;
- configuration->iPhysicalAddress = m_persistedConfiguration.iPhysicalAddress;
- snprintf(configuration->strDeviceName, 13, "%s", m_persistedConfiguration.strDeviceName);
+ configuration.iFirmwareVersion = m_persistedConfiguration.iFirmwareVersion;
+ configuration.deviceTypes = m_persistedConfiguration.deviceTypes;
+ configuration.iPhysicalAddress = m_persistedConfiguration.iPhysicalAddress;
+ snprintf(configuration.strDeviceName, 13, "%s", m_persistedConfiguration.strDeviceName);
return true;
}
bool CUSBCECAdapterCommands::PingAdapter(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending ping");
CCECAdapterMessage params;
CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_PING, params);
bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
CCECAdapterMessage params;
params.PushEscaped(iMask >> 8);
bool CUSBCECAdapterCommands::StartBootloader(void)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
CCECAdapterMessage params;
CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_START_BOOTLOADER, params);
bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the line timeout to %d", iTimeout);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the line timeout to %d", iTimeout);
CCECAdapterMessage params;
params.PushEscaped(iTimeout);
CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_TRANSMIT_IDLETIME, params);
bool CUSBCECAdapterCommands::SetControlledMode(bool controlled)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off");
CCECAdapterMessage params;
params.PushEscaped(controlled ? 1 : 0);
* @param configuration The configuration to persist.
* @return True when persisted, false otherwise.
*/
- bool PersistConfiguration(libcec_configuration *configuration);
+ bool PersistConfiguration(const libcec_configuration &configuration);
/*!
* @brief Get the persisted configuration from the EEPROM.
* @param configuration The persisted configuration.
* @return True when retrieved, false otherwise.
*/
- bool GetConfiguration(libcec_configuration *configuration);
+ bool GetConfiguration(libcec_configuration &configuration);
/*!
* @brief Send a ping command to the adapter.
#define CEC_ADAPTER_PING_TIMEOUT 15000
+// firmware version 2
+#define CEC_LATEST_ADAPTER_FW_VERSION 2
+// firmware date Thu Apr 26 20:14:49 2012 +0000
+#define CEC_LATEST_ADAPTER_FW_DATE 0x4F99ACB9
+
+#define LIB_CEC m_callback->GetLib()
+
CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
IAdapterCommunication(callback),
m_port(NULL),
m_bInitialised(false),
m_pingThread(NULL),
m_commands(NULL),
- m_adapterMessageQueue(NULL)
+ m_adapterMessageQueue(NULL),
+ m_iAckMask(0xFFFF)
{
for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
m_bWaitingForAck[iPtr] = false;
/* we need the port settings here */
if (!m_port)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "port is NULL");
return bConnectionOpened;
}
/* return true when the port is already open */
if (IsOpen())
{
- CLibCEC::AddLog(CEC_LOG_WARNING, "port is already open");
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "port is already open");
return true;
}
/* return false when we couldn't connect */
if (!bConnectionOpened)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, strError);
+ LIB_CEC->AddLog(CEC_LOG_ERROR, strError);
+
+ if (m_port->GetErrorNumber() == EACCES)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"No permission to open the device";
+ LIB_CEC->Alert(CEC_ALERT_PERMISSION_ERROR, param);
+ }
+ else if (m_port->GetErrorNumber() == EBUSY)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"The serial port is busy. Only one program can access the device directly.";
+ LIB_CEC->Alert(CEC_ALERT_PORT_BUSY, param);
+ }
return false;
}
- CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
ClearInputBytes();
}
if (!CreateThread())
{
bConnectionOpened = false;
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a communication thread");
}
else if (!bSkipChecks && !CheckAdapter())
{
bConnectionOpened = false;
- CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
}
else if (bStartListening)
{
else
{
bConnectionOpened = false;
- CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a ping thread");
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a ping thread");
}
}
CLockObject lock(m_mutex);
/* set the ackmask to 0 before closing the connection */
- if (IsRunning() && m_port->IsOpen() && m_port->GetErrorNumber() == 0)
+ if (IsOpen() && m_port->GetErrorNumber() == 0)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
SetAckMask(0);
if (m_commands->GetFirmwareVersion() >= 2)
SetControlledMode(false);
/* close and delete the com port connection */
if (m_port)
m_port->Close();
-
- libcec_parameter param;
- CLibCEC::Alert(CEC_ALERT_CONNECTION_LOST, param);
}
cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout)
void *CUSBCECAdapterCommunication::Process(void)
{
CCECAdapterMessage msg;
- CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread started");
while (!IsStopped())
{
/* read from the serial port */
if (!ReadFromDevice(50, 5))
+ {
+ libcec_parameter param;
+ param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
+ LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
+
break;
+ }
/* TODO sleep 5 ms so other threads can get a lock */
Sleep(5);
}
m_adapterMessageQueue->Clear();
- CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread ended");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread ended");
return NULL;
}
bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
{
CLockObject adapterLock(m_mutex);
- if (!m_port->IsOpen())
+ if (!IsOpen())
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str());
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str());
message->state = ADAPTER_MESSAGE_STATE_ERROR;
return false;
}
/* write the message */
if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
message->state = ADAPTER_MESSAGE_STATE_ERROR;
- Close();
+ // this will trigger an alert in the reader thread
+ m_port->Close();
return false;
}
- CLibCEC::AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
message->state = ADAPTER_MESSAGE_STATE_SENT;
return true;
}
/* read from the serial port */
{
CLockObject lock(m_mutex);
- if (!m_port || !m_port->IsOpen())
+ if (!IsOpen())
return false;
iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
if (m_port->GetErrorNumber())
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
m_port->Close();
return false;
}
CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage ¶ms, bool bIsRetry /* = false */)
{
- if (!m_port || !m_port->IsOpen() ||
- !m_adapterMessageQueue)
+ if (!IsOpen() || !m_adapterMessageQueue)
return NULL;
/* create the adapter message for this command */
/* write the command */
if (!m_adapterMessageQueue->Write(output))
{
+ // this will trigger an alert in the reader thread
if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
- Close();
+ m_port->Close();
return output;
}
else
/* if the controller reported that the command was rejected, and we didn't send the command
to set controlled mode, then the controller probably switched to auto mode. set controlled
mode and retry */
- CLibCEC::AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
delete output;
if (SetControlledMode(true))
return SendCommand(msgCode, params, true);
unsigned iPingTry(0);
while (timeout.TimeLeft() > 0 && (bPinged = PingAdapter()) == false)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
CEvent::Sleep(500);
}
bool bControlled(false);
while (timeout.TimeLeft() > 0 && (bControlled = SetControlledMode(true)) == false)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
CEvent::Sleep(500);
}
bReturn = bControlled;
{
if (m_port->IsOpen() && m_commands->StartBootloader())
{
- Close();
+ m_port->Close();
return true;
}
return false;
bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
{
- return m_port->IsOpen() ? m_commands->SetAckMask(iMask) : false;
+ if (m_iAckMask == iMask)
+ return true;
+
+ if (IsOpen() && m_commands->SetAckMask(iMask))
+ {
+ m_iAckMask = iMask;
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "couldn't change the ackmask: the connection is closed");
+ return false;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetAckMask(void)
+{
+ return m_iAckMask;
}
bool CUSBCECAdapterCommunication::PingAdapter(void)
{
- return m_port->IsOpen() ? m_commands->PingAdapter() : false;
+ return IsOpen() ? m_commands->PingAdapter() : false;
}
uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
{
- return m_commands->GetFirmwareVersion();
+ return IsOpen() ? m_commands->GetFirmwareVersion() : CEC_FW_VERSION_UNKNOWN;
}
uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
{
- return m_commands->RequestBuildDate();
+ return IsOpen() ? m_commands->RequestBuildDate() : 0;
+}
+
+bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
+{
+ return GetFirmwareVersion() >= CEC_LATEST_ADAPTER_FW_VERSION &&
+ GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE;
}
-bool CUSBCECAdapterCommunication::PersistConfiguration(libcec_configuration *configuration)
+bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration &configuration)
{
- return m_port->IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
+ return IsOpen() ? m_commands->PersistConfiguration(configuration) : false;
}
-bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration *configuration)
+bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration &configuration)
{
- return m_port->IsOpen() ? m_commands->GetConfiguration(configuration) : false;
+ return IsOpen() ? m_commands->GetConfiguration(configuration) : false;
}
CStdString CUSBCECAdapterCommunication::GetPortName(void)
bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
{
- return m_port->IsOpen() ? m_commands->SetControlledMode(controlled) : false;
+ return IsOpen() ? m_commands->SetControlledMode(controlled) : false;
}
void *CAdapterPingThread::Process(void)
if (iFailedCounter == 3)
{
/* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
- CLibCEC::AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
+ m_com->LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
m_com->StopThread(false);
break;
}
bool StartBootloader(void);
bool SetAckMask(uint16_t iMask);
+ uint16_t GetAckMask(void);
bool PingAdapter(void);
uint16_t GetFirmwareVersion(void);
uint32_t GetFirmwareBuildDate(void);
- bool PersistConfiguration(libcec_configuration *configuration);
- bool GetConfiguration(libcec_configuration *configuration);
+ bool IsRunningLatestFirmware(void);
+ bool PersistConfiguration(const libcec_configuration &configuration);
+ bool GetConfiguration(libcec_configuration &configuration);
CStdString GetPortName(void);
uint16_t GetPhysicalAddress(void) { return 0; }
bool SetControlledMode(bool controlled);
CAdapterPingThread * m_pingThread; /**< ping thread, that pings the adapter every 15 seconds */
CUSBCECAdapterCommands * m_commands; /**< commands that can be sent to the adapter */
CCECAdapterMessageQueue * m_adapterMessageQueue; /**< the incoming and outgoing message queue */
+ uint16_t m_iAckMask;
};
class CAdapterPingThread : public PLATFORM::CThread
{
if (HasStartMessage())
{
- CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+ //TODO CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
Clear();
}
PushBack(byte);
#define MESSAGE_QUEUE_SIGNAL_WAIT_TIME 1000
-CCECAdapterMessageQueueEntry::CCECAdapterMessageQueueEntry(CCECAdapterMessage *message) :
+CCECAdapterMessageQueueEntry::CCECAdapterMessageQueueEntry(CCECAdapterMessageQueue *queue, CCECAdapterMessage *message) :
+ m_queue(queue),
m_message(message),
m_iPacketsLeft(message->IsTranmission() ? message->Size() / 4 : 1),
m_bSucceeded(false),
strLog.Format("%s - command accepted", ToString());
if (m_iPacketsLeft > 0)
strLog.AppendFormat(" - waiting for %d more", m_iPacketsLeft);
- CLibCEC::AddLog(CEC_LOG_DEBUG, strLog);
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, strLog);
/* no more packets left and not a transmission, so we're done */
if (!m_message->IsTranmission() && m_iPacketsLeft == 0)
if (m_iPacketsLeft == 0)
{
/* transmission succeeded, so we're done */
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - transmit succeeded", ToString());
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - transmit succeeded", ToString());
m_message->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
m_message->response = message.packet;
}
{
/* error, we expected more acks
since the messages are processed in order, this should not happen, so this is an error situation */
- CLibCEC::AddLog(CEC_LOG_WARNING, "%s - received 'transmit succeeded' but not enough 'command accepted' messages (%d left)", ToString(), m_iPacketsLeft);
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, "%s - received 'transmit succeeded' but not enough 'command accepted' messages (%d left)", ToString(), m_iPacketsLeft);
m_message->state = ADAPTER_MESSAGE_STATE_ERROR;
}
}
{
{
CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
m_message->response = message.packet;
if (m_message->IsTranmission())
m_message->state = message.Message() == MSGCODE_TRANSMIT_SUCCEEDED ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
{
/* the message wasn't handled */
bool bIsError(m_com->HandlePoll(msg));
- CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
+ m_com->m_callback->GetLib()->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
/* push this message to the current frame */
if (!bIsError && msg.PushToCecCommand(m_currentCECFrame))
m_com->SetLineTimeout(msg->lineTimeout);
}
- CCECAdapterMessageQueueEntry *entry = new CCECAdapterMessageQueueEntry(msg);
+ CCECAdapterMessageQueueEntry *entry = new CCECAdapterMessageQueueEntry(this, msg);
uint64_t iEntryId(0);
/* add to the wait for ack queue */
if (msg->Message() != MSGCODE_START_BOOTLOADER)
{
if (!entry->Wait(msg->transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : msg->transmit_timeout))
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", CCECAdapterMessage::ToString(msg->Message()));
+ m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", CCECAdapterMessage::ToString(msg->Message()));
msg->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
bReturn = false;
}
namespace CEC
{
class CUSBCECAdapterCommunication;
+ class CCECAdapterMessageQueue;
class CCECAdapterMessageQueueEntry
{
public:
- CCECAdapterMessageQueueEntry(CCECAdapterMessage *message);
+ CCECAdapterMessageQueueEntry(CCECAdapterMessageQueue *queue, CCECAdapterMessage *message);
virtual ~CCECAdapterMessageQueueEntry(void);
/*!
*/
void Signal(void);
+ CCECAdapterMessageQueue * m_queue;
CCECAdapterMessage * m_message; /**< the message that was sent */
uint8_t m_iPacketsLeft; /**< the amount of acks that we're waiting on */
bool m_bSucceeded; /**< true when the command received a response, false otherwise */
class CCECAdapterMessageQueue : public PLATFORM::CThread
{
friend class CUSBCECAdapterCommunication;
+ friend class CCECAdapterMessageQueueEntry;
public:
/*!
using namespace CEC;
using namespace PLATFORM;
-#define ToString(p) m_processor->ToString(p)
+#define LIB_CEC m_processor->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
CCECBusDevice(processor, address, iPhysicalAddress),
CLockObject lock(m_mutex);
if (m_audioStatus != status)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): audio status changed from %2x to %2x", GetLogicalAddressName(), m_iLogicalAddress, m_audioStatus, status);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): audio status changed from %2x to %2x", GetLogicalAddressName(), m_iLogicalAddress, m_audioStatus, status);
m_audioStatus = status;
return true;
}
CLockObject lock(m_mutex);
if (m_systemAudioStatus != mode)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): system audio mode status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_systemAudioStatus), ToString(mode));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): system audio mode status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_systemAudioStatus), ToString(mode));
m_systemAudioStatus = mode;
return true;
}
uint8_t state;
{
CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
state = m_audioStatus;
}
cec_system_audio_status state;
{
CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
state = m_systemAudioStatus;
}
cec_system_audio_status state;
{
CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
state = m_systemAudioStatus;
}
return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state);
}
-uint8_t CCECAudioSystem::VolumeUp(bool bSendRelease /* = true */)
+uint8_t CCECAudioSystem::VolumeUp(const cec_logical_address source, bool bSendRelease /* = true */)
{
- if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP) && bSendRelease)
- TransmitKeyRelease();
+ TransmitKeypress(source, CEC_USER_CONTROL_CODE_VOLUME_UP);
+ if (bSendRelease)
+ TransmitKeyRelease(source);
CLockObject lock(m_mutex);
return m_audioStatus;
}
-uint8_t CCECAudioSystem::VolumeDown(bool bSendRelease /* = true */)
+uint8_t CCECAudioSystem::VolumeDown(const cec_logical_address source, bool bSendRelease /* = true */)
{
- if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN) && bSendRelease)
- TransmitKeyRelease();
+ TransmitKeypress(source, CEC_USER_CONTROL_CODE_VOLUME_DOWN);
+ if (bSendRelease)
+ TransmitKeyRelease(source);
CLockObject lock(m_mutex);
return m_audioStatus;
}
-uint8_t CCECAudioSystem::MuteAudio(bool bSendRelease /* = true */)
+uint8_t CCECAudioSystem::MuteAudio(const cec_logical_address source)
{
- if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE) && bSendRelease)
- TransmitKeyRelease();
+ TransmitKeypress(source, CEC_USER_CONTROL_CODE_MUTE);
+ TransmitKeyRelease(source);
CLockObject lock(m_mutex);
return m_audioStatus;
bool TransmitSetSystemAudioMode(cec_logical_address dest);
bool TransmitSystemAudioModeStatus(cec_logical_address dest);
- uint8_t VolumeUp(bool bSendRelease = true);
- uint8_t VolumeDown(bool bSendRelease = true);
- uint8_t MuteAudio(bool bSendRelease = true);
+ uint8_t VolumeUp(const cec_logical_address source, bool bSendRelease = true);
+ uint8_t VolumeDown(const cec_logical_address source, bool bSendRelease = true);
+ uint8_t MuteAudio(const cec_logical_address source);
bool TransmitActiveSource(void) { return false; }
#include "../LibCEC.h"
#include "../platform/util/timeutils.h"
+#include "CECAudioSystem.h"
+#include "CECPlaybackDevice.h"
+#include "CECRecordingDevice.h"
+#include "CECTuner.h"
+#include "CECTV.h"
+
+using namespace std;
using namespace CEC;
using namespace PLATFORM;
-#define ToString(p) m_processor->ToString(p)
+#define LIB_CEC m_processor->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
m_type (CEC_DEVICE_TYPE_RESERVED),
delete m_handler;
}
+bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
+{
+ bool bInitHandler(false);
+ {
+ CTryLockObject lock(m_mutex);
+ if (!lock.IsLocked())
+ return false;
+
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ return false;
+
+ MarkBusy();
+
+ if (m_vendor != m_handler->GetVendorId())
+ {
+ if (CCECCommandHandler::HasSpecificHandler(m_vendor))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+ 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;
+ }
+
+ m_handler->SetVendorId(m_vendor);
+ bInitHandler = true;
+ }
+ }
+ }
+
+ if (bInitHandler)
+ {
+ m_handler->InitHandler();
+
+ if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
+ m_handler->ActivateSource();
+ }
+
+ MarkReady();
+
+ return true;
+}
+
bool CCECBusDevice::HandleCommand(const cec_command &command)
{
bool bHandled(false);
bHandled = m_handler->HandleCommand(command);
/* change status to present */
- if (bHandled)
+ if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST)
{
CLockObject lock(m_mutex);
if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
{
if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
}
}
return bHandled;
}
-bool CCECBusDevice::PowerOn(void)
+const char* CCECBusDevice::GetLogicalAddressName(void) const
{
- bool bReturn(false);
- GetVendorId(); // ensure that we got the vendor id, because the implementations vary per vendor
+ return ToString(m_iLogicalAddress);
+}
+
+bool CCECBusDevice::IsPresent(void)
+{
+ CLockObject lock(m_mutex);
+ return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
+}
+
+bool CCECBusDevice::IsHandledByLibCEC(void)
+{
+ CLockObject lock(m_mutex);
+ return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
+}
+
+void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+{
+ // some commands should never be marked as unsupported
+ if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
+ opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
+ opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
+ opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
+ opcode == CEC_OPCODE_ABORT ||
+ opcode == CEC_OPCODE_FEATURE_ABORT ||
+ opcode == CEC_OPCODE_NONE)
+ return;
- MarkBusy();
- cec_power_status currentStatus = GetPowerStatus(false);
- if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
- currentStatus != CEC_POWER_STATUS_ON)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
- if (m_handler->PowerOn(GetMyLogicalAddress(), m_iLogicalAddress))
+ CLockObject lock(m_mutex);
+ if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
{
- SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
- bReturn = true;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+ m_unsupportedFeatures.insert(opcode);
}
}
- else
- {
- CLibCEC::AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
- }
+ // signal threads that are waiting for a reponse
+ MarkBusy();
+ m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
+ MarkReady();
+}
+
+bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
+{
+ CLockObject lock(m_mutex);
+ bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
+ if (bUnsupported)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+ return bUnsupported;
+}
+
+bool CCECBusDevice::TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait /* = true */)
+{
+ MarkBusy();
+ bool bReturn = m_handler->TransmitKeypress(initiator, m_iLogicalAddress, key, bWait);
MarkReady();
return bReturn;
}
-bool CCECBusDevice::Standby(void)
+bool CCECBusDevice::TransmitKeyRelease(const cec_logical_address initiator, bool bWait /* = true */)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
MarkBusy();
- bool bReturn = m_handler->TransmitStandby(GetMyLogicalAddress(), m_iLogicalAddress);
+ bool bReturn = m_handler->TransmitKeyRelease(initiator, m_iLogicalAddress, bWait);
MarkReady();
return bReturn;
}
-/** @name Getters */
-//@{
-cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
+cec_version CCECBusDevice::GetCecVersion(const cec_logical_address initiator, bool bUpdate /* = false */)
{
bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
bool bRequestUpdate(false);
if (bRequestUpdate)
{
- CheckVendorIdRequested();
- RequestCecVersion();
+ CheckVendorIdRequested(initiator);
+ RequestCecVersion(initiator);
}
CLockObject lock(m_mutex);
return m_cecVersion;
}
-bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetCecVersion(const cec_version newVersion)
{
- bool bReturn(false);
-
- if (MyLogicalAddressContains(m_iLogicalAddress))
- {
- MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting active source");
-
- bReturn = m_handler->TransmitRequestActiveSource(GetMyLogicalAddress(), bWaitForResponse);
- MarkReady();
- }
- return bReturn;
+ CLockObject lock(m_mutex);
+ if (m_cecVersion != newVersion)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
+ m_cecVersion = newVersion;
}
-bool CCECBusDevice::RequestCecVersion(bool bWaitForResponse /* = true */)
+bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ if (!IsHandledByLibCEC() &&
!IsUnsupportedFeature(CEC_OPCODE_GET_CEC_VERSION))
{
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-
- bReturn = m_handler->TransmitRequestCecVersion(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestCecVersion(initiator, m_iLogicalAddress, bWaitForResponse);
MarkReady();
}
return bReturn;
}
-const char* CCECBusDevice::GetLogicalAddressName(void) const
+bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination)
{
- return ToString(m_iLogicalAddress);
+ cec_version version;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_cecVersion));
+ version = m_cecVersion;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version);
+ MarkReady();
+ return bReturn;
}
-cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
+cec_menu_language &CCECBusDevice::GetMenuLanguage(const cec_logical_address initiator, bool bUpdate /* = false */)
{
bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
bool bRequestUpdate(false);
if (bRequestUpdate)
{
- CheckVendorIdRequested();
- RequestMenuLanguage();
+ CheckVendorIdRequested(initiator);
+ RequestMenuLanguage(initiator);
}
CLockObject lock(m_mutex);
return m_menuLanguage;
}
-bool CCECBusDevice::RequestMenuLanguage(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetMenuLanguage(const char *strLanguage)
+{
+ if (!strLanguage)
+ return;
+
+ CLockObject lock(m_mutex);
+ if (strcmp(strLanguage, m_menuLanguage.language))
+ {
+ memcpy(m_menuLanguage.language, strLanguage, 3);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, m_menuLanguage.language);
+ }
+}
+
+void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
+{
+ if (language.device == m_iLogicalAddress)
+ SetMenuLanguage(language.language);
+}
+
+bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ if (!IsHandledByLibCEC() &&
!IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
{
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
- bReturn = m_handler->TransmitRequestMenuLanguage(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestMenuLanguage(initiator, m_iLogicalAddress, bWaitForResponse);
MarkReady();
}
return bReturn;
}
-cec_menu_state CCECBusDevice::GetMenuState(void)
+bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination)
{
- CLockObject lock(m_mutex);
- return m_menuState;
+ bool bReturn(false);
+ cec_menu_language language;
+ {
+ CLockObject lock(m_mutex);
+ language = m_menuLanguage;
+ }
+
+ char lang[3];
+ {
+ CLockObject lock(m_mutex);
+ lang[0] = language.language[0];
+ lang[1] = language.language[1];
+ lang[2] = language.language[2];
+ }
+
+ MarkBusy();
+ if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): Menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+ m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+ bReturn = true;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
+ bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
+ }
+ MarkReady();
+ return bReturn;
}
-cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
+bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage)
{
- return m_processor->GetLogicalAddress();
+ bool bReturn(false);
+ if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage);
+ MarkBusy();
+ bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage);
+ MarkReady();
+ }
+ return bReturn;
}
-uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
+CStdString CCECBusDevice::GetCurrentOSDName(void)
{
- return m_processor->GetPhysicalAddress();
+ CLockObject lock(m_mutex);
+ return m_strDeviceName;
}
-CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
+CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
{
bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
bool bRequestUpdate(false);
if (bRequestUpdate)
{
- CheckVendorIdRequested();
- RequestOSDName();
+ CheckVendorIdRequested(initiator);
+ RequestOSDName(initiator);
}
CLockObject lock(m_mutex);
return m_strDeviceName;
}
-bool CCECBusDevice::RequestOSDName(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetOSDName(CStdString strName)
+{
+ CLockObject lock(m_mutex);
+ if (m_strDeviceName != strName)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
+ m_strDeviceName = strName;
+ }
+}
+
+bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ if (!IsHandledByLibCEC() &&
!IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
{
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
- bReturn = m_handler->TransmitRequestOSDName(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
MarkReady();
}
return bReturn;
}
-uint16_t CCECBusDevice::GetPhysicalAddress(bool bSuppressUpdate /* = true */)
+bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
+{
+ CStdString strDeviceName;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
+ strDeviceName = m_strDeviceName;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::HasValidPhysicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+ return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
+}
+
+uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+ return m_iPhysicalAddress;
+}
+
+uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
{
if (!bSuppressUpdate)
{
if (bRequestUpdate)
{
- CheckVendorIdRequested();
- if (!RequestPhysicalAddress())
- CLibCEC::AddLog(CEC_LOG_ERROR, "failed to request the physical address");
+ CheckVendorIdRequested(initiator);
+ if (!RequestPhysicalAddress(initiator))
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
}
}
return m_iPhysicalAddress;
}
-bool CCECBusDevice::RequestPhysicalAddress(bool bWaitForResponse /* = true */)
+bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
+{
+ CLockObject lock(m_mutex);
+ if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
+ m_iPhysicalAddress = iNewAddress;
+ }
+ return true;
+}
+
+bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress))
+ if (!IsHandledByLibCEC())
{
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
- bReturn = m_handler->TransmitRequestPhysicalAddress(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
MarkReady();
}
return bReturn;
}
-cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
+bool CCECBusDevice::TransmitPhysicalAddress(void)
+{
+ uint16_t iPhysicalAddress;
+ cec_device_type type;
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
+ return false;
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ iPhysicalAddress = m_iPhysicalAddress;
+ type = m_type;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
+ MarkReady();
+ return bReturn;
+}
+
+cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
+{
+ CLockObject lock(m_mutex);
+ return m_powerStatus;
+}
+
+cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
{
bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
bool bRequestUpdate(false);
if (bRequestUpdate)
{
- CheckVendorIdRequested();
- RequestPowerStatus();
+ CheckVendorIdRequested(initiator);
+ RequestPowerStatus(initiator);
}
CLockObject lock(m_mutex);
return m_powerStatus;
}
-bool CCECBusDevice::RequestPowerStatus(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
+{
+ CLockObject lock(m_mutex);
+ if (m_powerStatus != powerStatus)
+ {
+ m_iLastPowerStateUpdate = GetTimeMs();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
+ m_powerStatus = powerStatus;
+ }
+}
+
+bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+ if (!IsHandledByLibCEC() &&
!IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
{
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
- bReturn = m_handler->TransmitRequestPowerStatus(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
MarkReady();
}
return bReturn;
}
-cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */)
+bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
{
- bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
- bool bRequestUpdate(false);
+ cec_power_status state;
{
CLockObject lock(m_mutex);
- bRequestUpdate = (bIsPresent &&
- (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
+ state = m_powerStatus;
}
- if (bRequestUpdate)
- RequestVendorId();
-
+ MarkBusy();
+ bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
+ MarkReady();
+ return bReturn;
+}
+
+cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
+{
+ CLockObject lock(m_mutex);
+ return m_vendor;
+}
+
+cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = (bIsPresent &&
+ (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+ }
+
+ if (bRequestUpdate)
+ RequestVendorId(initiator);
+
CLockObject lock(m_mutex);
return m_vendor;
}
-bool CCECBusDevice::RequestVendorId(bool bWaitForResponse /* = true */)
+const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ return ToString(GetVendorId(initiator, bUpdate));
+}
+
+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;
+ }
+
+ if (bVendorChanged)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
+
+ return bVendorChanged;
+}
+
+bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
{
bool bReturn(false);
- if (!MyLogicalAddressContains(m_iLogicalAddress) && GetMyLogicalAddress() != CECDEVICE_UNKNOWN)
+ if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
{
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
- bReturn = m_handler->TransmitRequestVendorId(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
MarkReady();
if (bWaitForResponse)
return bReturn;
}
-const char *CCECBusDevice::GetVendorName(bool bUpdate /* = false */)
-{
- return ToString(GetVendorId(bUpdate));
-}
-
-bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
+bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
{
- return m_processor->HasLogicalAddress(address);
-}
+ bool bReturn(false);
+ uint64_t iVendorId;
+ {
+ CLockObject lock(m_mutex);
+ iVendorId = (uint64_t)m_vendor;
+ }
-bool CCECBusDevice::NeedsPoll(void)
-{
- bool bSendPoll(false);
- switch (m_iLogicalAddress)
+ MarkBusy();
+ if (iVendorId == CEC_VENDOR_UNKNOWN)
{
- case CECDEVICE_PLAYBACKDEVICE3:
- {
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE2]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
- }
- break;
- case CECDEVICE_PLAYBACKDEVICE2:
- {
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE1]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
- }
- break;
- case CECDEVICE_RECORDINGDEVICE3:
- {
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE2]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
- }
- break;
- case CECDEVICE_RECORDINGDEVICE2:
- {
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE1]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
- }
- break;
- case CECDEVICE_TUNER4:
- {
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_TUNER3]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
- }
- break;
- case CECDEVICE_TUNER3:
- {
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_TUNER2]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
- }
- break;
- case CECDEVICE_TUNER2:
+ if (bSendAbort)
{
- cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_TUNER1]->GetStatus();
- bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+ m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+ bReturn = true;
}
- break;
- case CECDEVICE_AUDIOSYSTEM:
- case CECDEVICE_PLAYBACKDEVICE1:
- case CECDEVICE_RECORDINGDEVICE1:
- case CECDEVICE_TUNER1:
- case CECDEVICE_TV:
- bSendPoll = true;
- break;
- default:
- break;
}
-
- return bSendPoll;
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
+ bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
+ }
+ MarkReady();
+ return bReturn;
}
cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
return status;
}
-//@}
-
-/** @name Setters */
-//@{
-void CCECBusDevice::SetCecVersion(const cec_version newVersion)
-{
- if (m_cecVersion != newVersion)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
- m_cecVersion = newVersion;
-}
-
-void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
-{
- CLockObject lock(m_mutex);
- if (language.device == m_iLogicalAddress &&
- strcmp(language.language, m_menuLanguage.language))
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, language.language);
- m_menuLanguage = language;
- }
-}
-
-void CCECBusDevice::SetOSDName(CStdString strName)
-{
- CLockObject lock(m_mutex);
- if (m_strDeviceName != strName)
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
- m_strDeviceName = strName;
- }
-}
-
-void CCECBusDevice::SetMenuState(const cec_menu_state state)
-{
- CLockObject lock(m_mutex);
- if (m_menuState != state)
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
- m_menuState = state;
- }
-}
-
-void CCECBusDevice::SetInactiveSource(void)
-{
- {
- CLockObject lock(m_mutex);
- if (m_bActiveSource)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
- m_bActiveSource = false;
- }
-}
-
-void CCECBusDevice::SetActiveSource(void)
-{
- CLockObject lock(m_mutex);
- if (!m_bActiveSource)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
- else
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
-
- for (int iPtr = 0; iPtr < 16; iPtr++)
- if (iPtr != m_iLogicalAddress)
- m_processor->m_busDevices[iPtr]->SetInactiveSource();
-
- m_bActiveSource = true;
- SetPowerStatus(CEC_POWER_STATUS_ON);
-}
-
-bool CCECBusDevice::TryLogicalAddress(void)
-{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
-
- m_processor->SetAckMask(0);
- if (!TransmitPoll(m_iLogicalAddress))
- {
- CLibCEC::AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
- SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-
- return true;
- }
-
- CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
- SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
- return false;
-}
-
-void CCECBusDevice::ResetDeviceStatus(void)
-{
- CLockObject lock(m_mutex);
- SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
- SetVendorId (CEC_VENDOR_UNKNOWN);
- SetMenuState (CEC_MENU_STATE_ACTIVATED);
- SetCecVersion (CEC_VERSION_UNKNOWN);
- SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
- SetOSDName (ToString(m_iLogicalAddress));
- SetInactiveSource();
- m_iLastActive = 0;
- m_unsupportedFeatures.clear();
-}
-
void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
{
{
CLockObject lock(m_mutex);
switch (newStatus)
{
- case CEC_DEVICE_STATUS_UNKNOWN:
- if (m_deviceStatus != newStatus)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
- ResetDeviceStatus();
- m_deviceStatus = newStatus;
- break;
case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
if (m_deviceStatus != newStatus)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), m_iLogicalAddress);
SetPowerStatus (CEC_POWER_STATUS_ON);
SetVendorId (CEC_VENDOR_UNKNOWN);
SetMenuState (CEC_MENU_STATE_ACTIVATED);
SetCecVersion (CEC_VERSION_1_3A);
SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
- SetInactiveSource();
+ MarkAsInactiveSource();
m_iLastActive = 0;
m_deviceStatus = newStatus;
break;
case CEC_DEVICE_STATUS_PRESENT:
if (m_deviceStatus != newStatus)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress);
m_deviceStatus = newStatus;
break;
case CEC_DEVICE_STATUS_NOT_PRESENT:
if (m_deviceStatus != newStatus)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
ResetDeviceStatus();
m_deviceStatus = newStatus;
}
break;
+ default:
+ ResetDeviceStatus();
+ break;
}
}
-
- if (newStatus == CEC_DEVICE_STATUS_PRESENT)
- RequestVendorId(false);
}
-void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
+void CCECBusDevice::ResetDeviceStatus(void)
{
CLockObject lock(m_mutex);
- if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
- m_iPhysicalAddress = iNewAddress;
- }
+ SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
+ SetVendorId (CEC_VENDOR_UNKNOWN);
+ SetMenuState (CEC_MENU_STATE_ACTIVATED);
+ SetCecVersion (CEC_VERSION_UNKNOWN);
+ SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
+ SetOSDName (ToString(m_iLogicalAddress));
+ MarkAsInactiveSource();
+
+ m_iLastActive = 0;
+ m_bVendorIdRequested = false;
+ m_unsupportedFeatures.clear();
+
+ if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
+ m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN;
}
-void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
+bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
{
- CLockObject lock(m_mutex);
- if (iNewAddress != m_iStreamPath)
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
- m_iStreamPath = iNewAddress;
- }
+ bool bReturn(false);
+ cec_logical_address destination(dest);
+ if (destination == CECDEVICE_UNKNOWN)
+ destination = m_iLogicalAddress;
- CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
- if (device)
+ CCECBusDevice *destDevice = m_processor->GetDevice(destination);
+ if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ return bReturn;
+
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
+ bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
+
+ CLockObject lock(m_mutex);
+ if (bReturn)
{
- // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
- device->SetActiveSource();
+ m_iLastActive = GetTimeMs();
+ destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
}
else
+ destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
+
+ MarkReady();
+ return bReturn;
+}
+
+void CCECBusDevice::HandlePoll(const cec_logical_address destination)
+{
+ if (destination >= 0 && destination < CECDEVICE_BROADCAST)
{
- // try to find the device with the old address, and mark it as inactive when found
- device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
+ CCECBusDevice *device = m_processor->GetDevice(destination);
if (device)
- device->SetInactiveSource();
+ device->HandlePollFrom(m_iLogicalAddress);
}
}
-void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
+void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
{
- CLockObject lock(m_mutex);
- if (m_powerStatus != powerStatus)
- {
- m_iLastPowerStateUpdate = GetTimeMs();
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
- m_powerStatus = powerStatus;
- }
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
+ m_bAwaitingReceiveFailed = true;
}
-void CCECBusDevice::MarkBusy(void)
+bool CCECBusDevice::HandleReceiveFailed(void)
{
- CLockObject handlerLock(m_handlerMutex);
- ++m_iHandlerUseCount;
+ bool bReturn = m_bAwaitingReceiveFailed;
+ m_bAwaitingReceiveFailed = false;
+ return bReturn;
}
-void CCECBusDevice::MarkReady(void)
+cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
{
- CLockObject handlerLock(m_handlerMutex);
- if (m_iHandlerUseCount > 0)
- --m_iHandlerUseCount;
+ CLockObject lock(m_mutex);
+ return m_menuState;
}
-bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
+void CCECBusDevice::SetMenuState(const cec_menu_state state)
{
- bool bInitHandler(false);
+ CLockObject lock(m_mutex);
+ if (m_menuState != state)
{
- CTryLockObject lock(m_mutex);
- if (!lock.IsLocked())
- return false;
-
- CLockObject handlerLock(m_handlerMutex);
- if (m_iHandlerUseCount > 0)
- return false;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
+ m_menuState = state;
+ }
+}
- MarkBusy();
+bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
+{
+ cec_menu_state menuState;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
+ menuState = m_menuState;
+ }
- if (m_vendor != m_handler->GetVendorId())
- {
- if (CCECCommandHandler::HasSpecificHandler(m_vendor))
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
- delete m_handler;
+ MarkBusy();
+ bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
+ MarkReady();
+ return bReturn;
+}
- 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;
- }
+bool CCECBusDevice::ActivateSource(void)
+{
+ MarkAsActiveSource();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
+ MarkBusy();
+ bool bReturn = m_handler->ActivateSource();
+ MarkReady();
+ return bReturn;
+}
- m_handler->SetVendorId(m_vendor);
- bInitHandler = true;
- }
- }
- }
+bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
- if (bInitHandler)
+ if (IsHandledByLibCEC())
{
- m_handler->InitHandler();
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
- if (bActivateSource && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised() && IsActiveSource())
- m_handler->ActivateSource();
+ bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
}
+ return bReturn;
+}
- MarkReady();
+void CCECBusDevice::MarkAsActiveSource(void)
+{
+ CLockObject lock(m_mutex);
+ if (!m_bActiveSource)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
- return true;
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->Get(devices);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
+ (*it)->MarkAsInactiveSource();
+
+ m_bActiveSource = true;
+ SetPowerStatus(CEC_POWER_STATUS_ON);
}
-bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
+void CCECBusDevice::MarkAsInactiveSource(void)
{
- bool bVendorChanged(false);
-
{
CLockObject lock(m_mutex);
- bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
- m_vendor = (cec_vendor_id)iVendorId;
+ if (m_bActiveSource)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ m_bActiveSource = false;
}
-
- if (bVendorChanged)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
-
- return bVendorChanged;
}
-//@}
-/** @name Transmit methods */
-//@{
bool CCECBusDevice::TransmitActiveSource(void)
{
bool bSendActiveSource(false);
{
CLockObject lock(m_mutex);
if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
else if (m_bActiveSource)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
bSendActiveSource = true;
}
else
- CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
}
if (bSendActiveSource)
return false;
}
-bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
-{
- cec_version version;
- {
- CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
- version = m_cecVersion;
- }
-
- MarkBusy();
- bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, dest, version);
- MarkReady();
- return bReturn;
-}
-
bool CCECBusDevice::TransmitImageViewOn(void)
{
{
CLockObject lock(m_mutex);
if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
return false;
}
}
uint16_t iPhysicalAddress;
{
CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
iPhysicalAddress = m_iPhysicalAddress;
}
return bReturn;
}
-bool CCECBusDevice::TransmitMenuState(cec_logical_address dest)
+bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
{
- cec_menu_state menuState;
- {
- CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
- menuState = m_menuState;
- }
-
MarkBusy();
- bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
+ bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
MarkReady();
return bReturn;
}
-bool CCECBusDevice::TransmitOSDName(cec_logical_address dest)
+void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
{
- CStdString strDeviceName;
+ CLockObject lock(m_mutex);
+ if (iNewAddress != m_iStreamPath)
{
- CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
- strDeviceName = m_strDeviceName;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
+ m_iStreamPath = iNewAddress;
}
- MarkBusy();
- bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, dest, strDeviceName);
- MarkReady();
- return bReturn;
-}
+ if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
+ return;
-bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage)
-{
- bool bReturn(false);
- if (!m_processor->m_busDevices[dest]->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
+ CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+ if (device)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
- MarkBusy();
- bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage);
- MarkReady();
+ // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
+ device->MarkAsActiveSource();
}
- return bReturn;
-}
-
-bool CCECBusDevice::TransmitPhysicalAddress(void)
-{
- uint16_t iPhysicalAddress;
- cec_device_type type;
+ else
{
- CLockObject lock(m_mutex);
- if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
- return false;
-
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
- iPhysicalAddress = m_iPhysicalAddress;
- type = m_type;
+ // try to find the device with the old address, and mark it as inactive when found
+ device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
+ if (device)
+ device->MarkAsInactiveSource();
}
-
- MarkBusy();
- bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
- MarkReady();
- return bReturn;
}
-bool CCECBusDevice::TransmitSetMenuLanguage(cec_logical_address dest)
+bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
{
bool bReturn(false);
- cec_menu_language language = GetMenuLanguage();
-
- char lang[3];
- {
- CLockObject lock(m_mutex);
- lang[0] = language.language[0];
- lang[1] = language.language[1];
- lang[2] = language.language[2];
- }
+ GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
MarkBusy();
- if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
+ cec_power_status currentStatus = GetPowerStatus(initiator, false);
+ if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
+ currentStatus != CEC_POWER_STATUS_ON)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): Menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
- m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ if (m_handler->PowerOn(initiator, m_iLogicalAddress))
+ {
+ SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
bReturn = true;
+ }
}
else
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
- bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
}
+
MarkReady();
return bReturn;
}
-bool CCECBusDevice::TransmitPoll(cec_logical_address dest)
+bool CCECBusDevice::Standby(const cec_logical_address initiator)
{
- bool bReturn(false);
- if (dest == CECDEVICE_UNKNOWN)
- dest = m_iLogicalAddress;
-
- CCECBusDevice *destDevice = m_processor->m_busDevices[dest];
- if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
- return bReturn;
+ GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
MarkBusy();
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
- bReturn = m_handler->TransmitPoll(m_iLogicalAddress, dest);
- CLibCEC::AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
-
- CLockObject lock(m_mutex);
- if (bReturn)
- {
- m_iLastActive = GetTimeMs();
- destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
- }
- else
- destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
-
+ bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
MarkReady();
return bReturn;
}
-bool CCECBusDevice::TransmitPowerState(cec_logical_address dest)
+bool CCECBusDevice::NeedsPoll(void)
{
- cec_power_status state;
+ bool bSendPoll(false);
+ cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
+ switch (m_iLogicalAddress)
{
- CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
- state = m_powerStatus;
+ case CECDEVICE_PLAYBACKDEVICE3:
+ pollAddress = CECDEVICE_PLAYBACKDEVICE2;
+ break;
+ case CECDEVICE_PLAYBACKDEVICE2:
+ pollAddress = CECDEVICE_PLAYBACKDEVICE1;
+ break;
+ case CECDEVICE_RECORDINGDEVICE3:
+ pollAddress = CECDEVICE_RECORDINGDEVICE2;
+ break;
+ case CECDEVICE_RECORDINGDEVICE2:
+ pollAddress = CECDEVICE_RECORDINGDEVICE1;
+ break;
+ case CECDEVICE_TUNER4:
+ pollAddress = CECDEVICE_TUNER3;
+ break;
+ case CECDEVICE_TUNER3:
+ pollAddress = CECDEVICE_TUNER2;
+ break;
+ case CECDEVICE_TUNER2:
+ pollAddress = CECDEVICE_TUNER1;
+ break;
+ case CECDEVICE_AUDIOSYSTEM:
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TV:
+ bSendPoll = true;
+ break;
+ default:
+ break;
}
- MarkBusy();
- bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, dest, state);
- MarkReady();
- return bReturn;
+ if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
+ {
+ CCECBusDevice *device = m_processor->GetDevice(pollAddress);
+ if (device)
+ {
+ cec_bus_device_status status = device->GetStatus();
+ bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+ }
+ else
+ {
+ bSendPoll = true;
+ }
+ }
+
+ return bSendPoll;
}
-bool CCECBusDevice::TransmitVendorID(cec_logical_address dest, bool bSendAbort /* = true */)
+void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
{
- bool bReturn(false);
- uint64_t iVendorId;
+ bool bRequestVendorId(false);
{
CLockObject lock(m_mutex);
- iVendorId = (uint64_t)m_vendor;
+ bRequestVendorId = !m_bVendorIdRequested;
+ m_bVendorIdRequested = true;
}
- MarkBusy();
- if (iVendorId == CEC_VENDOR_UNKNOWN)
- {
- if (bSendAbort)
- {
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
- m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
- bReturn = true;
- }
- }
- else
+ if (bRequestVendorId)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString((cec_vendor_id)iVendorId), iVendorId);
- bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
+ ReplaceHandler(false);
+ GetVendorId(initiator);
}
- MarkReady();
- return bReturn;
}
+//@}
-bool CCECBusDevice::TransmitKeypress(cec_user_control_code key, bool bWait /* = true */)
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
{
- MarkBusy();
- bool bReturn = m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key, bWait);
- MarkReady();
- return bReturn;
+ return AsAudioSystem(this);
}
-bool CCECBusDevice::TransmitKeyRelease(bool bWait /* = true */)
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
{
- MarkBusy();
- bool bReturn = m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress, bWait);
- MarkReady();
- return bReturn;
+ return AsPlaybackDevice(this);
}
-bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
{
- CLockObject lock(m_mutex);
- bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
- if (bUnsupported)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
- return bUnsupported;
+ return AsRecordingDevice(this);
}
-void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+CCECTuner *CCECBusDevice::AsTuner(void)
{
- // some commands should never be marked as unsupported
- if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
- opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
- opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
- opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
- opcode == CEC_OPCODE_ABORT ||
- opcode == CEC_OPCODE_FEATURE_ABORT ||
- opcode == CEC_OPCODE_NONE)
- return;
+ return AsTuner(this);
+}
- {
- CLockObject lock(m_mutex);
- if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
- {
- CLibCEC::AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
- m_unsupportedFeatures.insert(opcode);
- }
- }
+CCECTV *CCECBusDevice::AsTV(void)
+{
+ return AsTV(this);
+}
- // signal threads that are waiting for a reponse
- MarkBusy();
- m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
- MarkReady();
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ return static_cast<CCECAudioSystem *>(device);
+ return NULL;
}
-bool CCECBusDevice::ActivateSource(void)
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
- MarkBusy();
- bool bReturn = m_handler->ActivateSource();
- MarkReady();
- return bReturn;
+ if (device &&
+ (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+ device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+ return static_cast<CCECPlaybackDevice *>(device);
+ return NULL;
}
-void CCECBusDevice::HandlePoll(cec_logical_address destination)
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
{
- if (destination >= 0 && destination < CECDEVICE_BROADCAST)
- {
- CCECBusDevice *device = m_processor->m_busDevices[destination];
- if (device)
- device->HandlePollFrom(m_iLogicalAddress);
- }
+ if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ return static_cast<CCECRecordingDevice *>(device);
+ return NULL;
}
-void CCECBusDevice::HandlePollFrom(cec_logical_address initiator)
+CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
- m_bAwaitingReceiveFailed = true;
+ if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
+ return static_cast<CCECTuner *>(device);
+ return NULL;
}
-bool CCECBusDevice::HandleReceiveFailed(void)
+CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
{
- bool bReturn = m_bAwaitingReceiveFailed;
- m_bAwaitingReceiveFailed = false;
- return bReturn;
+ if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
+ return static_cast<CCECTV *>(device);
+ return NULL;
}
-void CCECBusDevice::CheckVendorIdRequested(void)
+void CCECBusDevice::MarkBusy(void)
{
- bool bRequestVendorId(false);
- {
- CLockObject lock(m_mutex);
- bRequestVendorId = !m_bVendorIdRequested;
- m_bVendorIdRequested = true;
- }
+ CLockObject handlerLock(m_handlerMutex);
+ ++m_iHandlerUseCount;
+}
- if (bRequestVendorId)
+void CCECBusDevice::MarkReady(void)
+{
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ --m_iHandlerUseCount;
+}
+
+bool CCECBusDevice::TryLogicalAddress(void)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
+
+ if (!TransmitPoll(m_iLogicalAddress))
{
- ReplaceHandler(false);
- GetVendorId();
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+
+ return true;
}
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
+ return false;
}
-bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
+CCECClient *CCECBusDevice::GetClient(void)
{
- MarkBusy();
- bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
- MarkReady();
- return bReturn;
+ return m_processor->GetClient(m_iLogicalAddress);
}
-
-//@}
namespace CEC
{
+ class CCECClient;
class CCECProcessor;
class CCECCommandHandler;
+ class CCECAudioSystem;
+ class CCECPlaybackDevice;
+ class CCECRecordingDevice;
+ class CCECTuner;
+ class CCECTV;
class CCECBusDevice
{
CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
virtual ~CCECBusDevice(void);
- virtual bool HandleCommand(const cec_command &command);
- virtual bool PowerOn(void);
- virtual bool Standby(void);
-
- virtual cec_version GetCecVersion(bool bUpdate = false);
- virtual CCECCommandHandler * GetHandler(void) const { return m_handler; };
- virtual uint64_t GetLastActive(void) const { return m_iLastActive; }
+ virtual bool ReplaceHandler(bool bActivateSource = true);
+ virtual CCECCommandHandler * GetHandler(void) const { return m_handler; };
+ virtual CCECProcessor * GetProcessor(void) const { return m_processor; }
+ virtual uint64_t GetLastActive(void) const { return m_iLastActive; }
+ virtual cec_device_type GetType(void) const { return m_type; }
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 uint16_t GetPhysicalAddress(bool bSuppressUpdate = true);
- virtual cec_power_status GetPowerStatus(bool bUpdate = false);
- virtual CCECProcessor * GetProcessor(void) const { return m_processor; }
- virtual cec_device_type GetType(void) const { return m_type; }
- virtual cec_vendor_id GetVendorId(bool bUpdate = false);
- virtual const char * GetVendorName(bool bUpdate = false);
- virtual bool MyLogicalAddressContains(cec_logical_address address) const;
- virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false);
- virtual bool IsActiveSource(void) const { return m_bActiveSource; }
+ virtual bool IsPresent(void);
+ virtual bool IsHandledByLibCEC(void);
+
+ virtual bool HandleCommand(const cec_command &command);
virtual bool IsUnsupportedFeature(cec_opcode opcode);
virtual void SetUnsupportedFeature(cec_opcode opcode);
- virtual void HandlePoll(cec_logical_address destination);
- virtual void HandlePollFrom(cec_logical_address initiator);
+
+ virtual bool TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait = true);
+ virtual bool TransmitKeyRelease(const cec_logical_address initiator, bool bWait = true);
+
+ virtual cec_version GetCecVersion(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetCecVersion(const cec_version newVersion);
+ virtual bool RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitCECVersion(const cec_logical_address destination);
+
+ virtual cec_menu_language & GetMenuLanguage(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetMenuLanguage(const char *strLanguage);
+ virtual void SetMenuLanguage(const cec_menu_language &menuLanguage);
+ virtual bool RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitSetMenuLanguage(const cec_logical_address destination);
+
+ virtual bool TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage);
+
+ virtual CStdString GetCurrentOSDName(void);
+ virtual CStdString GetOSDName(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetOSDName(CStdString strName);
+ virtual bool RequestOSDName(const cec_logical_address source, bool bWaitForResponse = true);
+ virtual bool TransmitOSDName(const cec_logical_address destination);
+
+ virtual uint16_t GetCurrentPhysicalAddress(void);
+ virtual bool HasValidPhysicalAddress(void);
+ virtual uint16_t GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate = false);
+ virtual bool SetPhysicalAddress(uint16_t iNewAddress);
+ virtual bool RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitPhysicalAddress(void);
+
+ virtual cec_power_status GetCurrentPowerStatus(void);
+ virtual cec_power_status GetPowerStatus(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetPowerStatus(const cec_power_status powerStatus);
+ virtual bool RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitPowerState(const cec_logical_address destination);
+
+ virtual cec_vendor_id GetCurrentVendorId(void);
+ virtual cec_vendor_id GetVendorId(const cec_logical_address initiator, bool bUpdate = false);
+ virtual const char * GetVendorName(const cec_logical_address initiator, bool bUpdate = false);
+ virtual bool SetVendorId(uint64_t iVendorId);
+ virtual bool RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitVendorID(const cec_logical_address destination, bool bSendAbort = true);
+
+ virtual cec_bus_device_status GetCurrentStatus(void) { return GetStatus(false, true); }
+ virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false);
+ virtual void SetDeviceStatus(const cec_bus_device_status newStatus);
+ virtual void ResetDeviceStatus(void);
+ virtual bool TransmitPoll(const cec_logical_address destination);
+ virtual void HandlePoll(const cec_logical_address destination);
+ virtual void HandlePollFrom(const cec_logical_address initiator);
virtual bool HandleReceiveFailed(void);
- 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 SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = CEC_INVALID_PHYSICAL_ADDRESS);
- virtual void SetCecVersion(const cec_version newVersion);
- 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);
- virtual void SetPowerStatus(const cec_power_status powerStatus);
-
- virtual bool TransmitActiveSource(void);
- virtual bool TransmitCECVersion(cec_logical_address dest);
- virtual bool TransmitImageViewOn(void);
- virtual bool TransmitInactiveSource(void);
- virtual bool TransmitMenuState(cec_logical_address dest);
- virtual bool TransmitOSDName(cec_logical_address dest);
- virtual bool TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage);
- virtual bool TransmitPhysicalAddress(void);
- virtual bool TransmitSetMenuLanguage(cec_logical_address dest);
- virtual bool TransmitPowerState(cec_logical_address dest);
- virtual bool TransmitPoll(cec_logical_address dest);
- virtual bool TransmitVendorID(cec_logical_address dest, bool bSendAbort = true);
- virtual bool TransmitKeypress(cec_user_control_code key, bool bWait = true);
- virtual bool TransmitKeyRelease(bool bWait = true);
-
- bool ReplaceHandler(bool bActivateSource = true);
- virtual bool TransmitPendingActiveSourceCommands(void);
-
- virtual bool RequestActiveSource(bool bWaitForResponse = true);
+ virtual cec_menu_state GetMenuState(const cec_logical_address initiator);
+ virtual void SetMenuState(const cec_menu_state state);
+ virtual bool TransmitMenuState(const cec_logical_address destination);
+
+ virtual bool ActivateSource(void);
+ virtual bool IsActiveSource(void) const { return m_bActiveSource; }
+ virtual bool RequestActiveSource(bool bWaitForResponse = true);
+ virtual void MarkAsActiveSource(void);
+ virtual void MarkAsInactiveSource(void);
+ virtual bool TransmitActiveSource(void);
+ virtual bool TransmitImageViewOn(void);
+ virtual bool TransmitInactiveSource(void);
+ virtual bool TransmitPendingActiveSourceCommands(void);
+ virtual void SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+
+ virtual bool PowerOn(const cec_logical_address initiator);
+ virtual bool Standby(const cec_logical_address initiator);
+
+ virtual bool TryLogicalAddress(void);
+
+ CCECClient * GetClient(void);
+
+ CCECAudioSystem * AsAudioSystem(void);
+ static CCECAudioSystem * AsAudioSystem(CCECBusDevice *device);
+ CCECPlaybackDevice * AsPlaybackDevice(void);
+ static CCECPlaybackDevice * AsPlaybackDevice(CCECBusDevice *device);
+ CCECRecordingDevice * AsRecordingDevice(void);
+ static CCECRecordingDevice * AsRecordingDevice(CCECBusDevice *device);
+ CCECTuner * AsTuner(void);
+ static CCECTuner * AsTuner(CCECBusDevice *device);
+ CCECTV * AsTV(void);
+ static CCECTV * AsTV(CCECBusDevice *device);
protected:
- void ResetDeviceStatus(void);
- void CheckVendorIdRequested(void);
+ void CheckVendorIdRequested(const cec_logical_address source);
void MarkBusy(void);
void MarkReady(void);
- bool RequestCecVersion(bool bWaitForResponse = true);
- bool RequestMenuLanguage(bool bWaitForResponse = true);
- bool RequestPowerStatus(bool bWaitForResponse = true);
- bool RequestVendorId(bool bWaitForResponse = true);
- bool RequestPhysicalAddress(bool bWaitForResponse = true);
- bool RequestOSDName(bool bWaitForResponse = true);
-
bool NeedsPoll(void);
cec_device_type m_type;
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "CECDeviceMap.h"
+#include "CECAudioSystem.h"
+#include "CECPlaybackDevice.h"
+#include "CECRecordingDevice.h"
+#include "CECTuner.h"
+#include "CECTV.h"
+#include "../CECProcessor.h"
+
+using namespace std;
+using namespace CEC;
+
+CCECDeviceMap::CCECDeviceMap(CCECProcessor *processor) :
+ m_processor(processor)
+{
+ for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+ {
+ switch(iPtr)
+ {
+ case CECDEVICE_AUDIOSYSTEM:
+ m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECAudioSystem(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_PLAYBACKDEVICE2:
+ case CECDEVICE_PLAYBACKDEVICE3:
+ m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECPlaybackDevice(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE2:
+ case CECDEVICE_RECORDINGDEVICE3:
+ m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECRecordingDevice(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TUNER2:
+ case CECDEVICE_TUNER3:
+ case CECDEVICE_TUNER4:
+ m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECTuner(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_TV:
+ m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECTV(processor, (cec_logical_address) iPtr)));
+ break;
+ default:
+ m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECBusDevice(processor, (cec_logical_address) iPtr)));
+ break;
+ }
+ }
+}
+CCECDeviceMap::~CCECDeviceMap(void)
+{
+ Clear();
+}
+
+CECDEVICEMAP::iterator CCECDeviceMap::Begin(void)
+{
+ return m_busDevices.begin();
+}
+
+CECDEVICEMAP::iterator CCECDeviceMap::End(void)
+{
+ return m_busDevices.end();
+}
+
+void CCECDeviceMap::ResetDeviceStatus(void)
+{
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ it->second->ResetDeviceStatus();
+}
+
+CCECBusDevice *CCECDeviceMap::operator[] (cec_logical_address iAddress) const
+{
+ return At(iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::operator[] (uint8_t iAddress) const
+{
+ return At(iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::At(cec_logical_address iAddress) const
+{
+ return At((uint8_t) iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::At(uint8_t iAddress) const
+{
+ CECDEVICEMAP::const_iterator it = m_busDevices.find((cec_logical_address)iAddress);
+ if (it != m_busDevices.end())
+ return it->second;
+ return NULL;
+}
+
+void CCECDeviceMap::Clear(void)
+{
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ delete it->second;
+ m_busDevices.clear();
+}
+
+CCECBusDevice *CCECDeviceMap::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
+{
+ CCECBusDevice *device(NULL);
+
+ // check each device until we found a match
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); !device && it != m_busDevices.end(); it++)
+ {
+ if (it->second->GetPhysicalAddress(m_processor->GetLogicalAddress(), bSuppressUpdate) == iPhysicalAddress)
+ device = it->second;
+ }
+
+ return device;
+}
+
+void CCECDeviceMap::Get(CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetByLogicalAddresses(CECDEVICEVEC &devices, const cec_logical_addresses &addresses)
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (addresses.IsSet(it->first))
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::GetByType(const cec_device_type type, CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ if (it->second->GetType() == type)
+ devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetLibCECControlled(CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ if (it->second->IsHandledByLibCEC())
+ devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetActive(CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ cec_bus_device_status status = it->second->GetStatus();
+ if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC ||
+ status == CEC_DEVICE_STATUS_PRESENT)
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (configuration.powerOffDevices[(uint8_t)it->first])
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (configuration.wakeDevices[(uint8_t)it->first])
+ devices.push_back(it->second);
+ }
+}
+
+CCECBusDevice *CCECDeviceMap::GetActiveSource(void) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (it->second->IsActiveSource())
+ return it->second;
+ }
+ return NULL;
+}
+
+void CCECDeviceMap::FilterLibCECControlled(CECDEVICEVEC &devices)
+{
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if ((*it)->IsHandledByLibCEC())
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+void CCECDeviceMap::FilterActive(CECDEVICEVEC &devices)
+{
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ cec_bus_device_status status = (*it)->GetCurrentStatus();
+ if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC ||
+ status == CEC_DEVICE_STATUS_PRESENT)
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+void CCECDeviceMap::FilterTypes(const cec_device_type_list &types, CECDEVICEVEC &devices)
+{
+ cec_device_type_list t(types);//silly, but needed to retain abi
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if (t.IsSet((*it)->GetType()))
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+void CCECDeviceMap::FilterType(const cec_device_type type, CECDEVICEVEC &devices)
+{
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if ((*it)->GetType() == type)
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+cec_logical_addresses CCECDeviceMap::ToLogicalAddresses(const CECDEVICEVEC &devices)
+{
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ addresses.Set((*it)->GetLogicalAddress());
+ return addresses;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "../../../include/cectypes.h"
+#include <map>
+#include <vector>
+
+namespace CEC
+{
+ class CCECBusDevice;
+
+ typedef std::map<cec_logical_address, CCECBusDevice *> CECDEVICEMAP;
+ typedef std::vector<CCECBusDevice *> CECDEVICEVEC;
+
+ class CCECProcessor;
+
+ class CCECDeviceMap
+ {
+ public:
+ CCECDeviceMap(CCECProcessor *processor);
+ virtual ~CCECDeviceMap(void);
+ CECDEVICEMAP::iterator Begin(void);
+ CECDEVICEMAP::iterator End(void);
+ void ResetDeviceStatus(void);
+ CCECBusDevice * operator[] (cec_logical_address iAddress) const;
+ CCECBusDevice * operator[] (uint8_t iAddress) const;
+ CCECBusDevice * At(cec_logical_address iAddress) const;
+ CCECBusDevice * At(uint8_t iAddress) const;
+ CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate = true);
+
+ void Get(CECDEVICEVEC &devices) const;
+ void GetLibCECControlled(CECDEVICEVEC &devices) const;
+ void GetByLogicalAddresses(CECDEVICEVEC &devices, const cec_logical_addresses &addresses);
+ void GetActive(CECDEVICEVEC &devices) const;
+ void GetByType(const cec_device_type type, CECDEVICEVEC &devices) const;
+
+ void GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const;
+ void GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const;
+
+ CCECBusDevice *GetActiveSource(void) const;
+
+ static void FilterLibCECControlled(CECDEVICEVEC &devices);
+ static void FilterActive(CECDEVICEVEC &devices);
+ static void FilterTypes(const cec_device_type_list &types, CECDEVICEVEC &devices);
+ static void FilterType(const cec_device_type type, CECDEVICEVEC &devices);
+ static cec_logical_addresses ToLogicalAddresses(const CECDEVICEVEC &devices);
+ private:
+ void Clear(void);
+
+ CECDEVICEMAP m_busDevices;
+ CCECProcessor *m_processor;
+ };
+}
using namespace CEC;
using namespace PLATFORM;
-#define ToString(p) m_processor->ToString(p)
+#define ToString(p) m_processor->GetLib()->ToString(p)
CCECPlaybackDevice::CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
CCECBusDevice(processor, address, iPhysicalAddress),
m_type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
}
-cec_deck_info CCECPlaybackDevice::GetDeckStatus(void)
+cec_deck_info CCECPlaybackDevice::GetDeckStatus(const cec_logical_address UNUSED(initiator))
{
CLockObject lock(m_mutex);
return m_deckStatus;
CLockObject lock(m_mutex);
if (m_deckStatus != deckStatus)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckStatus), ToString(deckStatus));
+ m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckStatus), ToString(deckStatus));
m_deckStatus = deckStatus;
}
}
-cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(void)
+cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(const cec_logical_address UNUSED(initiator))
{
CLockObject lock(m_mutex);
return m_deckControlMode;
CLockObject lock(m_mutex);
if (m_deckControlMode != mode)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckControlMode), ToString(mode));
+ m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckControlMode), ToString(mode));
m_deckControlMode = mode;
}
}
cec_deck_info state;
{
CLockObject lock(m_mutex);
- CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
+ m_processor->GetLib()->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
state = m_deckStatus;
}
return m_handler->TransmitDeckStatus(m_iLogicalAddress, dest, state);
}
+
+void CCECPlaybackDevice::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ m_deckStatus = CEC_DECK_INFO_STOP;
+ m_deckControlMode = CEC_DECK_CONTROL_MODE_STOP;
+ CCECBusDevice::ResetDeviceStatus();
+}
CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
virtual ~CCECPlaybackDevice(void) {};
- cec_deck_info GetDeckStatus(void);
- cec_deck_control_mode GetDeckControlMode(void);
+ cec_deck_info GetDeckStatus(const cec_logical_address initiator);
+ cec_deck_control_mode GetDeckControlMode(const cec_logical_address initiator);
void SetDeckStatus(cec_deck_info deckStatus);
void SetDeckControlMode(cec_deck_control_mode mode);
bool TransmitDeckStatus(cec_logical_address dest);
+ virtual void ResetDeviceStatus(void);
+
protected:
cec_deck_info m_deckStatus;
cec_deck_control_mode m_deckControlMode;
#include "CECRecordingDevice.h"
using namespace CEC;
+using namespace PLATFORM;
CCECRecordingDevice::CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
- CCECBusDevice(processor, address, iPhysicalAddress),
- m_playbackDevice(processor, address, iPhysicalAddress),
+ CCECPlaybackDevice(processor, address, iPhysicalAddress),
m_tuner(processor, address, iPhysicalAddress)
{
m_type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
}
-cec_deck_info CCECRecordingDevice::GetDeckStatus(void)
+void CCECRecordingDevice::ResetDeviceStatus(void)
{
- return m_playbackDevice.GetDeckStatus();
-}
-
-cec_deck_control_mode CCECRecordingDevice::GetDeckControlMode(void)
-{
- return m_playbackDevice.GetDeckControlMode();
-}
-
-void CCECRecordingDevice::SetDeckStatus(cec_deck_info deckStatus)
-{
- m_playbackDevice.SetDeckStatus(deckStatus);
-}
-
-void CCECRecordingDevice::SetDeckControlMode(cec_deck_control_mode mode)
-{
- m_playbackDevice.SetDeckControlMode(mode);
-}
-
-bool CCECRecordingDevice::TransmitDeckStatus(cec_logical_address dest)
-{
- return m_playbackDevice.TransmitDeckStatus(dest);
+ CLockObject lock(m_mutex);
+ m_tuner.ResetDeviceStatus();
+ CCECPlaybackDevice::ResetDeviceStatus();
}
namespace CEC
{
- class CCECRecordingDevice : public CCECBusDevice
+ class CCECRecordingDevice : public CCECPlaybackDevice
{
public:
CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
virtual ~CCECRecordingDevice(void) {};
- /* playback device methods */
- cec_deck_info GetDeckStatus(void);
- cec_deck_control_mode GetDeckControlMode(void);
-
- void SetDeckStatus(cec_deck_info deckStatus);
- void SetDeckControlMode(cec_deck_control_mode mode);
-
- bool TransmitDeckStatus(cec_logical_address dest);
-
- /* tuner methods */
- //TODO
+ virtual void ResetDeviceStatus(void);
+ /* TODO: tuner methods */
protected:
- CCECPlaybackDevice m_playbackDevice;
CCECTuner m_tuner;
};
}
#include "CECTV.h"
using namespace CEC;
+using namespace PLATFORM;
CCECTV::CCECTV(CCECProcessor *processor, cec_logical_address address) :
CCECBusDevice(processor, address, CEC_PHYSICAL_ADDRESS_TV)
{
m_type = CEC_DEVICE_TYPE_TV;
}
+
+void CCECTV::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ CCECBusDevice::ResetDeviceStatus();
+}
public:
CCECTV(CCECProcessor *processor, cec_logical_address address);
virtual ~CCECTV(void) {};
+
+ virtual void ResetDeviceStatus(void);
};
}
#include "CECTuner.h"
using namespace CEC;
+using namespace PLATFORM;
CCECTuner::CCECTuner(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
CCECBusDevice(processor, address, iPhysicalAddress)
{
- m_type = CEC_DEVICE_TYPE_TUNER;
+ m_type = CEC_DEVICE_TYPE_TUNER;
+}
+
+void CCECTuner::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ CCECBusDevice::ResetDeviceStatus();
}
public:
CCECTuner(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
virtual ~CCECTuner(void) {};
+
+ virtual void ResetDeviceStatus(void);
};
}
#include "../devices/CECBusDevice.h"
#include "../CECProcessor.h"
#include "../LibCEC.h"
+#include "../CECClient.h"
using namespace CEC;
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
CCECCommandHandler(busDevice)
{
bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
{
- if (m_processor->IsRunning() && command.parameters.size > 0)
+ if (m_processor->CECInitialised() && command.parameters.size > 0)
{
+ CCECClient *client = m_processor->GetClient(command.destination);
+
cec_keypress key;
key.duration = CEC_BUTTON_TIMEOUT;
key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
switch (command.parameters[0])
{
case CEC_USER_CONTROL_CODE_AN_RETURN:
- key.keycode = m_processor->GetClientVersion() >= CEC_CLIENT_VERSION_1_5_0 ?
+ key.keycode = client && client->GetClientVersion() >= CEC_CLIENT_VERSION_1_5_0 ?
CEC_USER_CONTROL_CODE_AN_RETURN :
CEC_USER_CONTROL_CODE_EXIT;
break;
break;
}
- if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
- CLibCEC::AddKey(key);
+ if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client)
+ client->AddKey(key);
}
return true;
bool CANCommandHandler::HandleCommand(const cec_command &command)
{
bool bHandled(false);
- if (m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->IsHandledByLibCEC(command.destination))
{
switch(command.opcode)
{
#include "../devices/CECBusDevice.h"
#include "../devices/CECAudioSystem.h"
#include "../devices/CECPlaybackDevice.h"
+#include "../CECClient.h"
#include "../CECProcessor.h"
#include "../LibCEC.h"
using namespace std;
using namespace PLATFORM;
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
m_busDevice(busDevice),
m_processor(m_busDevice->GetProcessor()),
bool bHandled(true);
- CLibCEC::AddCommand(command);
+ CCECClient *client = m_busDevice->GetClient();
+ if (client)
+ client->AddCommand(command);
switch(command.opcode)
{
HandleSetMenuLanguage(command);
break;
case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGivePhysicalAddress(command);
break;
case CEC_OPCODE_GET_MENU_LANGUAGE:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveMenuLanguage(command);
break;
case CEC_OPCODE_GIVE_OSD_NAME:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveOSDName(command);
break;
case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveDeviceVendorId(command);
break;
case CEC_OPCODE_DEVICE_VENDOR_ID:
HandleDeviceVendorCommandWithId(command);
break;
case CEC_OPCODE_GIVE_DECK_STATUS:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveDeckStatus(command);
break;
case CEC_OPCODE_DECK_CONTROL:
HandleDeckControl(command);
break;
case CEC_OPCODE_MENU_REQUEST:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleMenuRequest(command);
break;
case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveDevicePowerStatus(command);
break;
case CEC_OPCODE_GET_CEC_VERSION:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGetCecVersion(command);
break;
case CEC_OPCODE_USER_CONTROL_PRESSED:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleUserControlPressed(command);
break;
case CEC_OPCODE_USER_CONTROL_RELEASE:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleUserControlRelease(command);
break;
case CEC_OPCODE_GIVE_AUDIO_STATUS:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveAudioStatus(command);
break;
case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleGiveSystemAudioModeStatus(command);
break;
case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleSystemAudioModeRequest(command);
break;
case CEC_OPCODE_REPORT_AUDIO_STATUS:
HandleSetSystemAudioMode(command);
break;
case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleRequestActiveSource(command);
break;
case CEC_OPCODE_SET_STREAM_PATH:
HandleRoutingInformation(command);
break;
case CEC_OPCODE_STANDBY:
- if (m_processor->IsInitialised())
+ if (m_processor->CECInitialised())
HandleStandby(command);
break;
case CEC_OPCODE_ACTIVE_SOURCE:
HandleVendorCommand(command);
break;
default:
- UnhandledCommand(command);
bHandled = false;
break;
}
if (bHandled)
m_waitForResponse->Received((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode);
+ else
+ UnhandledCommand(command);
return bHandled;
}
if (command.parameters.size == 2)
{
uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
- return m_processor->SetActiveSource(iAddress);
+ CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
+ if (device)
+ device->MarkAsActiveSource();
}
return true;
bool CCECCommandHandler::HandleDeckControl(const cec_command &command)
{
- CCECBusDevice *device = GetDevice(command.destination);
- if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) && command.parameters.size > 0)
+ CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+ if (device && command.parameters.size > 0)
{
- ((CCECPlaybackDevice *) device)->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
+ device->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
return true;
}
bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
- m_processor->TransmitAbort(command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ m_processor->TransmitAbort(command.destination, command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
return true;
}
if (command.parameters.size == 2 &&
(command.parameters[1] == CEC_ABORT_REASON_UNRECOGNIZED_OPCODE ||
command.parameters[1] == CEC_ABORT_REASON_REFUSED))
- m_processor->m_busDevices[command.initiator]->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
+ m_processor->GetDevice(command.initiator)->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
return true;
}
bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
- CCECBusDevice *device = GetDevice(command.destination);
- if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
- return ((CCECAudioSystem *) device)->TransmitAudioStatus(command.initiator);
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
+ if (device)
+ return device->TransmitAudioStatus(command.initiator);
}
return false;
bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
- CCECBusDevice *device = GetDevice(command.destination);
- if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
- return ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
+ CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+ if (device)
+ return device->TransmitDeckStatus(command.initiator);
}
return false;
bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
bool CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
- CCECBusDevice *device = GetDevice(command.destination);
- if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
- return ((CCECAudioSystem *) device)->TransmitSystemAudioModeStatus(command.initiator);
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
+ if (device)
+ return device->TransmitSystemAudioModeStatus(command.initiator);
}
return false;
bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
{
- m_processor->m_busDevices[command.initiator]->SetActiveSource();
+ m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
return true;
}
bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device)
{
- if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_ACTIVATE)
- {
- if (CLibCEC::MenuStateChanged(CEC_MENU_STATE_ACTIVATED) == 1)
- device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
- }
- else if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_DEACTIVATE)
+ CCECClient *client = device->GetClient();
+ if (client)
{
- if (CLibCEC::MenuStateChanged(CEC_MENU_STATE_DEACTIVATED) == 1)
- device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+ if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_ACTIVATE)
+ {
+ if (client->MenuStateChanged(CEC_MENU_STATE_ACTIVATED) == 1)
+ device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+ }
+ else if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_DEACTIVATE)
+ {
+ if (client->MenuStateChanged(CEC_MENU_STATE_DEACTIVATED) == 1)
+ device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+ }
}
return device->TransmitMenuState(command.initiator);
}
{
if (command.parameters.size == 1)
{
- CCECBusDevice *device = GetDevice(command.initiator);
- if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.initiator));
+ if (device)
{
- ((CCECAudioSystem *)device)->SetAudioStatus(command.parameters[0]);
+ device->SetAudioStatus(command.parameters[0]);
return true;
}
}
bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
{
- if (m_processor->IsRunning())
+ if (m_processor->CECInitialised())
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %i requests active source", (uint8_t) command.initiator);
- m_processor->m_busDevices[command.initiator]->SetPowerStatus(CEC_POWER_STATUS_ON);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source", (uint8_t) command.initiator);
+ m_processor->GetDevice(command.initiator)->SetPowerStatus(CEC_POWER_STATUS_ON);
vector<CCECBusDevice *> devices;
for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++)
if (command.parameters.size == 2)
{
uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
- m_processor->SetActiveSource(iNewAddress);
+ CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+ if (device)
+ device->MarkAsActiveSource();
}
return false;
bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
{
- if (m_processor->IsRunning() && command.parameters.size >= 2)
+ if (m_processor->CECInitialised() && command.parameters.size >= 2)
{
uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
/* one of the device handled by libCEC has been made active */
CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
- if (device && m_busDevice->MyLogicalAddressContains(device->GetLogicalAddress()))
- {
- device->SetActiveSource();
- device->TransmitImageViewOn();
- device->TransmitActiveSource();
-
- device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
- device->TransmitMenuState(command.initiator);
- }
+ if (device && device->IsHandledByLibCEC())
+ device->ActivateSource();
}
return false;
}
bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
- CCECBusDevice *device = GetDevice(command.destination);
- if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
+ if (device)
{
if (command.parameters.size >= 2)
{
device->SetPowerStatus(CEC_POWER_STATUS_ON);
- ((CCECAudioSystem *) device)->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_ON);
+ device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_ON);
uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress);
if (newActiveDevice)
- newActiveDevice->SetActiveSource();
- return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
+ newActiveDevice->MarkAsActiveSource();
+ return device->TransmitSetSystemAudioMode(command.initiator);
}
else
{
- ((CCECAudioSystem *) device)->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
- return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
+ device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
+ return device->TransmitSetSystemAudioMode(command.initiator);
}
}
}
{
if (command.parameters.size == 1)
{
- CCECBusDevice *device = GetDevice(command.initiator);
- if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.initiator));
+ if (device)
{
- ((CCECAudioSystem *)device)->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
+ device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
return true;
}
}
{
if (command.parameters.size == 1)
{
- CCECBusDevice *device = GetDevice(command.initiator);
- if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.initiator));
+ if (device)
{
- ((CCECAudioSystem *)device)->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
+ device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
return true;
}
}
bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
{
- m_processor->m_busDevices[command.initiator]->SetActiveSource();
+ m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
return true;
}
bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
{
- if (m_processor->IsRunning() &&
- m_busDevice->MyLogicalAddressContains(command.destination) &&
+ if (m_processor->CECInitialised() &&
+ m_processor->IsHandledByLibCEC(command.destination) &&
command.parameters.size > 0)
{
- CLibCEC::AddKey();
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (!device)
+ return true;
+
+ CCECClient *client = device->GetClient();
+ if (client)
+ client->AddKey();
+
if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
- CLibCEC::SetCurrentButton((cec_user_control_code) command.parameters[0]);
+ client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
{
bool bPowerOn(true);
- CCECBusDevice *device = GetDevice(command.destination);
if (!device)
return true;
// assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER)
{
- cec_power_status status = device->GetPowerStatus();
+ cec_power_status status = device->GetCurrentPowerStatus();
bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
}
if (bPowerOn)
{
- device->SetActiveSource();
- device->TransmitImageViewOn();
- device->TransmitActiveSource();
-
- if (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
- device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
- ((CCECPlaybackDevice *)device)->TransmitDeckStatus(command.initiator);
+ device->ActivateSource();
}
else
{
- device->SetInactiveSource();
+ device->MarkAsInactiveSource();
device->TransmitInactiveSource();
device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
}
bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
- CLibCEC::AddKey();
-
+ CCECClient *client = m_processor->GetClient(command.destination);
+ if (client)
+ client->AddKey();
return true;
}
void CCECCommandHandler::UnhandledCommand(const cec_command &command)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
+
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ m_processor->TransmitAbort(m_busDevice->GetLogicalAddress(), command.initiator, command.opcode, CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
}
size_t CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress) const
{
- CCECBusDevice *device = NULL;
-
- if (iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST)
- device = m_processor->m_busDevices[iLogicalAddress];
-
- return device;
+ return m_processor->GetDevice(iLogicalAddress);
}
CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
return m_processor->GetDeviceByPhysicalAddress(iPhysicalAddress);
}
-CCECBusDevice *CCECCommandHandler::GetDeviceByType(cec_device_type type) const
-{
- return m_processor->GetDeviceByType(type);
-}
-
bool CCECCommandHandler::SetVendorId(const cec_command &command)
{
bool bChanged(false);
if (command.parameters.size < 3)
{
- CLibCEC::AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
return bChanged;
}
void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
{
- if (!m_busDevice->MyLogicalAddressContains(iAddress))
+ if (!m_processor->IsHandledByLibCEC(iAddress))
{
- bool bOurAddress(m_processor->GetPhysicalAddress() == iNewAddress);
- GetDevice(iAddress)->SetPhysicalAddress(iNewAddress);
- if (bOurAddress)
+ CCECBusDevice *otherDevice = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+ CCECClient *client = otherDevice ? otherDevice->GetClient() : NULL;
+
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ device->SetPhysicalAddress(iNewAddress);
+ else
{
- /* another device reported the same physical address as ours
- * since we don't have physical address detection yet, we'll just use the
- * given address, increased by 0x100 for now */
- m_processor->SetPhysicalAddress(iNewAddress + 0x100);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "device with logical address %X not found", iAddress);
}
+
+ /* another device reported the same physical address as ours */
+ if (client)
+ client->ResetPhysicalAddress();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "ignore physical address report for device %s (%X) because it's marked as handled by libCEC", ToString(iAddress), iAddress);
}
}
if (command.initiator == CECDEVICE_UNKNOWN)
{
- CLibCEC::AddLog(CEC_LOG_ERROR, "not transmitting a command without a valid initiator");
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "not transmitting a command without a valid initiator");
return bReturn;
}
{
if ((bReturn = m_processor->Transmit(command)) == true)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "command transmitted");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted");
if (bExpectResponse)
{
bReturn = m_waitForResponse->Wait(expectedResponse);
- CLibCEC::AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, m_processor->ToString(expectedResponse));
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, ToString(expectedResponse));
}
}
}
bool CCECCommandHandler::ActivateSource(void)
{
if (m_busDevice->IsActiveSource() &&
- m_busDevice->GetStatus(false) == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ m_busDevice->IsHandledByLibCEC())
{
m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED);
m_busDevice->TransmitImageViewOn();
m_busDevice->TransmitActiveSource();
m_busDevice->TransmitMenuState(CECDEVICE_TV);
- if ((m_busDevice->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
- m_busDevice->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
- SendDeckStatusUpdateOnActiveSource())
- ((CCECPlaybackDevice *)m_busDevice)->TransmitDeckStatus(CECDEVICE_TV);
+
+ CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
+ if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
+ playbackDevice->TransmitDeckStatus(CECDEVICE_TV);
m_bHandlerInited = true;
}
return true;
virtual size_t GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
virtual CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
virtual CCECBusDevice *GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const;
- virtual CCECBusDevice *GetDeviceByType(cec_device_type type) const;
virtual bool SetVendorId(const cec_command &command);
virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
#define SL_COMMAND_CONNECT_REQUEST 0x04
#define SL_COMMAND_SET_DEVICE_MODE 0x05
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
CCECCommandHandler(busDevice),
m_bSLEnabled(false),
return true;
}
-bool CSLCommandHandler::ActivateSource(void)
-{
- if (!m_processor->GetPrimaryDevice()->IsActiveSource())
- {
- CLibCEC::AddLog(CEC_LOG_NOTICE, "not activating the source because we're not marked as active");
- return true;
- }
-
- {
- CLockObject lock(m_SLMutex);
- m_bActiveSourceSent = true;
- }
-
- CCECBusDevice *primary = m_processor->GetPrimaryDevice();
- primary->SetActiveSource();
- primary->SetPowerStatus(CEC_POWER_STATUS_ON);
- primary->TransmitPowerState(CECDEVICE_TV);
- primary->TransmitImageViewOn();
- 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]);
CCECBusDevice *primary = m_processor->GetPrimaryDevice();
- bool bSendPowerOffState(iAddress != primary->GetPhysicalAddress() && primary->IsActiveSource());
+ bool bSendPowerOffState(iAddress != primary->GetCurrentPhysicalAddress() && primary->IsActiveSource());
- m_processor->SetActiveSource(iAddress);
+ CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
+ if (device)
+ device->MarkAsActiveSource();
if (bSendPowerOffState)
{
{
if (!SLInitialised() && command.initiator == CECDEVICE_TV)
{
cec_command response;
- cec_command::Format(response, m_processor->GetLogicalAddress(), command.initiator, CEC_OPCODE_FEATURE_ABORT);
+ cec_command::Format(response, command.destination, command.initiator, CEC_OPCODE_FEATURE_ABORT);
return Transmit(response);
}
return true;
bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
{
- if (!m_busDevice->MyLogicalAddressContains(command.destination))
+ if (!m_processor->IsHandledByLibCEC(command.destination))
return true;
if (command.parameters.size == 1 &&
if (device)
{
SetSLInitialised();
- device->SetActiveSource();
+ device->MarkAsActiveSource();
device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
device->TransmitPowerState(command.initiator);
{
if (command.destination != CECDEVICE_BROADCAST)
{
- CCECBusDevice *device = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
- device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
- device->TransmitPowerState(command.initiator);
- device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ CCECBusDevice *device = m_processor->GetPrimaryDevice();
+ if (device)
+ {
+ device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ device->TransmitPowerState(command.initiator);
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
}
}
void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
{
SetSLInitialised();
- TransmitVendorCommandSetDeviceMode(m_processor->GetLogicalAddress(), command.initiator, CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ TransmitVendorCommandSetDeviceMode(command.destination, command.initiator, CEC_DEVICE_TYPE_RECORDING_DEVICE);
ActivateSource();
}
bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
{
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
{
bool bReturn(false);
- if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination) && command.initiator == CECDEVICE_TV)
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination) && command.initiator == CECDEVICE_TV)
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device && device->GetPowerStatus(false) != CEC_POWER_STATUS_ON)
+ if (device && device->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
{
bReturn = device->TransmitPowerState(command.initiator);
device->SetPowerStatus(CEC_POWER_STATUS_ON);
else if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
{
/* TODO assume that we've bugged out. the return button no longer works after this */
- CLibCEC::AddLog(CEC_LOG_WARNING, "FIXME: LG seems to have bugged out. resetting to 'in transition standby to on'. the return button will not work");
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "FIXME: LG seems to have bugged out. resetting to 'in transition standby to on'. the return button will not work");
{
CLockObject lock(m_SLMutex);
m_bActiveSourceSent = false;
bool CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
{
- if (m_processor->IsRunning())
+ if (m_processor->CECInitialised())
{
if (ActiveSourceSent())
- CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
else
ActivateSource();
return true;
bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
{
- if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
+ if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
command.initiator == CECDEVICE_TV)
{
m_processor->GetPrimaryDevice()->TransmitPowerState(command.initiator);
void CSLCommandHandler::ResetSLState(void)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "resetting SL initialised state");
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "resetting SL initialised state");
CLockObject lock(m_SLMutex);
m_bSLEnabled = false;
m_bActiveSourceSent = false;
void CSLCommandHandler::SetSLInitialised(void)
{
- CLibCEC::AddLog(CEC_LOG_NOTICE, "SL initialised");
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "SL initialised");
CLockObject lock(m_SLMutex);
m_bSLEnabled = true;
}
virtual ~CSLCommandHandler(void) {};
bool InitHandler(void);
- bool ActivateSource(void);
protected:
bool HandleActiveSource(const cec_command &command);
#include "../devices/CECBusDevice.h"
#include "../CECProcessor.h"
#include "../LibCEC.h"
+#include "../CECClient.h"
#define VL_POWER_CHANGE 0x20
#define VL_POWERED_UP 0x00
using namespace CEC;
using namespace PLATFORM;
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) :
CCECCommandHandler(busDevice),
m_bActiveSourcePending(false),
{
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 m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
return CCECCommandHandler::InitHandler();
}
{
if (command.parameters.At(4) == VL_POWERED_UP)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "TV powered up");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered up");
{
CLockObject lock(m_mutex);
m_bPowerUpEventReceived = true;
m_processor->TransmitPendingActiveSourceCommands();
}
else if (command.parameters.At(4) == VL_POWERED_DOWN)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "TV powered down");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered down");
else if (command.parameters.At(4) == VL_POWERED_DOWN)
- CLibCEC::AddLog(CEC_LOG_DEBUG, "unknown vendor command");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "unknown vendor command");
return true;
}
{
bool bPowerUpEventReceived(false);
- CCECBusDevice *tv = m_processor->m_busDevices[CECDEVICE_TV];
- if (tv && tv->GetVendorId(false) == CEC_VENDOR_PANASONIC)
+ CCECBusDevice *tv = m_processor->GetDevice(CECDEVICE_TV);
+ if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC)
{
CVLCommandHandler *handler = static_cast<CVLCommandHandler *>(tv->GetHandler());
bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false;
if (bTransmitCommand)
{
- CLibCEC::AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
- return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetPhysicalAddress());
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+ return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetCurrentPhysicalAddress());
}
return true;
}
return true;
}
- cec_power_status powerStatus = m_busDevice->GetPowerStatus();
+ cec_power_status powerStatus = m_busDevice->GetCurrentPowerStatus();
CLockObject lock(m_mutex);
m_bPowerUpEventReceived = (powerStatus == CEC_POWER_STATUS_ON);
}
typedef pthread_t thread_t;
+ #define INVALID_THREAD_VALUE 0
#define ThreadsCreate(thread, func, arg) (pthread_create(&thread, NULL, (void *(*) (void *))func, (void *)arg) == 0)
#define ThreadsWait(thread, retval) (thread ? pthread_join(thread, retval) == 0 : true)
#include <semaphore.h>
#include <stdint.h>
+extern "C" {
+#include <sys/types.h>
+}
+
#define LIBTYPE
#define DECLSPEC
#ifndef IUCLC
#define IUCLC 0
#endif
+#else
+#include <lockdev.h>
#endif
+
using namespace std;
using namespace PLATFORM;
+inline bool RemoveLock(const char *strDeviceName)
+{
+ #if !defined(__APPLE__) && !defined(__FreeBSD__)
+ return dev_unlock(strDeviceName, 0) == 0;
+ #endif
+}
+
void CSerialSocket::Close(void)
{
if (IsOpen())
+ {
SocketClose(m_socket);
+ RemoveLock(m_strName.c_str());
+ }
}
void CSerialSocket::Shutdown(void)
{
if (IsOpen())
+ {
SocketClose(m_socket);
+ RemoveLock(m_strName.c_str());
+ }
}
ssize_t CSerialSocket::Write(void* data, size_t len)
{
iTimeoutMs = 0;
if (IsOpen())
+ {
+ m_iError = EINVAL;
return false;
+ }
if (m_iDatabits != SERIAL_DATA_BITS_FIVE && m_iDatabits != SERIAL_DATA_BITS_SIX &&
m_iDatabits != SERIAL_DATA_BITS_SEVEN && m_iDatabits != SERIAL_DATA_BITS_EIGHT)
{
m_strError = "Databits has to be between 5 and 8";
+ m_iError = EINVAL;
return false;
}
if (m_iStopbits != SERIAL_STOP_BITS_ONE && m_iStopbits != SERIAL_STOP_BITS_TWO)
{
m_strError = "Stopbits has to be 1 or 2";
+ m_iError = EINVAL;
return false;
}
if (m_iParity != SERIAL_PARITY_NONE && m_iParity != SERIAL_PARITY_EVEN && m_iParity != SERIAL_PARITY_ODD)
{
m_strError = "Parity has to be none, even or odd";
+ m_iError = EINVAL;
+ return false;
+ }
+
+ #if !defined(__APPLE__) && !defined(__FreeBSD__)
+ if (dev_lock(m_strName.c_str()) != 0)
+ {
+ m_strError = "Couldn't lock the serial port";
+ m_iError = EBUSY;
return false;
}
+ #endif
m_socket = open(m_strName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (m_socket == INVALID_SERIAL_SOCKET_VALUE)
{
m_strError = strerror(errno);
+ RemoveLock(m_strName.c_str());
return false;
}
if (tcsetattr(m_socket, TCSANOW, &m_options) != 0)
{
m_strError = strerror(errno);
+ RemoveLock(m_strName.c_str());
return false;
}
CThread(void) :
m_bStop(false),
m_bRunning(false),
- m_bStopped(false) {}
+ m_bStopped(false),
+ m_thread(INVALID_THREAD_VALUE) {}
virtual ~CThread(void)
{
StopThread(0);
- void *retVal;
- ThreadsWait(m_thread, &retVal);
- #if defined(__WINDOWS__)
- (void *)retVal; //"unreferenced local variable" warning
- #endif
+ void *retVal = NULL;
+ if (m_thread != INVALID_THREAD_VALUE)
+ ThreadsWait(m_thread, &retVal);
}
static void *ThreadHandler(CThread *thread)
namespace PLATFORM
{
#define thread_t HANDLE
+ #define INVALID_THREAD_VALUE INVALID_HANDLE
#define ThreadsWait(thread, retVal) (::WaitForSingleObject(thread, INFINITE) < 0)
#define ThreadsCreate(thread, func, arg) ((thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL)) == NULL ? false : true)
" -s --single-command Execute a single command and exit. Does not power" << endl <<
" on devices on startup and power them off on exit." << endl <<
" -o --osd-name {osd name} Use a custom osd name." << endl <<
+ " -m --monitor Start a monitor-only client." << endl <<
" [COM PORT] The com port to connect to. If no COM" << endl <<
" port is given, the client tries to connect to the" << endl <<
" first device that is detected." << endl <<
}
++iArgPtr;
}
+ else if (!strcmp(argv[iArgPtr], "-m") ||
+ !strcmp(argv[iArgPtr], "--monitor"))
+ {
+ cout << "starting a monitor-only client. use 'mon 0' to switch to normal mode" << endl;
+ g_config.bMonitorOnly = 1;
+ ++iArgPtr;
+ }
else
{
g_strPort = argv[iArgPtr++];
{
g_config.Clear();
snprintf(g_config.strDeviceName, 13, "CECTester");
- g_config.clientVersion = CEC_CLIENT_VERSION_1_6_2;
+ g_config.clientVersion = CEC_CLIENT_VERSION_1_6_3;
g_config.bActivateSource = 0;
g_callbacks.CBCecLogMessage = &CecLogMessage;
g_callbacks.CBCecKeyPress = &CecKeyPress;