diff -Nru libcec-2.0.1/ChangeLog libcec-2.0.3/ChangeLog --- libcec-2.0.1/ChangeLog 2012-10-11 21:16:24.000000000 +0000 +++ libcec-2.0.3/ChangeLog 2012-10-31 14:58:41.000000000 +0000 @@ -1,4 +1,50 @@ -libcec (2.0.1-1) unstable; urgency=low +libcec (2.0.3-1) unstable; urgency=low + + * changed: + * log unhandled vendor remote keycodes in the log, so they get logged + without debugging enabled + * double tap timeout increased from 200ms to 250ms + * CuBox/NXP* renamed to TDA995x* + * fixed: + * handling of active route changes. github issue #56 and issue #58 + * new combo key handling broke samsung's vendor specific remote buttons. + github issue #54 + * don't try to set controlled mode when using firmware version 1 and crash. + github issue #76 + * fix for LG models that send a vendor key up after a normal key down. + github issue #71 + * some TVs send keypresses to us without making us the active source. mark + us as active source when this happens. github issue #71 + * LG doesn't send routing changes, and marks the TV as active source when + switching to another source that's not been selected in the simplink menu + instead. this change keeps libCEC marked as powered on and keep the deck + state set to CEC_DECK_INFO_OTHER_STATUS_LG. fixes keypresses not working + after switching to another source and back to libCEC's hdmi port via the + source select menu instead of the simplink menu. github issue #71 + * don't respond with an abort message when receiving a vendor remote button + command + * respond with CEC_ABORT_REASON_INVALID_OPERAND when receiving a keypress + without a parameter + * typo in stop+pause combo key that prevented one of the keys from working + * rpi: log what data we received exactly when we receive an response from + the pi's firmware that doesn't match any command that we sent. issue #77 + * cubox: added adapter ID interface + + -- Pulse-Eight Packaging Wed, 31 Oct 2012 15:57:00 +0100 + +libcec (2.0.2-2) unstable; urgency=medium + + * fixed: + * updating the device status after a poll was broken and could reset the + status of devices that were marked as handled by libCEC to 'not + present' + * don't keep spamming the bus with a vendor command when an active source + switch is pending for panasonic, but only send it when needed + * reset CVLCommandHandler::m_bCapabilitiesSent when the TV goes to standby + + -- Pulse-Eight Packaging Mon, 15 Oct 2012 13:52:00 +0100 + +libcec (2.0.2-1) unstable; urgency=low * changed/added: * missing from the previous changelog: added support for the CuBox TDA995x @@ -35,7 +81,7 @@ -- Pulse-Eight Packaging Thu, 11 Oct 2012 15:48:00 +0100 -libcec (2.0.0-1) unstable; urgency=low +libcec (2.0.1-1) unstable; urgency=low * changed/added: * added Loewe support diff -Nru libcec-2.0.1/README libcec-2.0.3/README --- libcec-2.0.1/README 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/README 2012-10-31 14:58:41.000000000 +0000 @@ -4,7 +4,7 @@ http://libcec.pulse-eight.com/faq =============================================================================== - === Linux === + === Linux & BSD === =============================================================================== libCEC needs the following dependencies in order to work correctly: @@ -25,7 +25,7 @@ * udev development headers v151 or later To compile, execute the following commands: -# autoreconf -vif +# ./bootstrap # ./configure # make # sudo make install @@ -40,8 +40,8 @@ * pkg-config * xcode 3.2.6 or later -To compile, execute the following commands (TODO: please verify): -# autoreconf -vif +To compile, execute the following command: +# ./bootstrap # ./configure # make # sudo make install @@ -100,15 +100,15 @@ --with-rpi-lib-path="/path/to/libbcm_host.so" =============================================================================== - === CuBox === + === CuBox / TDA995x === =============================================================================== Solid-Run's CuBox uses a combined HDMI tranceiver / CEC controller by NXP. The device driver for it is based on an SDK by the chip vendor and is compiled into the Linux kernel. The following options for 'configure' have been introduced: -To enable support for the CuBox: ---enable-cubox +To enable support for the CuBox / TDA995x: +--enable-tda995x To specify the path to the SDK part of the kernel driver: --with-tda995x-toolkit-path='path/to/linux/drivers/video/dovefb/nxp_hdmi' @@ -120,6 +120,10 @@ === Debugging / Testing === =============================================================================== +To compile libCEC with extensive debugging output, pass the following argument +to configure on Linux/OS-X/BSD: +--enable-debug + We provide a test client, named cec-client, to debug the device. To check whether the device can be detected, execute the following command: * cec-client -l diff -Nru libcec-2.0.1/bootstrap libcec-2.0.3/bootstrap --- libcec-2.0.1/bootstrap 1970-01-01 00:00:00.000000000 +0000 +++ libcec-2.0.3/bootstrap 2012-10-31 14:58:41.000000000 +0000 @@ -0,0 +1,4 @@ +#!/bin/sh + +autoreconf -vif + diff -Nru libcec-2.0.1/configure.ac libcec-2.0.3/configure.ac --- libcec-2.0.1/configure.ac 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/configure.ac 2012-10-31 14:58:41.000000000 +0000 @@ -43,10 +43,10 @@ [use_optimisation=$enableval], [use_optimisation=yes]) -## CuBox support +## TDA995x support AC_ARG_ENABLE([cubox], - [AS_HELP_STRING([--enable-cubox], - [enable support for the CuBox (default is no)])], + [AS_HELP_STRING([--enable-tda995x], + [enable support for the TDA995x (default is no)])], [use_tda995x=$enableval], [use_tda995x=no]) @@ -110,7 +110,7 @@ AC_SEARCH_LIBS([dlopen], [dl], [test "$ac_cv_search_dlopen" = "none required" || LIBS_DL=$ac_cv_search_dlopen], AC_MSG_ERROR($msg_dl_missing)) -AC_CHECK_FUNCS([dlopen dlcose dlsym]) +AC_CHECK_FUNCS([dlopen dlclose dlsym]) ## platform specific libs, required by all targets case "${host}" in @@ -250,16 +250,16 @@ features="$features\n Raspberry Pi support :\t\tno" fi -## mark CuBox support as available +## mark TDA995x support as available if test "x$use_tda995x" != "xno"; then AC_DEFINE([HAVE_TDA995X_API],[1],[Define to 1 to include CuBox support]) AM_CONDITIONAL(USE_TDA995X_API, true) - features="$features\n CuBox support :\t\t\tyes" - LIB_INFO="$LIB_INFO 'CuBox'" + features="$features\n TDA995x support :\t\t\tyes" + LIB_INFO="$LIB_INFO 'TDA995x'" CPPFLAGS="$CPPFLAGS $TDA995X_CFLAGS" else AM_CONDITIONAL(USE_TDA995X_API, false) - features="$features\n CuBox support :\t\t\tno" + features="$features\n TDA995x support :\t\t\tno" fi ## check if our build system is complete diff -Nru libcec-2.0.1/debian/changelog libcec-2.0.3/debian/changelog --- libcec-2.0.1/debian/changelog 2012-10-11 22:02:55.000000000 +0000 +++ libcec-2.0.3/debian/changelog 2012-11-03 19:53:03.000000000 +0000 @@ -1,10 +1,56 @@ -libcec (2.0.1-1~ppa1~lucid) lucid; urgency=low +libcec (2.0.3-1~ppa1~lucid) lucid; urgency=low - * Upload to PPA for lucid + * New upstream release - -- Nathan Rennie-Waldock Thu, 11 Oct 2012 23:02:55 +0100 + -- Nathan Rennie-Waldock Sat, 03 Nov 2012 19:53:03 +0000 -libcec (2.0.1-1) unstable; urgency=low +libcec (2.0.3-1) unstable; urgency=low + + * changed: + * log unhandled vendor remote keycodes in the log, so they get logged + without debugging enabled + * double tap timeout increased from 200ms to 250ms + * CuBox/NXP* renamed to TDA995x* + * fixed: + * handling of active route changes. github issue #56 and issue #58 + * new combo key handling broke samsung's vendor specific remote buttons. + github issue #54 + * don't try to set controlled mode when using firmware version 1 and crash. + github issue #76 + * fix for LG models that send a vendor key up after a normal key down. + github issue #71 + * some TVs send keypresses to us without making us the active source. mark + us as active source when this happens. github issue #71 + * LG doesn't send routing changes, and marks the TV as active source when + switching to another source that's not been selected in the simplink menu + instead. this change keeps libCEC marked as powered on and keep the deck + state set to CEC_DECK_INFO_OTHER_STATUS_LG. fixes keypresses not working + after switching to another source and back to libCEC's hdmi port via the + source select menu instead of the simplink menu. github issue #71 + * don't respond with an abort message when receiving a vendor remote button + command + * respond with CEC_ABORT_REASON_INVALID_OPERAND when receiving a keypress + without a parameter + * typo in stop+pause combo key that prevented one of the keys from working + * rpi: log what data we received exactly when we receive an response from + the pi's firmware that doesn't match any command that we sent. issue #77 + * cubox: added adapter ID interface + + -- Pulse-Eight Packaging Wed, 31 Oct 2012 15:57:00 +0100 + +libcec (2.0.2-2) unstable; urgency=medium + + * fixed: + * updating the device status after a poll was broken and could reset the + status of devices that were marked as handled by libCEC to 'not + present' + * don't keep spamming the bus with a vendor command when an active source + switch is pending for panasonic, but only send it when needed + * reset CVLCommandHandler::m_bCapabilitiesSent when the TV goes to standby + + -- Pulse-Eight Packaging Mon, 15 Oct 2012 13:52:00 +0100 + +libcec (2.0.2-1) unstable; urgency=low * changed/added: * missing from the previous changelog: added support for the CuBox TDA995x @@ -41,7 +87,7 @@ -- Pulse-Eight Packaging Thu, 11 Oct 2012 15:48:00 +0100 -libcec (2.0.0-1) unstable; urgency=low +libcec (2.0.1-1) unstable; urgency=low * changed/added: * added Loewe support diff -Nru libcec-2.0.1/include/cec.h libcec-2.0.3/include/cec.h --- libcec-2.0.1/include/cec.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/include/cec.h 2012-10-31 14:58:41.000000000 +0000 @@ -36,7 +36,7 @@ #include "cectypes.h" -#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_2_0_1 +#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_2_0_3 namespace CEC { diff -Nru libcec-2.0.1/include/cectypes.h libcec-2.0.3/include/cectypes.h --- libcec-2.0.1/include/cectypes.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/include/cectypes.h 2012-10-31 14:58:41.000000000 +0000 @@ -82,7 +82,7 @@ /*! * don't send the same key twice within this timeout in milliseconds */ -#define CEC_DOUBLE_TAP_TIMEOUT_MS 200 +#define CEC_DOUBLE_TAP_TIMEOUT_MS 250 /*! * don't query the power state for the same device within this timeout in milliseconds @@ -1375,6 +1375,8 @@ CEC_CLIENT_VERSION_1_99_0 = 0x1990, CEC_CLIENT_VERSION_2_0_0 = 0x2000, CEC_CLIENT_VERSION_2_0_1 = 0x2001, + CEC_CLIENT_VERSION_2_0_2 = 0x2002, + CEC_CLIENT_VERSION_2_0_3 = 0x2003, } cec_client_version; typedef enum cec_server_version @@ -1398,6 +1400,8 @@ CEC_SERVER_VERSION_1_99_0 = 0x1990, CEC_SERVER_VERSION_2_0_0 = 0x2000, CEC_SERVER_VERSION_2_0_1 = 0x2001, + CEC_SERVER_VERSION_2_0_2 = 0x2002, + CEC_SERVER_VERSION_2_0_3 = 0x2003, } cec_server_version; struct libcec_configuration Binary files /tmp/5Fde_IFumH/libcec-2.0.1/project/cec-config.rc and /tmp/WbNsrFOP9n/libcec-2.0.3/project/cec-config.rc differ diff -Nru libcec-2.0.1/project/libCEC.nsi libcec-2.0.3/project/libCEC.nsi --- libcec-2.0.1/project/libCEC.nsi 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/project/libCEC.nsi 2012-10-31 14:58:41.000000000 +0000 @@ -7,7 +7,7 @@ !include "LogicLib.nsh" !include "x64.nsh" -Name "Pulse-Eight libCEC version 2.0.0" +Name "Pulse-Eight libCEC version 2.0.2" OutFile "..\build\libCEC-installer.exe" XPStyle on Binary files /tmp/5Fde_IFumH/libcec-2.0.1/project/libcec.rc and /tmp/WbNsrFOP9n/libcec-2.0.3/project/libcec.rc differ Binary files /tmp/5Fde_IFumH/libcec-2.0.1/project/testclient.rc and /tmp/WbNsrFOP9n/libcec-2.0.3/project/testclient.rc differ diff -Nru libcec-2.0.1/src/CecSharpTester/CecSharpClient.cs libcec-2.0.3/src/CecSharpTester/CecSharpClient.cs --- libcec-2.0.1/src/CecSharpTester/CecSharpClient.cs 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/CecSharpTester/CecSharpClient.cs 2012-10-31 14:58:41.000000000 +0000 @@ -43,7 +43,7 @@ Config = new LibCECConfiguration(); Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; Config.DeviceName = "CEC Tester"; - Config.ClientVersion = CecClientVersion.Version2_0_0; + Config.ClientVersion = CecClientVersion.Version2_0_3; Config.SetCallbacks(this); LogLevel = (int)CecLogLevel.All; diff -Nru libcec-2.0.1/src/CecSharpTester/Properties/AssemblyInfo.cs libcec-2.0.3/src/CecSharpTester/Properties/AssemblyInfo.cs --- libcec-2.0.1/src/CecSharpTester/Properties/AssemblyInfo.cs 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/CecSharpTester/Properties/AssemblyInfo.cs 2012-10-31 14:58:41.000000000 +0000 @@ -32,5 +32,5 @@ // 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("2.0.1.0")] -[assembly: AssemblyFileVersion("2.0.1.0")] +[assembly: AssemblyVersion("2.0.3.0")] +[assembly: AssemblyFileVersion("2.0.3.0")] diff -Nru libcec-2.0.1/src/LibCecSharp/AssemblyInfo.cpp libcec-2.0.3/src/LibCecSharp/AssemblyInfo.cpp --- libcec-2.0.1/src/LibCecSharp/AssemblyInfo.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/LibCecSharp/AssemblyInfo.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -13,7 +13,7 @@ [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; -[assembly:AssemblyVersionAttribute("2.0.1.0")]; +[assembly:AssemblyVersionAttribute("2.0.3.0")]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; diff -Nru libcec-2.0.1/src/LibCecSharp/CecSharpTypes.h libcec-2.0.3/src/LibCecSharp/CecSharpTypes.h --- libcec-2.0.1/src/LibCecSharp/CecSharpTypes.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/LibCecSharp/CecSharpTypes.h 2012-10-31 14:58:41.000000000 +0000 @@ -1167,7 +1167,15 @@ /// /// v2.0.1 /// - Version2_0_1 = 0x2001 + Version2_0_1 = 0x2001, + /// + /// v2.0.2 + /// + Version2_0_2 = 0x2002, + /// + /// v2.0.3 + /// + Version2_0_3 = 0x2003 }; /// @@ -1250,7 +1258,15 @@ /// /// v2.0.1 /// - Version2_0_1 = 0x2001 + Version2_0_1 = 0x2001, + /// + /// v2.0.2 + /// + Version2_0_2 = 0x2002, + /// + /// v2.0.3 + /// + Version2_0_3 = 0x2003 }; /// diff -Nru libcec-2.0.1/src/LibCecTray/Properties/AssemblyInfo.cs libcec-2.0.3/src/LibCecTray/Properties/AssemblyInfo.cs --- libcec-2.0.1/src/LibCecTray/Properties/AssemblyInfo.cs 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/LibCecTray/Properties/AssemblyInfo.cs 2012-10-31 14:58:41.000000000 +0000 @@ -31,5 +31,5 @@ // 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("2.0.1.0")] -[assembly: AssemblyFileVersion("2.0.1.0")] +[assembly: AssemblyVersion("2.0.3.0")] +[assembly: AssemblyFileVersion("2.0.3.0")] diff -Nru libcec-2.0.1/src/LibCecTray/controller/CECController.cs libcec-2.0.3/src/LibCecTray/controller/CECController.cs --- libcec-2.0.1/src/LibCecTray/controller/CECController.cs 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/LibCecTray/controller/CECController.cs 2012-10-31 14:58:41.000000000 +0000 @@ -438,7 +438,7 @@ { if (_config == null) { - _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_0_0 }; + _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_0_3 }; _config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; _config.SetCallbacks(this); diff -Nru libcec-2.0.1/src/cec-config/cec-config.cpp libcec-2.0.3/src/cec-config/cec-config.cpp --- libcec-2.0.1/src/cec-config/cec-config.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/cec-config/cec-config.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -160,7 +160,7 @@ g_config.Clear(); snprintf(g_config.strDeviceName, 13, "CEC-config"); g_config.callbackParam = NULL; - g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_2_0_0; + g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_2_0_2; g_callbacks.CBCecLogMessage = &CecLogMessage; g_callbacks.CBCecKeyPress = &CecKeyPress; g_callbacks.CBCecCommand = &CecCommand; diff -Nru libcec-2.0.1/src/lib/CECClient.cpp libcec-2.0.3/src/lib/CECClient.cpp --- libcec-2.0.1/src/lib/CECClient.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/CECClient.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -940,21 +940,21 @@ // send back the previous key if there is one AddKey(); + if (key.keycode > CEC_USER_CONTROL_CODE_MAX && + key.keycode < CEC_USER_CONTROL_CODE_SELECT) + return; + cec_keypress transmitKey(key); { CLockObject lock(m_mutex); - if (key.duration > 0 || key.keycode > CEC_USER_CONTROL_CODE_MAX) - { - transmitKey.keycode = CEC_USER_CONTROL_CODE_UNKNOWN; - } - else if (m_iCurrentButton == COMBO_KEY) + if (m_iCurrentButton == COMBO_KEY && key.duration == 0) { // stop + ok -> exit if (key.keycode == CEC_USER_CONTROL_CODE_SELECT) transmitKey.keycode = CEC_USER_CONTROL_CODE_EXIT; // stop + pause -> root menu - else if (key.keycode == CEC_USER_CONTROL_CODE_ROOT_MENU) + else if (key.keycode == CEC_USER_CONTROL_CODE_PAUSE) transmitKey.keycode = CEC_USER_CONTROL_CODE_ROOT_MENU; // stop + play -> dot (which is handled as context menu in xbmc) else if (key.keycode == CEC_USER_CONTROL_CODE_PLAY) @@ -968,8 +968,11 @@ m_buttontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs(); } - LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x)", ToString(transmitKey.keycode), transmitKey.keycode); - CallbackAddKey(transmitKey); + if (key.keycode != COMBO_KEY || key.duration > 0) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x)", ToString(transmitKey.keycode), transmitKey.keycode); + CallbackAddKey(transmitKey); + } } void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode) @@ -1255,7 +1258,7 @@ CCECBusDevice *primary = GetPrimaryDevice(); // poll the destination, with the primary as source if (primary) - return primary->TransmitPoll(iAddress, false); + return primary->TransmitPoll(iAddress, true); return m_processor ? m_processor->PollDevice(iAddress) : false; } diff -Nru libcec-2.0.1/src/lib/CECProcessor.cpp libcec-2.0.3/src/lib/CECProcessor.cpp --- libcec-2.0.1/src/lib/CECProcessor.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/CECProcessor.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -315,11 +315,11 @@ CCECBusDevice *primary = GetPrimaryDevice(); // poll the destination, with the primary as source if (primary) - return primary->TransmitPoll(iAddress, false); + return primary->TransmitPoll(iAddress, true); CCECBusDevice *device = m_busDevices->At(CECDEVICE_UNREGISTERED); if (device) - return device->TransmitPoll(iAddress, false); + return device->TransmitPoll(iAddress, true); return false; } diff -Nru libcec-2.0.1/src/lib/CECTypeUtils.h libcec-2.0.3/src/lib/CECTypeUtils.h --- libcec-2.0.1/src/lib/CECTypeUtils.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/CECTypeUtils.h 2012-10-31 14:58:41.000000000 +0000 @@ -559,6 +559,10 @@ return "2.0.0"; case CEC_CLIENT_VERSION_2_0_1: return "2.0.1"; + case CEC_CLIENT_VERSION_2_0_2: + return "2.0.2"; + case CEC_CLIENT_VERSION_2_0_3: + return "2.0.3"; default: return "Unknown"; } @@ -602,10 +606,14 @@ return "1.9.0"; case CEC_SERVER_VERSION_1_99_0: return "2.0.0-pre"; - case CEC_CLIENT_VERSION_2_0_0: + case CEC_SERVER_VERSION_2_0_0: return "2.0.0"; - case CEC_CLIENT_VERSION_2_0_1: + case CEC_SERVER_VERSION_2_0_1: return "2.0.1"; + case CEC_SERVER_VERSION_2_0_2: + return "2.0.2"; + case CEC_SERVER_VERSION_2_0_3: + return "2.0.3"; default: return "Unknown"; } @@ -815,5 +823,16 @@ return "unknown"; } } + + static bool PhysicalAddressIsIncluded(uint16_t iParent, uint16_t iChild) + { + for (int iPtr = 3; iPtr >= 0; iPtr--) + { + if (((iParent >> 4*iPtr) & 0xF) > 0 && + ((iParent >> 4*iPtr) & 0xF) != ((iChild >> 4*iPtr) & 0xF)) + return false; + } + return true; + } }; } diff -Nru libcec-2.0.1/src/lib/Makefile.am libcec-2.0.3/src/lib/Makefile.am --- libcec-2.0.1/src/lib/Makefile.am 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/Makefile.am 2012-10-31 14:58:41.000000000 +0000 @@ -52,8 +52,8 @@ ## CuBox (NXP) support if USE_TDA995X_API -libcec_la_SOURCES += adapter/CuBox/NxpCECAdapterDetection.cpp \ - adapter/CuBox/NxpCECAdapterCommunication.cpp +libcec_la_SOURCES += adapter/TDA995x/TDA995xCECAdapterDetection.cpp \ + adapter/TDA995x/TDA995xCECAdapterCommunication.cpp endif diff -Nru libcec-2.0.1/src/lib/adapter/AdapterFactory.cpp libcec-2.0.3/src/lib/adapter/AdapterFactory.cpp --- libcec-2.0.1/src/lib/adapter/AdapterFactory.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/AdapterFactory.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -48,8 +48,8 @@ #endif #if defined(HAVE_TDA995X_API) -#include "CuBox/NxpCECAdapterDetection.h" -#include "CuBox/NxpCECAdapterCommunication.h" +#include "TDA995x/TDA995xCECAdapterDetection.h" +#include "TDA995x/TDA995xCECAdapterCommunication.h" #endif using namespace std; @@ -81,7 +81,7 @@ #endif #if defined(HAVE_TDA995X_API) - if (iAdaptersFound < iBufSize && CNxpCECAdapterDetection::FindAdapter() && + if (iAdaptersFound < iBufSize && CTDA995xCECAdapterDetection::FindAdapter() && (!strDevicePath || !strcmp(strDevicePath, CEC_TDA995x_VIRTUAL_COM))) { snprintf(deviceList[iAdaptersFound].path, 1024, CEC_TDA995x_PATH); @@ -100,7 +100,7 @@ { #if defined(HAVE_TDA995X_API) if (!strcmp(strPort, CEC_TDA995x_VIRTUAL_COM)) - return new CNxpCECAdapterCommunication(m_lib->m_cec); + return new CTDA995xCECAdapterCommunication(m_lib->m_cec); #endif #if defined(HAVE_RPI_API) diff -Nru libcec-2.0.1/src/lib/adapter/CuBox/AdapterMessageQueue.h libcec-2.0.3/src/lib/adapter/CuBox/AdapterMessageQueue.h --- libcec-2.0.1/src/lib/adapter/CuBox/AdapterMessageQueue.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/CuBox/AdapterMessageQueue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -#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 - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -#include "lib/platform/threads/mutex.h" - -namespace CEC -{ - using namespace PLATFORM; - - class CAdapterMessageQueueEntry - { - public: - CAdapterMessageQueueEntry(const cec_command &command) - : m_bWaiting(true), m_retval((uint32_t)-1), m_bSucceeded(false) - { - m_hash = hashValue( - uint32_t(command.opcode_set ? command.opcode : CEC_OPCODE_NONE), - command.initiator, command.destination); - } - - virtual ~CAdapterMessageQueueEntry(void) {} - - /*! - * @brief Query result from worker thread - */ - uint32_t Result() const - { - return m_retval; - } - - /*! - * @brief Signal waiting threads - */ - void Broadcast(void) - { - CLockObject lock(m_mutex); - m_condition.Broadcast(); - } - - /*! - * @brief Signal waiting thread(s) when message matches this entry - */ - bool CheckMatch(uint32_t opcode, cec_logical_address initiator, - cec_logical_address destination, uint32_t response) - { - uint32_t hash = hashValue(opcode, initiator, destination); - - if (hash == m_hash) - { - CLockObject lock(m_mutex); - - m_retval = response; - m_bSucceeded = true; - m_condition.Signal(); - return true; - } - - return false; - } - - /*! - * @brief Wait for a response to this command. - * @param iTimeout The timeout to use while waiting. - * @return True when a response was received before the timeout passed, false otherwise. - */ - bool Wait(uint32_t iTimeout) - { - CLockObject lock(m_mutex); - - bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout); - m_bWaiting = false; - return bReturn; - } - - /*! - * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise. - */ - bool IsWaiting(void) - { - CLockObject lock(m_mutex); - return m_bWaiting; - } - - /*! - * @return Hash value for given cec_command - */ - static uint32_t hashValue(uint32_t opcode, - cec_logical_address initiator, - cec_logical_address destination) - { - return 1 | ((uint32_t)initiator << 8) | - ((uint32_t)destination << 16) | ((uint32_t)opcode << 16); - } - - private: - bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */ - PLATFORM::CCondition m_condition; /**< the condition to wait on */ - PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */ - uint32_t m_hash; - uint32_t m_retval; - bool m_bSucceeded; - }; - -}; diff -Nru libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp --- libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterCommunication.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,372 +0,0 @@ -/* - * 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 - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -#include "env.h" - -#if defined(HAVE_TDA995X_API) -#include "NxpCECAdapterCommunication.h" - -#include "lib/CECTypeUtils.h" -#include "lib/LibCEC.h" -#include "lib/platform/sockets/cdevsocket.h" -#include "lib/platform/util/StdString.h" -#include "lib/platform/util/buffer.h" - -extern "C" { -#define __cec_h__ -#include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h> -#include <../tda998x_ioctl.h> -} - -using namespace std; -using namespace CEC; -using namespace PLATFORM; - -#include "AdapterMessageQueue.h" - -#define LIB_CEC m_callback->GetLib() - -// these are defined in nxp private header file -#define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/ -#define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/ -#define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/ -#define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/ -#define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/ -#define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/ -#define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/ -#define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/ - - -CNxpCECAdapterCommunication::CNxpCECAdapterCommunication(IAdapterCommunicationCallback *callback) : - IAdapterCommunication(callback), - m_bLogicalAddressChanged(false) -{ - CLockObject lock(m_mutex); - - m_iNextMessage = 0; - m_logicalAddresses.Clear(); - m_dev = new CCDevSocket(CEC_TDA995x_PATH); -} - - -CNxpCECAdapterCommunication::~CNxpCECAdapterCommunication(void) -{ - Close(); - - CLockObject lock(m_mutex); - delete m_dev; - m_dev = 0; -} - - -bool CNxpCECAdapterCommunication::IsOpen(void) -{ - return IsInitialised() && m_dev->IsOpen(); -} - - -bool CNxpCECAdapterCommunication::Open(uint32_t iTimeoutMs, bool UNUSED(bSkipChecks), bool bStartListening) -{ - if (m_dev->Open(iTimeoutMs)) - { - unsigned char raw_mode = 0xff; - - if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_MODE, &raw_mode) == 0) - { - raw_mode = 1; - if (m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode) == 0) - { - if (!bStartListening || CreateThread()) - return true; - } - else - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RAW_MODE failed !", __func__); - } - - raw_mode = 0; - m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode); - } - else - { - LIB_CEC->AddLog(CEC_LOG_ERROR, - "%s: CEC_IOCTL_GET_RAW_MODE not supported. Please update your kernel.", __func__); - } - - m_dev->Close(); - } - - return false; -} - - -void CNxpCECAdapterCommunication::Close(void) -{ - StopThread(0); - - unsigned char raw_mode = 0; - m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode); - - m_dev->Close(); -} - - -std::string CNxpCECAdapterCommunication::GetError(void) const -{ - std::string strError(m_strError); - return strError; -} - - -cec_adapter_message_state CNxpCECAdapterCommunication::Write( - const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply)) -{ - cec_frame frame; - CAdapterMessageQueueEntry *entry; - cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR; - - if ((size_t)data.parameters.size + data.opcode_set > sizeof(frame.data)) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__); - return ADAPTER_MESSAGE_STATE_ERROR; - } - - frame.size = 0; - frame.service = 0; - frame.addr = (data.initiator << 4) | (data.destination & 0x0f); - - if (data.opcode_set) - { - frame.data[0] = data.opcode; - frame.size++; - - memcpy(&frame.data[frame.size], data.parameters.data, data.parameters.size); - frame.size += data.parameters.size; - } - - frame.size += 3; - - entry = new CAdapterMessageQueueEntry(data); - - m_messageMutex.Lock(); - uint32_t msgKey = ++m_iNextMessage; - m_messages.insert(make_pair(msgKey, entry)); - - if (m_dev->Write((char *)&frame, sizeof(frame)) == sizeof(frame)) - { - m_messageMutex.Unlock(); - - if (entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT)) - { - uint32_t status = entry->Result(); - - if (status == CEC_MSG_FAIL_DEST_NOT_ACK) - rc = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; - else if (status == CEC_MSG_SUCCESS) - rc = ADAPTER_MESSAGE_STATE_SENT_ACKED; - } - else - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: command timed out !", __func__); - - m_messageMutex.Lock(); - } - else - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: write failed !", __func__); - - m_messages.erase(msgKey); - m_messageMutex.Unlock(); - - delete entry; - - return rc; -} - - -uint16_t CNxpCECAdapterCommunication::GetFirmwareVersion(void) -{ - cec_sw_version vers = { 0 }; - - m_dev->Ioctl(CEC_IOCTL_GET_SW_VERSION, &vers); - - return (vers.majorVersionNr * 100) + vers.minorVersionNr; -} - - -cec_vendor_id CNxpCECAdapterCommunication::GetVendorId(void) -{ - cec_raw_info info; - - if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__); - return CEC_VENDOR_LG; - } - - return cec_vendor_id(info.VendorID); -} - - -uint16_t CNxpCECAdapterCommunication::GetPhysicalAddress(void) -{ - cec_raw_info info; - - if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__); - return CEC_INVALID_PHYSICAL_ADDRESS; - } - - return info.PhysicalAddress; -} - - -cec_logical_addresses CNxpCECAdapterCommunication::GetLogicalAddresses(void) -{ - CLockObject lock(m_mutex); - - if (m_bLogicalAddressChanged || m_logicalAddresses.IsEmpty() ) - { - cec_raw_info info; - - m_logicalAddresses.Clear(); - - if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__); - } - else if (info.LogicalAddress != CECDEVICE_UNREGISTERED) - { - m_logicalAddresses.Set(cec_logical_address(info.LogicalAddress)); - - for (int la = CECDEVICE_TV; la < CECDEVICE_BROADCAST; la++) - { - m_logicalAddresses.Set(cec_logical_address(la)); - } - } - - m_bLogicalAddressChanged = false; - } - - return m_logicalAddresses; -} - - -bool CNxpCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses) -{ - unsigned char log_addr = addresses.primary; - - if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__); - return false; - } - - cec_rx_mask all_addresses; - - all_addresses.SwitchOn = addresses.AckMask() & 0x7fff; - all_addresses.SwitchOff = ~all_addresses.SwitchOn; - - if (all_addresses.SwitchOn != (1 << addresses.primary) && - m_dev->Ioctl(CEC_IOCTL_SET_RX_ADDR_MASK, &all_addresses) != 0) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RX_ADDR_MASK failed !", __func__); - return false; - } - - m_bLogicalAddressChanged = true; - - return true; -} - - -void CNxpCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress)) -{ - unsigned char log_addr = CECDEVICE_BROADCAST; - - if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0) - { - LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__); - } -} - - -void *CNxpCECAdapterCommunication::Process(void) -{ - bool bHandled; - cec_frame frame; - uint32_t opcode, status; - cec_logical_address initiator, destination; - - while (!IsStopped()) - { - if (m_dev->Read((char *)&frame, sizeof(frame), 500) == sizeof(frame)) - { - initiator = cec_logical_address(frame.addr >> 4); - destination = cec_logical_address(frame.addr & 0x0f); - - if (frame.service == CEC_RX_PKT) - { - cec_command cmd; - - cec_command::Format( - cmd, initiator, destination, - ( frame.size > 3 ) ? cec_opcode(frame.data[0]) : CEC_OPCODE_NONE); - - for( uint8_t i = 1; i < frame.size-3; i++ ) - cmd.parameters.PushBack(frame.data[i]); - - m_callback->OnCommandReceived(cmd); - } - else if (frame.service == CEC_ACK_PKT) - { - bHandled = false; - status = ( frame.size > 3 ) ? frame.data[0] : 255; - opcode = ( frame.size > 4 ) ? frame.data[1] : (uint32_t)CEC_OPCODE_NONE; - - m_messageMutex.Lock(); - for (map::iterator it = m_messages.begin(); - !bHandled && it != m_messages.end(); it++) - { - bHandled = it->second->CheckMatch(opcode, initiator, destination, status); - } - m_messageMutex.Unlock(); - - if (!bHandled) - LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: unhandled response received !", __func__); - } - } - } - - return 0; -} - -#endif // HAVE_TDA995X_API diff -Nru libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h --- libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterCommunication.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -#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 - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -#if defined(HAVE_TDA995X_API) - -#include "lib/platform/threads/mutex.h" -#include "lib/platform/threads/threads.h" -#include "lib/platform/sockets/socket.h" -#include "lib/adapter/AdapterCommunication.h" -#include - - -namespace PLATFORM -{ - class CCDevSocket; -}; - - -namespace CEC -{ - class CAdapterMessageQueueEntry; - - class CNxpCECAdapterCommunication : public IAdapterCommunication, public PLATFORM::CThread - { - public: - /*! - * @brief Create a new USB-CEC communication handler. - * @param callback The callback to use for incoming CEC commands. - */ - CNxpCECAdapterCommunication(IAdapterCommunicationCallback *callback); - virtual ~CNxpCECAdapterCommunication(void); - - /** @name IAdapterCommunication implementation */ - ///{ - bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true); - void Close(void); - bool IsOpen(void); - std::string GetError(void) const; - cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply); - - bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; } - bool StartBootloader(void) { return false; } - bool SetLogicalAddresses(const cec_logical_addresses &addresses); - cec_logical_addresses GetLogicalAddresses(void); - bool PingAdapter(void) { return IsInitialised(); } - uint16_t GetFirmwareVersion(void); - uint32_t GetFirmwareBuildDate(void) { return 0; } - bool IsRunningLatestFirmware(void) { return true; } - bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; } - bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; } - std::string GetPortName(void) { return std::string("NXP"); } - uint16_t GetPhysicalAddress(void); - bool SetControlledMode(bool UNUSED(controlled)) { return true; } - cec_vendor_id GetVendorId(void); - bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; } - cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_TDA995x; } - void HandleLogicalAddressLost(cec_logical_address oldAddress); - ///} - - /** @name PLATFORM::CThread implementation */ - ///{ - void *Process(void); - ///} - - private: - bool IsInitialised(void) const { return m_dev != 0; }; - - std::string m_strError; /**< current error message */ - - bool m_bLogicalAddressChanged; - cec_logical_addresses m_logicalAddresses; - - PLATFORM::CMutex m_mutex; - PLATFORM::CCDevSocket *m_dev; /**< the device connection */ - - PLATFORM::CMutex m_messageMutex; - uint32_t m_iNextMessage; - std::map m_messages; - }; - -}; - -#endif diff -Nru libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp --- libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterDetection.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - * 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 - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -#include "env.h" -#include - -#if defined(HAVE_TDA995X_API) -#include "NxpCECAdapterDetection.h" - -extern "C" { -#define __cec_h__ -#include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h> -#include <../tda998x_ioctl.h> -} - -using namespace CEC; - -bool CNxpCECAdapterDetection::FindAdapter(void) -{ - return access(CEC_TDA995x_PATH, 0) == 0; -} - -#endif diff -Nru libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterDetection.h libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterDetection.h --- libcec-2.0.1/src/lib/adapter/CuBox/NxpCECAdapterDetection.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/CuBox/NxpCECAdapterDetection.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#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 - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -namespace CEC -{ - class CNxpCECAdapterDetection - { - public: - static bool FindAdapter(void); - }; -} diff -Nru libcec-2.0.1/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp libcec-2.0.3/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp --- libcec-2.0.1/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -85,7 +85,9 @@ while (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN && iFwVersionTry++ < 3) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting the firmware version"); +#endif cec_datapacket response = RequestSetting(MSGCODE_FIRMWARE_VERSION); if (response.size == 2) m_persistedConfiguration.iFirmwareVersion = (response[0] << 8 | response[1]); @@ -102,12 +104,18 @@ m_persistedConfiguration.iFirmwareVersion = 1; } + // firmware versions < 2 don't have an autonomous mode + if (m_persistedConfiguration.iFirmwareVersion < 2) + m_bControlledMode = true; + return m_persistedConfiguration.iFirmwareVersion; } bool CUSBCECAdapterCommands::RequestSettingAutoEnabled(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_AUTO_ENABLED); if (response.size == 1) @@ -121,7 +129,9 @@ bool CUSBCECAdapterCommands::RequestSettingCECVersion(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting CEC version setting"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_HDMI_VERSION); if (response.size == 1) @@ -137,7 +147,9 @@ { if (m_adapterType == P8_ADAPTERTYPE_UNKNOWN) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting adapter type"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_ADAPTER_TYPE); if (response.size == 1) @@ -150,7 +162,9 @@ { if (m_iBuildDate == CEC_FW_BUILD_UNKNOWN) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting firmware build date"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_BUILDDATE); if (response.size == 4) @@ -161,7 +175,9 @@ bool CUSBCECAdapterCommands::RequestSettingDefaultLogicalAddress(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting default logical address setting"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS); if (response.size == 1) @@ -175,7 +191,9 @@ bool CUSBCECAdapterCommands::RequestSettingDeviceType(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting device type setting"); +#endif m_persistedConfiguration.deviceTypes.Clear(); cec_datapacket response = RequestSetting(MSGCODE_GET_DEVICE_TYPE); @@ -191,7 +209,9 @@ bool CUSBCECAdapterCommands::RequestSettingLogicalAddressMask(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_LOGICAL_ADDRESS_MASK); if (response.size == 2) @@ -205,7 +225,9 @@ bool CUSBCECAdapterCommands::RequestSettingOSDName(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting OSD name setting"); +#endif memset(m_persistedConfiguration.strDeviceName, 0, 13); cec_datapacket response = RequestSetting(MSGCODE_GET_OSD_NAME); @@ -227,7 +249,9 @@ bool CUSBCECAdapterCommands::RequestSettingPhysicalAddress(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting physical address setting"); +#endif cec_datapacket response = RequestSetting(MSGCODE_GET_PHYSICAL_ADDRESS); if (response.size == 2) @@ -544,7 +568,9 @@ bool CUSBCECAdapterCommands::PingAdapter(void) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending ping"); +#endif CCECAdapterMessage params; CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_PING, params); diff -Nru libcec-2.0.1/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp libcec-2.0.3/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp --- libcec-2.0.1/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -110,7 +110,9 @@ { VC_CEC_NOTIFY_T reason = (VC_CEC_NOTIFY_T)CEC_CB_REASON(header); +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "received data: header:%08X p0:%08X p1:%08X p2:%08X p3:%08X reason:%x", header, p0, p1, p2, p3, reason); +#endif switch (reason) { diff -Nru libcec-2.0.1/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp libcec-2.0.3/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp --- libcec-2.0.1/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -121,7 +121,7 @@ bHandled = it->second->MessageReceived(opcode, initiator, destination, response); if (!bHandled) - LIB_CEC->AddLog(CEC_LOG_WARNING, "unhandled response received"); + LIB_CEC->AddLog(CEC_LOG_WARNING, "unhandled response received: opcode=%x initiator=%x destination=%x response=%x", (int)opcode, (int)initiator, (int)destination, response); } bool CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool bIsReply) @@ -151,11 +151,13 @@ message.payload[iPtr + 1] = command.parameters.At(iPtr); } +#ifdef CEC_DEBUGGING CStdString strDump; strDump.Format("len = %d, payload = %X%X", message.length, (int)message.initiator, (int)message.follower); for (uint8_t iPtr = 0; iPtr < message.length - 1; iPtr++) strDump.AppendFormat(":%02X", message.payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); +#endif int iReturn = vc_cec_send_message2(&message); #else @@ -172,11 +174,13 @@ payload[iPtr + 1] = command.parameters.At(iPtr); } +#ifdef CEC_DEBUGGING CStdString strDump; strDump.Format("len = %d, payload = %X%X", iLength, (int)command.initiator, (int)command.destination); for (uint8_t iPtr = 0; iPtr < iLength; iPtr++) strDump.AppendFormat(":%02X", payload[iPtr]); LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); +#endif int iReturn = vc_cec_send_message((uint32_t)command.destination, (uint8_t*)&payload, iLength, bIsReply); #endif diff -Nru libcec-2.0.1/src/lib/adapter/TDA995x/AdapterMessageQueue.h libcec-2.0.3/src/lib/adapter/TDA995x/AdapterMessageQueue.h --- libcec-2.0.1/src/lib/adapter/TDA995x/AdapterMessageQueue.h 1970-01-01 00:00:00.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/TDA995x/AdapterMessageQueue.h 2012-10-31 14:58:41.000000000 +0000 @@ -0,0 +1,134 @@ +#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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "lib/platform/threads/mutex.h" + +namespace CEC +{ + using namespace PLATFORM; + + class CAdapterMessageQueueEntry + { + public: + CAdapterMessageQueueEntry(const cec_command &command) + : m_bWaiting(true), m_retval((uint32_t)-1), m_bSucceeded(false) + { + m_hash = hashValue( + uint32_t(command.opcode_set ? command.opcode : CEC_OPCODE_NONE), + command.initiator, command.destination); + } + + virtual ~CAdapterMessageQueueEntry(void) {} + + /*! + * @brief Query result from worker thread + */ + uint32_t Result() const + { + return m_retval; + } + + /*! + * @brief Signal waiting threads + */ + void Broadcast(void) + { + CLockObject lock(m_mutex); + m_condition.Broadcast(); + } + + /*! + * @brief Signal waiting thread(s) when message matches this entry + */ + bool CheckMatch(uint32_t opcode, cec_logical_address initiator, + cec_logical_address destination, uint32_t response) + { + uint32_t hash = hashValue(opcode, initiator, destination); + + if (hash == m_hash) + { + CLockObject lock(m_mutex); + + m_retval = response; + m_bSucceeded = true; + m_condition.Signal(); + return true; + } + + return false; + } + + /*! + * @brief Wait for a response to this command. + * @param iTimeout The timeout to use while waiting. + * @return True when a response was received before the timeout passed, false otherwise. + */ + bool Wait(uint32_t iTimeout) + { + CLockObject lock(m_mutex); + + bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout); + m_bWaiting = false; + return bReturn; + } + + /*! + * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise. + */ + bool IsWaiting(void) + { + CLockObject lock(m_mutex); + return m_bWaiting; + } + + /*! + * @return Hash value for given cec_command + */ + static uint32_t hashValue(uint32_t opcode, + cec_logical_address initiator, + cec_logical_address destination) + { + return 1 | ((uint32_t)initiator << 8) | + ((uint32_t)destination << 16) | ((uint32_t)opcode << 16); + } + + private: + bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */ + PLATFORM::CCondition m_condition; /**< the condition to wait on */ + PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */ + uint32_t m_hash; + uint32_t m_retval; + bool m_bSucceeded; + }; + +}; diff -Nru libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.cpp libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.cpp --- libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -0,0 +1,372 @@ +/* + * 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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" + +#if defined(HAVE_TDA995X_API) +#include "TDA995xCECAdapterCommunication.h" + +#include "lib/CECTypeUtils.h" +#include "lib/LibCEC.h" +#include "lib/platform/sockets/cdevsocket.h" +#include "lib/platform/util/StdString.h" +#include "lib/platform/util/buffer.h" + +extern "C" { +#define __cec_h__ +#include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h> +#include <../tda998x_ioctl.h> +} + +using namespace std; +using namespace CEC; +using namespace PLATFORM; + +#include "AdapterMessageQueue.h" + +#define LIB_CEC m_callback->GetLib() + +// these are defined in nxp private header file +#define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/ +#define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/ +#define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/ +#define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/ +#define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/ +#define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/ +#define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/ +#define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/ + + +CTDA995xCECAdapterCommunication::CTDA995xCECAdapterCommunication(IAdapterCommunicationCallback *callback) : + IAdapterCommunication(callback), + m_bLogicalAddressChanged(false) +{ + CLockObject lock(m_mutex); + + m_iNextMessage = 0; + m_logicalAddresses.Clear(); + m_dev = new CCDevSocket(CEC_TDA995x_PATH); +} + + +CTDA995xCECAdapterCommunication::~CTDA995xCECAdapterCommunication(void) +{ + Close(); + + CLockObject lock(m_mutex); + delete m_dev; + m_dev = 0; +} + + +bool CTDA995xCECAdapterCommunication::IsOpen(void) +{ + return IsInitialised() && m_dev->IsOpen(); +} + + +bool CTDA995xCECAdapterCommunication::Open(uint32_t iTimeoutMs, bool UNUSED(bSkipChecks), bool bStartListening) +{ + if (m_dev->Open(iTimeoutMs)) + { + unsigned char raw_mode = 0xff; + + if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_MODE, &raw_mode) == 0) + { + raw_mode = 1; + if (m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode) == 0) + { + if (!bStartListening || CreateThread()) + return true; + } + else + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RAW_MODE failed !", __func__); + } + + raw_mode = 0; + m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode); + } + else + { + LIB_CEC->AddLog(CEC_LOG_ERROR, + "%s: CEC_IOCTL_GET_RAW_MODE not supported. Please update your kernel.", __func__); + } + + m_dev->Close(); + } + + return false; +} + + +void CTDA995xCECAdapterCommunication::Close(void) +{ + StopThread(0); + + unsigned char raw_mode = 0; + m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode); + + m_dev->Close(); +} + + +std::string CTDA995xCECAdapterCommunication::GetError(void) const +{ + std::string strError(m_strError); + return strError; +} + + +cec_adapter_message_state CTDA995xCECAdapterCommunication::Write( + const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply)) +{ + cec_frame frame; + CAdapterMessageQueueEntry *entry; + cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR; + + if ((size_t)data.parameters.size + data.opcode_set > sizeof(frame.data)) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__); + return ADAPTER_MESSAGE_STATE_ERROR; + } + + frame.size = 0; + frame.service = 0; + frame.addr = (data.initiator << 4) | (data.destination & 0x0f); + + if (data.opcode_set) + { + frame.data[0] = data.opcode; + frame.size++; + + memcpy(&frame.data[frame.size], data.parameters.data, data.parameters.size); + frame.size += data.parameters.size; + } + + frame.size += 3; + + entry = new CAdapterMessageQueueEntry(data); + + m_messageMutex.Lock(); + uint32_t msgKey = ++m_iNextMessage; + m_messages.insert(make_pair(msgKey, entry)); + + if (m_dev->Write((char *)&frame, sizeof(frame)) == sizeof(frame)) + { + m_messageMutex.Unlock(); + + if (entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT)) + { + uint32_t status = entry->Result(); + + if (status == CEC_MSG_FAIL_DEST_NOT_ACK) + rc = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; + else if (status == CEC_MSG_SUCCESS) + rc = ADAPTER_MESSAGE_STATE_SENT_ACKED; + } + else + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: command timed out !", __func__); + + m_messageMutex.Lock(); + } + else + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: write failed !", __func__); + + m_messages.erase(msgKey); + m_messageMutex.Unlock(); + + delete entry; + + return rc; +} + + +uint16_t CTDA995xCECAdapterCommunication::GetFirmwareVersion(void) +{ + cec_sw_version vers = { 0 }; + + m_dev->Ioctl(CEC_IOCTL_GET_SW_VERSION, &vers); + + return (vers.majorVersionNr * 100) + vers.minorVersionNr; +} + + +cec_vendor_id CTDA995xCECAdapterCommunication::GetVendorId(void) +{ + cec_raw_info info; + + if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__); + return CEC_VENDOR_LG; + } + + return cec_vendor_id(info.VendorID); +} + + +uint16_t CTDA995xCECAdapterCommunication::GetPhysicalAddress(void) +{ + cec_raw_info info; + + if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__); + return CEC_INVALID_PHYSICAL_ADDRESS; + } + + return info.PhysicalAddress; +} + + +cec_logical_addresses CTDA995xCECAdapterCommunication::GetLogicalAddresses(void) +{ + CLockObject lock(m_mutex); + + if (m_bLogicalAddressChanged || m_logicalAddresses.IsEmpty() ) + { + cec_raw_info info; + + m_logicalAddresses.Clear(); + + if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__); + } + else if (info.LogicalAddress != CECDEVICE_UNREGISTERED) + { + m_logicalAddresses.Set(cec_logical_address(info.LogicalAddress)); + + for (int la = CECDEVICE_TV; la < CECDEVICE_BROADCAST; la++) + { + m_logicalAddresses.Set(cec_logical_address(la)); + } + } + + m_bLogicalAddressChanged = false; + } + + return m_logicalAddresses; +} + + +bool CTDA995xCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses) +{ + unsigned char log_addr = addresses.primary; + + if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__); + return false; + } + + cec_rx_mask all_addresses; + + all_addresses.SwitchOn = addresses.AckMask() & 0x7fff; + all_addresses.SwitchOff = ~all_addresses.SwitchOn; + + if (all_addresses.SwitchOn != (1 << addresses.primary) && + m_dev->Ioctl(CEC_IOCTL_SET_RX_ADDR_MASK, &all_addresses) != 0) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RX_ADDR_MASK failed !", __func__); + return false; + } + + m_bLogicalAddressChanged = true; + + return true; +} + + +void CTDA995xCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress)) +{ + unsigned char log_addr = CECDEVICE_BROADCAST; + + if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__); + } +} + + +void *CTDA995xCECAdapterCommunication::Process(void) +{ + bool bHandled; + cec_frame frame; + uint32_t opcode, status; + cec_logical_address initiator, destination; + + while (!IsStopped()) + { + if (m_dev->Read((char *)&frame, sizeof(frame), 500) == sizeof(frame)) + { + initiator = cec_logical_address(frame.addr >> 4); + destination = cec_logical_address(frame.addr & 0x0f); + + if (frame.service == CEC_RX_PKT) + { + cec_command cmd; + + cec_command::Format( + cmd, initiator, destination, + ( frame.size > 3 ) ? cec_opcode(frame.data[0]) : CEC_OPCODE_NONE); + + for( uint8_t i = 1; i < frame.size-3; i++ ) + cmd.parameters.PushBack(frame.data[i]); + + m_callback->OnCommandReceived(cmd); + } + else if (frame.service == CEC_ACK_PKT) + { + bHandled = false; + status = ( frame.size > 3 ) ? frame.data[0] : 255; + opcode = ( frame.size > 4 ) ? frame.data[1] : (uint32_t)CEC_OPCODE_NONE; + + m_messageMutex.Lock(); + for (map::iterator it = m_messages.begin(); + !bHandled && it != m_messages.end(); it++) + { + bHandled = it->second->CheckMatch(opcode, initiator, destination, status); + } + m_messageMutex.Unlock(); + + if (!bHandled) + LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: unhandled response received !", __func__); + } + } + } + + return 0; +} + +#endif // HAVE_TDA995X_API diff -Nru libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h --- libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h 1970-01-01 00:00:00.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h 2012-10-31 14:58:41.000000000 +0000 @@ -0,0 +1,117 @@ +#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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#if defined(HAVE_TDA995X_API) + +#include "lib/platform/threads/mutex.h" +#include "lib/platform/threads/threads.h" +#include "lib/platform/sockets/socket.h" +#include "lib/adapter/AdapterCommunication.h" +#include + +#define TDA995X_ADAPTER_VID 0x0471 +#define TDA995X_ADAPTER_PID 0x1001 + +namespace PLATFORM +{ + class CCDevSocket; +}; + + +namespace CEC +{ + class CAdapterMessageQueueEntry; + + class CTDA995xCECAdapterCommunication : public IAdapterCommunication, public PLATFORM::CThread + { + public: + /*! + * @brief Create a new USB-CEC communication handler. + * @param callback The callback to use for incoming CEC commands. + */ + CTDA995xCECAdapterCommunication(IAdapterCommunicationCallback *callback); + virtual ~CTDA995xCECAdapterCommunication(void); + + /** @name IAdapterCommunication implementation */ + ///{ + bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true); + void Close(void); + bool IsOpen(void); + std::string GetError(void) const; + cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply); + + bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; } + bool StartBootloader(void) { return false; } + bool SetLogicalAddresses(const cec_logical_addresses &addresses); + cec_logical_addresses GetLogicalAddresses(void); + bool PingAdapter(void) { return IsInitialised(); } + uint16_t GetFirmwareVersion(void); + uint32_t GetFirmwareBuildDate(void) { return 0; } + bool IsRunningLatestFirmware(void) { return true; } + bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; } + bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; } + std::string GetPortName(void) { return std::string("TDA995X"); } + uint16_t GetPhysicalAddress(void); + bool SetControlledMode(bool UNUSED(controlled)) { return true; } + cec_vendor_id GetVendorId(void); + bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; } + cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_TDA995x; } + uint16_t GetAdapterVendorId(void) const { return TDA995X_ADAPTER_VID; } + uint16_t GetAdapterProductId(void) const { return TDA995X_ADAPTER_PID; } + void HandleLogicalAddressLost(cec_logical_address oldAddress); + ///} + + /** @name PLATFORM::CThread implementation */ + ///{ + void *Process(void); + ///} + + private: + bool IsInitialised(void) const { return m_dev != 0; }; + + std::string m_strError; /**< current error message */ + + bool m_bLogicalAddressChanged; + cec_logical_addresses m_logicalAddresses; + + PLATFORM::CMutex m_mutex; + PLATFORM::CCDevSocket *m_dev; /**< the device connection */ + + PLATFORM::CMutex m_messageMutex; + uint32_t m_iNextMessage; + std::map m_messages; + }; + +}; + +#endif diff -Nru libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.cpp libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.cpp --- libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -0,0 +1,52 @@ +/* + * 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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" +#include + +#if defined(HAVE_TDA995X_API) +#include "TDA995xCECAdapterDetection.h" + +extern "C" { +#define __cec_h__ +#include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h> +#include <../tda998x_ioctl.h> +} + +using namespace CEC; + +bool CTDA995xCECAdapterDetection::FindAdapter(void) +{ + return access(CEC_TDA995x_PATH, 0) == 0; +} + +#endif diff -Nru libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.h libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.h --- libcec-2.0.1/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.h 1970-01-01 00:00:00.000000000 +0000 +++ libcec-2.0.3/src/lib/adapter/TDA995x/TDA995xCECAdapterDetection.h 2012-10-31 14:58:41.000000000 +0000 @@ -0,0 +1,41 @@ +#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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +namespace CEC +{ + class CTDA995xCECAdapterDetection + { + public: + static bool FindAdapter(void); + }; +} diff -Nru libcec-2.0.1/src/lib/devices/CECBusDevice.cpp libcec-2.0.3/src/lib/devices/CECBusDevice.cpp --- libcec-2.0.1/src/lib/devices/CECBusDevice.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/devices/CECBusDevice.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -618,7 +618,6 @@ !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS)) { MarkBusy(); - LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse); MarkReady(); } @@ -741,7 +740,8 @@ CLockObject lock(m_mutex); status = m_deviceStatus; bNeedsPoll = !bSuppressPoll && - (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN); + (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN) && + m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC; } if (bNeedsPoll) @@ -782,6 +782,7 @@ if (m_deviceStatus != newStatus) LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress); m_deviceStatus = newStatus; + m_iLastActive = GetTimeMs(); break; case CEC_DEVICE_STATUS_NOT_PRESENT: if (m_deviceStatus != newStatus) @@ -819,7 +820,7 @@ m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN; } -bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bIsReply) +bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bUpdateDeviceStatus) { bool bReturn(false); cec_logical_address destination(dest); @@ -832,17 +833,11 @@ MarkBusy(); LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest); - bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, bIsReply); + bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, false); LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent"); - CLockObject lock(m_mutex); - if (bReturn) - { - m_iLastActive = GetTimeMs(); - SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT); - } - else - SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT); + if (bUpdateDeviceStatus) + destDevice->SetDeviceStatus(bReturn ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT); MarkReady(); return bReturn; @@ -1071,6 +1066,26 @@ return bReturn; } +void CCECBusDevice::SetActiveRoute(uint16_t iRoute) +{ + CCECDeviceMap* map = m_processor->GetDevices(); + if (!map) + return; + + CCECBusDevice* previouslyActive = map->GetActiveSource(); + if (!previouslyActive) + return; + + CECDEVICEVEC devices; + m_processor->GetDevices()->GetChildrenOf(devices, this); + + for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++) + { + if (!CCECTypeUtils::PhysicalAddressIsIncluded(iRoute, (*it)->GetCurrentPhysicalAddress())) + (*it)->MarkAsInactiveSource(); + } +} + void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) { CLockObject lock(m_mutex); diff -Nru libcec-2.0.1/src/lib/devices/CECBusDevice.h libcec-2.0.3/src/lib/devices/CECBusDevice.h --- libcec-2.0.1/src/lib/devices/CECBusDevice.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/devices/CECBusDevice.h 2012-10-31 14:58:41.000000000 +0000 @@ -206,7 +206,7 @@ virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false); virtual void SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion = CEC_VERSION_1_4); virtual void ResetDeviceStatus(void); - virtual bool TransmitPoll(const cec_logical_address destination, bool bIsReply); + virtual bool TransmitPoll(const cec_logical_address destination, bool bUpdateDeviceStatus); virtual void HandlePoll(const cec_logical_address destination); virtual void HandlePollFrom(const cec_logical_address initiator); virtual bool HandleReceiveFailed(void); @@ -224,6 +224,7 @@ virtual bool TransmitImageViewOn(void); virtual bool TransmitInactiveSource(void); virtual bool TransmitPendingActiveSourceCommands(void); + virtual void SetActiveRoute(uint16_t iRoute); virtual void SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = CEC_INVALID_PHYSICAL_ADDRESS); virtual bool PowerOn(const cec_logical_address initiator); diff -Nru libcec-2.0.1/src/lib/devices/CECDeviceMap.cpp libcec-2.0.3/src/lib/devices/CECDeviceMap.cpp --- libcec-2.0.1/src/lib/devices/CECDeviceMap.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/devices/CECDeviceMap.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -39,6 +39,7 @@ #include "CECTuner.h" #include "CECTV.h" #include "lib/CECProcessor.h" +#include "lib/CECTypeUtils.h" using namespace std; using namespace CEC; @@ -266,3 +267,19 @@ addresses.Set((*it)->GetLogicalAddress()); return addresses; } + +void CCECDeviceMap::GetChildrenOf(CECDEVICEVEC& devices, CCECBusDevice* device) const +{ + devices.clear(); + if (!device) + return; + + uint16_t iPA = device->GetCurrentPhysicalAddress(); + + for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++) + { + uint16_t iCurrentPA = it->second->GetCurrentPhysicalAddress(); + if (CCECTypeUtils::PhysicalAddressIsIncluded(iPA, iCurrentPA)) + devices.push_back(it->second); + } +} diff -Nru libcec-2.0.1/src/lib/devices/CECDeviceMap.h libcec-2.0.3/src/lib/devices/CECDeviceMap.h --- libcec-2.0.1/src/lib/devices/CECDeviceMap.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/devices/CECDeviceMap.h 2012-10-31 14:58:41.000000000 +0000 @@ -62,6 +62,7 @@ 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 GetChildrenOf(CECDEVICEVEC& devices, CCECBusDevice* device) const; void GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const; void GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const; diff -Nru libcec-2.0.1/src/lib/implementations/ANCommandHandler.cpp libcec-2.0.3/src/lib/implementations/ANCommandHandler.cpp --- libcec-2.0.1/src/lib/implementations/ANCommandHandler.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/ANCommandHandler.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -68,23 +68,9 @@ cec_keypress key; key.duration = CEC_BUTTON_TIMEOUT; - key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN; + key.keycode = (cec_user_control_code)command.parameters[0]; - switch (command.parameters[0]) - { - case CEC_USER_CONTROL_CODE_AN_RETURN: - key.keycode = client && client->GetClientVersion() >= CEC_CLIENT_VERSION_1_5_0 ? - CEC_USER_CONTROL_CODE_AN_RETURN : - CEC_USER_CONTROL_CODE_EXIT; - break; - case CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST: - key.keycode = CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST; - break; - default: - break; - } - - if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client) + if (client) client->AddKey(key); return COMMAND_HANDLED; diff -Nru libcec-2.0.1/src/lib/implementations/CECCommandHandler.cpp libcec-2.0.3/src/lib/implementations/CECCommandHandler.cpp --- libcec-2.0.1/src/lib/implementations/CECCommandHandler.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/CECCommandHandler.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -48,6 +48,7 @@ #define LIB_CEC m_busDevice->GetProcessor()->GetLib() #define ToString(p) CCECTypeUtils::ToString(p) +#define REQUEST_POWER_STATUS_TIMEOUT 5000 CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice, int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */, @@ -62,7 +63,8 @@ m_bHandlerInited(false), m_bOPTSendDeckStatusUpdateOnActiveSource(false), m_vendorId(CEC_VENDOR_UNKNOWN), - m_iActiveSourcePending(iActiveSourcePending) + m_iActiveSourcePending(iActiveSourcePending), + m_iPowerStatusRequested(0) { } @@ -486,13 +488,11 @@ { if (command.parameters.size == 4) { - uint16_t iOldAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); - uint16_t iNewAddress = ((uint16_t)command.parameters[2] << 8) | ((uint16_t)command.parameters[3]); - CCECBusDevice *device = GetDevice(command.initiator); if (device) { - device->SetStreamPath(iNewAddress, iOldAddress); + uint16_t iNewAddress = ((uint16_t)command.parameters[2] << 8) | ((uint16_t)command.parameters[3]); + device->SetActiveRoute(iNewAddress); return COMMAND_HANDLED; } } @@ -504,11 +504,11 @@ { if (command.parameters.size == 2) { - uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); - CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress); + CCECBusDevice *device = GetDevice(command.initiator); if (device) { - device->MarkAsActiveSource(); + uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); + device->SetActiveRoute(iNewAddress); return COMMAND_HANDLED; } } @@ -568,9 +568,6 @@ uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%x) sets stream path to physical address %04x", ToString(command.initiator), command.initiator, iStreamAddress); - // a device will only change the stream path when it's powered on - m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON); - /* one of the device handled by libCEC has been made active */ CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress); if (device && device->IsHandledByLibCEC()) @@ -676,13 +673,15 @@ 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) + command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION|| + command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION) { bool bPowerOn(true); - // CEC_USER_CONTROL_CODE_POWER operates as a toggle + // CEC_USER_CONTROL_CODE_POWER and CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION operate as a toggle // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not - if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER) + if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER || + command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION) { cec_power_status status = device->GetCurrentPowerStatus(); bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); @@ -699,6 +698,12 @@ device->SetMenuState(CEC_MENU_STATE_DEACTIVATED); } } + else if (command.parameters[0] != CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION) + { + // we're not marked as active source, but the tv sends keypresses to us, so assume it forgot to activate us + if (!device->IsActiveSource() && command.initiator == CECDEVICE_TV) + device->ActivateSource(); + } return COMMAND_HANDLED; } @@ -721,6 +726,15 @@ return CEC_ABORT_REASON_INVALID_OPERAND; } +int CCECCommandHandler::HandleVendorRemoteButtonDown(const cec_command& command) +{ + if (command.parameters.size == 0) + return CEC_ABORT_REASON_INVALID_OPERAND; + + LIB_CEC->AddLog(CEC_LOG_NOTICE, "unhandled vendor remote button received with keycode %x", command.parameters[0]); + return COMMAND_HANDLED; +} + void CCECCommandHandler::UnhandledCommand(const cec_command &command, const cec_abort_reason reason) { if (m_processor->IsHandledByLibCEC(command.destination)) @@ -815,7 +829,14 @@ cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON); - return Transmit(command, false, false); + if (Transmit(command, false, false)) + { + CCECBusDevice* dest = m_processor->GetDevice(iDestination); + if (dest && dest->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON) + dest->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); + return true; + } + return false; } bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -868,6 +889,16 @@ bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) { + if (iDestination == CECDEVICE_TV) + { + int64_t now(GetTimeMs()); + if (now - m_iPowerStatusRequested < REQUEST_POWER_STATUS_TIMEOUT) + return true; + m_iPowerStatusRequested = now; + } + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting power status of '%s' (%X)", m_busDevice->GetLogicalAddressName(), iDestination); + cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS); @@ -1100,7 +1131,9 @@ { if ((bReturn = m_processor->Transmit(command, bIsReply)) == true) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted"); +#endif if (bExpectResponse) { bReturn = m_busDevice->WaitForOpcode(expectedResponse); @@ -1126,7 +1159,9 @@ if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending) return false; +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command"); +#endif } } diff -Nru libcec-2.0.1/src/lib/implementations/CECCommandHandler.h libcec-2.0.3/src/lib/implementations/CECCommandHandler.h --- libcec-2.0.1/src/lib/implementations/CECCommandHandler.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/CECCommandHandler.h 2012-10-31 14:58:41.000000000 +0000 @@ -135,8 +135,8 @@ virtual int HandleUserControlPressed(const cec_command &command); virtual int HandleUserControlRelease(const cec_command &command); virtual int HandleVendorCommand(const cec_command &command); - virtual int HandleVendorRemoteButtonDown(const cec_command & UNUSED(command)) { return CEC_ABORT_REASON_REFUSED; } - virtual int HandleVendorRemoteButtonUp(const cec_command & UNUSED(command)) { return CEC_ABORT_REASON_REFUSED; } + virtual int HandleVendorRemoteButtonDown(const cec_command& command); + virtual int HandleVendorRemoteButtonUp(const cec_command & UNUSED(command)) { return COMMAND_HANDLED; } virtual void UnhandledCommand(const cec_command &command, const cec_abort_reason reason); virtual void VendorPreActivateSourceHook(void) {}; @@ -152,15 +152,16 @@ virtual bool SourceSwitchAllowed(void) { return true; } - CCECBusDevice * m_busDevice; - CCECProcessor * m_processor; - int32_t m_iTransmitTimeout; - int32_t m_iTransmitWait; - int8_t m_iTransmitRetries; - bool m_bHandlerInited; - bool m_bOPTSendDeckStatusUpdateOnActiveSource; - cec_vendor_id m_vendorId; - int64_t m_iActiveSourcePending; - PLATFORM::CMutex m_mutex; + CCECBusDevice * m_busDevice; + CCECProcessor * m_processor; + int32_t m_iTransmitTimeout; + int32_t m_iTransmitWait; + int8_t m_iTransmitRetries; + bool m_bHandlerInited; + bool m_bOPTSendDeckStatusUpdateOnActiveSource; + cec_vendor_id m_vendorId; + int64_t m_iActiveSourcePending; + PLATFORM::CMutex m_mutex; + int64_t m_iPowerStatusRequested; }; }; diff -Nru libcec-2.0.1/src/lib/implementations/SLCommandHandler.cpp libcec-2.0.3/src/lib/implementations/SLCommandHandler.cpp --- libcec-2.0.1/src/lib/implementations/SLCommandHandler.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/SLCommandHandler.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -115,19 +115,13 @@ 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->GetCurrentPhysicalAddress() && primary->IsActiveSource()); - CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress); if (device) device->MarkAsActiveSource(); - if (bSendPowerOffState) + { - { - CLockObject lock(m_SLMutex); - m_bActiveSourceSent = false; - } - primary->TransmitPowerState(CECDEVICE_TV, false); + CLockObject lock(m_SLMutex); + m_bActiveSourceSent = false; } return COMMAND_HANDLED; @@ -273,7 +267,7 @@ if (!device || command.parameters.size == 0) return CEC_ABORT_REASON_INVALID_OPERAND; - device->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG); + device->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG); if (command.parameters[0] == CEC_STATUS_REQUEST_ON) { device->TransmitDeckStatus(command.initiator, true); diff -Nru libcec-2.0.1/src/lib/implementations/SLCommandHandler.h libcec-2.0.3/src/lib/implementations/SLCommandHandler.h --- libcec-2.0.1/src/lib/implementations/SLCommandHandler.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/SLCommandHandler.h 2012-10-31 14:58:41.000000000 +0000 @@ -68,6 +68,7 @@ int HandleStandby(const cec_command &command); bool TransmitMenuState(const cec_logical_address UNUSED(iInitiator), const cec_logical_address UNUSED(iDestination), cec_menu_state UNUSED(menuState), bool UNUSED(bIsReply)) { return true; } bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); + int HandleVendorRemoteButtonUp(const cec_command& command) { return HandleUserControlRelease(command); } void ResetSLState(void); bool SLInitialised(void); diff -Nru libcec-2.0.1/src/lib/implementations/VLCommandHandler.cpp libcec-2.0.3/src/lib/implementations/VLCommandHandler.cpp --- libcec-2.0.1/src/lib/implementations/VLCommandHandler.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/VLCommandHandler.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -45,8 +45,6 @@ #define VL_POWERED_DOWN 0x01 #define VL_UNKNOWN1 0x06 -#define VL_REQUEST_POWER_STATUS_TIMEOUT 5000 - using namespace CEC; using namespace PLATFORM; @@ -63,8 +61,7 @@ int64_t iActiveSourcePending /* = 0 */) : CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending), m_iPowerUpEventReceived(0), - m_bCapabilitiesSent(false), - m_iPowerStatusRequested(0) + m_bCapabilitiesSent(false) { m_vendorId = CEC_VENDOR_PANASONIC; } @@ -203,6 +200,7 @@ { CLockObject lock(m_mutex); m_iPowerUpEventReceived = 0; + m_bCapabilitiesSent = false; } return CCECCommandHandler::HandleStandby(command); @@ -221,14 +219,14 @@ void CVLCommandHandler::SendVendorCommandCapabilities(const cec_logical_address initiator, const cec_logical_address destination) { - cec_command response; - cec_command::Format(response, initiator, destination, CEC_OPCODE_VENDOR_COMMAND); - uint8_t iResponseData[] = {0x10, 0x02, 0xFF, 0xFF, 0x00, 0x05, 0x05, 0x45, 0x55, 0x5c, 0x58, 0x32}; - response.PushArray(12, iResponseData); - - if (Transmit(response, false, true)) + if (PowerUpEventReceived()) { - if (PowerUpEventReceived()) + cec_command response; + cec_command::Format(response, initiator, destination, CEC_OPCODE_VENDOR_COMMAND); + uint8_t iResponseData[] = {0x10, 0x02, 0xFF, 0xFF, 0x00, 0x05, 0x05, 0x45, 0x55, 0x5c, 0x58, 0x32}; + response.PushArray(12, iResponseData); + + if (Transmit(response, false, true)) { CLockObject lock(m_mutex); m_bCapabilitiesSent = true; @@ -252,16 +250,9 @@ return CEC_ABORT_REASON_INVALID_OPERAND; } -bool CVLCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) -{ - m_iPowerStatusRequested = GetTimeMs(); - return CCECCommandHandler::TransmitRequestPowerStatus(iInitiator, iDestination, bWaitForResponse); -} - bool CVLCommandHandler::SourceSwitchAllowed(void) { - int64_t now(GetTimeMs()); - if (!PowerUpEventReceived() && now - m_iPowerStatusRequested > VL_REQUEST_POWER_STATUS_TIMEOUT) + if (!PowerUpEventReceived()) TransmitRequestPowerStatus(m_processor->GetPrimaryDevice()->GetLogicalAddress(), CECDEVICE_TV, false); return PowerUpEventReceived(); diff -Nru libcec-2.0.1/src/lib/implementations/VLCommandHandler.h libcec-2.0.3/src/lib/implementations/VLCommandHandler.h --- libcec-2.0.1/src/lib/implementations/VLCommandHandler.h 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/lib/implementations/VLCommandHandler.h 2012-10-31 14:58:41.000000000 +0000 @@ -55,7 +55,6 @@ bool PowerUpEventReceived(void); bool SupportsDeviceType(const cec_device_type type) const { return type != CEC_DEVICE_TYPE_RECORDING_DEVICE; }; cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type == CEC_DEVICE_TYPE_RECORDING_DEVICE ? CEC_DEVICE_TYPE_PLAYBACK_DEVICE : type; } - bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true); bool SourceSwitchAllowed(void); @@ -67,6 +66,5 @@ PLATFORM::CMutex m_mutex; uint64_t m_iPowerUpEventReceived; bool m_bCapabilitiesSent; - int64_t m_iPowerStatusRequested; }; }; diff -Nru libcec-2.0.1/src/testclient/main.cpp libcec-2.0.3/src/testclient/main.cpp --- libcec-2.0.1/src/testclient/main.cpp 2012-10-11 15:14:12.000000000 +0000 +++ libcec-2.0.3/src/testclient/main.cpp 2012-10-31 14:58:41.000000000 +0000 @@ -48,7 +48,7 @@ using namespace std; using namespace PLATFORM; -#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_2_0_1; +#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_2_0_3; #include "../../include/cecloader.h"