+libcec (1.7.2-1) unstable; urgency=low
+
+ * changed/added:
+ * display a warning message if libCEC was not compiled with adapter
+ detection for the target platform
+ * panasonic: added a vendor command for panasonic that will enable routing
+ of some more buttons on the remote (guide, text, ...)
+ * standby command won't be forwarded more than once every 10 seconds
+ * added vendor ids for Akai, AOC, Benq, Daewoo, Grundig, Medion, Sharp and
+ Vizio
+ * cec-client: don't display debug output by default in 'cec-client -l'
+
+ * interface changes:
+ * added a callback for clients that is called when a source is
+ (de)activated, so the client can respond to this action
+ * added cec_command::PushArray()
+
+ * fixed:
+ * command forwarding. fixes player not going into standby mode
+ * missing virtual keyword in CCECCommandHandler::
+ GetReplacementDeviceType()
+ * replace the handler (if needed) in GetHandler()
+ * reply with abort reason 'invalid operand' to vendor commands that we
+ don't understand
+ * changed all Handle...() commands to return a cec_abort_reason and send
+ the correct abort reason to the initiator as a response to directly
+ addressed messages
+ * changed 'couldn't change the ackmask: the connection is closed' into a
+ debug message
+ * don't send active source commands when the physical address is invalid or
+ unknown
+ * set the power status of a device to 'powered on' after it sends a stream
+ path change. can save an unneeded power state update request
+ * removed dupe code around delayed activate source commands. check for
+ delayed active source commands every 5 seconds instead of 15 seconds.
+ * panasonic: reset m_bPowerUpEventReceived in CVLCommandHandler when the
+ device lets us know it went into standby mode. fixes possibly failed
+ active source switches after it succeeded once
+ * panasonic: fixed delayed source switch for panasonic
+ * panasonic: mark the tv as powered up once it sends the audiomode request
+ * set the physical address of each device controlled by a CCECClient if
+ it's valid
+ * Windows could get stuck in a loop in case there an error occured while
+ reading registry entries
+ * ABI fixes (binary compat with v1.2 for Windows and v1.5.2 for others)
+ * replace the handler directly after getting the vendor id of a device when
+ registering a client
+ * copy the class member values of the old handler when creating a new
+ command handler, or a delayed activate source will get lost when the
+ handler is switched
+ * cec-client: wrong client version
+ * Makefile cleanups. don't link cec-client and cec-config against libudev
+ and liblockdev
+ * pin libcec to the same version as libcec1
+ * LibCecSharp: update the local configuration after connecting
+ * LibCecSharp: better handling of callbacks
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Wed, 27 Jun 2012 02:06:00 +0100
+
libcec (1.7.1-1) unstable; urgency=low
* changed/added:
-AC_INIT([libcec], 1:7:0)
+AC_PREREQ(2.59)
+AC_INIT([libcec], [1:7:0], [http://libcec.pulse-eight.com/])
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
AC_PROG_CXX
AC_PROG_LIBTOOL
+# search for pthread, required by all targets
+AC_SEARCH_LIBS([pthread_create],[pthread],,
+ AC_MSG_ERROR("required library 'pthread' is missing"))
+
+# search for dlopen, required by all targets
+AC_SEARCH_LIBS([dlopen], [dl],
+ [test "$ac_cv_search_dlopen" = "none required" || LIBS_DL=$ac_cv_search_dlopen],
+ AC_MSG_ERROR("required library 'dl' is missing"))
+
+
+# platform specific libs, required by all targets
+case "${host}" in
+ *-*-linux*)
+ LIBS+=" -lrt"
+ ;;
+ *-apple-darwin*)
+ ;;
+ *-freebsd*)
+ ;;
+esac
+
+libs_client=$LIBS
+
+# search for udev and lockdev, only required by libCEC
has_libudev="yes"
case "${host}" in
*-*-linux*)
- PKG_CHECK_MODULES([UDEV],[libudev],,[has_libudev="no"]; AC_MSG_WARN("library 'udev' is missing - adapter detection will not be available"))
- AC_CHECK_HEADER(lockdev.h,, AC_MSG_ERROR("required library 'liblockdev' is missing"))
- LIBS+=" -lrt -llockdev"
+ PKG_CHECK_MODULES([UDEV],[libudev],,
+ [has_libudev="no"]; AC_MSG_WARN("library 'udev' is missing - adapter detection will not be available"))
+
+ AC_CHECK_HEADER(lockdev.h,,
+ AC_MSG_ERROR("required library 'liblockdev' is missing"))
+
+ LIBS+=" -llockdev"
;;
*-apple-darwin*)
has_libudev="no";
;;
esac
+# mark udev as available if it was found, so we can include adapter autodetection code
if test "x$has_libudev" != "xno"; then
INCLUDES="$INCLUDES $UDEV_CFLAGS";LIBS="$LIBS $UDEV_LIBS"
AC_DEFINE([HAVE_LIBUDEV],[1],["Define to 1 if libudev is installed"])
REQUIRES="udev"
fi
-AC_SEARCH_LIBS([pthread_create],[pthread],, AC_MSG_ERROR("required library 'pthread' is missing"))
-
-libs_pre_dl=$LIBS
- AC_SEARCH_LIBS(dlopen, [dl],
- [test "$ac_cv_search_dlopen" = "none required" || LIBS_DL=$ac_cv_search_dlopen],
- AC_MSG_ERROR("required library 'dl' is missing"))
- AC_SUBST([LIBS_DL])
-LIBS=$libs_pre_dl
+LIBS_LIBCEC=$LIBS
+LIBS=$libs_client
CXXFLAGS="-fPIC -Wall -Wextra -Wno-missing-field-initializers $CXXFLAGS"
-AC_SUBST(REQUIRES)
+AC_SUBST([REQUIRES])
+AC_SUBST([LIBS])
+AC_SUBST([LIBS_LIBCEC])
AC_CONFIG_FILES([src/lib/libcec.pc])
AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile src/cec-config/Makefile])
+libcec (1.7.2-1) unstable; urgency=low
+
+ * changed/added:
+ * display a warning message if libCEC was not compiled with adapter
+ detection for the target platform
+ * panasonic: added a vendor command for panasonic that will enable routing
+ of some more buttons on the remote (guide, text, ...)
+ * standby command won't be forwarded more than once every 10 seconds
+ * added vendor ids for Akai, AOC, Benq, Daewoo, Grundig, Medion, Sharp and
+ Vizio
+ * cec-client: don't display debug output by default in 'cec-client -l'
+
+ * interface changes:
+ * added a callback for clients that is called when a source is
+ (de)activated, so the client can respond to this action
+ * added cec_command::PushArray()
+
+ * fixed:
+ * command forwarding. fixes player not going into standby mode
+ * missing virtual keyword in CCECCommandHandler::
+ GetReplacementDeviceType()
+ * replace the handler (if needed) in GetHandler()
+ * reply with abort reason 'invalid operand' to vendor commands that we
+ don't understand
+ * changed all Handle...() commands to return a cec_abort_reason and send
+ the correct abort reason to the initiator as a response to directly
+ addressed messages
+ * changed 'couldn't change the ackmask: the connection is closed' into a
+ debug message
+ * don't send active source commands when the physical address is invalid or
+ unknown
+ * set the power status of a device to 'powered on' after it sends a stream
+ path change. can save an unneeded power state update request
+ * removed dupe code around delayed activate source commands. check for
+ delayed active source commands every 5 seconds instead of 15 seconds.
+ * panasonic: reset m_bPowerUpEventReceived in CVLCommandHandler when the
+ device lets us know it went into standby mode. fixes possibly failed
+ active source switches after it succeeded once
+ * panasonic: fixed delayed source switch for panasonic
+ * panasonic: mark the tv as powered up once it sends the audiomode request
+ * set the physical address of each device controlled by a CCECClient if
+ it's valid
+ * Windows could get stuck in a loop in case there an error occured while
+ reading registry entries
+ * ABI fixes (binary compat with v1.2 for Windows and v1.5.2 for others)
+ * replace the handler directly after getting the vendor id of a device when
+ registering a client
+ * copy the class member values of the old handler when creating a new
+ command handler, or a delayed activate source will get lost when the
+ handler is switched
+ * cec-client: wrong client version
+ * Makefile cleanups. don't link cec-client and cec-config against libudev
+ and liblockdev
+ * pin libcec to the same version as libcec1
+ * LibCecSharp: update the local configuration after connecting
+ * LibCecSharp: better handling of callbacks
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Wed, 27 Jun 2012 02:06:00 +0100
+
libcec (1.7.1-1) unstable; urgency=low
* changed/added:
Package: libcec
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1
+Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1 (= ${binary:Version})
Description: Transitional package libcec.
Package: libcec
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1
+Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1 (= ${binary:Version})
Description: Transitional package libcec.
#include "cectypes.h"
-#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_7_0
+#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_7_1
namespace CEC
{
*/
virtual void Close(void) = 0;
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if !defined(_WIN32) && !defined(_WIN64)
/*!
* @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used.
* @param cbParam Parameter to pass to callback methods.
* @return True when enabled, false otherwise.
*/
virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0;
+#endif
/*!
* @brief Try to find all connected CEC adapters. Only implemented on Linux and Windows at the moment.
*/
virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS) = 0;
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if !defined(_WIN32) && !defined(_WIN64)
/*!
* @deprecated Use libcec_configuration instead.
* @brief Enable physical address detection (if the connected adapter supports this).
* @return True when changed, false otherwise.
*/
virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort) = 0;
+#endif
/*!
* @brief Power on the connected CEC capable devices.
*/
virtual cec_power_status GetDevicePowerStatus(cec_logical_address iLogicalAddress) = 0;
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if !defined(_WIN32) && !defined(_WIN64)
/*!
* @brief Get the physical address of the device with the given logical address.
* @param iLogicalAddress The device to get the vendor id for.
* @return The physical address or 0 if it wasn't found.
*/
virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0;
+#endif
/*!
* @brief Sends a POLL message to a device.
* @return True when the device was found, false otherwise
*/
virtual bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = 10000) = 0;
+
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if defined(_WIN32) || defined(_WIN64)
+ /*!
+ * @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used.
+ * @param cbParam Parameter to pass to callback methods.
+ * @param callbacks The callbacks to set.
+ * @return True when enabled, false otherwise.
+ */
+ virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0;
+
+ /*!
+ * @deprecated Use libcec_configuration instead.
+ * @brief Enable physical address detection (if the connected adapter supports this).
+ * @return True when physical address detection was enabled, false otherwise.
+ */
+ virtual bool EnablePhysicalAddressDetection(void) = 0;
+
+ /*!
+ * @brief Changes the active HDMI port.
+ * @param iBaseDevice The device to which this libcec is connected.
+ * @param iPort The new port number.
+ * @return True when changed, false otherwise.
+ */
+ virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort) = 0;
+
+ /*!
+ * @brief Get the physical address of the device with the given logical address.
+ * @param iLogicalAddress The device to get the vendor id for.
+ * @return The physical address or 0 if it wasn't found.
+ */
+ virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0;
+#endif
};
};
* @brief Load the CEC adapter library.
* @param strDeviceName How to present this device to other devices.
* @param deviceTypes The device types to use on the CEC bus.
- * @param iPhysicalAddress The physical address to assume on the bus. If set to 0, libCEC will try to autodetect the address, with the data provided via SetHDMIPort()
* @return An instance of ICECAdapter or NULL on error.
*/
-extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_type_list deviceTypes, uint16_t iPhysicalAddress = 0);
+extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_type_list deviceTypes);
+
+/*!
+ * @deprecated
+ */
+extern "C" DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+
+/*!
+ * @brief Unload the CEC adapter library.
+ */
+extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);
/*!
* @brief Load the CEC adapter library.
*/
extern "C" DECLSPEC bool CECStartBootloader(void);
-/*!
- * @brief Unload the CEC adapter library.
- */
-extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);
-
#endif /* CECEXPORTS_H_ */
#define CEC_SERIAL_DEFAULT_BAUDRATE 38400
#define CEC_CLEAR_INPUT_DEFAULT_WAIT 1000
+#define CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS 5000
+#define CEC_FORWARD_STANDBY_MIN_INTERVAL 10000
+
#define CEC_MIN_LIB_VERSION 1
#define CEC_LIB_VERSION_MAJOR 1
#define CEC_LIB_VERSION_MAJOR_STR "1"
CEC_VENDOR_PHILIPS = 0x00903E,
CEC_VENDOR_SONY = 0x080046,
CEC_VENDOR_TOSHIBA = 0x000039,
+ CEC_VENDOR_AKAI = 0x0020C7,
+ CEC_VENDOR_AOC = 0x002467,
+ CEC_VENDOR_BENQ = 0x8065E9,
+ CEC_VENDOR_DAEWOO = 0x009053,
+ CEC_VENDOR_GRUNDIG = 0x00D0D5,
+ CEC_VENDOR_MEDION = 0x000CB8,
+ CEC_VENDOR_SHARP = 0x08001F,
+ CEC_VENDOR_VIZIO = 0x6B746D,
+
CEC_VENDOR_UNKNOWN = 0
} cec_vendor_id;
int32_t transmit_timeout; /**< the timeout to use in ms */
#ifdef __cplusplus
- cec_command(void)
- {
- Clear();
- }
+ // @todo re-add in v2.0 (breaks ABI)
+ //cec_command(void)
+ //{
+ // Clear();
+ //}
cec_command &operator =(const struct cec_command &command)
{
return CEC_OPCODE_NONE;
}
+
+ void PushArray(size_t len, uint8_t *data)
+ {
+ for (size_t iPtr = 0; iPtr < len; iPtr++)
+ PushBack(data[iPtr]);
+ }
#endif
} cec_command;
typedef int (CEC_CDECL* CBCecConfigurationChangedType)(void *param, const libcec_configuration &);
typedef int (CEC_CDECL* CBCecAlertType)(void *param, const libcec_alert, const libcec_parameter &);
typedef int (CEC_CDECL* CBCecMenuStateChangedType)(void *param, const cec_menu_state);
+typedef void (CEC_CDECL* CBCecSourceActivatedType)(void *param, const cec_logical_address, const uint8_t);
typedef struct ICECCallbacks
{
*/
CBCecMenuStateChangedType CBCecMenuStateChanged;
+ /*!
+ * @brief Called when a source that's handled by this client is activated.
+ * @param logicalAddress The address that was just activated.
+ * @param bActivated 1 when activated, 0 when deactivated.
+ */
+ CBCecSourceActivatedType CBCecSourceActivated;
+
#ifdef __cplusplus
- ICECCallbacks(void) { Clear(); }
- ~ICECCallbacks(void) { Clear(); };
+ // @todo re-add in v2.0 (breaks ABI)
+ // ICECCallbacks(void) { Clear(); }
+ //~ICECCallbacks(void) { Clear(); };
void Clear(void)
{
CBCecConfigurationChanged = NULL;
CBCecAlert = NULL;
CBCecMenuStateChanged = NULL;
+ CBCecSourceActivated = NULL;
}
#endif
} ICECCallbacks;
CEC_CLIENT_VERSION_1_6_1 = 0x1601,
CEC_CLIENT_VERSION_1_6_2 = 0x1602,
CEC_CLIENT_VERSION_1_6_3 = 0x1603,
- CEC_CLIENT_VERSION_1_7_0 = 0x1700
+ CEC_CLIENT_VERSION_1_7_0 = 0x1700,
+ CEC_CLIENT_VERSION_1_7_1 = 0x1701
} cec_client_version;
typedef enum cec_server_version
CEC_SERVER_VERSION_1_6_1 = 0x1601,
CEC_SERVER_VERSION_1_6_2 = 0x1602,
CEC_SERVER_VERSION_1_6_3 = 0x1603,
- CEC_SERVER_VERSION_1_7_0 = 0x1700
+ CEC_SERVER_VERSION_1_7_0 = 0x1700,
+ CEC_SERVER_VERSION_1_7_1 = 0x1701
} cec_server_version;
typedef struct libcec_configuration
uint8_t bMonitorOnly; /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */
#ifdef __cplusplus
- libcec_configuration(void) { Clear(); }
- ~libcec_configuration(void) { Clear(); }
+ // @todo re-add in v2.0 (breaks ABI)
+ // libcec_configuration(void) { Clear(); }
+ //~libcec_configuration(void) { Clear(); }
bool operator==(const libcec_configuration &other) const
{
#endif
} libcec_configuration;
-#ifdef UNUSED
-#elif defined(__GNUC__)
-#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
-#elif defined(__LCLINT__)
-#define UNUSED(x) /*@unused@*/ x
-#else
-#define UNUSED(x) x
-#endif
-
#ifdef __cplusplus
};
};
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""$(SolutionDir)..\include";"$(SolutionDir)..\src\lib\platform\windows""
- PreprocessorDefinitions="_DEBUG"
+ PreprocessorDefinitions="_DEBUG;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""$(SolutionDir)..\include";"$(SolutionDir)..\src\lib\platform\windows""
- PreprocessorDefinitions="_DEBUG"
+ PreprocessorDefinitions="_DEBUG;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""$(SolutionDir)..\include";"$(SolutionDir)..\src\lib\platform\windows""
- PreprocessorDefinitions="NDEBUG"
+ PreprocessorDefinitions="NDEBUG;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""$(SolutionDir)..\include";"$(SolutionDir)..\src\lib\platform\windows""
- PreprocessorDefinitions="NDEBUG"
+ PreprocessorDefinitions="NDEBUG;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Config = new LibCECConfiguration();
Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
Config.DeviceName = "CEC Tester";
- Config.ClientVersion = CecClientVersion.Version1_6_2;
+ Config.ClientVersion = CecClientVersion.Version1_7_1;
Config.SetCallbacks(this);
LogLevel = (int)CecLogLevel.All;
Lib = new LibCecSharp(Config);
- Console.WriteLine("CEC Parser created - libcec version " + Lib.ToString(Config.ServerVersion));
+ Console.WriteLine("CEC Parser created - libCEC version " + Lib.ToString(Config.ServerVersion));
}
public override int ReceiveCommand(CecCommand command)
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.0.0")]
-[assembly: AssemblyFileVersion("1.7.0.0")]
+[assembly: AssemblyVersion("1.7.1.0")]
+[assembly: AssemblyFileVersion("1.7.1.0")]
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
-[assembly:AssemblyVersionAttribute("1.7.0.0")];
+[assembly:AssemblyVersionAttribute("1.7.1.0")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
* http://www.pulse-eight.net/
*/
-#include <windows.h>
+#include "../lib/platform/threads/mutex.h"
#include <vcclr.h>
#include <msclr/marshal.h>
#include "../../include/cec.h"
+#include <vector>
#using <System.dll>
public enum class CecVendorId
{
- Samsung = 0x00F0,
- LG = 0xE091,
- Panasonic = 0x8045,
- Pioneer = 0xE036,
- Onkyo = 0x09B0,
- Yamaha = 0xA0DE,
- Philips = 0x903E,
+ Samsung = 0x0000F0,
+ LG = 0x00E091,
+ Panasonic = 0x008045,
+ Pioneer = 0x00E036,
+ Onkyo = 0x0009B0,
+ Yamaha = 0x00A0DE,
+ Philips = 0x00903E,
Sony = 0x080046,
+ Toshiba = 0x000039,
+ Akai = 0x0020C7,
+ Benq = 0x8065E9,
+ Daewoo = 0x009053,
+ Grundig = 0x00D0D5,
+ Medion = 0x000CB8,
+ Sharp = 0x08001F,
+ Vizio = 0x6B746D,
Unknown = 0
};
Version1_5_3 = 0x1503,
Version1_6_0 = 0x1600,
Version1_6_1 = 0x1601,
- Version1_6_2 = 0x1602,
- Version1_6_3 = 0x1603,
- Version1_7_0 = 0x1700
+ Version1_6_2 = 0x1602,
+ Version1_6_3 = 0x1603,
+ Version1_7_0 = 0x1700,
+ Version1_7_1 = 0x1701
};
public enum class CecServerVersion
Version1_5_3 = 0x1503,
Version1_6_0 = 0x1600,
Version1_6_1 = 0x1601,
- Version1_6_2 = 0x1602,
- Version1_6_3 = 0x1603,
- Version1_7_0 = 0x1700
+ Version1_6_2 = 0x1602,
+ Version1_6_3 = 0x1603,
+ Version1_7_0 = 0x1700,
+ Version1_7_1 = 0x1701
};
public ref class CecAdapter
typedef int (__stdcall *CONFIGCB) (const CEC::libcec_configuration &config);
typedef int (__stdcall *ALERTCB) (const CEC::libcec_alert, const CEC::libcec_parameter &data);
typedef int (__stdcall *MENUCB) (const CEC::cec_menu_state newVal);
+ typedef void (__stdcall *ACTICB) (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
- static LOGCB g_logCB;
- static KEYCB g_keyCB;
- static COMMANDCB g_commandCB;
- static CONFIGCB g_configCB;
- static ALERTCB g_alertCB;
- static MENUCB g_menuCB;
- static CEC::ICECCallbacks g_cecCallbacks;
+ typedef struct
+ {
+ LOGCB logCB;
+ KEYCB keyCB;
+ COMMANDCB commandCB;
+ CONFIGCB configCB;
+ ALERTCB alertCB;
+ MENUCB menuCB;
+ ACTICB sourceActivatedCB;
+ } UnmanagedCecCallbacks;
+
+ static PLATFORM::CMutex g_callbackMutex;
+ static std::vector<UnmanagedCecCallbacks> g_unmanagedCallbacks;
+ static CEC::ICECCallbacks g_cecCallbacks;
int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message)
{
- if (g_logCB)
- return g_logCB(message);
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].logCB(message);
+ }
return 0;
}
int CecKeyPressCB(void *cbParam, const CEC::cec_keypress &key)
{
- if (g_keyCB)
- return g_keyCB(key);
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].keyCB(key);
+ }
return 0;
}
int CecCommandCB(void *cbParam, const CEC::cec_command &command)
{
- if (g_commandCB)
- return g_commandCB(command);
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].commandCB(command);
+ }
return 0;
}
int CecConfigCB(void *cbParam, const CEC::libcec_configuration &config)
{
- if (g_configCB)
- return g_configCB(config);
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].configCB(config);
+ }
return 0;
}
int CecAlertCB(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter &data)
{
- if (g_alertCB)
- return g_alertCB(alert, data);
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].alertCB(alert, data);
+ }
return 0;
}
int CecMenuCB(void *cbParam, const CEC::cec_menu_state newVal)
{
- if (g_menuCB)
- return g_menuCB(newVal);
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].menuCB(newVal);
+ }
return 0;
}
+ void CecSourceActivatedCB(void *cbParam, const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].sourceActivatedCB(logicalAddress, bActivated);
+ }
+ }
+
#pragma managed
// delegates for the unmanaged callback methods
- public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &);
- public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &);
- public delegate int CecCommandManagedDelegate(const CEC::cec_command &);
- public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &);
- public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &);
- public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state newVal);
+ public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &);
+ public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &);
+ public delegate int CecCommandManagedDelegate(const CEC::cec_command &);
+ public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &);
+ public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &);
+ public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state newVal);
+ public delegate void CecSourceActivatedManagedDelegate(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
+
+ void AssignCallbacks()
+ {
+ g_cecCallbacks.CBCecLogMessage = CecLogMessageCB;
+ g_cecCallbacks.CBCecKeyPress = CecKeyPressCB;
+ g_cecCallbacks.CBCecCommand = CecCommandCB;
+ g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB;
+ g_cecCallbacks.CBCecAlert = CecAlertCB;
+ g_cecCallbacks.CBCecMenuStateChanged = CecMenuCB;
+ g_cecCallbacks.CBCecSourceActivated = CecSourceActivatedCB;
+ }
// callback method interface
public ref class CecCallbackMethods
public:
CecCallbackMethods(void)
{
+ m_iCallbackPtr = -1;
+ AssignCallbacks();
m_bHasCallbacks = false;
m_bDelegatesCreated = false;
}
- ~CecCallbackMethods(void)
- {
- DestroyDelegates();
- }
+ ~CecCallbackMethods(void)
+ {
+ DestroyDelegates();
+ }
+
+ size_t GetCallbackPtr(void)
+ {
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ return m_iCallbackPtr;
+ }
protected:
!CecCallbackMethods(void)
return 0;
}
+ virtual void SourceActivated(CecLogicalAddress logicalAddress, bool bActivated)
+ {
+ }
+
protected:
// managed callback methods
int CecLogMessageManaged(const CEC::cec_log_message &message)
return iReturn;
}
+ void CecSourceActivatedManaged(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
+ {
+ if (m_bHasCallbacks)
+ m_callbacks->SourceActivated((CecLogicalAddress)logicalAddress, bActivated == 1);
+ }
+
void DestroyDelegates()
{
m_bHasCallbacks = false;
m_commandGCHandle.Free();
m_alertGCHandle.Free();
m_menuGCHandle.Free();
+ m_sourceActivatedGCHandle.Free();
}
}
msclr::interop::marshal_context ^ context = gcnew msclr::interop::marshal_context();
// create the delegate method for the log message callback
- m_logMessageDelegate = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged);
- m_logMessageGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate);
- g_logCB = static_cast<LOGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer());
- g_cecCallbacks.CBCecLogMessage = CecLogMessageCB;
+ m_logMessageDelegate = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged);
+ m_logMessageGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate);
+ m_logMessageCallback = static_cast<LOGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer());
// create the delegate method for the keypress callback
- m_keypressDelegate = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged);
- m_keypressGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate);
- g_keyCB = static_cast<KEYCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer());
- g_cecCallbacks.CBCecKeyPress = CecKeyPressCB;
+ m_keypressDelegate = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged);
+ m_keypressGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate);
+ m_keypressCallback = static_cast<KEYCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer());
// create the delegate method for the command callback
- m_commandDelegate = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged);
- m_commandGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate);
- g_commandCB = static_cast<COMMANDCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer());
- g_cecCallbacks.CBCecCommand = CecCommandCB;
+ m_commandDelegate = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged);
+ m_commandGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate);
+ m_commandCallback = static_cast<COMMANDCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer());
// create the delegate method for the configuration change callback
- m_configDelegate = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged);
- m_configGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate);
- g_configCB = static_cast<CONFIGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer());
- g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB;
+ m_configDelegate = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged);
+ m_configGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate);
+ m_configCallback = static_cast<CONFIGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer());
// create the delegate method for the alert callback
- m_alertDelegate = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged);
- m_alertGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate);
- g_alertCB = static_cast<ALERTCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer());
- g_cecCallbacks.CBCecAlert = CecAlertCB;
+ m_alertDelegate = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged);
+ m_alertGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate);
+ m_alertCallback = static_cast<ALERTCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer());
// create the delegate method for the menu callback
- m_menuDelegate = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged);
- m_menuGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate);
- g_menuCB = static_cast<MENUCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer());
- g_cecCallbacks.CBCecMenuStateChanged = CecMenuCB;
+ m_menuDelegate = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged);
+ m_menuGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate);
+ m_menuCallback = static_cast<MENUCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer());
+
+ // create the delegate method for the source activated callback
+ m_sourceActivatedDelegate = gcnew CecSourceActivatedManagedDelegate(this, &CecCallbackMethods::CecSourceActivatedManaged);
+ m_sourceActivatedGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_sourceActivatedDelegate);
+ m_sourceActivatedCallback = static_cast<ACTICB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_sourceActivatedDelegate).ToPointer());
delete context;
- m_bDelegatesCreated = true;
+
+ UnmanagedCecCallbacks unmanagedCallbacks;
+ unmanagedCallbacks.logCB = m_logMessageCallback;
+ unmanagedCallbacks.keyCB = m_keypressCallback;
+ unmanagedCallbacks.commandCB = m_commandCallback;
+ unmanagedCallbacks.configCB = m_configCallback;
+ unmanagedCallbacks.alertCB = m_alertCallback;
+ unmanagedCallbacks.menuCB = m_menuCallback;
+ unmanagedCallbacks.sourceActivatedCB = m_sourceActivatedCallback;
+
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ g_unmanagedCallbacks.push_back(unmanagedCallbacks);
+ m_iCallbackPtr = g_unmanagedCallbacks.size() - 1;
+ m_bDelegatesCreated = true;
}
}
CecAlertManagedDelegate ^ m_alertDelegate;
static System::Runtime::InteropServices::GCHandle m_alertGCHandle;
- CONFIGCB m_alertCallback;
+ ALERTCB m_alertCallback;
CecMenuManagedDelegate ^ m_menuDelegate;
static System::Runtime::InteropServices::GCHandle m_menuGCHandle;
MENUCB m_menuCallback;
+ CecSourceActivatedManagedDelegate ^ m_sourceActivatedDelegate;
+ static System::Runtime::InteropServices::GCHandle m_sourceActivatedGCHandle;
+ ACTICB m_sourceActivatedCallback;
+
CecCallbackMethods ^ m_callbacks;
bool m_bHasCallbacks;
bool m_bDelegatesCreated;
+ size_t m_iCallbackPtr;
};
}
ConvertConfiguration(context, config, libCecConfig);
m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig);
+ config->Update(libCecConfig);
delete context;
return m_libCec != NULL;
}
if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3)
- {
- config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
- }
+ config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
- config.callbacks = &g_cecCallbacks;
+ config.callbacks = &g_cecCallbacks;
}
public:
virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
{
if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
- return m_libCec->EnableCallbacks(NULL, &g_cecCallbacks);
+ return m_libCec->EnableCallbacks((void*)GetCallbackPtr(), &g_cecCallbacks);
return false;
}
Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
Config.DeviceName = "CEC Config";
Config.GetSettingsFromROM = true;
- Config.ClientVersion = CecClientVersion.Version1_5_1;
+ Config.ClientVersion = CecClientVersion.Version1_7_1;
Callbacks = new CecCallbackWrapper(this);
Config.SetCallbacks(Callbacks);
LoadXMLConfiguration(ref Config);
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.0.0")]
-[assembly: AssemblyFileVersion("1.7.0.0")]
+[assembly: AssemblyVersion("1.7.1.0")]
+[assembly: AssemblyFileVersion("1.7.1.0")]
cec_config_SOURCES = cec-config.cpp
cec_config_CPPFLAGS = -I@abs_top_srcdir@/include
-cec_config_LDFLAGS = @LIBS_DL@
\ No newline at end of file
+cec_config_LDFLAGS = @LIBS@
int main (int UNUSED(argc), char *UNUSED(argv[]))
{
+ g_callbacks.Clear();
+ g_config.Clear();
PrintToStdOut("=== USB-CEC Adapter Configuration ===\n");
if (!OpenConnection())
return 1;
m_bInitialised(false),
m_bRegistered(false),
m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
- m_buttontime(0)
+ m_buttontime(0),
+ m_iPreventForwardingPowerOffCommand(0)
{
+ m_configuration.Clear();
// set the initial configuration
SetConfiguration(configuration);
}
// make the primary device the active source if the option is set
if (m_configuration.bActivateSource == 1)
- GetPrimaryDevice()->ActivateSource();
+ GetPrimaryDevice()->ActivateSource(500);
return true;
}
iPort > CEC_MAX_HDMI_PORTNUMBER)
return bReturn;
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
// update the configuration
{
if (!types.IsSet(type))
types.Add(type);
}
+ m_processor->GetTV()->MarkHandlerReady();
// set the new type list
m_configuration.deviceTypes = types;
void CCECClient::AddCommand(const cec_command &command)
{
- CLockObject lock(m_mutex);
+ // don't forward the standby opcode more than once every 10 seconds
+ if (command.opcode == CEC_OPCODE_STANDBY)
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPreventForwardingPowerOffCommand != 0 &&
+ m_iPreventForwardingPowerOffCommand > GetTimeMs())
+ return;
+ else
+ m_iPreventForwardingPowerOffCommand = GetTimeMs() + CEC_FORWARD_STANDBY_MIN_INTERVAL;
+ }
- LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode);
+ if (command.destination == CECDEVICE_BROADCAST || GetLogicalAddresses().IsSet(command.destination))
+ {
+ CLockObject lock(m_mutex);
- if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand)
- m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command);
- else if (!m_commandBuffer.Push(command))
- LIB_CEC->AddLog(CEC_LOG_WARNING, "command buffer is full");
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode);
+
+ if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand)
+ m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command);
+ else if (!m_commandBuffer.Push(command))
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "command buffer is full");
+ }
}
int CCECClient::MenuStateChanged(const cec_menu_state newState)
return 0;
}
+void CCECClient::SourceActivated(const cec_logical_address logicalAddress)
+{
+ CLockObject lock(m_mutex);
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source activated: %s (%x)", ToString(logicalAddress), logicalAddress);
+
+ if (m_configuration.callbacks &&
+ m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_7_1 &&
+ m_configuration.callbacks->CBCecSourceActivated)
+ m_configuration.callbacks->CBCecSourceActivated(m_configuration.callbackParam, logicalAddress, 1);
+}
+
+void CCECClient::SourceDeactivated(const cec_logical_address logicalAddress)
+{
+ CLockObject lock(m_mutex);
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source deactivated: %s (%x)", ToString(logicalAddress), logicalAddress);
+
+ if (m_configuration.callbacks &&
+ m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_7_1 &&
+ m_configuration.callbacks->CBCecSourceActivated)
+ m_configuration.callbacks->CBCecSourceActivated(m_configuration.callbackParam, logicalAddress, 0);
+}
+
void CCECClient::Alert(const libcec_alert type, const libcec_parameter ¶m)
{
CLockObject lock(m_mutex);
bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress)
{
if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - not setting invalid physical address %04x", __FUNCTION__, iPhysicalAddress);
return false;
+ }
// reconfigure all devices
cec_logical_address reactivateSource(CECDEVICE_UNKNOWN);
virtual void AddKey(const cec_keypress &key);
virtual void SetCurrentButton(const cec_user_control_code iButtonCode);
virtual void CheckKeypressTimeout(void);
+ virtual void SourceActivated(const cec_logical_address logicalAddress);
+ virtual void SourceDeactivated(const cec_logical_address logicalAddress);
protected:
/*!
PLATFORM::CMutex m_logMutex; /**< mutex that is held when sending a log message back to the client */
cec_user_control_code m_iCurrentButton; /**< the control code of the button that's currently held down (if any) */
int64_t m_buttontime; /**< the timestamp when the button was pressed (in seconds since epoch), or 0 if none was pressed. */
+ int64_t m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */
PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer; /**< @deprecated will be removed in v2.0. buffer for log messages */
PLATFORM::SyncedBuffer<cec_keypress> m_keyBuffer; /**< @deprecated will be removed in v2.0. buffer for keypresses */
PLATFORM::SyncedBuffer<cec_command> m_commandBuffer; /**< @deprecated will be removed in v2.0. buffer for commands */
using namespace PLATFORM;
#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
-#define ACTIVE_SOURCE_CHECK_TIMEOUT 15000
+#define ACTIVE_SOURCE_CHECK_INTERVAL 500
#define ToString(x) CCECTypeUtils::ToString(x)
it->second->ReplaceHandler(true);
}
-void CCECProcessor::CheckPendingActiveSource(void)
-{
- if (!CECInitialised())
- return;
-
- // check each device
- for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
- {
- if (it->second->GetHandler()->ActiveSourcePending())
- it->second->ActivateSource();
- }
-}
-
bool CCECProcessor::OnCommandReceived(const cec_command &command)
{
return m_inBuffer.Push(command);
{
m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
- cec_command command;
- CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_TIMEOUT);
+ cec_command command; command.Clear();
+ CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL);
// as long as we're not being stopped and the connection is open
while (!IsStopped() && m_communication->IsOpen())
// check whether we need to activate a source, if it failed before
if (activeSourceCheck.TimeLeft() == 0)
{
- CheckPendingActiveSource();
- activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_TIMEOUT);
+ if (CECInitialised())
+ TransmitPendingActiveSourceCommands();
+ activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL);
}
}
}
m_iLastTransmission = GetTimeMs();
// set the number of tries
iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
+ initiator->MarkHandlerReady();
}
// and try to send the command
bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
{
// stream path changes are sent by the TV
- return GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
+ bool bReturn = GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
+ GetTV()->MarkHandlerReady();
+ return bReturn;
}
bool CCECProcessor::CanPersistConfiguration(void)
}
// ensure that we know the vendor id of the TV
- GetTV()->GetVendorId(CECDEVICE_UNREGISTERED);
+ CCECBusDevice *tv = GetTV();
+ tv->GetVendorId(CECDEVICE_UNREGISTERED);
+ tv->ReplaceHandler(false);
// unregister the client first if it's already been marked as registered
if (client->IsRegistered())
m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
{
+ // set the physical address of the device at this LA
+ if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+ (*it)->SetPhysicalAddress(configuration.iPhysicalAddress);
+
// replace a previous client
CLockObject lock(m_mutex);
m_clients.erase((*it)->GetLogicalAddress());
// get the settings from the rom
if (configuration.bGetSettingsFromROM == 1)
{
- libcec_configuration config;
+ libcec_configuration config; config.Clear();
m_communication->GetConfiguration(config);
CLockObject lock(m_mutex);
CCECCommandHandler *handler = GetTV()->GetHandler();
if (handler)
handler->InitHandler();
+ GetTV()->MarkHandlerReady();
}
return bReturn;
void SetCECInitialised(bool bSetTo = true);
void ReplaceHandlers(void);
- void CheckPendingActiveSource(void);
bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
bool SetAckMask(uint16_t iMask);
return "Sony";
case CEC_VENDOR_TOSHIBA:
return "Toshiba";
+ case CEC_VENDOR_AKAI:
+ return "Akai";
+ case CEC_VENDOR_AOC:
+ return "AOC";
+ case CEC_VENDOR_BENQ:
+ return "Benq";
+ case CEC_VENDOR_DAEWOO:
+ return "Daewoo";
+ case CEC_VENDOR_GRUNDIG:
+ return "Grundig";
+ case CEC_VENDOR_MEDION:
+ return "Medion";
+ case CEC_VENDOR_SHARP:
+ return "Sharp";
+ case CEC_VENDOR_VIZIO:
+ return "Vizio";
default:
return "Unknown";
}
return "1.6.3";
case CEC_CLIENT_VERSION_1_7_0:
return "1.7.0";
+ case CEC_CLIENT_VERSION_1_7_1:
+ return "1.7.1";
default:
return "Unknown";
}
return "1.6.3";
case CEC_SERVER_VERSION_1_7_0:
return "1.7.0";
+ case CEC_SERVER_VERSION_1_7_1:
+ return "1.7.1";
default:
return "Unknown";
}
}
+
+ static const char *ToString(const cec_abort_reason reason)
+ {
+ switch(reason)
+ {
+ case CEC_ABORT_REASON_UNRECOGNIZED_OPCODE:
+ return "unrecognised opcode";
+ case CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND:
+ return "not in correct mode to respond";
+ case CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE:
+ return "cannot provide source";
+ case CEC_ABORT_REASON_INVALID_OPERAND:
+ return "invalid operand";
+ case CEC_ABORT_REASON_REFUSED:
+ return "refused";
+ default:
+ return "unknown";
+ }
+ }
};
}
int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
{
+ if (!CUSBCECAdapterDetection::CanAutodetect())
+ {
+ AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with adapter detection code for this target, so the path to the COM port has to be provided to libCEC");
+ return 0;
+ }
+
return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
}
(*it)->AddLog(message);
}
+void CLibCEC::AddCommand(const cec_command &command)
+{
+ // send the command to all clients
+ for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->AddCommand(command);
+}
+
void CLibCEC::Alert(const libcec_alert type, const libcec_parameter ¶m)
{
// send the alert to all clients
return static_cast< void* > (lib);
}
-void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */)
+void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types)
{
- libcec_configuration configuration;
+ libcec_configuration configuration; configuration.Clear();
// client version < 1.5.0
snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
configuration.deviceTypes = types;
- configuration.iPhysicalAddress = iPhysicalAddress;
+ configuration.iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS;
if (configuration.deviceTypes.IsEmpty())
configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
return CECInitialise(&configuration);
}
+void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress /* = CEC::CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
+{
+ libcec_configuration configuration; configuration.Clear();
+
+ // client version < 1.5.0
+ snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
+ configuration.iPhysicalAddress = iPhysicalAddress;
+ configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+
+ return CECInitialise(&configuration);
+}
+
bool CECStartBootloader(void)
{
bool bReturn(false);
// no longer being used
void CLibCEC::AddKey(const cec_keypress &UNUSED(key)) {}
-void CLibCEC::AddCommand(const cec_command &UNUSED(command)) {}
void CLibCEC::ConfigurationChanged(const libcec_configuration &UNUSED(config)) {}
void CLibCEC::SetCurrentButton(cec_user_control_code UNUSED(iButtonCode)) {}
CLibCEC *CLibCEC::GetInstance(void) { return NULL; }
void AddLog(const cec_log_level level, const char *strFormat, ...);
static void AddKey(void) {} //UNUSED
static void AddKey(const cec_keypress &key); //UNUSED
- static void AddCommand(const cec_command &command); //UNUSED
+ void AddCommand(const cec_command &command);
static void ConfigurationChanged(const libcec_configuration &config); //UNUSED
static void SetCurrentButton(cec_user_control_code iButtonCode); //UNUSED
void CheckKeypressTimeout(void);
platform/adl/adl-edid.cpp \
platform/nvidia/nv-edid.cpp
-libcec_la_LDFLAGS = @LIBS@ -version-info @VERSION@
+libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@
libcec_la_CPPFLAGS = -I@abs_top_srcdir@/include
return true;
}
- LIB_CEC->AddLog(CEC_LOG_ERROR, "couldn't change the ackmask: the connection is closed");
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "couldn't change the ackmask: the connection is closed");
return false;
}
}
#endif
+bool CUSBCECAdapterDetection::CanAutodetect(void)
+{
+#if defined(__APPLE__) || defined(HAVE_LIBUDEV) || defined(__WINDOWS__) || defined(__FreeBSD__)
+ return true;
+#else
+ return false;
+#endif
+}
+
uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
{
uint8_t iFound(0);
class CUSBCECAdapterDetection
{
public:
- static uint8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ static uint8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ static bool CanAutodetect(void);
};
};
CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com) :
PLATFORM::CThread(),
m_com(com),
- m_iNextMessage(0) {}
+ m_iNextMessage(0)
+ {
+ m_currentCECFrame.Clear();
+ }
+
virtual ~CCECAdapterMessageQueue(void);
/*!
#include "CECBusDevice.h"
#include "../CECProcessor.h"
+#include "../CECClient.h"
#include "../implementations/ANCommandHandler.h"
#include "../implementations/CECCommandHandler.h"
#include "../implementations/SLCommandHandler.h"
m_deviceStatus (CEC_DEVICE_STATUS_UNKNOWN),
m_iHandlerUseCount (0),
m_bAwaitingReceiveFailed(false),
- m_bVendorIdRequested (false)
+ m_bVendorIdRequested (false),
+ m_waitForResponse (new CWaitForResponse)
{
m_handler = new CCECCommandHandler(this);
CCECBusDevice::~CCECBusDevice(void)
{
DELETE_AND_NULL(m_handler);
+ DELETE_AND_NULL(m_waitForResponse);
}
bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
if (CCECCommandHandler::HasSpecificHandler(m_vendor))
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+
+ int32_t iTransmitTimeout = m_handler->m_iTransmitTimeout;
+ int32_t iTransmitWait = m_handler->m_iTransmitWait;
+ int8_t iTransmitRetries = m_handler->m_iTransmitRetries;
+ int64_t iActiveSourcePending = m_handler->m_iActiveSourcePending;
+
DELETE_AND_NULL(m_handler);
switch (m_vendor)
{
case CEC_VENDOR_SAMSUNG:
- m_handler = new CANCommandHandler(this);
+ m_handler = new CANCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
case CEC_VENDOR_LG:
- m_handler = new CSLCommandHandler(this);
+ m_handler = new CSLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
case CEC_VENDOR_PANASONIC:
- m_handler = new CVLCommandHandler(this);
+ m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
default:
- m_handler = new CCECCommandHandler(this);
+ m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
break;
}
return true;
}
+CCECCommandHandler *CCECBusDevice::GetHandler(void)
+{
+ ReplaceHandler(false);
+ MarkBusy();
+ return m_handler;
+}
+
bool CCECBusDevice::HandleCommand(const cec_command &command)
{
bool bHandled(false);
// signal threads that are waiting for a reponse
MarkBusy();
- m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
+ SignalOpcode(cec_command::GetResponseOpcode(opcode));
MarkReady();
}
m_iLastActive = 0;
m_bVendorIdRequested = false;
m_unsupportedFeatures.clear();
+ m_waitForResponse->Clear();
if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
return bReturn;
}
-bool CCECBusDevice::ActivateSource(void)
+bool CCECBusDevice::ActivateSource(uint64_t iDelay /* = 0 */)
{
MarkAsActiveSource();
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
MarkBusy();
- bool bReturn = m_handler->ActivateSource();
+ bool bReturn(true);
+ if (iDelay == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending active source message for '%s'", ToString(m_iLogicalAddress));
+ bReturn = m_handler->ActivateSource();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "scheduling active source message for '%s'", ToString(m_iLogicalAddress));
+ m_handler->ScheduleActivateSource(iDelay);
+ }
MarkReady();
return bReturn;
}
void CCECBusDevice::MarkAsActiveSource(void)
{
- CLockObject lock(m_mutex);
- if (!m_bActiveSource)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
- else
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+ bool bWasActivated(false);
+
+ // set the power status to powered on
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+ // mark this device as active source
+ {
+ CLockObject lock(m_mutex);
+ if (!m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasActivated = true;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+
+ m_bActiveSource = true;
+ }
+
+ // mark other devices as inactive sources
CECDEVICEVEC devices;
m_processor->GetDevices()->Get(devices);
for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
(*it)->MarkAsInactiveSource();
- m_bActiveSource = true;
- SetPowerStatus(CEC_POWER_STATUS_ON);
+ if (bWasActivated)
+ {
+ CCECClient *client = GetClient();
+ if (client)
+ client->SourceActivated(m_iLogicalAddress);
+ }
}
void CCECBusDevice::MarkAsInactiveSource(void)
{
+ bool bWasDeactivated(false);
{
CLockObject lock(m_mutex);
if (m_bActiveSource)
+ {
LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasDeactivated = true;
+ }
m_bActiveSource = false;
}
+
+ if (bWasDeactivated)
+ {
+ CCECClient *client = GetClient();
+ if (client)
+ client->SourceDeactivated(m_iLogicalAddress);
+ }
}
bool CCECBusDevice::TransmitActiveSource(void)
{
bool bSendActiveSource(false);
+ uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
{
CLockObject lock(m_mutex);
+ if (!HasValidPhysicalAddress())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X) has an invalid physical address (%04x), not sending active source commands", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ return false;
+ }
+
+ iPhysicalAddress = m_iPhysicalAddress;
+
if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
else if (m_bActiveSource)
if (bSendActiveSource)
{
MarkBusy();
- bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+ bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress);
MarkReady();
}
bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
{
MarkBusy();
- bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
+ bool bReturn = m_handler->ActivateSource(true);
MarkReady();
return bReturn;
}
{
return m_processor->GetClient(m_iLogicalAddress);
}
+
+void CCECBusDevice::SignalOpcode(cec_opcode opcode)
+{
+ m_waitForResponse->Received(opcode);
+}
+
+bool CCECBusDevice::WaitForOpcode(cec_opcode opcode)
+{
+ return m_waitForResponse->Wait(opcode);
+}
#include "../../../include/cectypes.h"
#include <set>
+#include <map>
#include "../platform/threads/mutex.h"
#include "../platform/util/StdString.h"
class CCECTuner;
class CCECTV;
+ class CResponse
+ {
+ public:
+ CResponse(cec_opcode opcode) :
+ m_opcode(opcode){}
+ ~CResponse(void)
+ {
+ Broadcast();
+ }
+
+ bool Wait(uint32_t iTimeout)
+ {
+ return m_event.Wait(iTimeout);
+ }
+
+ void Broadcast(void)
+ {
+ m_event.Broadcast();
+ }
+
+ private:
+ cec_opcode m_opcode;
+ PLATFORM::CEvent m_event;
+ };
+
+ class CWaitForResponse
+ {
+ public:
+ CWaitForResponse(void) {}
+ ~CWaitForResponse(void)
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ PLATFORM::CLockObject lock(m_mutex);
+ for (std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.begin(); it != m_waitingFor.end(); it++)
+ it->second->Broadcast();
+ m_waitingFor.clear();
+ }
+
+ bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT)
+ {
+ CResponse *response = GetEvent(opcode);
+ return response ? response->Wait(iTimeout) : false;
+ }
+
+ void Received(cec_opcode opcode)
+ {
+ CResponse *response = GetEvent(opcode);
+ if (response)
+ response->Broadcast();
+ }
+
+ private:
+ CResponse *GetEvent(cec_opcode opcode)
+ {
+ CResponse *retVal(NULL);
+ {
+ PLATFORM::CLockObject lock(m_mutex);
+ std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
+ if (it != m_waitingFor.end())
+ {
+ retVal = it->second;
+ }
+ else
+ {
+ retVal = new CResponse(opcode);
+ m_waitingFor[opcode] = retVal;
+ }
+ return retVal;
+ }
+ }
+
+ PLATFORM::CMutex m_mutex;
+ std::map<cec_opcode, CResponse*> m_waitingFor;
+ };
+
class CCECBusDevice
{
friend class CCECProcessor;
virtual ~CCECBusDevice(void);
virtual bool ReplaceHandler(bool bActivateSource = true);
- virtual CCECCommandHandler * GetHandler(void) const { return m_handler; };
+
+ // TODO use something smarter than this
+ /*!
+ * @brief Get the command handler for this device. Call MarkHandlerReady() when done with it.
+ * @return The current handler.
+ */
+ virtual CCECCommandHandler * GetHandler(void);
+
+ /*!
+ * @brief To be called after GetHandler(), when no longer using it.
+ */
+ virtual void MarkHandlerReady(void) { MarkReady(); }
+
virtual CCECProcessor * GetProcessor(void) const { return m_processor; }
virtual uint64_t GetLastActive(void) const { return m_iLastActive; }
virtual cec_device_type GetType(void) const { return m_type; }
virtual void SetMenuState(const cec_menu_state state);
virtual bool TransmitMenuState(const cec_logical_address destination);
- virtual bool ActivateSource(void);
+ virtual bool ActivateSource(uint64_t iDelay = 0);
virtual bool IsActiveSource(void) const { return m_bActiveSource; }
virtual bool RequestActiveSource(bool bWaitForResponse = true);
virtual void MarkAsActiveSource(void);
virtual bool TryLogicalAddress(void);
CCECClient * GetClient(void);
+ void SignalOpcode(cec_opcode opcode);
+ bool WaitForOpcode(cec_opcode opcode);
CCECAudioSystem * AsAudioSystem(void);
static CCECAudioSystem * AsAudioSystem(CCECBusDevice *device);
unsigned m_iHandlerUseCount;
bool m_bAwaitingReceiveFailed;
bool m_bVendorIdRequested;
+ CWaitForResponse *m_waitForResponse;
};
};
#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
#define ToString(p) LIB_CEC->ToString(p)
-CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
- CCECCommandHandler(busDevice)
+CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
{
m_vendorId = CEC_VENDOR_SAMSUNG;
m_bOPTSendDeckStatusUpdateOnActiveSource = false;
}
-bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
+int CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
{
- if (m_processor->CECInitialised() && command.parameters.size > 0)
- {
- CCECClient *client = m_processor->GetClient(command.destination);
-
- cec_keypress key;
- key.duration = CEC_BUTTON_TIMEOUT;
- key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+ if (command.parameters.size == 0)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
- 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 (!m_processor->CECInitialised())
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
- if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client)
- client->AddKey(key);
- }
+ CCECClient *client = m_processor->GetClient(command.destination);
+ if (!client)
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
- return true;
-}
+ cec_keypress key;
+ key.duration = CEC_BUTTON_TIMEOUT;
+ key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
-bool CANCommandHandler::HandleCommand(const cec_command &command)
-{
- bool bHandled(false);
- if (m_processor->IsHandledByLibCEC(command.destination))
+ switch (command.parameters[0])
{
- switch(command.opcode)
- {
- case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
- bHandled = true;
- HandleVendorRemoteButtonDown(command);
- break;
- case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
- bHandled = true;
- HandleUserControlRelease(command);
- break;
- default:
- break;
- }
+ 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 (!bHandled)
- bHandled = CCECCommandHandler::HandleCommand(command);
+ if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client)
+ client->AddKey(key);
+
+ return COMMAND_HANDLED;
+}
- return bHandled;
+int CANCommandHandler::HandleVendorRemoteButtonUp(const cec_command &command)
+{
+ return HandleUserControlRelease(command);
}
bool CANCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
class CANCommandHandler : public CCECCommandHandler
{
public:
- CANCommandHandler(CCECBusDevice *busDevice);
+ CANCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
virtual ~CANCommandHandler(void) {};
- bool HandleCommand(const cec_command &command);
+ int HandleVendorRemoteButtonDown(const cec_command &command);
+ int HandleVendorRemoteButtonUp(const cec_command &command);
protected:
- bool HandleVendorRemoteButtonDown(const cec_command &command);
bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
};
};
#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
#define ToString(p) CCECTypeUtils::ToString(p)
-CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
+CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
m_busDevice(busDevice),
m_processor(m_busDevice->GetProcessor()),
- m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
- m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
- m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
+ m_iTransmitTimeout(iTransmitTimeout),
+ m_iTransmitWait(iTransmitWait),
+ m_iTransmitRetries(iTransmitRetries),
m_bHandlerInited(false),
m_bOPTSendDeckStatusUpdateOnActiveSource(false),
m_vendorId(CEC_VENDOR_UNKNOWN),
- m_waitForResponse(new CWaitForResponse),
- m_bActiveSourcePending(false)
+ m_iActiveSourcePending(iActiveSourcePending)
{
}
-CCECCommandHandler::~CCECCommandHandler(void)
-{
- DELETE_AND_NULL(m_waitForResponse);
-}
-
bool CCECCommandHandler::HandleCommand(const cec_command &command)
{
if (command.opcode_set == 0)
return HandlePoll(command);
- bool bHandled(true);
+ int iHandled(CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
- CCECClient *client = m_busDevice->GetClient();
- if (client)
- client->AddCommand(command);
+ LIB_CEC->AddCommand(command);
switch(command.opcode)
{
case CEC_OPCODE_REPORT_POWER_STATUS:
- HandleReportPowerStatus(command);
+ iHandled = HandleReportPowerStatus(command);
break;
case CEC_OPCODE_CEC_VERSION:
- HandleDeviceCecVersion(command);
+ iHandled = HandleDeviceCecVersion(command);
break;
case CEC_OPCODE_SET_MENU_LANGUAGE:
- HandleSetMenuLanguage(command);
+ iHandled = HandleSetMenuLanguage(command);
break;
case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
- if (m_processor->CECInitialised())
- HandleGivePhysicalAddress(command);
+ iHandled = HandleGivePhysicalAddress(command);
break;
case CEC_OPCODE_GET_MENU_LANGUAGE:
- if (m_processor->CECInitialised())
- HandleGiveMenuLanguage(command);
+ iHandled = HandleGiveMenuLanguage(command);
break;
case CEC_OPCODE_GIVE_OSD_NAME:
- if (m_processor->CECInitialised())
- HandleGiveOSDName(command);
+ iHandled = HandleGiveOSDName(command);
break;
case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
- if (m_processor->CECInitialised())
- HandleGiveDeviceVendorId(command);
+ iHandled = HandleGiveDeviceVendorId(command);
break;
case CEC_OPCODE_DEVICE_VENDOR_ID:
- HandleDeviceVendorId(command);
+ iHandled = HandleDeviceVendorId(command);
break;
case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
- HandleDeviceVendorCommandWithId(command);
+ iHandled = HandleDeviceVendorCommandWithId(command);
break;
case CEC_OPCODE_GIVE_DECK_STATUS:
- if (m_processor->CECInitialised())
- HandleGiveDeckStatus(command);
+ iHandled = HandleGiveDeckStatus(command);
break;
case CEC_OPCODE_DECK_CONTROL:
- HandleDeckControl(command);
+ iHandled = HandleDeckControl(command);
break;
case CEC_OPCODE_MENU_REQUEST:
- if (m_processor->CECInitialised())
- HandleMenuRequest(command);
+ iHandled = HandleMenuRequest(command);
break;
case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
- if (m_processor->CECInitialised())
- HandleGiveDevicePowerStatus(command);
+ iHandled = HandleGiveDevicePowerStatus(command);
break;
case CEC_OPCODE_GET_CEC_VERSION:
- if (m_processor->CECInitialised())
- HandleGetCecVersion(command);
+ iHandled = HandleGetCecVersion(command);
break;
case CEC_OPCODE_USER_CONTROL_PRESSED:
- if (m_processor->CECInitialised())
- HandleUserControlPressed(command);
+ iHandled = HandleUserControlPressed(command);
break;
case CEC_OPCODE_USER_CONTROL_RELEASE:
- if (m_processor->CECInitialised())
- HandleUserControlRelease(command);
+ iHandled = HandleUserControlRelease(command);
break;
case CEC_OPCODE_GIVE_AUDIO_STATUS:
- if (m_processor->CECInitialised())
- HandleGiveAudioStatus(command);
+ iHandled = HandleGiveAudioStatus(command);
break;
case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
- if (m_processor->CECInitialised())
- HandleGiveSystemAudioModeStatus(command);
+ iHandled = HandleGiveSystemAudioModeStatus(command);
break;
case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
- if (m_processor->CECInitialised())
- HandleSystemAudioModeRequest(command);
+ iHandled = HandleSystemAudioModeRequest(command);
break;
case CEC_OPCODE_REPORT_AUDIO_STATUS:
- HandleReportAudioStatus(command);
+ iHandled = HandleReportAudioStatus(command);
break;
case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
- HandleSystemAudioModeStatus(command);
+ iHandled = HandleSystemAudioModeStatus(command);
break;
case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
- HandleSetSystemAudioMode(command);
+ iHandled = HandleSetSystemAudioMode(command);
break;
case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
- if (m_processor->CECInitialised())
- HandleRequestActiveSource(command);
+ iHandled = HandleRequestActiveSource(command);
break;
case CEC_OPCODE_SET_STREAM_PATH:
- HandleSetStreamPath(command);
+ iHandled = HandleSetStreamPath(command);
break;
case CEC_OPCODE_ROUTING_CHANGE:
- HandleRoutingChange(command);
+ iHandled = HandleRoutingChange(command);
break;
case CEC_OPCODE_ROUTING_INFORMATION:
- HandleRoutingInformation(command);
+ iHandled = HandleRoutingInformation(command);
break;
case CEC_OPCODE_STANDBY:
- if (m_processor->CECInitialised())
- HandleStandby(command);
+ iHandled = HandleStandby(command);
break;
case CEC_OPCODE_ACTIVE_SOURCE:
- HandleActiveSource(command);
+ iHandled = HandleActiveSource(command);
break;
case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
- HandleReportPhysicalAddress(command);
+ iHandled = HandleReportPhysicalAddress(command);
break;
case CEC_OPCODE_SET_OSD_NAME:
- HandleSetOSDName(command);
+ iHandled = HandleSetOSDName(command);
break;
case CEC_OPCODE_IMAGE_VIEW_ON:
- HandleImageViewOn(command);
+ iHandled = HandleImageViewOn(command);
break;
case CEC_OPCODE_TEXT_VIEW_ON:
- HandleTextViewOn(command);
+ iHandled = HandleTextViewOn(command);
break;
case CEC_OPCODE_FEATURE_ABORT:
- HandleFeatureAbort(command);
+ iHandled = HandleFeatureAbort(command);
break;
case CEC_OPCODE_VENDOR_COMMAND:
- HandleVendorCommand(command);
+ iHandled = HandleVendorCommand(command);
+ break;
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
+ iHandled = HandleVendorRemoteButtonDown(command);
+ break;
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
+ iHandled = HandleVendorRemoteButtonUp(command);
break;
case CEC_OPCODE_PLAY:
// libCEC (currently) doesn't need to do anything with this, since player applications handle it
// but it should not respond with a feature abort
+ iHandled = COMMAND_HANDLED;
break;
default:
- bHandled = false;
break;
}
- if (bHandled)
- m_waitForResponse->Received((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode);
+ if (iHandled == COMMAND_HANDLED)
+ m_busDevice->SignalOpcode((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode);
else
- UnhandledCommand(command);
+ UnhandledCommand(command, (cec_abort_reason)iHandled);
- return bHandled;
+ return iHandled == COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleActiveSource(const cec_command &command)
+int CCECCommandHandler::HandleActiveSource(const cec_command &command)
{
if (command.parameters.size == 2)
{
uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
if (device)
+ {
device->MarkAsActiveSource();
+ return COMMAND_HANDLED;
+ }
}
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleDeckControl(const cec_command &command)
+int CCECCommandHandler::HandleDeckControl(const cec_command &command)
{
CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
if (device && command.parameters.size > 0)
{
device->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
- return true;
+ return COMMAND_HANDLED;
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
+int CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
{
if (command.parameters.size == 1)
{
CCECBusDevice *device = GetDevice(command.initiator);
if (device)
device->SetCecVersion((cec_version) command.parameters[0]);
+
+ return COMMAND_HANDLED;
}
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+int CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command & UNUSED(command))
{
- if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
- m_processor->TransmitAbort(command.destination, command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
-
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
+int CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
{
- return SetVendorId(command);
+ SetVendorId(command);
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
+int CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
{
if (command.parameters.size == 2 &&
(command.parameters[1] == CEC_ABORT_REASON_UNRECOGNIZED_OPCODE ||
command.parameters[1] == CEC_ABORT_REASON_REFUSED))
m_processor->GetDevice(command.initiator)->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
- return true;
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
+int CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- return device->TransmitCECVersion(command.initiator);
+ if (device && device->TransmitCECVersion(command.initiator))
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
- if (device)
- return device->TransmitAudioStatus(command.initiator);
+ if (device && device->TransmitAudioStatus(command.initiator))
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
- if (device)
- return device->TransmitDeckStatus(command.initiator);
+ if (device && device->TransmitDeckStatus(command.initiator))
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- return device->TransmitPowerState(command.initiator);
+ if (device && device->TransmitPowerState(command.initiator))
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
+int CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- return device->TransmitVendorID(command.initiator);
+ if (device && device->TransmitVendorID(command.initiator))
+ return COMMAND_HANDLED;
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
+int CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- return device->TransmitOSDName(command.initiator);
+ if (device && device->TransmitOSDName(command.initiator))
+ return COMMAND_HANDLED;
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
+int CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- return device->TransmitPhysicalAddress();
+ if (device && device->TransmitPhysicalAddress())
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
+int CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *device = GetDevice(command.destination);
- if (device)
- return device->TransmitSetMenuLanguage(command.initiator);
+ if (device && device->TransmitSetMenuLanguage(command.initiator))
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
- if (device)
- return device->TransmitSystemAudioModeStatus(command.initiator);
+ if (device && device->TransmitSystemAudioModeStatus(command.initiator))
+ return COMMAND_HANDLED;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
+int CCECCommandHandler::HandleImageViewOn(const cec_command &command)
{
m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
- return true;
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
+int CCECCommandHandler::HandleMenuRequest(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
}
}
- return device->TransmitMenuState(command.initiator);
+ if (device->TransmitMenuState(command.initiator))
+ return COMMAND_HANDLED;
}
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
bool CCECCommandHandler::HandlePoll(const cec_command &command)
return true;
}
-bool CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
+int CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
{
if (command.parameters.size == 1)
{
if (device)
{
device->SetAudioStatus(command.parameters[0]);
- return true;
+ return COMMAND_HANDLED;
}
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
+int CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
{
if (command.parameters.size == 3)
{
uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
SetPhysicalAddress(command.initiator, iNewAddress);
+ return COMMAND_HANDLED;
}
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
+int CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
{
if (command.parameters.size == 1)
{
CCECBusDevice *device = GetDevice(command.initiator);
if (device)
+ {
device->SetPowerStatus((cec_power_status) command.parameters[0]);
+ return COMMAND_HANDLED;
+ }
}
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
+int CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
{
if (m_processor->CECInitialised())
{
vector<CCECBusDevice *> devices;
for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++)
devices[iDevicePtr]->TransmitActiveSource();
-
- return true;
}
- return false;
+
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleRoutingChange(const cec_command &command)
+int CCECCommandHandler::HandleRoutingChange(const cec_command &command)
{
if (command.parameters.size == 4)
{
CCECBusDevice *device = GetDevice(command.initiator);
if (device)
+ {
device->SetStreamPath(iNewAddress, iOldAddress);
+ return COMMAND_HANDLED;
+ }
}
- return true;
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
+int CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
{
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);
if (device)
+ {
device->MarkAsActiveSource();
+ return COMMAND_HANDLED;
+ }
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
+int CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
{
if (command.parameters.size == 3)
{
language.language[iPtr] = command.parameters[iPtr];
language.language[3] = 0;
device->SetMenuLanguage(language);
- return true;
+ return COMMAND_HANDLED;
}
}
- return false;
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleSetOSDName(const cec_command &command)
+int CCECCommandHandler::HandleSetOSDName(const cec_command &command)
{
if (command.parameters.size > 0)
{
CStdString strName(buf);
device->SetOSDName(strName);
- return true;
+ return COMMAND_HANDLED;
}
}
- return false;
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
+int CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
{
- if (m_processor->CECInitialised() && command.parameters.size >= 2)
+ if (!m_processor->CECInitialised())
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ if (command.parameters.size >= 2)
{
uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
- LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
+ 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())
+ {
device->ActivateSource();
+ return COMMAND_HANDLED;
+ }
}
- return false;
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
+int CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
{
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
{
CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress);
if (newActiveDevice)
newActiveDevice->MarkAsActiveSource();
- return device->TransmitSetSystemAudioMode(command.initiator);
+ if (device->TransmitSetSystemAudioMode(command.initiator))
+ return COMMAND_HANDLED;
}
else
{
device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
- return device->TransmitSetSystemAudioMode(command.initiator);
+ if (device->TransmitSetSystemAudioMode(command.initiator))
+ return COMMAND_HANDLED;
}
}
}
- return false;
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CCECCommandHandler::HandleStandby(const cec_command &command)
+int CCECCommandHandler::HandleStandby(const cec_command &command)
{
CCECBusDevice *device = GetDevice(command.initiator);
if (device)
device->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
- return true;
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
+int CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
{
if (command.parameters.size == 1)
{
if (device)
{
device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
- return true;
+ return COMMAND_HANDLED;
}
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
+int CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
{
if (command.parameters.size == 1)
{
if (device)
{
device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
- return true;
+ return COMMAND_HANDLED;
}
}
- return false;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
+int CCECCommandHandler::HandleTextViewOn(const cec_command &command)
{
m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
- return true;
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
+int CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
{
- if (m_processor->CECInitialised() &&
- m_processor->IsHandledByLibCEC(command.destination) &&
- command.parameters.size > 0)
- {
- CCECBusDevice *device = GetDevice(command.destination);
- if (!device)
- return true;
+ if (!m_processor->CECInitialised() ||
+ !m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
- CCECClient *client = device->GetClient();
- if (client)
- client->AddKey();
+ if (command.parameters.size == 0)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
- if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
- client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (!device)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
- if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
- command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
- {
- bool bPowerOn(true);
- if (!device)
- return true;
+ CCECClient *client = device->GetClient();
+ if (client)
+ client->AddKey();
- // CEC_USER_CONTROL_CODE_POWER operates as a toggle
- // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
- if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER)
- {
- cec_power_status status = device->GetCurrentPowerStatus();
- bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
- }
+ if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
+ client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
- if (bPowerOn)
- {
- device->ActivateSource();
- }
- else
- {
- device->MarkAsInactiveSource();
- device->TransmitInactiveSource();
- device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
- }
+ if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
+ command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
+ {
+ bool bPowerOn(true);
+
+ // CEC_USER_CONTROL_CODE_POWER operates as a toggle
+ // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
+ if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER)
+ {
+ cec_power_status status = device->GetCurrentPowerStatus();
+ bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
}
- return true;
+ if (bPowerOn)
+ {
+ device->ActivateSource();
+ }
+ else
+ {
+ device->MarkAsInactiveSource();
+ device->TransmitInactiveSource();
+ device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+ }
}
- return false;
+
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
+int CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
{
+ if (!m_processor->CECInitialised() ||
+ !m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
CCECClient *client = m_processor->GetClient(command.destination);
if (client)
client->AddKey();
- return true;
+
+ return COMMAND_HANDLED;
}
-bool CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command))
+int CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command))
{
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-void CCECCommandHandler::UnhandledCommand(const cec_command &command)
+void CCECCommandHandler::UnhandledCommand(const cec_command &command, const cec_abort_reason reason)
{
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
-
- if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
- m_processor->TransmitAbort(m_busDevice->GetLogicalAddress(), command.initiator, command.opcode, CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
+ if (m_processor->IsHandledByLibCEC(command.destination))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending abort with opcode %02x and reason '%s' to %s", command.opcode, ToString(reason), ToString(command.initiator));
+ m_processor->TransmitAbort(command.destination, command.initiator, command.opcode, reason);
+ }
}
size_t CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted");
if (bExpectResponse)
{
- bReturn = m_waitForResponse->Wait(expectedResponse);
+ bReturn = m_busDevice->WaitForOpcode(expectedResponse);
LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, ToString(expectedResponse));
}
}
return bReturn;
}
-bool CCECCommandHandler::ActivateSource(void)
+bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */)
{
if (m_busDevice->IsActiveSource() &&
- m_busDevice->IsHandledByLibCEC())
+ m_busDevice->IsHandledByLibCEC())
{
{
CLockObject lock(m_mutex);
- m_bActiveSourcePending = false;
+ // check if we need to send a delayed source switch
+ if (bTransmitDelayedCommandsOnly)
+ {
+ if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending)
+ return false;
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+ }
+
+ // clear previous pending active source command
+ m_iActiveSourcePending = 0;
}
+ // update the power state and menu state
m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
- m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+ m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); // TODO: LG
+
+ // power on the TV
+ bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn();
- bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn() ||
- !m_busDevice->TransmitActiveSource() ||
- !m_busDevice->TransmitMenuState(CECDEVICE_TV);
+ // check if we're allowed to switch sources
+ bool bSourceSwitchAllowed = SourceSwitchAllowed();
+ if (!bSourceSwitchAllowed)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler");
- if (!bActiveSourceFailed)
+ // switch sources (if allowed)
+ if (!bActiveSourceFailed && bSourceSwitchAllowed)
{
- CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
- if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
- bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV);
+ bActiveSourceFailed = !m_busDevice->TransmitActiveSource() ||
+ !m_busDevice->TransmitMenuState(CECDEVICE_TV);
+
+ // update the deck status for playback devices
+ if (!bActiveSourceFailed)
+ {
+ CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
+ if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
+ bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV);
+ }
}
- if (bActiveSourceFailed)
+ // retry later
+ if (bActiveSourceFailed || !bSourceSwitchAllowed)
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName());
CLockObject lock(m_mutex);
- m_bActiveSourcePending = true;
+ m_iActiveSourcePending = GetTimeMs() + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
return false;
}
+ // mark the handler as initialised
+ CLockObject lock(m_mutex);
m_bHandlerInited = true;
}
return true;
}
-void CCECCommandHandler::SignalOpcode(cec_opcode opcode)
-{
- m_waitForResponse->Received(opcode);
-}
-
-bool CCECCommandHandler::ActiveSourcePending(void)
+void CCECCommandHandler::ScheduleActivateSource(uint64_t iDelay)
{
CLockObject lock(m_mutex);
- return m_bActiveSourcePending;
+ m_iActiveSourcePending = GetTimeMs() + iDelay;
}
#include "../../../include/cectypes.h"
#include <vector>
-#include <map>
#include "../platform/threads/mutex.h"
#include "../platform/util/StdString.h"
namespace CEC
{
+ #define COMMAND_HANDLED 0xFF
+
class CCECProcessor;
class CCECBusDevice;
- class CResponse
- {
- public:
- CResponse(cec_opcode opcode) :
- m_opcode(opcode){}
- ~CResponse(void)
- {
- Broadcast();
- }
-
- bool Wait(uint32_t iTimeout)
- {
- return m_event.Wait(iTimeout);
- }
-
- void Broadcast(void)
- {
- m_event.Broadcast();
- }
-
- private:
- cec_opcode m_opcode;
- PLATFORM::CEvent m_event;
- };
-
- class CWaitForResponse
- {
- public:
- CWaitForResponse(void) {}
- ~CWaitForResponse(void)
- {
- PLATFORM::CLockObject lock(m_mutex);
- m_waitingFor.clear();
- }
-
- bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT)
- {
- CResponse *response = GetEvent(opcode);
- return response ? response->Wait(iTimeout) : false;
- }
-
- void Received(cec_opcode opcode)
- {
- CResponse *response = GetEvent(opcode);
- if (response)
- response->Broadcast();
- }
-
- private:
- CResponse *GetEvent(cec_opcode opcode)
- {
- CResponse *retVal(NULL);
- {
- PLATFORM::CLockObject lock(m_mutex);
- std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
- if (it != m_waitingFor.end())
- {
- retVal = it->second;
- }
- else
- {
- retVal = new CResponse(opcode);
- m_waitingFor[opcode] = retVal;
- }
- return retVal;
- }
- }
-
- PLATFORM::CMutex m_mutex;
- std::map<cec_opcode, CResponse*> m_waitingFor;
- };
-
class CCECCommandHandler
{
+ friend class CCECBusDevice;
+
public:
- CCECCommandHandler(CCECBusDevice *busDevice);
- virtual ~CCECCommandHandler(void);
+ CCECCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CCECCommandHandler(void) {};
virtual bool HandleCommand(const cec_command &command);
virtual cec_vendor_id GetVendorId(void) { return m_vendorId; };
static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC;}
virtual bool InitHandler(void) { return true; }
- virtual bool ActivateSource(void);
+ virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; }
virtual bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true);
virtual bool TransmitSetStreamPath(uint16_t iStreamPath);
virtual bool SendDeckStatusUpdateOnActiveSource(void) const { return m_bOPTSendDeckStatusUpdateOnActiveSource; };
- virtual bool TransmitPendingActiveSourceCommands(void) { return true; }
- virtual void SignalOpcode(cec_opcode opcode);
+ virtual void ScheduleActivateSource(uint64_t iDelay);
- virtual bool ActiveSourcePending(void);
virtual bool SupportsDeviceType(const cec_device_type UNUSED(type)) const { return true; };
- cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; }
+ virtual cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; }
protected:
- virtual bool HandleActiveSource(const cec_command &command);
- virtual bool HandleDeckControl(const cec_command &command);
- virtual bool HandleDeviceCecVersion(const cec_command &command);
- virtual bool HandleDeviceVendorCommandWithId(const cec_command &command);
- virtual bool HandleDeviceVendorId(const cec_command &command);
- virtual bool HandleFeatureAbort(const cec_command &command);
- virtual bool HandleGetCecVersion(const cec_command &command);
- virtual bool HandleGiveAudioStatus(const cec_command &command);
- virtual bool HandleGiveDeckStatus(const cec_command &command);
- virtual bool HandleGiveDevicePowerStatus(const cec_command &command);
- virtual bool HandleGiveDeviceVendorId(const cec_command &command);
- virtual bool HandleGiveOSDName(const cec_command &command);
- virtual bool HandleGivePhysicalAddress(const cec_command &command);
- virtual bool HandleGiveMenuLanguage(const cec_command &command);
- virtual bool HandleGiveSystemAudioModeStatus(const cec_command &command);
- virtual bool HandleImageViewOn(const cec_command &command);
- virtual bool HandleMenuRequest(const cec_command &command);
+ virtual int HandleActiveSource(const cec_command &command);
+ virtual int HandleDeckControl(const cec_command &command);
+ virtual int HandleDeviceCecVersion(const cec_command &command);
+ virtual int HandleDeviceVendorCommandWithId(const cec_command &command);
+ virtual int HandleDeviceVendorId(const cec_command &command);
+ virtual int HandleFeatureAbort(const cec_command &command);
+ virtual int HandleGetCecVersion(const cec_command &command);
+ virtual int HandleGiveAudioStatus(const cec_command &command);
+ virtual int HandleGiveDeckStatus(const cec_command &command);
+ virtual int HandleGiveDevicePowerStatus(const cec_command &command);
+ virtual int HandleGiveDeviceVendorId(const cec_command &command);
+ virtual int HandleGiveOSDName(const cec_command &command);
+ virtual int HandleGivePhysicalAddress(const cec_command &command);
+ virtual int HandleGiveMenuLanguage(const cec_command &command);
+ virtual int HandleGiveSystemAudioModeStatus(const cec_command &command);
+ virtual int HandleImageViewOn(const cec_command &command);
+ virtual int HandleMenuRequest(const cec_command &command);
virtual bool HandlePoll(const cec_command &command);
- virtual bool HandleReportAudioStatus(const cec_command &command);
- virtual bool HandleReportPhysicalAddress(const cec_command &command);
- virtual bool HandleReportPowerStatus(const cec_command &command);
- virtual bool HandleRequestActiveSource(const cec_command &command);
- virtual bool HandleRoutingChange(const cec_command &command);
- virtual bool HandleRoutingInformation(const cec_command &command);
- virtual bool HandleSetMenuLanguage(const cec_command &command);
- virtual bool HandleSetOSDName(const cec_command &command);
- virtual bool HandleSetStreamPath(const cec_command &command);
- virtual bool HandleSystemAudioModeRequest(const cec_command &command);
- virtual bool HandleStandby(const cec_command &command);
- virtual bool HandleSystemAudioModeStatus(const cec_command &command);
- virtual bool HandleSetSystemAudioMode(const cec_command &command);
- virtual bool HandleTextViewOn(const cec_command &command);
- virtual bool HandleUserControlPressed(const cec_command &command);
- virtual bool HandleUserControlRelease(const cec_command &command);
- virtual bool HandleVendorCommand(const cec_command &command);
- virtual void UnhandledCommand(const cec_command &command);
+ virtual int HandleReportAudioStatus(const cec_command &command);
+ virtual int HandleReportPhysicalAddress(const cec_command &command);
+ virtual int HandleReportPowerStatus(const cec_command &command);
+ virtual int HandleRequestActiveSource(const cec_command &command);
+ virtual int HandleRoutingChange(const cec_command &command);
+ virtual int HandleRoutingInformation(const cec_command &command);
+ virtual int HandleSetMenuLanguage(const cec_command &command);
+ virtual int HandleSetOSDName(const cec_command &command);
+ virtual int HandleSetStreamPath(const cec_command &command);
+ virtual int HandleSystemAudioModeRequest(const cec_command &command);
+ virtual int HandleStandby(const cec_command &command);
+ virtual int HandleSystemAudioModeStatus(const cec_command &command);
+ virtual int HandleSetSystemAudioMode(const cec_command &command);
+ virtual int HandleTextViewOn(const cec_command &command);
+ 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 void UnhandledCommand(const cec_command &command, const cec_abort_reason reason);
virtual size_t GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
virtual CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
virtual bool Transmit(cec_command &command, bool bSuppressWait = false);
+ virtual bool SourceSwitchAllowed(void) { return true; }
+
CCECBusDevice * m_busDevice;
CCECProcessor * m_processor;
int32_t m_iTransmitTimeout;
bool m_bHandlerInited;
bool m_bOPTSendDeckStatusUpdateOnActiveSource;
cec_vendor_id m_vendorId;
- CWaitForResponse *m_waitForResponse;
- bool m_bActiveSourcePending;
+ int64_t m_iActiveSourcePending;
PLATFORM::CMutex m_mutex;
};
};
using namespace CEC;
using namespace PLATFORM;
-CRLCommandHandler::CRLCommandHandler(CCECBusDevice *busDevice) :
- CCECCommandHandler(busDevice)
+CRLCommandHandler::CRLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
{
m_vendorId = CEC_VENDOR_TOSHIBA;
}
class CRLCommandHandler : public CCECCommandHandler
{
public:
- CRLCommandHandler(CCECBusDevice *busDevice);
+ CRLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
virtual ~CRLCommandHandler(void) {};
bool InitHandler(void);
#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
#define ToString(p) LIB_CEC->ToString(p)
-CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
- CCECCommandHandler(busDevice),
+CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
m_bSLEnabled(false),
m_bActiveSourceSent(false)
{
return true;
}
-bool CSLCommandHandler::HandleActiveSource(const cec_command &command)
+int CSLCommandHandler::HandleActiveSource(const cec_command &command)
{
if (command.parameters.size == 2)
{
}
primary->TransmitPowerState(CECDEVICE_TV);
}
+
+ return COMMAND_HANDLED;
}
- return true;
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
+int CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
{
SetVendorId(command);
cec_command response;
cec_command::Format(response, initiator, command.initiator, CEC_OPCODE_FEATURE_ABORT);
- return Transmit(response);
+ Transmit(response);
+ return COMMAND_HANDLED;
}
}
- return true;
+
+ return CCECCommandHandler::HandleDeviceVendorId(command);
}
-bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
+int CSLCommandHandler::HandleVendorCommand(const cec_command &command)
{
if (!m_processor->IsHandledByLibCEC(command.destination))
return true;
command.parameters[0] == SL_COMMAND_UNKNOWN_01)
{
HandleVendorCommand01(command);
- return true;
+ return COMMAND_HANDLED;
}
else if (command.parameters.size == 2 &&
command.parameters[0] == SL_COMMAND_POWER_ON)
{
HandleVendorCommandPowerOn(command);
- return true;
+ return COMMAND_HANDLED;
}
else if (command.parameters.size == 2 &&
command.parameters[0] == SL_COMMAND_CONNECT_REQUEST)
{
HandleVendorCommandSLConnect(command);
- return true;
+ return COMMAND_HANDLED;
}
else if (command.parameters.size == 1 &&
command.parameters[0] == SL_COMMAND_REQUEST_POWER_STATUS)
{
HandleVendorCommandPowerOnStatus(command);
- return true;
+ return COMMAND_HANDLED;
}
- return false;
+ return CCECCommandHandler::HandleVendorCommand(command);
}
void CSLCommandHandler::HandleVendorCommand01(const cec_command &command)
Transmit(response);
}
-bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+int CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
{
- if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ if (!m_processor->CECInitialised() ||
+ !m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+ 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);
+ if (command.parameters[0] == CEC_STATUS_REQUEST_ON)
{
- CCECBusDevice *device = GetDevice(command.destination);
- if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
- {
- if (command.parameters.size > 0)
- {
- ((CCECPlaybackDevice *) device)->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG);
- if (command.parameters[0] == CEC_STATUS_REQUEST_ON)
- {
- bool bReturn = ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
- if (!ActiveSourceSent())
- ActivateSource();
- return bReturn;
- }
- else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE)
- {
- return ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
- }
- }
- }
- return CCECCommandHandler::HandleGiveDeckStatus(command);
+ device->TransmitDeckStatus(command.initiator);
+ if (!ActiveSourceSent())
+ ActivateSource();
+ return COMMAND_HANDLED;
+ }
+ else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE)
+ {
+ device->TransmitDeckStatus(command.initiator);
+ return COMMAND_HANDLED;
}
- return false;
+ return CCECCommandHandler::HandleGiveDeckStatus(command);
}
-bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
+int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
{
- bool bReturn(false);
if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination) && command.initiator == CECDEVICE_TV)
{
CCECBusDevice *device = GetDevice(command.destination);
if (device && device->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
{
- bReturn = device->TransmitPowerState(command.initiator);
+ device->TransmitPowerState(command.initiator);
device->SetPowerStatus(CEC_POWER_STATUS_ON);
}
else
if (!ActiveSourceSent())
{
device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
- bReturn = device->TransmitPowerState(command.initiator);
+ device->TransmitPowerState(command.initiator);
ActivateSource();
}
else if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
m_bActiveSourceSent = false;
}
device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
- bReturn = device->TransmitPowerState(command.initiator);
+ device->TransmitPowerState(command.initiator);
device->SetPowerStatus(CEC_POWER_STATUS_ON);
m_resetPowerState.Init(5000);
}
else
{
- bReturn = device->TransmitPowerState(command.initiator);
+ device->TransmitPowerState(command.initiator);
m_resetPowerState.Init(5000);
}
}
+
+ return COMMAND_HANDLED;
}
- return bReturn;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
+int CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
{
if (m_processor->CECInitialised())
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
else
ActivateSource();
- return true;
+ return COMMAND_HANDLED;
}
- return false;
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
}
-bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
+int CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
{
if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
command.initiator == CECDEVICE_TV)
return CCECCommandHandler::HandleFeatureAbort(command);
}
-bool CSLCommandHandler::HandleStandby(const cec_command &command)
+int CSLCommandHandler::HandleStandby(const cec_command &command)
{
if (command.initiator == CECDEVICE_TV)
{
class CSLCommandHandler : public CCECCommandHandler
{
public:
- CSLCommandHandler(CCECBusDevice *busDevice);
+ CSLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
virtual ~CSLCommandHandler(void) {};
bool InitHandler(void);
protected:
- bool HandleActiveSource(const cec_command &command);
- bool HandleDeviceVendorId(const cec_command &command);
- bool HandleVendorCommand(const cec_command &command);
+ int HandleActiveSource(const cec_command &command);
+ int HandleDeviceVendorId(const cec_command &command);
+ int HandleVendorCommand(const cec_command &command);
void HandleVendorCommand01(const cec_command &command);
void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
void HandleVendorCommandSLConnect(const cec_command &command);
void TransmitVendorCommandSetDeviceMode(const cec_logical_address iSource, const cec_logical_address iDestination, const cec_device_type type);
- bool HandleGiveDevicePowerStatus(const cec_command &command);
- bool HandleGiveDeckStatus(const cec_command &command);
- bool HandleRequestActiveSource(const cec_command &command);
- bool HandleFeatureAbort(const cec_command &command);
- bool HandleStandby(const cec_command &command);
+ int HandleGiveDevicePowerStatus(const cec_command &command);
+ int HandleGiveDeckStatus(const cec_command &command);
+ int HandleRequestActiveSource(const cec_command &command);
+ int HandleFeatureAbort(const cec_command &command);
+ 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)) { return true; }
bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
#include "VLCommandHandler.h"
#include "../devices/CECBusDevice.h"
+#include "../devices/CECPlaybackDevice.h"
+#include "../devices/CECTV.h"
#include "../CECProcessor.h"
#include "../LibCEC.h"
#include "../CECClient.h"
#define VL_POWER_CHANGE 0x20
#define VL_POWERED_UP 0x00
#define VL_POWERED_DOWN 0x01
+#define VL_UNKNOWN1 0x06
using namespace CEC;
using namespace PLATFORM;
#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
#define ToString(p) LIB_CEC->ToString(p)
-CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) :
- CCECCommandHandler(busDevice),
- m_bActiveSourcePending(false),
- m_bPowerUpEventReceived(false)
+// wait this amount of ms before trying to switch sources after receiving the message from the TV that it's powered on
+#define SOURCE_SWITCH_DELAY_MS 1000
+
+CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+ m_iPowerUpEventReceived(0)
{
m_vendorId = CEC_VENDOR_PANASONIC;
}
if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+
+ m_processor->GetTV()->RequestPowerStatus(primary->GetLogicalAddress(), false);
}
return CCECCommandHandler::InitHandler();
}
-bool CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
{
+ if (command.parameters[0] != 0x00 ||
+ command.parameters[1] != 0x80 ||
+ command.parameters[2] != 0x45)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
if (command.initiator == CECDEVICE_TV &&
+ command.parameters.At(3) == VL_UNKNOWN1)
+ {
+ // set the power up event time
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
+ }
+ // mark the TV as powered on
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
+ else if (command.initiator == CECDEVICE_TV &&
command.destination == CECDEVICE_BROADCAST &&
command.parameters.At(3) == VL_POWER_CHANGE)
{
if (command.parameters.At(4) == VL_POWERED_UP)
{
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered up");
+ // set the power up event time
{
CLockObject lock(m_mutex);
- m_bPowerUpEventReceived = true;
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
}
- m_processor->TransmitPendingActiveSourceCommands();
+ // mark the TV as powered on
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
}
else if (command.parameters.At(4) == VL_POWERED_DOWN)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered down");
- else if (command.parameters.At(4) == VL_POWERED_DOWN)
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "unknown vendor command");
+ {
+ // reset the power up event time
+ {
+ CLockObject lock(m_mutex);
+ m_iPowerUpEventReceived = 0;
+ }
+ // mark the TV as powered off
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "skipping unknown vendor command");
- return true;
+ return COMMAND_HANDLED;
}
return CCECCommandHandler::HandleDeviceVendorCommandWithId(command);
}
-bool CVLCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
+bool CVLCommandHandler::PowerUpEventReceived(void)
{
- bool bPowerUpEventReceived(false);
-
- CCECBusDevice *tv = m_processor->GetDevice(CECDEVICE_TV);
- if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC)
- {
- CVLCommandHandler *handler = static_cast<CVLCommandHandler *>(tv->GetHandler());
- bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false;
- }
+ bool bPowerUpEventReceived(true);
- if (!bPowerUpEventReceived)
+ if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV)
{
- CLockObject lock(m_mutex);
- // wait until we received the event
- m_bActiveSourcePending = true;
- return true;
+ // get the status from the TV
+ CCECBusDevice *tv = m_processor->GetTV();
+ if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC)
+ {
+ CVLCommandHandler *handler = static_cast<CVLCommandHandler *>(tv->GetHandler());
+ bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false;
+ tv->MarkHandlerReady();
+ }
}
else
{
- // transmit standard active source message
- return CCECCommandHandler::TransmitActiveSource(iInitiator, iPhysicalAddress) &&
- TransmitMenuState(iInitiator, CECDEVICE_TV, CEC_MENU_STATE_ACTIVATED);
+ // get the current status
+ {
+ CLockObject lock(m_mutex);
+ bPowerUpEventReceived = m_iPowerUpEventReceived > 0 &&
+ GetTimeMs() - m_iPowerUpEventReceived > SOURCE_SWITCH_DELAY_MS;
+ }
+
+ // if we didn't receive the event, check if the TV is already marked as powered on
+ if (!bPowerUpEventReceived && m_busDevice->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON)
+ {
+ CLockObject lock(m_mutex);
+ m_iPowerUpEventReceived = GetTimeMs();
+ bPowerUpEventReceived = true;
+ }
}
+
+ return bPowerUpEventReceived;
}
-bool CVLCommandHandler::TransmitPendingActiveSourceCommands(void)
+int CVLCommandHandler::HandleStandby(const cec_command &command)
{
- bool bTransmitCommand(false);
+ // reset the power up event time
{
CLockObject lock(m_mutex);
- bTransmitCommand = m_bActiveSourcePending;
- m_bActiveSourcePending = false;
+ m_iPowerUpEventReceived = 0;
}
- if (bTransmitCommand)
+ return CCECCommandHandler::HandleStandby(command);
+}
+
+int CVLCommandHandler::HandleVendorCommand(const cec_command &command)
+{
+ // some vendor command voodoo that will enable more buttons on the remote
+ if (command.parameters.size == 3 &&
+ command.parameters[0] == 0x10 &&
+ command.parameters[1] == 0x01 &&
+ command.parameters[2] == 0x05)
{
- LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
- return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetCurrentPhysicalAddress()) &&
- TransmitMenuState(m_busDevice->GetLogicalAddress(), CECDEVICE_TV, CEC_MENU_STATE_ACTIVATED);
+ cec_command response;
+ cec_command::Format(response, command.destination, command.initiator, CEC_OPCODE_VENDOR_COMMAND);
+ uint8_t iResponseData[] = {0x10, 0x02, 0xFF, 0xFF, 0x00, 0x05, 0x05, 0x45, 0x55, 0x5c, 0x58, 0x32};
+ response.PushArray(12, iResponseData);
+
+ Transmit(response, true);
+
+ return COMMAND_HANDLED;
}
- return true;
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
}
-bool CVLCommandHandler::PowerUpEventReceived(void)
+bool CVLCommandHandler::SourceSwitchAllowed(void)
+{
+ return PowerUpEventReceived();
+}
+
+int CVLCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
{
+ if (command.initiator == CECDEVICE_TV)
{
- CLockObject lock(m_mutex);
- if (m_bPowerUpEventReceived)
- return true;
+ // set the power up event time
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
+ }
+ // mark the TV as powered on
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
}
- cec_power_status powerStatus = m_busDevice->GetCurrentPowerStatus();
-
- CLockObject lock(m_mutex);
- m_bPowerUpEventReceived = (powerStatus == CEC_POWER_STATUS_ON);
- return m_bPowerUpEventReceived;
+ return CCECCommandHandler::HandleSystemAudioModeRequest(command);
}
class CVLCommandHandler : public CCECCommandHandler
{
public:
- CVLCommandHandler(CCECBusDevice *busDevice);
+ CVLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
virtual ~CVLCommandHandler(void) {};
bool InitHandler(void);
- bool HandleDeviceVendorCommandWithId(const cec_command &command);
- bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress);
- bool TransmitPendingActiveSourceCommands(void);
+ int HandleDeviceVendorCommandWithId(const cec_command &command);
+ int HandleStandby(const cec_command &command);
+ int HandleSystemAudioModeRequest(const cec_command &command);
+ int HandleVendorCommand(const cec_command &command);
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 SourceSwitchAllowed(void);
+
private:
PLATFORM::CMutex m_mutex;
- bool m_bActiveSourcePending;
- bool m_bPowerUpEventReceived;
+ uint64_t m_iPowerUpEventReceived;
};
};
* http://www.pulse-eight.net/
*/
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
+
#if (defined(_WIN32) || defined(_WIN64))
#include "windows/os-types.h"
#else
private:
inline PreventCopy(const PreventCopy &c) { *this = c; }
- inline PreventCopy &operator=(const PreventCopy &c){ *this = c; return *this; }
+ inline PreventCopy &operator=(const PreventCopy & UNUSED(c)){ return *this; }
};
template <typename _Predicate>
using namespace PLATFORM;
static GUID MONITOR_GUID = { 0x4D36E96E, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+#define PA_MAX_REGENTRIES_TO_CHECK 1024
uint16_t GetPhysicalAddressFromDevice(IN HDEVINFO hDevHandle, IN PSP_DEVINFO_DATA deviceInfoData)
{
CHAR regEntryName[128];
DWORD regEntryNameLength(128);
DWORD type;
- LONG retVal(0);
+ LONG retVal(ERROR_SUCCESS);
- for (LONG ptr = 0; iPA == 0 && retVal != ERROR_NO_MORE_ITEMS; ptr++)
+ for (LONG ptr = 0; iPA == 0 && retVal == ERROR_SUCCESS && ptr < PA_MAX_REGENTRIES_TO_CHECK; ptr++)
{
BYTE regEntryData[1024];
DWORD regEntryDataSize = sizeof(regEntryData);
retVal = RegEnumValue(hDevRegKey, ptr, ®EntryName[0], ®EntryNameLength, NULL, &type, regEntryData, ®EntryDataSize);
- if (retVal == 0 && !strcmp(regEntryName,"EDID"))
+ if (retVal == ERROR_SUCCESS && !strcmp(regEntryName,"EDID"))
iPA = CEDIDParser::GetPhysicalAddressFromEDID(regEntryData, regEntryDataSize);
}
RegCloseKey(hDevRegKey);
cec_client_SOURCES = main.cpp
cec_client_CPPFLAGS = -I@abs_top_srcdir@/include
-cec_client_LDFLAGS = @LIBS_DL@
\ No newline at end of file
+cec_client_LDFLAGS = @LIBS@
using namespace std;
using namespace PLATFORM;
+#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_1_7_1;
+
#include <cecloader.h>
ICECCallbacks g_callbacks;
libcec_configuration g_config;
-int g_cecLogLevel(CEC_LOG_ALL);
+int g_cecLogLevel(-1);
+int g_cecDefaultLogLevel(CEC_LOG_ALL);
ofstream g_logOutput;
bool g_bShortLog(false);
CStdString g_strPort;
else if (!strcmp(argv[iArgPtr], "--list-devices") ||
!strcmp(argv[iArgPtr], "-l"))
{
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
ICECAdapter *parser = LibCecInitialise(&g_config);
if (parser)
{
else if (!strcmp(argv[iArgPtr], "--help") ||
!strcmp(argv[iArgPtr], "-h"))
{
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+
ShowHelpCommandLine(argv[0]);
return 0;
}
int main (int argc, char *argv[])
{
g_config.Clear();
+ g_callbacks.Clear();
snprintf(g_config.strDeviceName, 13, "CECTester");
- g_config.clientVersion = CEC_CLIENT_VERSION_1_6_3;
+ g_config.clientVersion = CEC_CONFIG_VERSION;
g_config.bActivateSource = 0;
g_callbacks.CBCecLogMessage = &CecLogMessage;
g_callbacks.CBCecKeyPress = &CecKeyPress;
if (!ProcessCommandLineArguments(argc, argv))
return 0;
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = g_cecDefaultLogLevel;
+
if (g_config.deviceTypes.IsEmpty())
{
if (!g_bSingleCommand)