From: Lars Op den Kamp Date: Fri, 27 Jul 2012 18:09:57 +0000 (+0200) Subject: Merge branch 'master' into release X-Git-Tag: upstream/2.2.0~1^2~20 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=b0a5e4fc9b66620b00f937f7e9a406bf22aaaf1d;hp=cd67a2745661905fef6a462499a74bcc091a5fa6;p=deb_libcec.git Merge branch 'master' into release --- diff --git a/.gitignore b/.gitignore index 38b8af7..420dc5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /build /.cproject /.project +/.settings *.dll *.exe *.exp @@ -14,6 +15,8 @@ *.suo *.user +*~ + /support/private /driver/p8usb-cec.cat @@ -34,6 +37,10 @@ ltmain.sh Makefile Makefile.in missing +config.h +config.h.in +config.h.in~ +stamp-h1 include/boost @@ -48,6 +55,10 @@ project/Properties project/x64 +project/RPi/toolchain +project/RPi/firmware +project/RPi/deps + src/lib/.deps src/lib/.libs src/lib/*.a diff --git a/ChangeLog b/ChangeLog index b8b13b9..12e2792 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +libcec (1.8.1-1) unstable; urgency=low + + * changed/added: + * added support for the Raspberry Pi. + * added cec-client -i / cec-client --info that calls GetLibInfo() + * header cleanups + * added CAdapterFactory, to create IAdapterCommunication instances + * added --debug to configure, to include -ggdb + + * interface changes: + * added GetLibInfo()/cec_get_lib_info(), that shows how libCEC was compiled + and with which features included. + * added ToString(cec_user_control_code_key) to the interface + + * fixed: + * disallow sending CEC_OPCODE_SET_STREAM_PATH - not allowed by the CEC spec + * persist the configuration in the eeprom after initialising the client. + fixes wrong/old settings being used in autonomous mode, which broke the + wake on cec funtion + * persist the new configuration when the hdmi port setting changed + * cleaned locks around callbacks + * always set controlled mode to false when unregistering the last client. + fixes 30 second timeout before controlled mode gets deactivated + * updated the cached device type setting properly when persisting new + settings. correct return value from WriteEEPROM(). lock a mutex when + updating the state + * LibCecSharp: set the primary LA in CecLogicalAddresses + + -- Pulse-Eight Packaging Tue, 25 Jul 2012 13:05:00 +0100 + libcec (1.7.2-1) unstable; urgency=low * changed/added: diff --git a/Doxyfile b/Doxyfile index c8162fe..a87a171 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1295,7 +1295,7 @@ INCLUDE_PATH = # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = config.h # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of diff --git a/README b/README index 7825aef..5c7364b 100644 --- a/README +++ b/README @@ -1,5 +1,8 @@ This library provides support for the Pulse-Eight USB-CEC adapter. +You can find a list of frequently asked questions on the following page: + http://libcec.pulse-eight.com/faq + =============================================================================== === Linux === =============================================================================== @@ -12,12 +15,15 @@ libCEC needs the following dependencies in order to work correctly: To compile libCEC on Linux, you'll need the following dependencies: * autoconf 2.13 or later * automake 1.11 or later -* pkg-config * libtool -* udev development headers v151 or later * gcc 4.2 or later * liblockdev 1.0 development headers +The following dependencies are recommended. Without them, the adapter can not +be auto-detected. +* pkg-config +* udev development headers v151 or later + To compile, execute the following commands: # autoreconf -vif # ./configure @@ -68,6 +74,31 @@ you will need to manually build libcec with Visual C++ 2010 and then build LibCecSharp.sln with Visual Studio 2008. See create-installer.bat for the required steps. +=============================================================================== + === Raspberry Pi === +=============================================================================== + +We've included a script that builds libCEC with support for the Raspberry Pi +in /project/RPi/build.sh. This script pulls in the latest toolchain and +firmware, builds the necessary dependencies, and finally builds libCEC. The +result will be a softfp build. + +To build libCEc on your development machine, follow these instructions: +* run '/project/RPi/build.sh /desired/destination/path/for/binaries' +* run 'make install' + +To build libCEC on the Pi itself, just follow the instructions for Linux. +The configure script automatically checks whether the required headers and +libraries can be found. + +To specify the path of the Raspberry Pi's development headers, use the +following option for 'configure': +--with-rpi-include-path="/path/to/opt/vc/include" + +To specify the path of the Raspberry Pi's libraries, use the following option +for 'configure': +--with-rpi-lib-path="/path/to/libbcm_host.so" + =============================================================================== === Debugging / Testing === =============================================================================== diff --git a/configure.ac b/configure.ac index 9e72964..ae1b5a5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,68 +1,356 @@ AC_PREREQ(2.59) -AC_INIT([libcec], [1:7:0], [http://libcec.pulse-eight.com/]) +AC_INIT([libcec], [1:8:0], [http://libcec.pulse-eight.com/]) +AC_CONFIG_HEADERS([config.h]) +AH_TOP([#pragma once]) + +AM_INIT_AUTOMAKE([foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) + AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) +AC_CANONICAL_HOST + +cflags_reset="$CFLAGS" +AC_LANG(C++) AC_PROG_CXX AC_PROG_LIBTOOL +AC_PROG_INSTALL +AC_LIBTOOL_DLOPEN +CFLAGS="$cflags_reset" + +msg_pkg_config_missing="'pkg-config' is missing - adapter detection will not be available" +msg_pthread_missing="required library 'pthread' is missing" +msg_dl_missing="required library 'dl' is missing" +msg_udev_missing="library 'udev' is missing - adapter detection will not be available" +msg_dirent_missing="dirent.h header is missing - adapter detection will not be available" +msg_lockdev_missing="required library 'liblockdev' is missing" +msg_rpi_api_missing="Raspberry Pi API not found or incompatible with libCEC" +msg_rpi_will_check="will check for RPi support" +msg_rpi_unsupported_target="will not check for RPi support (unsupported cpu: ${host_cpu})" +msg_required_header_missing="required header is missing" + +## debugging symbols +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [include debug symbols (default is no)])], + [use_debug=$enableval], + [use_debug=no]) + +## optimisation +AC_ARG_ENABLE([optimisation], + [AS_HELP_STRING([--enable-optimisation], + [optimisation flag (default is yes)])], + [use_optimisation=$enableval], + [use_optimisation=yes]) + +## Raspberry Pi support +AC_ARG_ENABLE([rpi], + [AS_HELP_STRING([--enable-rpi], + [enable support for the Raspberry Pi (default is auto)])], + [use_rpi=$enableval], + [use_rpi=auto]) + +## Optional path to the RPi's dev headers +AC_ARG_WITH([rpi-include-path], + [AS_HELP_STRING([--with-rpi-include-path], + [location of the Raspberry Pi headers (location of /opt/vc/include, default is auto)])], + [RPI_CFLAGS="-I$withval -I$withval/interface/vcos/pthreads"]) -# search for pthread, required by all targets -AC_SEARCH_LIBS([pthread_create],[pthread],, - AC_MSG_ERROR("required library 'pthread' is missing")) +## Optional path to libbcm_host.so +AC_ARG_WITH([rpi-lib-path], + [AS_HELP_STRING([--with-rpi-lib-path], + [location of the Raspberry Pi libraries (location of libbcm_host.so, default is auto)])], + [RPI_LIBS="-L$withval"]) -# search for dlopen, required by all targets +## only check for the RPi API on ARM targets +if test "x$use_rpi" != "xno"; then + case "${host_cpu}" in + arm*) + AC_MSG_NOTICE($msg_rpi_will_check) + ;; + *) + if test "x$use_rpi" = "xyes"; then + AC_MSG_ERROR($msg_rpi_unsupported_target) + else + AC_MSG_NOTICE($msg_rpi_unsupported_target) + fi + use_rpi="no" + ;; + esac +fi + +## add the top dir and include to the include path, so we can include config.h and cec.h +CPPFLAGS="$CPPFLAGS -I\$(abs_top_srcdir)/src -I\$(abs_top_srcdir)/include" + +## search for pkg-config +AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) +if test "x$HAVE_PKG_CONFIG" != "xyes" ; then + AC_MSG_WARN($msg_pkg_config_missing) +fi + +## search for pthread, required by all targets +AC_SEARCH_LIBS([pthread_create],[pthread],,AC_MSG_ERROR($msg_pthread_missing)) +AC_CHECK_FUNCS([pthread_mutexattr_init pthread_cond_init pthread_cond_destroy pthread_cond_signal pthread_cond_broadcast pthread_cond_wait pthread_cond_timedwait]) + +## 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")) - + AC_MSG_ERROR($msg_dl_missing)) +AC_CHECK_FUNCS([dlopen dlcose dlsym]) -# platform specific libs, required by all targets +## platform specific libs, required by all targets case "${host}" in *-*-linux*) - LIBS+=" -lrt" + # for timeutils + LIBS="$LIBS -lrt" ;; *-apple-darwin*) - LIBS+="-framework CoreVideo -framework IOKit" - ;; - *-freebsd*) + LIBS="$LIBS -framework CoreVideo -framework IOKit" ;; esac -libs_client=$LIBS +## we found all the libs and headers that we need for the client applications +libs_client="$LIBS" -# search for udev and lockdev, only required by libCEC -has_libudev="yes" +## search for udev, lockdev and the RPi API, only required by libCEC +use_udev="no" +use_adapter_detection="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")) + ## search for udev if pkg-config was found + if test "x$HAVE_PKG_CONFIG" = "xyes" ; then + PKG_CHECK_MODULES([UDEV],[libudev],use_udev="yes",AC_MSG_WARN($msg_udev_missing)) + fi + + ## we need dirent.h on linux too + if test "$use_udev" = "yes"; then + AC_CHECK_HEADER(dirent.h,,[use_udev="no";AC_MSG_WARN($msg_dirent_missing)]) + fi + + if test "$use_udev" != "yes"; then + use_adapter_detection="no" + fi + + ## search for lockdev + AC_CHECK_HEADER(lockdev.h,,AC_MSG_ERROR($msg_lockdev_missing)) + AC_CHECK_LIB(lockdev,dev_unlock,,AC_MSG_ERROR($msg_lockdev_missing)) + + AC_CHECK_HEADER(time.h,,AC_MSG_ERROR($msg_required_header_missing)) + AC_CHECK_HEADER(sys/prctl.h,,AC_MSG_ERROR($msg_required_header_missing)) + + ## search for the RPi API. we need to check a couple of things to see if + ## it's recent enough and contains the calls needed for libCEC to operate + ## correctly. + if test "x$use_rpi" != "xno"; then + CPPFLAGS="$CPPFLAGS $RPI_CFLAGS" + libs_pre_rpi="$LIBS" + LIBS="$LIBS $RPI_LIBS -lvcos -lvchiq_arm" + + check_rpi_cec_service="yes" + + ## check for headers we need + AC_CHECK_HEADER(interface/vmcs_host/vc_cec.h,,check_rpi_cec_service="no") + AC_CHECK_HEADER(interface/vmcs_host/vc_cecservice.h,,check_rpi_cec_service="no") + AC_CHECK_HEADER(interface/vchiq_arm/vchiq_if.h,,check_rpi_cec_service="no") + AC_CHECK_HEADER(bcm_host.h,,check_rpi_cec_service="no") - AC_CHECK_HEADER(lockdev.h,, - AC_MSG_ERROR("required library 'liblockdev' is missing")) + ## check if the headers contain support for libCEC. + ## VC_CECSERVICE_VER needs to be defined + AC_MSG_CHECKING([interface/vmcs_host/vc_cec.h compatibility]) - LIBS+=" -llockdev" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include +#if !defined(VC_CECSERVICE_VER) +#error RPi headers does not contain libCEC support +#endif]], [[]])],[AC_MSG_RESULT([yes])],[check_rpi_cec_service="no"; AC_MSG_RESULT([no])]) + + ## check if the methods we're using can be found in libbcm_host.so, so we don't use an incompatible version + AC_CHECK_LIB(bcm_host,vchi_initialise,,check_rpi_cec_service="no") + libs_tmp="$LIBS" + AC_CHECK_LIB(bcm_host,vc_vchi_cec_init,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_get_logical_address,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_get_physical_address,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_param2message,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_poll_address,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_register_callback,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_release_logical_address,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vc_cec_set_passive,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vcos_init,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vchiq_initialise,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vchi_initialise,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,vchi_create_connection,,check_rpi_cec_service="no") + AC_CHECK_LIB(bcm_host,bcm_host_init,,check_rpi_cec_service="no") + LIBS="$libs_tmp" + + if test "x$check_rpi_cec_service" != "xyes" && test "x$use_rpi" = "xyes"; then + AC_MSG_ERROR($msg_rpi_api_missing) + elif test "x$check_rpi_cec_service" != "xyes"; then + use_rpi="no" + LIBS="$libs_pre_rpi" + fi + fi ;; *-apple-darwin*) - has_libudev="no"; - ;; - *-freebsd*) - has_libudev="no" + AC_CHECK_HEADER(mach/mach_time.h,,AC_MSG_ERROR($msg_required_header_missing)) + AC_CHECK_HEADER(CoreVideo/CVHostTime.h,,AC_MSG_ERROR($msg_required_header_missing)) ;; 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" +## define the build info +LIB_INFO="host: ${host}, features:" + +features="Configured features:\n Pulse-Eight CEC Adapter :\t\tyes" +LIB_INFO="$LIB_INFO 'P8 USB'" +AC_DEFINE([HAVE_P8_USB],[1],[Define to 1 to include support for the Pulse-Eight USB-CEC Adapter]) +AM_CONDITIONAL(USE_P8_USB, true) + +## mark adapter detection as available if the required deps were found +if test "x$use_adapter_detection" = "xyes"; then + ## mark udev as available if it was found + if test "x$use_udev" = "xyes"; then + INCLUDES="$INCLUDES $UDEV_CFLAGS" + LIBS="$LIBS $UDEV_LIBS" + AC_DEFINE([HAVE_LIBUDEV],[1],[Define to 1 if libudev is installed]) + REQUIRES="$REQUIRES udev" + fi + + AC_DEFINE([HAVE_P8_USB_DETECT],[1],[Define to 1 to include autodetection support for the Pulse-Eight USB-CEC Adapter]) + AM_CONDITIONAL(USE_P8_USB_DETECT, true) + + features="$features\n Pulse-Eight CEC Adapter detection :\tyes" + LIB_INFO="$LIB_INFO 'P8 USB detect'" +else + AM_CONDITIONAL(USE_P8_USB_DETECT, false) + features="$features\n Pulse-Eight CEC Adapter detection :\tno" fi -LIBS_LIBCEC=$LIBS -LIBS=$libs_client +## mark RPi support as available if the required headers and libs were found +if test "x$use_rpi" != "xno"; then + AC_DEFINE([HAVE_RPI_API],[1],[Define to 1 to include RPi support]) + AM_CONDITIONAL(USE_RPI_API, true) + features="$features\n Raspberry Pi support :\t\tyes" + LIB_INFO="$LIB_INFO 'RPi'" +else + AM_CONDITIONAL(USE_RPI_API, false) + features="$features\n Raspberry Pi support :\t\tno" +fi + +## check if our build system is complete +AC_CHECK_HEADER(algorithm,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(ctype.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(dlfcn.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(errno.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(fcntl.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(functional,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(locale,,AC_DEFINE([SS_NO_LOCALE],[1],[Define to 1 to exclude locale support])) +AC_CHECK_HEADER(map,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(netdb.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(poll.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(pthread.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(queue,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(semaphore.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(set,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(stdarg.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(stdint.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(stdio.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(stdlib.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(string,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(string.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(termios.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(unistd.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(vector,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(wchar.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(wctype.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(arpa/inet.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(netinet/in.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(netinet/tcp.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(sys/socket.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(sys/time.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_HEADER(sys/types.h,,AC_MSG_ERROR($msg_required_header_missing)) +AC_CHECK_FUNCS([close fcntl select write read shutdown send recv memset sprintf getaddrinfo getsockopt setsockopt connect poll sched_yield open strerror tcsetattr tcgetattr cfsetispeed cfsetospeed bind freeaddrinfo listen accept socket]) + +## add the build date to LIB_INFO +AC_CHECK_PROG(HAVE_GIT, git, yes) +if test "x$HAVE_GIT" = "xyes"; then + revision=$(git --no-pager log --abbrev=7 -n 1 --pretty=format:"%h" HEAD) +fi +if test "x$revision" != "x"; then + LIB_INFO="$LIB_INFO, git revision: ${revision}" +fi + +AC_CHECK_PROG(HAVE_DATE, date, yes) +if test "x$HAVE_DATE" = "xyes"; then + LIB_INFO="$LIB_INFO, compiled on: `date -u`" +else + LIB_INFO="$LIB_INFO, compiled on: (unknown date)" +fi -CXXFLAGS="-fPIC -Wall -Wextra -Wno-missing-field-initializers $CXXFLAGS" +## add the name of the user who built libCEC to LIB_INFO +AC_CHECK_PROG(HAVE_WHOAMI, whoami, yes) +if test "x$HAVE_WHOAMI" = "xyes" ; then + LIB_INFO="$LIB_INFO by `whoami`" +else + LIB_INFO="$LIB_INFO by (unknown user)" +fi + +## add the hostname of the build host of libCEC to LIB_INFO +AC_CHECK_PROG(HAVE_HOSTNAME, hostname, yes) +if test "x$HAVE_HOSTNAME" = "xyes"; then + LIB_INFO="$LIB_INFO@`hostname -f`" +fi + +## add the system info of the build host of libCEC to LIB_INFO +AC_CHECK_PROG(HAVE_UNAME, uname, yes) +if test "x$HAVE_UNAME" = "xyes"; then + LIB_INFO="$LIB_INFO on `uname -s` `uname -r` (`uname -m`)" +fi + +## redefine the LIBS, so cec-client and cec-config aren't linked against things they don't need +LIBS_LIBCEC="$LIBS" +LIBS="$libs_client" + +CXXFLAGS="$CXXFLAGS -fPIC -Wall -Wextra -Wno-missing-field-initializers" + +if test "x$use_debug" = "xyes"; then + CXXFLAGS="$CXXFLAGS -g" +fi + +if test "x$optimisation" = "xyes"; then + CXXFLAGS="$CXXFLAGS -O2" +fi + +AC_DEFINE_UNQUOTED(LIB_INFO,"$LIB_INFO", "information about how libCEC was compiled") AC_SUBST([REQUIRES]) AC_SUBST([LIBS]) AC_SUBST([LIBS_LIBCEC]) +AC_SUBST([LIB_INFO]) +AC_SUBST([USE_P8_USB]) +AC_SUBST([USE_P8_USB_DETECT]) +AC_SUBST([USE_RPI_API]) AC_CONFIG_FILES([src/lib/libcec.pc]) AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile src/cec-config/Makefile]) + +cat < Tue, 25 Jul 2012 13:05:00 +0100 + libcec (1.7.2-1) unstable; urgency=low * changed/added: diff --git a/include/cec.h b/include/cec.h index de7129d..807bcd9 100644 --- a/include/cec.h +++ b/include/cec.h @@ -36,7 +36,7 @@ #include "cectypes.h" -#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_7_1 +#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_8_0 namespace CEC { @@ -482,6 +482,24 @@ namespace CEC */ virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0; #endif + + /*! + * @return A string with information about how libCEC was compiled. + */ + virtual const char *GetLibInfo(void) = 0; + + virtual const char *ToString(const cec_user_control_code key) = 0; + + /*! + * @brief Calling this method will initialise the host on which libCEC is running. + * Calling this method will initialise the host on which libCEC is running. On the RPi, it calls + * bcm_host_init(), which may only be called once per process, and is called by any process using + * the video api on that system. So only call this method if libCEC is used in an application that + * does not already initialise the video api. + * + * Should be called as first call to libCEC, directly after CECInitialise() and before using Open() + */ + virtual void InitVideoStandalone(void) = 0; }; }; diff --git a/include/cecc.h b/include/cecc.h index 779f211..60b54bd 100644 --- a/include/cecc.h +++ b/include/cecc.h @@ -302,6 +302,10 @@ extern DECLSPEC int cec_get_device_information(const char *strPort, CEC::libcec_ extern DECLSPEC int cec_get_device_information(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs); #endif +extern DECLSPEC const char * cec_get_lib_info(void); + +extern DECLSPEC void cec_init_video_standalone(void); + #ifdef __cplusplus }; #endif diff --git a/include/cectypes.h b/include/cectypes.h index 47168a2..794e124 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -99,6 +99,7 @@ namespace CEC { #define CEC_DEFAULT_DEVICE_LANGUAGE "eng" #define CEC_DEFAULT_SETTING_AUTODETECT_ADDRESS 0 #define CEC_DEFAULT_SETTING_GET_SETTINGS_FROM_ROM 0 +#define CEC_DEFAULT_SETTING_CEC_VERSION 0x05 #define CEC_DEFAULT_TRANSMIT_RETRY_WAIT 500 #define CEC_DEFAULT_TRANSMIT_TIMEOUT 1000 @@ -113,10 +114,13 @@ namespace CEC { #define CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS 5000 #define CEC_FORWARD_STANDBY_MIN_INTERVAL 10000 +#define CEC_RPI_VIRTUAL_PATH "Raspberry Pi" +#define CEC_RPI_VIRTUAL_COM "RPI" + #define CEC_MIN_LIB_VERSION 1 #define CEC_LIB_VERSION_MAJOR 1 #define CEC_LIB_VERSION_MAJOR_STR "1" -#define CEC_LIB_VERSION_MINOR 7 +#define CEC_LIB_VERSION_MINOR 8 typedef enum cec_abort_reason { @@ -684,6 +688,7 @@ typedef enum cec_vendor_id CEC_VENDOR_MEDION = 0x000CB8, CEC_VENDOR_SHARP = 0x08001F, CEC_VENDOR_VIZIO = 0x6B746D, + CEC_VENDOR_BROADCOM = 0x18C086, CEC_VENDOR_UNKNOWN = 0 } cec_vendor_id; @@ -1223,7 +1228,9 @@ typedef enum cec_client_version 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_1 = 0x1701 + CEC_CLIENT_VERSION_1_7_1 = 0x1701, + CEC_CLIENT_VERSION_1_7_2 = 0x1702, + CEC_CLIENT_VERSION_1_8_0 = 0x1800 } cec_client_version; typedef enum cec_server_version @@ -1238,7 +1245,9 @@ typedef enum cec_server_version 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_1 = 0x1701 + CEC_SERVER_VERSION_1_7_1 = 0x1701, + CEC_SERVER_VERSION_1_7_2 = 0x1702, + CEC_SERVER_VERSION_1_8_0 = 0x1800 } cec_server_version; typedef struct libcec_configuration @@ -1274,6 +1283,7 @@ typedef struct libcec_configuration char strDeviceLanguage[3]; /*!< the menu language used by the client. 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/ added in 1.6.2 */ uint32_t iFirmwareBuildDate; /*!< (read-only) the build date of the firmware, in seconds since epoch. if not available, this value will be set to 0. added in 1.6.2 */ uint8_t bMonitorOnly; /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */ + cec_version cecVersion; /*!< CEC spec version to use by libCEC. defaults to v1.4. added in 1.8.0 */ #ifdef __cplusplus // @todo re-add in v2.0 (breaks ABI) @@ -1309,7 +1319,9 @@ typedef struct libcec_configuration (other.clientVersion < CEC_CLIENT_VERSION_1_6_2 || !strncmp(strDeviceLanguage, other.strDeviceLanguage, 3)) && (other.clientVersion < CEC_CLIENT_VERSION_1_6_2 || iFirmwareBuildDate == other.iFirmwareBuildDate) && /* libcec 1.6.3+ */ - (other.clientVersion < CEC_CLIENT_VERSION_1_6_3 || bMonitorOnly == other.bMonitorOnly)); + (other.clientVersion < CEC_CLIENT_VERSION_1_6_3 || bMonitorOnly == other.bMonitorOnly) && + /* libcec 1.8.0+ */ + (other.clientVersion < CEC_CLIENT_VERSION_1_8_0 || cecVersion == other.cecVersion)); } bool operator!=(const libcec_configuration &other) const @@ -1341,6 +1353,7 @@ typedef struct libcec_configuration memcpy(strDeviceLanguage, CEC_DEFAULT_DEVICE_LANGUAGE, 3); iFirmwareBuildDate = CEC_FW_BUILD_UNKNOWN; bMonitorOnly = 0; + cecVersion = (cec_version)CEC_DEFAULT_SETTING_CEC_VERSION; memset(strDeviceName, 0, 13); deviceTypes.clear(); diff --git a/project/LibCecSharp.vcproj b/project/LibCecSharp.vcproj index 38be809..39f93b5 100644 --- a/project/LibCecSharp.vcproj +++ b/project/LibCecSharp.vcproj @@ -47,7 +47,7 @@ + + diff --git a/project/RPi/bootstrap.sh b/project/RPi/bootstrap.sh new file mode 100755 index 0000000..83f184c --- /dev/null +++ b/project/RPi/bootstrap.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +_usage() +{ + echo "Usage: $0 /path/to/toolchain /source/path" + exit 1 +} + +if [[ -z "$2" || ! -d "$1" || ! -d "$2" ]]; then + echo "1 = '$1'" + echo "2 = '$2'" + _usage +fi + +SCRIPT_PATH=`dirname $0` +cd $SCRIPT_PATH +SCRIPT_PATH=`pwd` +cd - + +source $SCRIPT_PATH/config +mkdir -p $SCRIPT_PATH/deps + +cd "$2" + +if [ -f "configure.ac" ]; then + _set_toolchain_path "$1" + autoreconf -vif + exit $? +fi + +exit 0 + diff --git a/project/RPi/build-deps.sh b/project/RPi/build-deps.sh new file mode 100755 index 0000000..be6b22a --- /dev/null +++ b/project/RPi/build-deps.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +SCRIPT_PATH=`dirname $0` +cd $SCRIPT_PATH +SCRIPT_PATH=`pwd` +cd - + +source $SCRIPT_PATH/config + +mkdir -p $SCRIPT_PATH/deps/build +cd $SCRIPT_PATH/deps/build + +if [ ! -d lockdev ]; then + wget ${TARBALL_LOCATION}${LOCKDEV_TARBALL} + tar -Jxf $LOCKDEV_TARBALL + + mv `echo $LOCKDEV_TARBALL | sed 's/.tar.xz//'` lockdev + rm $LOCKDEV_TARBALL + + cd $SCRIPT_PATH/deps/build/lockdev && \ + $SCRIPT_PATH/bootstrap.sh $SCRIPT_PATH/toolchain . + + if [ $? -eq 0 ]; then + _set_toolchain_path "$SCRIPT_PATH/toolchain" + ./configure --host=$TARGET_HOST --build=`cc -dumpmachine` --prefix=$SCRIPT_PATH/deps && \ + make && \ + make install + + exit $? + else + exit 1 + fi +fi + +exit 0 + diff --git a/project/RPi/build.sh b/project/RPi/build.sh new file mode 100755 index 0000000..1d684e1 --- /dev/null +++ b/project/RPi/build.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +SCRIPT_PATH=`dirname $0` +cd $SCRIPT_PATH +SCRIPT_PATH=`pwd` +cd - + +if [ -z "$1" ]; then + DEST_DIR="/opt/libcec-rpi" +else + DEST_DIR="$1" +fi + +source $SCRIPT_PATH/config + +$SCRIPT_PATH/get-toolchain.sh && \ +$SCRIPT_PATH/build-deps.sh && \ +$SCRIPT_PATH/bootstrap.sh $SCRIPT_PATH/toolchain . + +if [ $? -eq 0 ]; then + _set_toolchain_path "$SCRIPT_PATH/toolchain" + # configure with --enable-rpi-cec-api so we bug out if we can't find Pi support or can't build it + ./configure --host=$TARGET_HOST \ + --build=`cc -dumpmachine` \ + --prefix=$DEST_DIR \ + --enable-debug \ + --enable-rpi \ + --with-rpi-include-path="${SCRIPT_PATH}/firmware/hardfp/opt/vc/include" \ + --with-rpi-lib-path="${SCRIPT_PATH}/firmware/hardfp/opt/vc/lib" && \ + make clean && \ + make V=0 + + exit $? +else + exit 1 +fi + diff --git a/project/RPi/config b/project/RPi/config new file mode 100644 index 0000000..b81021d --- /dev/null +++ b/project/RPi/config @@ -0,0 +1,37 @@ +TOOLCHAIN_GIT="git://github.com/raspberrypi/tools.git" +FIRMWARE_GIT="git://github.com/raspberrypi/firmware.git" +TARBALL_LOCATION="http://sources.openelec.tv/devel/" +LOCKDEV_TARBALL="lockdev-16b8996.tar.xz" + +_set_toolchain_path() +{ + echo "Setting toolchain path to: '$1'" + + export TARGET_TOOLCHAIN_PATH="$1/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin" + export TARGET_TOOLCHAIN_LIB_PATH="$1/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/lib" + export TARGET_HOST="arm-bcm2708hardfp-linux-gnueabi" + + export CC=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-gcc + export CXX=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-g++ + export LD=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-ld + export AS=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-as + export AR=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-ar + export NM=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-nm + export RANLIB=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-ranlib + export OBJCOPY=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-objcopy + export OBJDUMP=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-objdump + export STRIP=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-strip + + export CPPFLAGS="-I${SCRIPT_PATH}/deps/include" + export CFLAGS="-march=armv6 -mfpu=vfp -mfloat-abi=hard -Wno-psabi -Wa,-mno-warn-deprecated -O3 -fexcess-precision=fast -ffast-math -I${SCRIPT_PATH}/deps/include" + export CXXFLAGS="$CFLAGS" + export LDFLAGS="-march=armv6 -mtune=arm1176jzf-s -L${SCRIPT_PATH}/deps/lib" + + #export PKG_CONFIG_PATH="$TARGET_PKG_CONFIG_PATH" + export PKG_CONFIG_LIBDIR="${SCRIPT_PATH}/deps/lib/pkgconfig:${SCRIPT_PATH}/deps/lib/share/pkgconfig" + export PKG_CONFIG_SYSROOT_DIR="${SCRIPT_PATH}/deps" + + export PATH="$TARGET_TOOLCHAIN_PATH:$PATH" + export LD_LIBRARY_PATH="$TARGET_TOOLCHAIN_LIB_PATH:$LD_LIBRARY_PATH" +} + diff --git a/project/RPi/get-toolchain.sh b/project/RPi/get-toolchain.sh new file mode 100755 index 0000000..96e3634 --- /dev/null +++ b/project/RPi/get-toolchain.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +SCRIPT_PATH=`dirname $0` +cd $SCRIPT_PATH +SCRIPT_PATH=`pwd` +cd - + +source $SCRIPT_PATH/config + +if [ ! -d $SCRIPT_PATH/toolchain ]; then + git clone $TOOLCHAIN_GIT $SCRIPT_PATH/toolchain +else + cd $SCRIPT_PATH/toolchain +# git pull +fi + +if [ ! -d $SCRIPT_PATH/firmware ]; then + git clone $FIRMWARE_GIT $SCRIPT_PATH/firmware +else + cd $SCRIPT_PATH/firmware +# git pull +fi + +if [[ -d $SCRIPT_PATH/toolchain && -d $SCRIPT_PATH/firmware ]]; then + exit 0 +else + exit 1 +fi + diff --git a/project/cec-config.rc b/project/cec-config.rc index e47ea2d..be84610 100644 Binary files a/project/cec-config.rc and b/project/cec-config.rc differ diff --git a/project/cec-config.vcxproj b/project/cec-config.vcxproj index 6ca84e4..5fef417 100644 --- a/project/cec-config.vcxproj +++ b/project/cec-config.vcxproj @@ -87,7 +87,7 @@ true - $(SolutiontDir)..\include;%(AdditionalIncludeDirectories) + $(SolutiontDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Console @@ -106,7 +106,7 @@ true - $(SolutiontDir)..\include;%(AdditionalIncludeDirectories) + $(SolutiontDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Console @@ -129,7 +129,7 @@ true - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Speed @@ -152,7 +152,7 @@ true - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Speed diff --git a/project/libcec.rc b/project/libcec.rc index 547d08c..a73c7fd 100644 Binary files a/project/libcec.rc and b/project/libcec.rc differ diff --git a/project/libcec.vcxproj b/project/libcec.vcxproj index 29fb689..3c26ad7 100644 --- a/project/libcec.vcxproj +++ b/project/libcec.vcxproj @@ -24,11 +24,12 @@ - - - - - + + + + + + @@ -69,11 +70,12 @@ - - - - - + + + + + + @@ -175,8 +177,8 @@ Level4 Disabled - _USE_32BIT_TIME_T;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + HAVE_P8_USB;_USE_32BIT_TIME_T;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) true @@ -191,8 +193,8 @@ Level4 Disabled - _WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + HAVE_P8_USB;_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) true @@ -213,8 +215,8 @@ Full true true - $(SolutionDir)..\src\lib\platform\pthread_win32;$(SolutionDir)..\include;%(AdditionalIncludeDirectories) - _USE_32BIT_TIME_T;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) + HAVE_P8_USB;_USE_32BIT_TIME_T;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) true @@ -233,8 +235,8 @@ Level4 Full true - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) - _WIN64;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) + HAVE_P8_USB;_WIN64;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions) true diff --git a/project/libcec.vcxproj.filters b/project/libcec.vcxproj.filters index 58d0dbb..e867399 100644 --- a/project/libcec.vcxproj.filters +++ b/project/libcec.vcxproj.filters @@ -34,6 +34,9 @@ {685e2589-204d-4f9a-a637-a7ba1b61c669} + + {a5e91a49-0595-49bd-9bdb-d729d63f024e} + @@ -122,27 +125,9 @@ platform\windows - - adapter - - - adapter - - - adapter - - - adapter - implementations - - adapter - - - adapter - @@ -170,6 +155,27 @@ platform\nvidia + + adapter + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter + @@ -212,24 +218,9 @@ platform\windows - - adapter - - - adapter - implementations - - adapter - - - adapter - - - adapter - devices @@ -246,6 +237,24 @@ platform\nvidia + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter\Pulse-Eight + + + adapter + diff --git a/project/testclient.rc b/project/testclient.rc index 1025fcc..0ee2868 100644 Binary files a/project/testclient.rc and b/project/testclient.rc differ diff --git a/project/testclient.vcxproj b/project/testclient.vcxproj index 0862f27..53cebe5 100644 --- a/project/testclient.vcxproj +++ b/project/testclient.vcxproj @@ -86,7 +86,7 @@ true - $(SolutiontDir)..\include;%(AdditionalIncludeDirectories) + $(SolutiontDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Console @@ -105,7 +105,7 @@ true - $(SolutiontDir)..\include;%(AdditionalIncludeDirectories) + $(SolutiontDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Console @@ -128,7 +128,7 @@ true - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Speed @@ -151,7 +151,7 @@ true - $(SolutionDir)..\include;%(AdditionalIncludeDirectories) + $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) Speed diff --git a/src/CecSharpTester/CecSharpClient.cs b/src/CecSharpTester/CecSharpClient.cs index 4afbb53..843823c 100644 --- a/src/CecSharpTester/CecSharpClient.cs +++ b/src/CecSharpTester/CecSharpClient.cs @@ -43,11 +43,12 @@ namespace CecSharpClient Config = new LibCECConfiguration(); Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; Config.DeviceName = "CEC Tester"; - Config.ClientVersion = CecClientVersion.Version1_7_1; + Config.ClientVersion = CecClientVersion.Version1_8_0; Config.SetCallbacks(this); LogLevel = (int)CecLogLevel.All; Lib = new LibCecSharp(Config); + Lib.InitVideoStandalone(); Console.WriteLine("CEC Parser created - libCEC version " + Lib.ToString(Config.ServerVersion)); } diff --git a/src/CecSharpTester/Properties/AssemblyInfo.cs b/src/CecSharpTester/Properties/AssemblyInfo.cs index 1e6b929..d941918 100644 --- a/src/CecSharpTester/Properties/AssemblyInfo.cs +++ b/src/CecSharpTester/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.7.1.0")] -[assembly: AssemblyFileVersion("1.7.1.0")] +[assembly: AssemblyVersion("1.8.0.0")] +[assembly: AssemblyFileVersion("1.8.0.0")] diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp index 4aa58ec..1640d3c 100644 --- a/src/LibCecSharp/AssemblyInfo.cpp +++ b/src/LibCecSharp/AssemblyInfo.cpp @@ -13,7 +13,7 @@ using namespace System::Security::Permissions; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; -[assembly:AssemblyVersionAttribute("1.7.1.0")]; +[assembly:AssemblyVersionAttribute("1.8.0.0")]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; diff --git a/src/LibCecSharp/CecSharpTypes.h b/src/LibCecSharp/CecSharpTypes.h index 33f3200..0ba3c04 100644 --- a/src/LibCecSharp/CecSharpTypes.h +++ b/src/LibCecSharp/CecSharpTypes.h @@ -368,7 +368,9 @@ namespace CecSharp Version1_6_2 = 0x1602, Version1_6_3 = 0x1603, Version1_7_0 = 0x1700, - Version1_7_1 = 0x1701 + Version1_7_1 = 0x1701, + Version1_7_2 = 0x1702, + Version1_8_0 = 0x1800 }; public enum class CecServerVersion @@ -383,7 +385,9 @@ namespace CecSharp Version1_6_2 = 0x1602, Version1_6_3 = 0x1603, Version1_7_0 = 0x1700, - Version1_7_1 = 0x1701 + Version1_7_1 = 0x1701, + Version1_7_2 = 0x1702, + Version1_8_0 = 0x1800 }; public ref class CecAdapter @@ -423,6 +427,7 @@ namespace CecSharp void Clear(void) { + Primary = CecLogicalAddress::Unknown; for (unsigned int iPtr = 0; iPtr < 16; iPtr++) Addresses[iPtr] = CecLogicalAddress::Unknown; } @@ -435,6 +440,8 @@ namespace CecSharp void Set(CecLogicalAddress iAddress) { Addresses[(unsigned int)iAddress] = iAddress; + if (Primary == CecLogicalAddress::Unknown) + Primary = iAddress; } property CecLogicalAddress Primary; diff --git a/src/LibCecSharp/LibCecSharp.cpp b/src/LibCecSharp/LibCecSharp.cpp index cd0f6d0..81c857f 100644 --- a/src/LibCecSharp/LibCecSharp.cpp +++ b/src/LibCecSharp/LibCecSharp.cpp @@ -598,6 +598,17 @@ namespace CecSharp return gcnew String(retVal); } + String ^ GetLibInfo() + { + const char *retVal = m_libCec->GetLibInfo(); + return gcnew String(retVal); + } + + void InitVideoStandalone() + { + m_libCec->InitVideoStandalone(); + } + private: ICECAdapter * m_libCec; CecCallbackMethods ^ m_callbacks; diff --git a/src/cec-config-gui/CecConfigGUI.cs b/src/cec-config-gui/CecConfigGUI.cs index 1bd2f07..a57ac35 100644 --- a/src/cec-config-gui/CecConfigGUI.cs +++ b/src/cec-config-gui/CecConfigGUI.cs @@ -28,11 +28,12 @@ namespace CecConfigGui Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; Config.DeviceName = "CEC Config"; Config.GetSettingsFromROM = true; - Config.ClientVersion = CecClientVersion.Version1_7_1; + Config.ClientVersion = CecClientVersion.Version1_8_0; Callbacks = new CecCallbackWrapper(this); Config.SetCallbacks(Callbacks); LoadXMLConfiguration(ref Config); Lib = new LibCecSharp(Config); + Lib.InitVideoStandalone(); InitializeComponent(); LoadButtonConfiguration(); diff --git a/src/cec-config-gui/Properties/AssemblyInfo.cs b/src/cec-config-gui/Properties/AssemblyInfo.cs index 56ca7ec..d47600b 100644 --- a/src/cec-config-gui/Properties/AssemblyInfo.cs +++ b/src/cec-config-gui/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.7.1.0")] -[assembly: AssemblyFileVersion("1.7.1.0")] +[assembly: AssemblyVersion("1.8.0.0")] +[assembly: AssemblyFileVersion("1.8.0.0")] diff --git a/src/cec-config/cec-config.cpp b/src/cec-config/cec-config.cpp index 7b203cb..fbfdd36 100644 --- a/src/cec-config/cec-config.cpp +++ b/src/cec-config/cec-config.cpp @@ -30,7 +30,8 @@ * http://www.pulse-eight.net/ */ -#include "../../include/cec.h" +#include "../env.h" +#include "../include/cec.h" #include #include @@ -41,6 +42,7 @@ #include "../lib/platform/threads/mutex.h" #include "../lib/platform/util/timeutils.h" #include "../lib/implementations/CECCommandHandler.h" +#include "../lib/platform/util/StdString.h" using namespace CEC; using namespace std; @@ -169,6 +171,9 @@ bool OpenConnection(cec_device_type type = CEC_DEVICE_TYPE_RECORDING_DEVICE) if (!g_parser) return false; + // init video on targets that need this + g_parser->InitVideoStandalone(); + CStdString strPort; cec_adapter devices[10]; uint8_t iDevicesFound = g_parser->FindAdapters(devices, 10, NULL); @@ -431,11 +436,11 @@ int main (int UNUSED(argc), char *UNUSED(argv[])) CStdString strWakeDevices; for (uint8_t iPtr = 0; iPtr < 16; iPtr++) if (g_config.wakeDevices[iPtr]) - strWakeDevices.AppendFormat(" %d" + iPtr); + strWakeDevices.AppendFormat(" %d", iPtr); CStdString strStandbyDevices; for (uint8_t iPtr = 0; iPtr < 16; iPtr++) if (g_config.powerOffDevices[iPtr]) - strStandbyDevices.AppendFormat(" %d" + iPtr); + strStandbyDevices.AppendFormat(" %d", iPtr); configOutput << "\n" << diff --git a/src/env.h b/src/env.h new file mode 100644 index 0000000..21f0d79 --- /dev/null +++ b/src/env.h @@ -0,0 +1,39 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../include/cectypes.h" +#include "lib/platform/os.h" diff --git a/src/lib/CECClient.cpp b/src/lib/CECClient.cpp index b0d7e18..b6c0812 100644 --- a/src/lib/CECClient.cpp +++ b/src/lib/CECClient.cpp @@ -30,7 +30,9 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECClient.h" + #include "CECProcessor.h" #include "LibCEC.h" #include "CECTypeUtils.h" @@ -183,7 +185,7 @@ bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_ // and set the address SetDevicePhysicalAddress(iPhysicalAddress); - ConfigurationChanged(m_configuration); + CallbackConfigurationChanged(m_configuration); return bReturn; } @@ -224,28 +226,27 @@ void CCECClient::SetPhysicalAddress(const libcec_configuration &configuration) bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress) { // update the configuration + bool bChanged(true); { CLockObject lock(m_mutex); if (m_configuration.iPhysicalAddress == iPhysicalAddress) - { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address unchanged (%04X)", iPhysicalAddress); - return true; - } + bChanged = false; else - { m_configuration.iPhysicalAddress = iPhysicalAddress; - LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress); - } + } + if (!bChanged) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address unchanged (%04X)", iPhysicalAddress); + return true; } - // persist the new configuration - m_processor->PersistConfiguration(m_configuration); + LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress); // set the physical address for each device SetDevicePhysicalAddress(iPhysicalAddress); // and send back the updated configuration - ConfigurationChanged(m_configuration); + CallbackConfigurationChanged(m_configuration); return true; } @@ -275,6 +276,9 @@ void CCECClient::SetSupportedDeviceTypes(void) // set the new type list m_configuration.deviceTypes = types; + + // persist the new configuration + PersistConfiguration(m_configuration); } bool CCECClient::AllocateLogicalAddresses(void) @@ -321,6 +325,9 @@ bool CCECClient::AllocateLogicalAddresses(void) m_configuration.logicalAddresses.Set(address); } + // persist the new configuration + PersistConfiguration(m_configuration); + return true; } @@ -329,11 +336,11 @@ cec_logical_address CCECClient::AllocateLogicalAddressRecordingDevice(void) cec_logical_address retVal(CECDEVICE_UNKNOWN); LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'"); - if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1)) + if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1, m_configuration.cecVersion)) retVal = CECDEVICE_RECORDINGDEVICE1; - else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2)) + else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2, m_configuration.cecVersion)) retVal = CECDEVICE_RECORDINGDEVICE2; - else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3)) + else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3, m_configuration.cecVersion)) retVal = CECDEVICE_RECORDINGDEVICE3; return retVal; @@ -344,13 +351,13 @@ cec_logical_address CCECClient::AllocateLogicalAddressTuner(void) cec_logical_address retVal(CECDEVICE_UNKNOWN); LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'"); - if (m_processor->TryLogicalAddress(CECDEVICE_TUNER1)) + if (m_processor->TryLogicalAddress(CECDEVICE_TUNER1, m_configuration.cecVersion)) retVal = CECDEVICE_TUNER1; - else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER2)) + else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER2, m_configuration.cecVersion)) retVal = CECDEVICE_TUNER2; - else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER3)) + else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER3, m_configuration.cecVersion)) retVal = CECDEVICE_TUNER3; - else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER4)) + else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER4, m_configuration.cecVersion)) retVal = CECDEVICE_TUNER4; return retVal; @@ -361,11 +368,11 @@ cec_logical_address CCECClient::AllocateLogicalAddressPlaybackDevice(void) cec_logical_address retVal(CECDEVICE_UNKNOWN); LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'"); - if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1)) + if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1, m_configuration.cecVersion)) retVal = CECDEVICE_PLAYBACKDEVICE1; - else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2)) + else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2, m_configuration.cecVersion)) retVal = CECDEVICE_PLAYBACKDEVICE2; - else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3)) + else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3, m_configuration.cecVersion)) retVal = CECDEVICE_PLAYBACKDEVICE3; return retVal; @@ -376,7 +383,7 @@ cec_logical_address CCECClient::AllocateLogicalAddressAudioSystem(void) cec_logical_address retVal(CECDEVICE_UNKNOWN); LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audiosystem'"); - if (m_processor->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM)) + if (m_processor->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM, m_configuration.cecVersion)) retVal = CECDEVICE_AUDIOSYSTEM; return retVal; @@ -398,31 +405,36 @@ CCECBusDevice *CCECClient::GetDeviceByType(const cec_device_type type) const bool CCECClient::ChangeDeviceType(const cec_device_type from, const cec_device_type to) { - LIB_CEC->AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to)); - - CLockObject lock(m_mutex); + if (from == to) + return true; - // get the previous device that was allocated - CCECBusDevice *previousDevice = GetDeviceByType(from); - if (!previousDevice) - return false; + LIB_CEC->AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to)); - // change the type in the device type list - bool bChanged(false); - for (uint8_t iPtr = 0; iPtr < 5; iPtr++) { - if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED) - continue; + CLockObject lock(m_mutex); - if (m_configuration.deviceTypes.types[iPtr] == from) - { - bChanged = true; - m_configuration.deviceTypes.types[iPtr] = to; - } - else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged) + // get the previous device that was allocated + CCECBusDevice *previousDevice = GetDeviceByType(from); + if (!previousDevice) + return false; + + // change the type in the device type list + bool bChanged(false); + for (uint8_t iPtr = 0; iPtr < 5; iPtr++) { - // ensure that dupes are removed - m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED; + if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED) + continue; + + if (m_configuration.deviceTypes.types[iPtr] == from) + { + bChanged = true; + m_configuration.deviceTypes.types[iPtr] = to; + } + else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged) + { + // ensure that dupes are removed + m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED; + } } } @@ -430,29 +442,38 @@ bool CCECClient::ChangeDeviceType(const cec_device_type from, const cec_device_t if (!m_processor->RegisterClient(this)) return false; + // persist the new configuration + PersistConfiguration(m_configuration); + return true; } bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress) { - CLockObject lock(m_mutex); + bool bReturn(true); + if (GetPrimaryLogicalAdddress() != iLogicalAddress) { + LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress); { CLockObject lock(m_mutex); - LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress); m_configuration.logicalAddresses.primary = iLogicalAddress; m_configuration.logicalAddresses.Set(iLogicalAddress); } - return m_processor->RegisterClient(this); + + bReturn = m_processor->RegisterClient(this); + + // persist the new configuration + if (bReturn) + PersistConfiguration(m_configuration); } - return true; + return bReturn; } -bool CCECClient::Transmit(const cec_command &data) +bool CCECClient::Transmit(const cec_command &data, bool bIsReply) { - return m_processor ? m_processor->Transmit(data) : false; + return m_processor ? m_processor->Transmit(data, bIsReply) : false; } bool CCECClient::SendPowerOnDevices(const cec_logical_address address /* = CECDEVICE_TV */) @@ -553,7 +574,7 @@ bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode, bool b // and set the deck control mode if there is a match device->SetDeckControlMode(mode); if (bSendUpdate) - return device->TransmitDeckStatus(CECDEVICE_TV); + return device->TransmitDeckStatus(CECDEVICE_TV, false); return true; } @@ -570,7 +591,7 @@ bool CCECClient::SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate /* = // and set the deck status if there is a match device->SetDeckStatus(info); if (bSendUpdate) - return device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV); + return device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV, false); return true; } @@ -588,7 +609,7 @@ bool CCECClient::SendSetMenuState(const cec_menu_state state, bool bSendUpdate / { (*it)->SetMenuState(state); if (bSendUpdate) - (*it)->TransmitMenuState(CECDEVICE_TV); + (*it)->TransmitMenuState(CECDEVICE_TV, false); } return true; @@ -616,7 +637,7 @@ bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress, con { CCECBusDevice *primary = GetPrimaryDevice(); if (primary) - return primary->TransmitOSDString(iLogicalAddress, duration, strMessage); + return primary->TransmitOSDString(iLogicalAddress, duration, strMessage, false); return false; } @@ -863,7 +884,8 @@ bool CCECClient::SetConfiguration(const libcec_configuration &configuration) SetPhysicalAddress(configuration); } - m_processor->PersistConfiguration(m_configuration); + // persist the new configuration + PersistConfiguration(m_configuration); if (!primary) primary = GetPrimaryDevice(); @@ -897,109 +919,51 @@ void CCECClient::AddCommand(const cec_command &command) if (command.destination == CECDEVICE_BROADCAST || GetLogicalAddresses().IsSet(command.destination)) { - CLockObject lock(m_mutex); - LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode); - - if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand) - m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command); - else if (!m_commandBuffer.Push(command)) - LIB_CEC->AddLog(CEC_LOG_WARNING, "command buffer is full"); + CallbackAddCommand(command); } } int CCECClient::MenuStateChanged(const cec_menu_state newState) { - CLockObject lock(m_mutex); - LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST), ToString(newState)); - - if (m_configuration.callbacks && - m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2 && - m_configuration.callbacks->CBCecMenuStateChanged) - return m_configuration.callbacks->CBCecMenuStateChanged(m_configuration.callbackParam, newState); - - return 0; -} - -void CCECClient::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); - - if (m_configuration.callbacks && - m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0 && - m_configuration.callbacks->CBCecAlert) - m_configuration.callbacks->CBCecAlert(m_configuration.callbackParam, type, param); -} - -void CCECClient::AddLog(const cec_log_message &message) -{ - CLockObject lock(m_logMutex); - if (m_configuration.callbacks && m_configuration.callbacks->CBCecLogMessage) - m_configuration.callbacks->CBCecLogMessage(m_configuration.callbackParam, message); - else - m_logBuffer.Push(message); + return CallbackMenuStateChanged(newState); } void CCECClient::AddKey(void) { - CLockObject lock(m_mutex); + cec_keypress key; + key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN; - if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN) { - cec_keypress key; - - key.duration = (unsigned int) (GetTimeMs() - m_buttontime); - key.keycode = m_iCurrentButton; - LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode); + CLockObject lock(m_mutex); + if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN) + { + key.duration = (unsigned int) (GetTimeMs() - m_buttontime); + key.keycode = m_iCurrentButton; - if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress) - m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key); - else - m_keyBuffer.Push(key); - m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN; + m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN; + m_buttontime = 0; + } } - m_buttontime = 0; + if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %s (%1x)", ToString(key.keycode), key.keycode); + CallbackAddKey(key); + } } void CCECClient::AddKey(const cec_keypress &key) { - CLockObject lock(m_mutex); - - LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode); - - if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress) - m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key); - else - m_keyBuffer.Push(key); + { + CLockObject lock(m_mutex); + m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode; + m_buttontime = key.duration > 0 ? 0 : GetTimeMs(); + } - m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode; - m_buttontime = key.duration > 0 ? 0 : GetTimeMs(); + LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x)", ToString(key.keycode), key.keycode); + CallbackAddKey(key); } void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode) @@ -1014,27 +978,34 @@ void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode) void CCECClient::CheckKeypressTimeout(void) { - if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT) + cec_keypress key; + { - AddKey(); - m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN; - } -} + CLockObject lock(m_mutex); + uint64_t iNow = GetTimeMs(); -void CCECClient::ConfigurationChanged(const libcec_configuration &config) -{ - CLockObject lock(m_mutex); + if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && + iNow - m_buttontime > CEC_BUTTON_TIMEOUT) + { + key.duration = (unsigned int) (iNow - m_buttontime); + key.keycode = m_iCurrentButton; - if (m_configuration.callbacks && - m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0 && - m_configuration.callbacks->CBCecConfigurationChanged && - m_processor->CECInitialised()) - m_configuration.callbacks->CBCecConfigurationChanged(m_configuration.callbackParam, config); + m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN; + m_buttontime = 0; + } + else + { + return; + } + } + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "key auto-released: %s (%1x)", ToString(key.keycode), key.keycode); + CallbackAddKey(key); } bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) { - CLockObject lock(m_mutex); + CLockObject lock(m_cbMutex); m_configuration.callbackParam = cbParam; m_configuration.callbacks = callbacks; return true; @@ -1060,7 +1031,7 @@ bool CCECClient::GetNextCommand(cec_command *command) return m_commandBuffer.Pop(*command); } -CStdString CCECClient::GetConnectionInfo(void) +std::string CCECClient::GetConnectionInfo(void) { CStdString strLog; strLog.Format("libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version)m_configuration.serverVersion), ToString((cec_client_version)m_configuration.clientVersion), m_configuration.iFirmwareVersion); @@ -1087,7 +1058,10 @@ CStdString CCECClient::GetConnectionInfo(void) else strLog.AppendFormat(", physical address: %04x", m_configuration.iPhysicalAddress); - return strLog; + strLog.AppendFormat(", %s", LIB_CEC->GetLibInfo()); + + std::string strReturn(strLog.c_str()); + return strReturn; } void CCECClient::SetTVVendorOverride(const cec_vendor_id id) @@ -1105,6 +1079,9 @@ void CCECClient::SetTVVendorOverride(const cec_vendor_id id) if (tv) tv->SetVendorId((uint64_t)id); } + + // persist the new configuration + PersistConfiguration(m_configuration); } cec_vendor_id CCECClient::GetTVVendorOverride(void) @@ -1113,7 +1090,7 @@ cec_vendor_id CCECClient::GetTVVendorOverride(void) return (cec_vendor_id)m_configuration.tvVendor; } -void CCECClient::SetOSDName(const CStdString &strDeviceName) +void CCECClient::SetOSDName(const std::string &strDeviceName) { { CLockObject lock(m_mutex); @@ -1123,25 +1100,32 @@ void CCECClient::SetOSDName(const CStdString &strDeviceName) LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, strDeviceName.c_str()); CCECBusDevice *primary = GetPrimaryDevice(); - if (primary && !primary->GetCurrentOSDName().Equals(strDeviceName)) + if (primary && !primary->GetCurrentOSDName().Equals(strDeviceName.c_str())) { primary->SetOSDName(strDeviceName); if (m_processor && m_processor->CECInitialised()) - primary->TransmitOSDName(CECDEVICE_TV); + primary->TransmitOSDName(CECDEVICE_TV, false); } + + // persist the new configuration + PersistConfiguration(m_configuration); } -CStdString CCECClient::GetOSDName(void) +std::string CCECClient::GetOSDName(void) { CLockObject lock(m_mutex); - CStdString strOSDName(m_configuration.strDeviceName); + std::string strOSDName(m_configuration.strDeviceName); return strOSDName; } void CCECClient::SetWakeDevices(const cec_logical_addresses &addresses) { - CLockObject lock(m_mutex); - m_configuration.wakeDevices = addresses; + { + CLockObject lock(m_mutex); + m_configuration.wakeDevices = addresses; + } + // persist the new configuration + PersistConfiguration(m_configuration); } cec_logical_addresses CCECClient::GetWakeDevices(void) @@ -1196,6 +1180,9 @@ bool CCECClient::SetDeviceTypes(const cec_device_type_list &deviceTypes) m_configuration.deviceTypes = deviceTypes; } + // persist the new configuration + PersistConfiguration(m_configuration); + if (bNeedReinit) LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(deviceTypes[0])); @@ -1237,7 +1224,7 @@ bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress) // and transmit it if (IsInitialised()) - (*it)->TransmitPhysicalAddress(); + (*it)->TransmitPhysicalAddress(false); } // reactivate the previous active source @@ -1250,6 +1237,9 @@ bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress) device->ActivateSource(); } + // persist the new configuration + PersistConfiguration(m_configuration); + return true; } @@ -1277,7 +1267,7 @@ bool CCECClient::PollDevice(const cec_logical_address iAddress) CCECBusDevice *primary = GetPrimaryDevice(); // poll the destination, with the primary as source if (primary) - return primary->TransmitPoll(iAddress); + return primary->TransmitPoll(iAddress, false); return m_processor ? m_processor->PollDevice(iAddress) : false; } @@ -1325,7 +1315,21 @@ bool CCECClient::SetStreamPath(const cec_logical_address iAddress) bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress) { - return m_processor ? m_processor->SetStreamPath(iPhysicalAddress) : false; + bool bReturn(false); + + CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_TV); + if (device) + { + device->SetStreamPath(iPhysicalAddress); + bReturn = device->GetHandler()->TransmitSetStreamPath(iPhysicalAddress, false); + device->MarkHandlerReady(); + } + else + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH"); + } + + return bReturn; } cec_logical_addresses CCECClient::GetLogicalAddresses(void) @@ -1343,7 +1347,9 @@ bool CCECClient::CanPersistConfiguration(void) bool CCECClient::PersistConfiguration(const libcec_configuration &configuration) { - return m_processor ? m_processor->PersistConfiguration(configuration) : false; + return m_processor && IsRegistered() ? + m_processor->PersistConfiguration(configuration) : + false; } void CCECClient::RescanActiveDevices(void) @@ -1364,3 +1370,92 @@ bool CCECClient::IsLibCECActiveSource(void) } return bReturn; } + +void CCECClient::SourceActivated(const cec_logical_address logicalAddress) +{ + LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source activated: %s (%x)", ToString(logicalAddress), logicalAddress); + CallbackSourceActivated(true, logicalAddress); +} + +void CCECClient::SourceDeactivated(const cec_logical_address logicalAddress) +{ + LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source deactivated: %s (%x)", ToString(logicalAddress), logicalAddress); + CallbackSourceActivated(false, logicalAddress); +} + +void CCECClient::CallbackAddCommand(const cec_command &command) +{ + { + CLockObject lock(m_cbMutex); + if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand) + { + m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command); + return; + } + } + m_commandBuffer.Push(command); +} + +void CCECClient::CallbackAddKey(const cec_keypress &key) +{ + { + CLockObject lock(m_cbMutex); + if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress) + { + m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key); + return; + } + } + m_keyBuffer.Push(key); +} + +void CCECClient::CallbackAddLog(const cec_log_message &message) +{ + { + CLockObject lock(m_cbMutex); + if (m_configuration.callbacks && m_configuration.callbacks->CBCecLogMessage) + { + m_configuration.callbacks->CBCecLogMessage(m_configuration.callbackParam, message); + return; + } + } + m_logBuffer.Push(message); +} + +void CCECClient::CallbackConfigurationChanged(const libcec_configuration &config) +{ + CLockObject lock(m_cbMutex); + if (m_configuration.callbacks && + m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0 && + m_configuration.callbacks->CBCecConfigurationChanged && + m_processor->CECInitialised()) + m_configuration.callbacks->CBCecConfigurationChanged(m_configuration.callbackParam, config); +} + +void CCECClient::CallbackSourceActivated(bool bActivated, const cec_logical_address logicalAddress) +{ + CLockObject lock(m_cbMutex); + 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, bActivated ? 1 : 0); +} + +void CCECClient::CallbackAlert(const libcec_alert type, const libcec_parameter ¶m) +{ + CLockObject lock(m_cbMutex); + if (m_configuration.callbacks && + m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0 && + m_configuration.callbacks->CBCecAlert) + m_configuration.callbacks->CBCecAlert(m_configuration.callbackParam, type, param); +} + +int CCECClient::CallbackMenuStateChanged(const cec_menu_state newState) +{ + CLockObject lock(m_cbMutex); + if (m_configuration.callbacks && + m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2 && + m_configuration.callbacks->CBCecMenuStateChanged) + return m_configuration.callbacks->CBCecMenuStateChanged(m_configuration.callbackParam, newState); + return 0; +} diff --git a/src/lib/CECClient.h b/src/lib/CECClient.h index 26944a7..be72448 100644 --- a/src/lib/CECClient.h +++ b/src/lib/CECClient.h @@ -31,15 +31,15 @@ * http://www.pulse-eight.net/ */ -#include "../../include/cectypes.h" +#include #include "platform/threads/mutex.h" #include "platform/util/buffer.h" -#include "devices/CECBusDevice.h" - namespace CEC { class CCECProcessor; + class CCECBusDevice; + class CCECPlaybackDevice; class CCECClient { @@ -97,7 +97,7 @@ namespace CEC /*! * @return A string that describes this client. */ - virtual CStdString GetConnectionInfo(void); + virtual std::string GetConnectionInfo(void); /*! * @return The current value of the TV vendor override setting. @@ -107,7 +107,7 @@ namespace CEC /*! * @return The current value of the OSD name setting. */ - virtual CStdString GetOSDName(void); + virtual std::string GetOSDName(void); /*! * @return Get the current value of the wake device setting. @@ -130,7 +130,7 @@ namespace CEC virtual bool GetNextLogMessage(cec_log_message *message); /**< @deprecated will be removed in v2.0 */ virtual bool GetNextKeypress(cec_keypress *key); /**< @deprecated will be removed in v2.0 */ virtual bool GetNextCommand(cec_command *command); /**< @deprecated will be removed in v2.0 */ - virtual bool Transmit(const cec_command &data); + virtual bool Transmit(const cec_command &data, bool bIsReply); virtual bool SetLogicalAddress(const cec_logical_address iLogicalAddress); virtual bool SetPhysicalAddress(const uint16_t iPhysicalAddress); virtual bool SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce = false); @@ -176,8 +176,8 @@ namespace CEC // callbacks virtual void AddCommand(const cec_command &command); virtual int MenuStateChanged(const cec_menu_state newState); - virtual void Alert(const libcec_alert type, const libcec_parameter ¶m); - virtual void AddLog(const cec_log_message &message); + virtual void Alert(const libcec_alert type, const libcec_parameter ¶m) { CallbackAlert(type, param); } + virtual void AddLog(const cec_log_message &message) { CallbackAddLog(message); } virtual void AddKey(void); virtual void AddKey(const cec_keypress &key); virtual void SetCurrentButton(const cec_user_control_code iButtonCode); @@ -219,7 +219,7 @@ namespace CEC * @brief Change the OSD name of the primary device that this client is controlling. * @param strDeviceName The new value. */ - virtual void SetOSDName(const CStdString &strDeviceName); + virtual void SetOSDName(const std::string &strDeviceName); /*! * @brief Change the value of the devices to wake. @@ -282,12 +282,6 @@ namespace CEC */ virtual bool SetDevicePhysicalAddress(const uint16_t iPhysicalAddress); - /*! - * @brief Called when the configuration changed and needs to be sent back to the client. - * @param config The new configuration. - */ - virtual void ConfigurationChanged(const libcec_configuration &config); - /*! * @brief Try to autodetect the physical address. * @return True when autodetected (and set in m_configuration), false otherwise. @@ -299,12 +293,20 @@ namespace CEC */ virtual void SetSupportedDeviceTypes(void); + virtual void CallbackAddCommand(const cec_command &command); + virtual void CallbackAddKey(const cec_keypress &key); + virtual void CallbackAddLog(const cec_log_message &message); + virtual void CallbackAlert(const libcec_alert type, const libcec_parameter ¶m); + virtual void CallbackConfigurationChanged(const libcec_configuration &config); + virtual int CallbackMenuStateChanged(const cec_menu_state newState); + virtual void CallbackSourceActivated(bool bActivated, const cec_logical_address logicalAddress); + CCECProcessor * m_processor; /**< a pointer to the processor */ libcec_configuration m_configuration; /**< the configuration of this client */ bool m_bInitialised; /**< true when initialised, false otherwise */ bool m_bRegistered; /**< true when registered in the processor, false otherwise */ PLATFORM::CMutex m_mutex; /**< mutex for changes to this instance */ - PLATFORM::CMutex m_logMutex; /**< mutex that is held when sending a log message back to the client */ + PLATFORM::CMutex m_cbMutex; /**< mutex that is held when doing anything with callbacks */ 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 */ diff --git a/src/lib/CECInputBuffer.h b/src/lib/CECInputBuffer.h index 9daf582..019cfdd 100644 --- a/src/lib/CECInputBuffer.h +++ b/src/lib/CECInputBuffer.h @@ -31,7 +31,6 @@ * http://www.pulse-eight.net/ */ -#include "../../include/cectypes.h" #include "platform/threads/mutex.h" #include "platform/util/buffer.h" diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 28adee3..76c2465 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -30,9 +30,10 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECProcessor.h" -#include "adapter/USBCECAdapterCommunication.h" +#include "adapter/AdapterFactory.h" #include "devices/CECBusDevice.h" #include "devices/CECAudioSystem.h" #include "devices/CECPlaybackDevice.h" @@ -135,7 +136,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint } // create a new connection - m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate); + m_communication = CAdapterFactory(this->m_libcec).GetInstance(strPort, iBaudRate); // open a new connection unsigned iConnectTry(0); @@ -170,7 +171,7 @@ void CCECProcessor::SetCECInitialised(bool bSetTo /* = true */) UnregisterClients(); } -bool CCECProcessor::TryLogicalAddress(cec_logical_address address) +bool CCECProcessor::TryLogicalAddress(cec_logical_address address, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */) { // find the device CCECBusDevice *device = m_busDevices->At(address); @@ -181,8 +182,7 @@ bool CCECProcessor::TryLogicalAddress(cec_logical_address address) return false; // poll the LA if not - SetAckMask(0); - return device->TryLogicalAddress(); + return device->TryLogicalAddress(libCECSpecVersion); } return false; @@ -308,13 +308,11 @@ bool CCECProcessor::PollDevice(cec_logical_address iAddress) CCECBusDevice *primary = GetPrimaryDevice(); // poll the destination, with the primary as source if (primary) - return primary->TransmitPoll(iAddress); + return primary->TransmitPoll(iAddress, false); - // try to find the destination - CCECBusDevice *device = m_busDevices->At(iAddress); - // and poll the destination, with the same LA as source + CCECBusDevice *device = m_busDevices->At(CECDEVICE_UNREGISTERED); if (device) - return device->TransmitPoll(iAddress); + return device->TransmitPoll(iAddress, false); return false; } @@ -361,8 +359,9 @@ bool CCECProcessor::IsActiveSource(cec_logical_address iAddress) return device && device->IsActiveSource(); } -bool CCECProcessor::Transmit(const cec_command &data) +bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply) { + cec_command transmitData(data); uint8_t iMaxTries(0); bool bRetry(true); uint8_t iTries(0); @@ -373,10 +372,24 @@ bool CCECProcessor::Transmit(const cec_command &data) // reset the state of this message to 'unknown' cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN; - LogOutput(data); + if (!m_communication->SupportsSourceLogicalAddress(transmitData.initiator)) + { + if (transmitData.initiator == CECDEVICE_UNREGISTERED && m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) + { + m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter. using '%s' instead", ToString(transmitData.initiator), ToString(CECDEVICE_FREEUSE)); + transmitData.initiator = CECDEVICE_FREEUSE; + } + else + { + m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter", ToString(transmitData.initiator)); + return false; + } + } + + LogOutput(transmitData); // find the initiator device - CCECBusDevice *initiator = m_busDevices->At(data.initiator); + CCECBusDevice *initiator = m_busDevices->At(transmitData.initiator); if (!initiator) { m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator"); @@ -384,10 +397,10 @@ bool CCECProcessor::Transmit(const cec_command &data) } // find the destination device, if it's not the broadcast address - if (data.destination != CECDEVICE_BROADCAST) + if (transmitData.destination != CECDEVICE_BROADCAST) { // check if the device is marked as handled by libCEC - CCECBusDevice *destination = m_busDevices->At(data.destination); + CCECBusDevice *destination = m_busDevices->At(transmitData.destination); if (destination && destination->IsHandledByLibCEC()) { // and reject the command if it's trying to send data to a device that is handled by libCEC @@ -407,11 +420,11 @@ bool CCECProcessor::Transmit(const cec_command &data) // and try to send the command while (bRetry && ++iTries < iMaxTries) { - if (initiator->IsUnsupportedFeature(data.opcode)) + if (initiator->IsUnsupportedFeature(transmitData.opcode)) return false; adapterState = !IsStopped() && m_communication && m_communication->IsOpen() ? - m_communication->Write(data, bRetry, iLineTimeout) : + m_communication->Write(transmitData, bRetry, iLineTimeout, bIsReply) : ADAPTER_MESSAGE_STATE_ERROR; iLineTimeout = m_iRetryLineTimeout; } @@ -428,7 +441,7 @@ void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_addres command.parameters.PushBack((uint8_t)opcode); command.parameters.PushBack((uint8_t)reason); - Transmit(command); + Transmit(command, true); } void CCECProcessor::ProcessCommand(const cec_command &command) @@ -468,9 +481,15 @@ uint16_t CCECProcessor::GetDetectedPhysicalAddress(void) const return m_communication ? m_communication->GetPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS; } -bool CCECProcessor::SetAckMask(uint16_t iMask) +bool CCECProcessor::ClearLogicalAddresses(void) { - return m_communication ? m_communication->SetAckMask(iMask) : false; + cec_logical_addresses addresses; addresses.Clear(); + return SetLogicalAddresses(addresses); +} + +bool CCECProcessor::SetLogicalAddresses(const cec_logical_addresses &addresses) +{ + return m_communication ? m_communication->SetLogicalAddresses(addresses) : false; } bool CCECProcessor::StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices) @@ -507,7 +526,8 @@ bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */) // open a connection if no connection has been opened if (!m_communication && strPort) { - IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort); + CAdapterFactory factory(this->m_libcec); + IAdapterCommunication *comm = factory.GetInstance(strPort); CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT); int iConnectTry(0); while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false) @@ -551,14 +571,6 @@ bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator) return !device || !device->HandleReceiveFailed(); } -bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress) -{ - // stream path changes are sent by the TV - bool bReturn = GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress); - GetTV()->MarkHandlerReady(); - return bReturn; -} - bool CCECProcessor::CanPersistConfiguration(void) { return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false; @@ -566,7 +578,15 @@ bool CCECProcessor::CanPersistConfiguration(void) bool CCECProcessor::PersistConfiguration(const libcec_configuration &configuration) { - return m_communication ? m_communication->PersistConfiguration(configuration) : false; + libcec_configuration persistConfiguration = configuration; + if (!CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress)) + { + CCECBusDevice *device = GetPrimaryDevice(); + if (device) + persistConfiguration.iPhysicalAddress = device->GetCurrentPhysicalAddress(); + } + + return m_communication ? m_communication->PersistConfiguration(persistConfiguration) : false; } void CCECProcessor::RescanActiveDevices(void) @@ -636,15 +656,20 @@ bool CCECProcessor::RegisterClient(CCECClient *client) return false; } - // ensure that we know the vendor id of the TV - 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()) UnregisterClient(client); + // ensure that controlled mode is enabled + m_communication->SetControlledMode(true); + + // ensure that we know the vendor id of the TV + CCECBusDevice *tv = GetTV(); + if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED)) + tv->GetVendorId(CECDEVICE_UNREGISTERED); + else if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) + tv->GetVendorId(CECDEVICE_FREEUSE); + // get the configuration from the client m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion)); @@ -653,13 +678,13 @@ bool CCECProcessor::RegisterClient(CCECClient *client) client->SetInitialised(false); // get the current ackmask, so we can restore it if polling fails - uint16_t iPreviousMask(m_communication->GetAckMask()); + cec_logical_addresses previousMask = GetLogicalAddresses(); // find logical addresses for this client if (!client->AllocateLogicalAddresses()) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types"); - SetAckMask(iPreviousMask); + SetLogicalAddresses(previousMask); return false; } @@ -701,7 +726,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client) client->SetRegistered(true); // set the new ack mask - bool bReturn = SetAckMask(GetLogicalAddresses().AckMask()) && + bool bReturn = SetLogicalAddresses(GetLogicalAddresses()) && // and initialise the client client->OnRegister(); @@ -762,7 +787,17 @@ bool CCECProcessor::UnregisterClient(CCECClient *client) } // set the new ackmask - return SetAckMask(GetLogicalAddresses().AckMask()); + cec_logical_addresses addresses = GetLogicalAddresses(); + if (SetLogicalAddresses(addresses)) + { + // no more clients left, disable controlled mode + if (addresses.IsEmpty()) + m_communication->SetControlledMode(false); + + return true; + } + + return false; } void CCECProcessor::UnregisterClients(void) diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 5f496d2..5aa532b 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -32,7 +32,6 @@ */ #include -#include "../../include/cectypes.h" #include "platform/threads/threads.h" #include "platform/util/buffer.h" @@ -89,7 +88,6 @@ namespace CEC cec_logical_address GetActiveSource(bool bRequestActiveSource = true); bool IsActiveSource(cec_logical_address iAddress); bool CECInitialised(void); - bool SetStreamPath(uint16_t iPhysicalAddress); bool StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices); bool StandbyDevice(const cec_logical_address initiator, cec_logical_address address); @@ -109,7 +107,7 @@ namespace CEC bool SetLineTimeout(uint8_t iTimeout); - bool Transmit(const cec_command &data); + bool Transmit(const cec_command &data, bool bIsReply); void TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE); bool StartBootloader(const char *strPort = NULL); @@ -126,7 +124,7 @@ namespace CEC bool IsHandledByLibCEC(const cec_logical_address address) const; - bool TryLogicalAddress(cec_logical_address address); + bool TryLogicalAddress(cec_logical_address address, cec_version libCECSpecVersion = CEC_VERSION_1_4); bool IsRunningLatestFirmware(void); private: @@ -135,7 +133,9 @@ namespace CEC void ReplaceHandlers(void); bool PhysicalAddressInUse(uint16_t iPhysicalAddress); - bool SetAckMask(uint16_t iMask); + + bool ClearLogicalAddresses(void); + bool SetLogicalAddresses(const cec_logical_addresses &addresses); void LogOutput(const cec_command &data); void ProcessCommand(const cec_command &command); diff --git a/src/lib/CECTypeUtils.h b/src/lib/CECTypeUtils.h index a62637b..f088796 100644 --- a/src/lib/CECTypeUtils.h +++ b/src/lib/CECTypeUtils.h @@ -31,8 +31,6 @@ * http://www.pulse-eight.net/ */ -#include "../../include/cectypes.h" - namespace CEC { class CCECTypeUtils @@ -510,6 +508,8 @@ namespace CEC return "Sharp"; case CEC_VENDOR_VIZIO: return "Vizio"; + case CEC_VENDOR_BROADCOM: + return "Broadcom"; default: return "Unknown"; } @@ -541,6 +541,10 @@ namespace CEC return "1.7.0"; case CEC_CLIENT_VERSION_1_7_1: return "1.7.1"; + case CEC_CLIENT_VERSION_1_7_2: + return "1.7.2"; + case CEC_CLIENT_VERSION_1_8_0: + return "1.8.0"; default: return "Unknown"; } @@ -572,6 +576,10 @@ namespace CEC return "1.7.0"; case CEC_SERVER_VERSION_1_7_1: return "1.7.1"; + case CEC_SERVER_VERSION_1_7_2: + return "1.7.2"; + case CEC_SERVER_VERSION_1_8_0: + return "1.8.0"; default: return "Unknown"; } @@ -595,5 +603,174 @@ namespace CEC return "unknown"; } } + + static const char *ToString(const cec_user_control_code key) + { + switch (key) + { + case CEC_USER_CONTROL_CODE_SELECT: + return "select"; + case CEC_USER_CONTROL_CODE_UP: + return "up"; + case CEC_USER_CONTROL_CODE_DOWN: + return "down"; + case CEC_USER_CONTROL_CODE_LEFT: + return "left"; + case CEC_USER_CONTROL_CODE_RIGHT: + return "right"; + case CEC_USER_CONTROL_CODE_RIGHT_UP: + return "right+up"; + case CEC_USER_CONTROL_CODE_RIGHT_DOWN: + return "right+down"; + case CEC_USER_CONTROL_CODE_LEFT_UP: + return "left+up"; + case CEC_USER_CONTROL_CODE_LEFT_DOWN: + return "left+down"; + case CEC_USER_CONTROL_CODE_ROOT_MENU: + return "root menu"; + case CEC_USER_CONTROL_CODE_SETUP_MENU: + return "setup menu"; + case CEC_USER_CONTROL_CODE_CONTENTS_MENU: + return "contents menu"; + case CEC_USER_CONTROL_CODE_FAVORITE_MENU: + return "favourite menu"; + case CEC_USER_CONTROL_CODE_EXIT: + return "exit"; + case CEC_USER_CONTROL_CODE_NUMBER0: + return "0"; + case CEC_USER_CONTROL_CODE_NUMBER1: + return "1"; + case CEC_USER_CONTROL_CODE_NUMBER2: + return "2"; + case CEC_USER_CONTROL_CODE_NUMBER3: + return "3"; + case CEC_USER_CONTROL_CODE_NUMBER4: + return "4"; + case CEC_USER_CONTROL_CODE_NUMBER5: + return "5"; + case CEC_USER_CONTROL_CODE_NUMBER6: + return "6"; + case CEC_USER_CONTROL_CODE_NUMBER7: + return "7"; + case CEC_USER_CONTROL_CODE_NUMBER8: + return "8"; + case CEC_USER_CONTROL_CODE_NUMBER9: + return "9"; + case CEC_USER_CONTROL_CODE_DOT: + return "."; + case CEC_USER_CONTROL_CODE_ENTER: + return "enter"; + case CEC_USER_CONTROL_CODE_CLEAR: + return "clear"; + case CEC_USER_CONTROL_CODE_NEXT_FAVORITE: + return "next favourite"; + case CEC_USER_CONTROL_CODE_CHANNEL_UP: + return "channel up"; + case CEC_USER_CONTROL_CODE_CHANNEL_DOWN: + return "channel down"; + case CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL: + return "previous channel"; + case CEC_USER_CONTROL_CODE_SOUND_SELECT: + return "sound select"; + case CEC_USER_CONTROL_CODE_INPUT_SELECT: + return "input select"; + case CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION: + return "display information"; + case CEC_USER_CONTROL_CODE_HELP: + return "help"; + case CEC_USER_CONTROL_CODE_PAGE_UP: + return "page up"; + case CEC_USER_CONTROL_CODE_PAGE_DOWN: + return "page down"; + case CEC_USER_CONTROL_CODE_POWER: + return "power"; + case CEC_USER_CONTROL_CODE_VOLUME_UP: + return "volume up"; + case CEC_USER_CONTROL_CODE_VOLUME_DOWN: + return "volume down"; + case CEC_USER_CONTROL_CODE_MUTE: + return "mute"; + case CEC_USER_CONTROL_CODE_PLAY: + return "play"; + case CEC_USER_CONTROL_CODE_STOP: + return "stop"; + case CEC_USER_CONTROL_CODE_PAUSE: + return "pause"; + case CEC_USER_CONTROL_CODE_RECORD: + return "record"; + case CEC_USER_CONTROL_CODE_REWIND: + return "rewind"; + case CEC_USER_CONTROL_CODE_FAST_FORWARD: + return "Fast forward"; + case CEC_USER_CONTROL_CODE_EJECT: + return "eject"; + case CEC_USER_CONTROL_CODE_FORWARD: + return "forward"; + case CEC_USER_CONTROL_CODE_BACKWARD: + return "backward"; + case CEC_USER_CONTROL_CODE_STOP_RECORD: + return "stop record"; + case CEC_USER_CONTROL_CODE_PAUSE_RECORD: + return "pause record"; + case CEC_USER_CONTROL_CODE_ANGLE: + return "angle"; + case CEC_USER_CONTROL_CODE_SUB_PICTURE: + return "sub picture"; + case CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND: + return "video on demand"; + case CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE: + return "electronic program guide"; + case CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING: + return "timer programming"; + case CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION: + return "initial configuration"; + case CEC_USER_CONTROL_CODE_PLAY_FUNCTION: + return "play (function)"; + case CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION: + return "pause play (function)"; + case CEC_USER_CONTROL_CODE_RECORD_FUNCTION: + return "record (function)"; + case CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION: + return "pause record (function)"; + case CEC_USER_CONTROL_CODE_STOP_FUNCTION: + return "stop (function)"; + case CEC_USER_CONTROL_CODE_MUTE_FUNCTION: + return "mute (function)"; + case CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION: + return "restore volume"; + case CEC_USER_CONTROL_CODE_TUNE_FUNCTION: + return "tune"; + case CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION: + return "select media"; + case CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION: + return "select AV input"; + case CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION: + return "select audio input"; + case CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION: + return "power toggle"; + case CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION: + return "power off"; + case CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION: + return "power on"; + case CEC_USER_CONTROL_CODE_F1_BLUE: + return "F1 (blue)"; + case CEC_USER_CONTROL_CODE_F2_RED: + return "F2 (red)"; + case CEC_USER_CONTROL_CODE_F3_GREEN: + return "F3 (green)"; + case CEC_USER_CONTROL_CODE_F4_YELLOW: + return "F4 (yellow)"; + case CEC_USER_CONTROL_CODE_F5: + return "F5"; + case CEC_USER_CONTROL_CODE_DATA: + return "data"; + case CEC_USER_CONTROL_CODE_AN_RETURN: + return "return (Samsung)"; + case CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST: + return "channels list (Samsung)"; + default: + return "unknown"; + } + } }; } diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index c0931c3..ad4ce66 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -30,10 +30,11 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "LibCEC.h" -#include "adapter/USBCECAdapterDetection.h" -#include "adapter/USBCECAdapterCommunication.h" +#include "adapter/AdapterFactory.h" +#include "adapter/AdapterCommunication.h" #include "CECProcessor.h" #include "CECTypeUtils.h" #include "devices/CECAudioSystem.h" @@ -114,13 +115,7 @@ void CLibCEC::Close(void) 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); + return CAdapterFactory(this).FindAdapters(deviceList, iBufSize, strDevicePath); } bool CLibCEC::StartBootloader(void) @@ -171,7 +166,7 @@ bool CLibCEC::IsLibCECActiveSource(void) bool CLibCEC::Transmit(const cec_command &data) { - return m_client ? m_client->Transmit(data) : false; + return m_client ? m_client->Transmit(data, false) : false; } bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress) @@ -578,7 +573,7 @@ void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAdd // client version < 1.5.0 snprintf(configuration.strDeviceName, 13, "%s", strDeviceName); configuration.iPhysicalAddress = iPhysicalAddress; - configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE); + configuration.deviceTypes.Add(CCECTypeUtils::GetType(iLogicalAddress)); return CECInitialise(&configuration); } @@ -587,17 +582,24 @@ bool CECStartBootloader(void) { bool bReturn(false); cec_adapter deviceList[1]; - if (CUSBCECAdapterDetection::FindAdapters(deviceList, 1) > 0) + if (CAdapterFactory(NULL).FindAdapters(deviceList, 1, 0) > 0) { - CUSBCECAdapterCommunication comm(NULL, deviceList[0].comm); - CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT); - while (timeout.TimeLeft() > 0 && (bReturn = comm.Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false) + CAdapterFactory factory(NULL); + IAdapterCommunication *comm = factory.GetInstance(deviceList[0].comm); + if (comm) { - comm.Close(); - CEvent::Sleep(500); + CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT); + while (timeout.TimeLeft() > 0 && + (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false) + { + comm->Close(); + CEvent::Sleep(500); + } + if (comm->IsOpen()) + bReturn = comm->StartBootloader(); + + delete comm; } - if (comm.IsOpen()) - bReturn = comm.StartBootloader(); } return bReturn; @@ -616,6 +618,37 @@ bool CLibCEC::GetDeviceInformation(const char *strPort, libcec_configuration *co return m_cec->GetDeviceInformation(strPort, config, iTimeoutMs); } +const char *CLibCEC::GetLibInfo(void) +{ +#ifndef LIB_INFO +#ifdef _WIN32 +#define FEATURES "'P8 USB' 'P8 USB detect'" +#ifdef _WIN64 +#define HOST_TYPE "Windows (x64)" +#else +#define HOST_TYPE "Windows (x86)" +#endif +#else +#define HOST_TYPE "unknown" +#define FEATURES "unknown" +#endif + + return "host: " HOST_TYPE ", features: " FEATURES ", compiled: " __DATE__; +#else + return LIB_INFO; +#endif +} + +const char *CLibCEC::ToString(const cec_user_control_code key) +{ + return CCECTypeUtils::ToString(key); +} + +void CLibCEC::InitVideoStandalone(void) +{ + CAdapterFactory::InitVideoStandalone(); +} + // no longer being used void CLibCEC::AddKey(const cec_keypress &UNUSED(key)) {} void CLibCEC::ConfigurationChanged(const libcec_configuration &UNUSED(config)) {} diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index 6407e57..76d2919 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -32,7 +32,7 @@ */ #include -#include "../../include/cec.h" +#include "cec.h" #include "platform/util/buffer.h" namespace CEC @@ -146,6 +146,9 @@ namespace CEC CCECClient *RegisterClient(libcec_configuration &configuration); void UnregisterClients(void); std::vector GetClients(void) { return m_clients; }; + const char *GetLibInfo(void); + const char *ToString(const cec_user_control_code key); + void InitVideoStandalone(void); CCECProcessor * m_cec; diff --git a/src/lib/LibCECC.cpp b/src/lib/LibCECC.cpp index 4a7e0be..2576da0 100644 --- a/src/lib/LibCECC.cpp +++ b/src/lib/LibCECC.cpp @@ -30,8 +30,9 @@ * http://www.pulse-eight.net/ */ -#include "../../include/cec.h" -#include "../../include/cecc.h" +#include "env.h" +#include "cec.h" +#include "cecc.h" using namespace CEC; using namespace std; @@ -426,4 +427,15 @@ int cec_get_device_information(const char *strPort, CEC::libcec_configuration *c return cec_parser ? (cec_parser->GetDeviceInformation(strPort, config, iTimeoutMs) ? 1 : 0) : -1; } +const char * cec_get_lib_info(void) +{ + return cec_parser ? cec_parser->GetLibInfo() : NULL; +} + +void cec_init_video_standalone(void) +{ + if (cec_parser) + cec_parser->InitVideoStandalone(); +} + //@} diff --git a/src/lib/LibCECDll.cpp b/src/lib/LibCECDll.cpp index 819d609..9657b57 100644 --- a/src/lib/LibCECDll.cpp +++ b/src/lib/LibCECDll.cpp @@ -30,6 +30,7 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "platform/os.h" int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 3d34f83..7ea1e99 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -8,15 +8,12 @@ library_include_HEADERS = ../../include/cec.h \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libcec.pc +## libCEC core libcec_la_SOURCES = CECProcessor.cpp \ LibCEC.cpp \ LibCECC.cpp \ CECClient.cpp \ - adapter/USBCECAdapterCommands.cpp \ - adapter/USBCECAdapterCommunication.cpp \ - adapter/USBCECAdapterDetection.cpp \ - adapter/USBCECAdapterMessage.cpp \ - adapter/USBCECAdapterMessageQueue.cpp \ + adapter/AdapterFactory.cpp \ devices/CECAudioSystem.cpp \ devices/CECBusDevice.cpp \ devices/CECDeviceMap.cpp \ @@ -28,12 +25,29 @@ libcec_la_SOURCES = CECProcessor.cpp \ implementations/CECCommandHandler.cpp \ implementations/SLCommandHandler.cpp \ implementations/VLCommandHandler.cpp \ - implementations/RLCommandHandler.cpp \ - platform/posix/serialport.cpp \ - platform/posix/serversocket.cpp\ - platform/posix/os-edid.cpp \ - platform/adl/adl-edid.cpp \ - platform/nvidia/nv-edid.cpp - + implementations/RLCommandHandler.cpp + +## server sockets, currently unused +##libcec_la_SOURCES += platform/posix/serversocket.cpp + +## Pulse-Eight USB-CEC support +if USE_P8_USB +libcec_la_SOURCES += adapter/Pulse-Eight/USBCECAdapterMessage.cpp \ + adapter/Pulse-Eight/USBCECAdapterCommands.cpp \ + adapter/Pulse-Eight/USBCECAdapterCommunication.cpp \ + adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp \ + adapter/Pulse-Eight/USBCECAdapterDetection.cpp \ + platform/posix/serialport.cpp \ + platform/posix/os-edid.cpp \ + platform/adl/adl-edid.cpp \ + platform/nvidia/nv-edid.cpp +endif + +## Raspberry Pi support +if USE_RPI_API +libcec_la_SOURCES += adapter/RPi/RPiCECAdapterDetection.cpp \ + adapter/RPi/RPiCECAdapterCommunication.cpp \ + adapter/RPi/RPiCECAdapterMessageQueue.cpp +endif + libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@ -libcec_la_CPPFLAGS = -I@abs_top_srcdir@/include diff --git a/src/lib/adapter/AdapterCommunication.h b/src/lib/adapter/AdapterCommunication.h index 11af5e7..03880b6 100644 --- a/src/lib/adapter/AdapterCommunication.h +++ b/src/lib/adapter/AdapterCommunication.h @@ -31,13 +31,23 @@ * http://www.pulse-eight.net/ */ -#include "../platform/util/StdString.h" -#include "USBCECAdapterMessage.h" +#include namespace CEC { class CLibCEC; + typedef enum cec_adapter_message_state + { + ADAPTER_MESSAGE_STATE_UNKNOWN = 0, /**< the initial state */ + ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT, /**< waiting in the send queue of the adapter, or timed out */ + ADAPTER_MESSAGE_STATE_SENT, /**< sent and waiting on an ACK */ + ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED, /**< sent, but failed to ACK */ + ADAPTER_MESSAGE_STATE_SENT_ACKED, /**< sent, and ACK received */ + ADAPTER_MESSAGE_STATE_INCOMING, /**< received from another device */ + ADAPTER_MESSAGE_STATE_ERROR /**< an error occured */ + } cec_adapter_message_state; + class IAdapterCommunicationCallback { public: @@ -100,16 +110,17 @@ namespace CEC /*! * @return The last error message, or an empty string if there was none */ - virtual CStdString GetError(void) const = 0; + virtual std::string GetError(void) const = 0; /*! * @brief Write a cec_command to the adapter * @param data The command to write * @param bRetry The command can be retried * @param iLineTimeout The line timeout to be used + * @param bIsReply True when this message is a reply, false otherwise * @return The last state of the transmitted command */ - virtual cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout = 3) = 0; + virtual cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply) = 0; /*! * @brief Change the current line timeout on the CEC bus @@ -124,13 +135,8 @@ namespace CEC */ virtual bool StartBootloader(void) = 0; - /*! - * @brief Change the ACK-mask of the device, the mask for logical addresses to which the CEC device should ACK - * @param iMask The new mask - * @return True when set, false otherwise. - */ - virtual bool SetAckMask(uint16_t iMask) = 0; - virtual uint16_t GetAckMask(void) = 0; + virtual bool SetLogicalAddresses(const cec_logical_addresses &addresses) = 0; + virtual cec_logical_addresses GetLogicalAddresses(void) = 0; /*! * @brief Check whether the CEC adapter responds @@ -175,13 +181,25 @@ namespace CEC /*! * @return The name of the port */ - virtual CStdString GetPortName(void) = 0; + virtual std::string GetPortName(void) = 0; /*! * @return The physical address, if the adapter supports this. 0 otherwise. */ virtual uint16_t GetPhysicalAddress(void) = 0; + /*! + * @return The vendor id for this device + */ + virtual cec_vendor_id GetVendorId(void) = 0; + + /*! + * @brief Checks whether a logical address is supported by the adapter. + * @param address The address to check. + * @return True when supported, false otherwise. + */ + virtual bool SupportsSourceLogicalAddress(const cec_logical_address address) = 0; + IAdapterCommunicationCallback *m_callback; }; }; diff --git a/src/lib/adapter/AdapterFactory.cpp b/src/lib/adapter/AdapterFactory.cpp new file mode 100644 index 0000000..9ee9cc7 --- /dev/null +++ b/src/lib/adapter/AdapterFactory.cpp @@ -0,0 +1,106 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" +#include "AdapterFactory.h" + +#include +#include "lib/LibCEC.h" +#include "lib/CECProcessor.h" + +#if defined(HAVE_P8_USB) +#include "Pulse-Eight/USBCECAdapterDetection.h" +#include "Pulse-Eight/USBCECAdapterCommunication.h" +#endif + +#if defined(HAVE_RPI_API) +#include "RPi/RPiCECAdapterDetection.h" +#include "RPi/RPiCECAdapterCommunication.h" +#endif + +using namespace std; +using namespace CEC; + +int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) +{ + int8_t iAdaptersFound(0); + +#if defined(HAVE_P8_USB) + if (!CUSBCECAdapterDetection::CanAutodetect()) + { + if (m_lib) + m_lib->AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with detection code for the Pulse-Eight USB-CEC Adapter, so the path to the COM port has to be provided to libCEC if this adapter is being used"); + } + else + iAdaptersFound += CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath); +#else + m_lib->AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with support for the Pulse-Eight USB-CEC Adapter"); +#endif + +#if defined(HAVE_RPI_API) + if (iAdaptersFound < iBufSize && CRPiCECAdapterDetection::FindAdapter() && + (!strDevicePath || !strcmp(strDevicePath, CEC_RPI_VIRTUAL_COM))) + { + snprintf(deviceList[iAdaptersFound].path, 1024, CEC_RPI_VIRTUAL_PATH); + snprintf(deviceList[iAdaptersFound++].comm, 1024, CEC_RPI_VIRTUAL_COM); + } +#endif + +#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) +#error "libCEC doesn't have support for any type of adapter. please check your build system or configuration" +#endif + + return iAdaptersFound; +} + +IAdapterCommunication *CAdapterFactory::GetInstance(const char *strPort, uint16_t iBaudRate) +{ +#if defined(HAVE_RPI_API) + if (!strcmp(strPort, CEC_RPI_VIRTUAL_COM)) + return new CRPiCECAdapterCommunication(m_lib->m_cec); +#endif + +#if defined(HAVE_P8_USB) + return new CUSBCECAdapterCommunication(m_lib->m_cec, strPort, iBaudRate); +#endif + +#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) + return NULL; +#endif +} + +void CAdapterFactory::InitVideoStandalone(void) +{ +#if defined(HAVE_RPI_API) + CRPiCECAdapterCommunication::InitHost(); +#endif +} diff --git a/src/lib/adapter/AdapterFactory.h b/src/lib/adapter/AdapterFactory.h new file mode 100644 index 0000000..d8a1360 --- /dev/null +++ b/src/lib/adapter/AdapterFactory.h @@ -0,0 +1,57 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include +#include + +namespace CEC +{ + class CLibCEC; + class IAdapterCommunication; + + class CAdapterFactory + { + public: + CAdapterFactory(CLibCEC *lib) : + m_lib(lib) {} + virtual ~CAdapterFactory(void) {}; + + int8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL); + IAdapterCommunication *GetInstance(const char *strPort, uint16_t iBaudRate = CEC_SERIAL_DEFAULT_BAUDRATE); + + static void InitVideoStandalone(void); + + private: + CLibCEC *m_lib; + }; +} diff --git a/src/lib/adapter/USBCECAdapterCommands.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp similarity index 86% rename from src/lib/adapter/USBCECAdapterCommands.cpp rename to src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp index 6642ac8..457889c 100644 --- a/src/lib/adapter/USBCECAdapterCommands.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp @@ -30,10 +30,15 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "USBCECAdapterCommands.h" -#include "../LibCEC.h" -#include "../CECProcessor.h" -#include "../CECTypeUtils.h" + +#include "USBCECAdapterMessage.h" +#include "USBCECAdapterCommunication.h" +#include "lib/LibCEC.h" +#include "lib/CECProcessor.h" +#include "lib/CECTypeUtils.h" +#include using namespace CEC; using namespace PLATFORM; @@ -48,7 +53,8 @@ CUSBCECAdapterCommands::CUSBCECAdapterCommands(CUSBCECAdapterCommunication *comm m_settingCecVersion(CEC_VERSION_UNKNOWN), m_iSettingLAMask(0), m_bNeedsWrite(false), - m_iBuildDate(CEC_FW_BUILD_UNKNOWN) + m_iBuildDate(CEC_FW_BUILD_UNKNOWN), + m_bControlledMode(false) { m_persistedConfiguration.Clear(); } @@ -222,16 +228,16 @@ bool CUSBCECAdapterCommands::RequestSettingPhysicalAddress(void) bool CUSBCECAdapterCommands::SetSettingAutoEnabled(bool enabled) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ - if (m_bSettingAutoEnabled == enabled) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "autonomous mode setting unchanged (%s)", enabled ? "on" : "off"); - return bReturn; + CLockObject lock(m_mutex); + if (m_bSettingAutoEnabled == enabled) + return bReturn; + m_bNeedsWrite = true; } - m_bNeedsWrite = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off"); CCECAdapterMessage params; @@ -241,23 +247,26 @@ bool CUSBCECAdapterCommands::SetSettingAutoEnabled(bool enabled) delete message; if (bReturn) + { + CLockObject lock(m_mutex); m_bSettingAutoEnabled = enabled; + } return bReturn; } bool CUSBCECAdapterCommands::SetSettingDeviceType(cec_device_type type) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ - if (m_persistedConfiguration.deviceTypes.types[0] == type) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "device type setting unchanged (%X)", (uint8_t)type); - return bReturn; + CLockObject lock(m_mutex); + if (m_persistedConfiguration.deviceTypes.types[0] == type) + return bReturn; + m_bNeedsWrite = true; } - m_bNeedsWrite = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the device type to %X (previous: %X)", (uint8_t)type, (uint8_t)m_persistedConfiguration.deviceTypes.types[0]); CCECAdapterMessage params; @@ -266,21 +275,27 @@ bool CUSBCECAdapterCommands::SetSettingDeviceType(cec_device_type type) bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; delete message; + if (bReturn) + { + CLockObject lock(m_mutex); + m_persistedConfiguration.deviceTypes.types[0] = type; + } + return bReturn; } bool CUSBCECAdapterCommands::SetSettingDefaultLogicalAddress(cec_logical_address address) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ - if (m_persistedConfiguration.logicalAddresses.primary == address) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address setting unchanged (%X)", (uint8_t)address); - return bReturn; + CLockObject lock(m_mutex); + if (m_persistedConfiguration.logicalAddresses.primary == address) + return bReturn; + m_bNeedsWrite = true; } - m_bNeedsWrite = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the default logical address to %X (previous: %X)", (uint8_t)address, (uint8_t)m_persistedConfiguration.logicalAddresses.primary); CCECAdapterMessage params; @@ -290,23 +305,26 @@ bool CUSBCECAdapterCommands::SetSettingDefaultLogicalAddress(cec_logical_address delete message; if (bReturn) + { + CLockObject lock(m_mutex); m_persistedConfiguration.logicalAddresses.primary = address; + } return bReturn; } bool CUSBCECAdapterCommands::SetSettingLogicalAddressMask(uint16_t iMask) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ - if (m_iSettingLAMask == iMask) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address mask setting unchanged (%2X)", iMask); - return bReturn; + CLockObject lock(m_mutex); + if (m_iSettingLAMask == iMask) + return bReturn; + m_bNeedsWrite = true; } - m_bNeedsWrite = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X (previous: %2X)", iMask, m_iSettingLAMask); CCECAdapterMessage params; @@ -317,23 +335,26 @@ bool CUSBCECAdapterCommands::SetSettingLogicalAddressMask(uint16_t iMask) delete message; if (bReturn) + { + CLockObject lock(m_mutex); m_iSettingLAMask = iMask; + } return bReturn; } bool CUSBCECAdapterCommands::SetSettingPhysicalAddress(uint16_t iPhysicalAddress) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ - if (m_persistedConfiguration.iPhysicalAddress == iPhysicalAddress) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address setting unchanged (%04X)", iPhysicalAddress); - return bReturn; + CLockObject lock(m_mutex); + if (m_persistedConfiguration.iPhysicalAddress == iPhysicalAddress) + return bReturn; + m_bNeedsWrite = true; } - m_bNeedsWrite = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X (previous: %04X)", iPhysicalAddress, m_persistedConfiguration.iPhysicalAddress); CCECAdapterMessage params; @@ -344,23 +365,26 @@ bool CUSBCECAdapterCommands::SetSettingPhysicalAddress(uint16_t iPhysicalAddress delete message; if (bReturn) + { + CLockObject lock(m_mutex); m_persistedConfiguration.iPhysicalAddress = iPhysicalAddress; + } return bReturn; } bool CUSBCECAdapterCommands::SetSettingCECVersion(cec_version version) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ - if (m_settingCecVersion == version) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "CEC version setting unchanged (%s)", ToString(version)); - return bReturn; + CLockObject lock(m_mutex); + if (m_settingCecVersion == version) + return bReturn; + m_bNeedsWrite = true; } - m_bNeedsWrite = true; LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s (previous: %s)", ToString(version), ToString(m_settingCecVersion)); CCECAdapterMessage params; @@ -370,21 +394,21 @@ bool CUSBCECAdapterCommands::SetSettingCECVersion(cec_version version) delete message; if (bReturn) + { + CLockObject lock(m_mutex); m_settingCecVersion = version; + } return bReturn; } bool CUSBCECAdapterCommands::SetSettingOSDName(const char *strOSDName) { - bool bReturn(true); + bool bReturn(false); /* check whether this value was changed */ if (!strcmp(m_persistedConfiguration.strDeviceName, strOSDName)) - { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "OSD name setting unchanged (%s)", strOSDName); return bReturn; - } LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s (previous: %s)", strOSDName, m_persistedConfiguration.strDeviceName); @@ -403,35 +427,45 @@ bool CUSBCECAdapterCommands::SetSettingOSDName(const char *strOSDName) bool CUSBCECAdapterCommands::WriteEEPROM(void) { - if (!m_bNeedsWrite) - return true; + { + CLockObject lock(m_mutex); + if (!m_bNeedsWrite) + return true; + } LIB_CEC->AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM"); CCECAdapterMessage params; CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_WRITE_EEPROM, params); - m_bNeedsWrite = !(message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED); + bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; delete message; - return m_bNeedsWrite; + + if (bReturn) + { + CLockObject lock(m_mutex); + m_bNeedsWrite = false; + } + + return bReturn; } bool CUSBCECAdapterCommands::PersistConfiguration(const libcec_configuration &configuration) { + bool bReturn(false); if (m_persistedConfiguration.iFirmwareVersion < 2) - return false; + return bReturn; if (!RequestSettings()) - return false; + return bReturn; + + bReturn |= SetSettingAutoEnabled(true); + bReturn |= SetSettingDeviceType(CLibCEC::GetType(configuration.logicalAddresses.primary)); + bReturn |= SetSettingDefaultLogicalAddress(configuration.logicalAddresses.primary); + bReturn |= SetSettingLogicalAddressMask(CLibCEC::GetMaskForType(configuration.logicalAddresses.primary)); + bReturn |= SetSettingPhysicalAddress(configuration.iPhysicalAddress); + bReturn |= SetSettingCECVersion(configuration.clientVersion >= CEC_CLIENT_VERSION_1_8_0 ? configuration.cecVersion : CEC_VERSION_1_4); + bReturn |= SetSettingOSDName(configuration.strDeviceName); - bool bReturn(true); - bReturn &= SetSettingAutoEnabled(true); - bReturn &= SetSettingDeviceType(CLibCEC::GetType(configuration.logicalAddresses.primary)); - bReturn &= SetSettingDefaultLogicalAddress(configuration.logicalAddresses.primary); - bReturn &= SetSettingLogicalAddressMask(CLibCEC::GetMaskForType(configuration.logicalAddresses.primary)); - bReturn &= SetSettingPhysicalAddress(configuration.iPhysicalAddress); - bReturn &= SetSettingCECVersion(CEC_VERSION_1_3A); - bReturn &= SetSettingOSDName(configuration.strDeviceName); - bReturn &= WriteEEPROM(); return bReturn; } @@ -542,6 +576,12 @@ bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout) bool CUSBCECAdapterCommands::SetControlledMode(bool controlled) { + { + CLockObject lock(m_mutex); + if (m_bControlledMode == controlled) + return true; + } + LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off"); CCECAdapterMessage params; @@ -549,5 +589,12 @@ bool CUSBCECAdapterCommands::SetControlledMode(bool controlled) CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_CONTROLLED, params); bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED; delete message; + + if (bReturn) + { + CLockObject lock(m_mutex); + m_bControlledMode = controlled; + } + return bReturn; } diff --git a/src/lib/adapter/USBCECAdapterCommands.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h similarity index 91% rename from src/lib/adapter/USBCECAdapterCommands.h rename to src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h index 70feae9..897ed1c 100644 --- a/src/lib/adapter/USBCECAdapterCommands.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h @@ -31,10 +31,12 @@ * http://www.pulse-eight.net/ */ -#include "USBCECAdapterCommunication.h" +#include "lib/platform/threads/mutex.h" namespace CEC { + class CUSBCECAdapterCommunication; + class CUSBCECAdapterCommands { public: @@ -52,10 +54,10 @@ namespace CEC uint16_t GetFirmwareVersion(void) const { return m_persistedConfiguration.iFirmwareVersion; }; /*! - * @brief Persist the current configuration in the EEPROM. + * @brief Update the current configuration in the adapter. Does not do an eeprom update. * @attention Not all settings are persisted at this time. * @param configuration The configuration to persist. - * @return True when persisted, false otherwise. + * @return True when something changed, false otherwise. */ bool PersistConfiguration(const libcec_configuration &configuration); @@ -111,6 +113,12 @@ namespace CEC */ uint32_t GetPersistedBuildDate(void) const { return m_iBuildDate; }; + /*! + * @brief Persist the current settings in the EEPROM + * @return True when persisted, false otherwise. + */ + bool WriteEEPROM(void); + private: /*! * @brief Reads all settings from the eeprom. @@ -128,7 +136,7 @@ namespace CEC /*! * @brief Change the value of the "auto enabled" setting. * @param enabled The new value. - * @return True when set, false otherwise. + * @return True when changed and set, false otherwise. */ bool SetSettingAutoEnabled(bool enabled); @@ -141,7 +149,7 @@ namespace CEC /*! * @brief Change the value of the "device type" setting, used when the device is in autonomous mode. * @param type The new value. - * @return True when set, false otherwise. + * @return True when changed and set, false otherwise. */ bool SetSettingDeviceType(cec_device_type type); @@ -154,7 +162,7 @@ namespace CEC /*! * @brief Change the value of the "default logical address" setting, used when the device is in autonomous mode. * @param address The new value. - * @return True when set, false otherwise. + * @return True when changed and set, false otherwise. */ bool SetSettingDefaultLogicalAddress(cec_logical_address address); @@ -167,7 +175,7 @@ namespace CEC /*! * @brief Change the value of the "logical address mask" setting, used when the device is in autonomous mode. * @param iMask The new value. - * @return True when set, false otherwise. + * @return True when changed and set, false otherwise. */ bool SetSettingLogicalAddressMask(uint16_t iMask); @@ -180,7 +188,7 @@ namespace CEC /*! * @brief Change the value of the "physical address" setting, used when the device is in autonomous mode. * @param iPhysicalAddress The new value. - * @return True when set, false otherwise. + * @return True when changed and set, false otherwise. */ bool SetSettingPhysicalAddress(uint16_t iPhysicalAddress); @@ -193,7 +201,7 @@ namespace CEC /*! * @brief Change the value of the "CEC version" setting, used when the device is in autonomous mode. * @param version The new value. - * @return True when set, false otherwise. + * @return True when changed and set, false otherwise. */ bool SetSettingCECVersion(cec_version version); @@ -216,12 +224,6 @@ namespace CEC */ bool RequestSettingOSDName(void); - /*! - * @brief Persist the current settings in the EEPROM - * @return True when persisted, false otherwise. - */ - bool WriteEEPROM(void); - CUSBCECAdapterCommunication *m_comm; /**< the communication handler */ bool m_bSettingsRetrieved; /**< true when the settings were read from the eeprom, false otherwise */ bool m_bSettingAutoEnabled; /**< the value of the auto-enabled setting */ @@ -230,5 +232,7 @@ namespace CEC bool m_bNeedsWrite; /**< true when we sent changed settings to the adapter that have not been persisted */ libcec_configuration m_persistedConfiguration; /**< the configuration that is persisted in the eeprom */ uint32_t m_iBuildDate; /**< the build date of the firmware */ + bool m_bControlledMode; /**< current value of the controlled mode feature */ + PLATFORM::CMutex m_mutex; }; } diff --git a/src/lib/adapter/USBCECAdapterCommunication.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp similarity index 85% rename from src/lib/adapter/USBCECAdapterCommunication.cpp rename to src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp index b3f0f7d..053860e 100644 --- a/src/lib/adapter/USBCECAdapterCommunication.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp @@ -30,28 +30,33 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "USBCECAdapterCommunication.h" + #include "USBCECAdapterCommands.h" #include "USBCECAdapterMessageQueue.h" -#include "../platform/sockets/serialport.h" -#include "../platform/util/timeutils.h" -#include "../platform/util/util.h" -#include "../platform/util/edid.h" -#include "../platform/adl/adl-edid.h" -#include "../platform/nvidia/nv-edid.h" -#include "../LibCEC.h" -#include "../CECProcessor.h" +#include "USBCECAdapterMessage.h" +#include "lib/platform/sockets/serialport.h" +#include "lib/platform/util/timeutils.h" +#include "lib/platform/util/util.h" +#include "lib/platform/util/edid.h" +#include "lib/platform/adl/adl-edid.h" +#include "lib/platform/nvidia/nv-edid.h" +#include "lib/LibCEC.h" +#include "lib/CECProcessor.h" using namespace std; using namespace CEC; using namespace PLATFORM; -#define CEC_ADAPTER_PING_TIMEOUT 15000 +#define CEC_ADAPTER_PING_TIMEOUT 15000 +#define CEC_ADAPTER_EEPROM_WRITE_INTERVAL 30000 +#define CEC_ADAPTER_EEPROM_WRITE_RETRY 5000 // firmware version 2 #define CEC_LATEST_ADAPTER_FW_VERSION 2 // firmware date Thu Apr 26 20:14:49 2012 +0000 -#define CEC_LATEST_ADAPTER_FW_DATE 0x4F99ACB9 +#define CEC_LATEST_ADAPTER_FW_DATE 0x5009F0A3 #define LIB_CEC m_callback->GetLib() @@ -64,8 +69,10 @@ CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCa m_pingThread(NULL), m_commands(NULL), m_adapterMessageQueue(NULL), - m_iAckMask(0xFFFF) + m_iLastEepromWrite(0), + m_iScheduleEepromWrite(0) { + m_logicalAddresses.Clear(); for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++) m_bWaitingForAck[iPtr] = false; m_port = new CSerialPort(strPort, iBaudRate); @@ -149,7 +156,8 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN } // always start by setting the ackmask to 0, to clear previous values - SetAckMask(0); + cec_logical_addresses addresses; addresses.Clear(); + SetLogicalAddresses(addresses); if (!CreateThread()) { @@ -194,7 +202,8 @@ void CUSBCECAdapterCommunication::Close(void) if (IsOpen() && m_port->GetErrorNumber() == 0) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__); - SetAckMask(0); + cec_logical_addresses addresses; addresses.Clear(); + SetLogicalAddresses(addresses); if (m_commands->GetFirmwareVersion() >= 2) SetControlledMode(false); } @@ -209,7 +218,7 @@ void CUSBCECAdapterCommunication::Close(void) m_port->Close(); } -cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout) +cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool UNUSED(bIsReply)) { cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN); if (!IsRunning()) @@ -235,6 +244,7 @@ void *CUSBCECAdapterCommunication::Process(void) CCECAdapterMessage msg; LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread started"); + bool bWriteEeprom(false); while (!IsStopped()) { /* read from the serial port */ @@ -247,6 +257,31 @@ void *CUSBCECAdapterCommunication::Process(void) break; } + // check if we need to do another eeprom write + { + CLockObject lock(m_mutex); + int64_t iNow = GetTimeMs(); + if (m_iScheduleEepromWrite > 0 && + m_iScheduleEepromWrite >= iNow) + { + m_iScheduleEepromWrite = 0; + m_iLastEepromWrite = iNow; + bWriteEeprom = true; + } + } + + if (bWriteEeprom) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "updating the eeprom (scheduled)"); + bWriteEeprom = false; + if (!m_commands->WriteEEPROM()) + { + // failed, retry later + CLockObject lock(m_mutex); + m_iScheduleEepromWrite = GetTimeMs() + CEC_ADAPTER_EEPROM_WRITE_RETRY; + } + } + /* TODO sleep 5 ms so other threads can get a lock */ Sleep(5); } @@ -470,7 +505,7 @@ bool CUSBCECAdapterCommunication::IsOpen(void) return !IsStopped() && m_port->IsOpen() && IsRunning(); } -CStdString CUSBCECAdapterCommunication::GetError(void) const +std::string CUSBCECAdapterCommunication::GetError(void) const { return m_port->GetError(); } @@ -497,18 +532,18 @@ bool CUSBCECAdapterCommunication::StartBootloader(void) return false; } -bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask) +bool CUSBCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses) { { CLockObject lock(m_mutex); - if (m_iAckMask == iMask) + if (m_logicalAddresses == addresses) return true; } - if (IsOpen() && m_commands->SetAckMask(iMask)) + if (IsOpen() && m_commands->SetAckMask(addresses.AckMask())) { CLockObject lock(m_mutex); - m_iAckMask = iMask; + m_logicalAddresses = addresses; return true; } @@ -516,10 +551,12 @@ bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask) return false; } -uint16_t CUSBCECAdapterCommunication::GetAckMask(void) +cec_logical_addresses CUSBCECAdapterCommunication::GetLogicalAddresses(void) { + cec_logical_addresses addresses; CLockObject lock(m_mutex); - return m_iAckMask; + addresses = m_logicalAddresses; + return addresses; } bool CUSBCECAdapterCommunication::PingAdapter(void) @@ -545,6 +582,35 @@ bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void) bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration &configuration) { + if (IsOpen()) + { + // returns true when something changed + if (m_commands->PersistConfiguration(configuration)) + { + { + CLockObject lock(m_mutex); + uint64_t iNow = GetTimeMs(); + if (iNow - m_iLastEepromWrite < CEC_ADAPTER_EEPROM_WRITE_INTERVAL) + { + // if there was more than 1 write within the last 30 seconds, schedule another one + if (m_iScheduleEepromWrite == 0) + m_iScheduleEepromWrite = m_iLastEepromWrite + CEC_ADAPTER_EEPROM_WRITE_INTERVAL; + return true; + } + else + { + m_iLastEepromWrite = iNow; + } + } + + if (!m_commands->WriteEEPROM()) + { + // write failed, retry later + CLockObject lock(m_mutex); + m_iScheduleEepromWrite = GetTimeMs() + CEC_ADAPTER_EEPROM_WRITE_RETRY; + } + } + } return IsOpen() ? m_commands->PersistConfiguration(configuration) : false; } @@ -553,7 +619,7 @@ bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration &configu return IsOpen() ? m_commands->GetConfiguration(configuration) : false; } -CStdString CUSBCECAdapterCommunication::GetPortName(void) +std::string CUSBCECAdapterCommunication::GetPortName(void) { return m_port->GetName(); } diff --git a/src/lib/adapter/USBCECAdapterCommunication.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h similarity index 87% rename from src/lib/adapter/USBCECAdapterCommunication.h rename to src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h index 948f2de..5b065f3 100644 --- a/src/lib/adapter/USBCECAdapterCommunication.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h @@ -31,11 +31,8 @@ * http://www.pulse-eight.net/ */ -#include "../../../include/cectypes.h" -#include "../platform/threads/threads.h" -#include "../platform/util/buffer.h" -#include "AdapterCommunication.h" -#include "USBCECAdapterMessage.h" +#include "lib/platform/threads/threads.h" +#include "lib/adapter/AdapterCommunication.h" namespace PLATFORM { @@ -48,6 +45,7 @@ namespace CEC class CAdapterPingThread; class CUSBCECAdapterCommands; class CCECAdapterMessageQueue; + class CCECAdapterMessage; class CUSBCECAdapterCommunication : public IAdapterCommunication, public PLATFORM::CThread { @@ -69,21 +67,23 @@ namespace CEC bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true); void Close(void); bool IsOpen(void); - CStdString GetError(void) const; - cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout = 3); + std::string GetError(void) const; + cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply); bool StartBootloader(void); - bool SetAckMask(uint16_t iMask); - uint16_t GetAckMask(void); + bool SetLogicalAddresses(const cec_logical_addresses &addresses); + cec_logical_addresses GetLogicalAddresses(void); bool PingAdapter(void); uint16_t GetFirmwareVersion(void); uint32_t GetFirmwareBuildDate(void); bool IsRunningLatestFirmware(void); bool PersistConfiguration(const libcec_configuration &configuration); bool GetConfiguration(libcec_configuration &configuration); - CStdString GetPortName(void); + std::string GetPortName(void); uint16_t GetPhysicalAddress(void); bool SetControlledMode(bool controlled); + cec_vendor_id GetVendorId(void) { return CEC_VENDOR_UNKNOWN; } + bool SupportsSourceLogicalAddress(const cec_logical_address UNUSED(address)) { return true; } ///} void *Process(void); @@ -171,7 +171,9 @@ namespace CEC CAdapterPingThread * m_pingThread; /**< ping thread, that pings the adapter every 15 seconds */ CUSBCECAdapterCommands * m_commands; /**< commands that can be sent to the adapter */ CCECAdapterMessageQueue * m_adapterMessageQueue; /**< the incoming and outgoing message queue */ - uint16_t m_iAckMask; + cec_logical_addresses m_logicalAddresses; /**< the logical address list that this instance is using */ + int64_t m_iLastEepromWrite; /**< last time that this instance did an eeprom write */ + int64_t m_iScheduleEepromWrite; /**< in case there were more than 2 changes within 30 seconds, do another write at this time */ }; class CAdapterPingThread : public PLATFORM::CThread diff --git a/src/lib/adapter/USBCECAdapterDetection.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp similarity index 98% rename from src/lib/adapter/USBCECAdapterDetection.cpp rename to src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp index 78b2760..f9969d8 100644 --- a/src/lib/adapter/USBCECAdapterDetection.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp @@ -30,8 +30,9 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "USBCECAdapterDetection.h" -#include "../platform/util/StdString.h" +#include "lib/platform/util/StdString.h" #if defined(__APPLE__) #include @@ -348,6 +349,10 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", devicePath); } } +#else + //silence "unused" warnings + void *tmp = (void*)deviceList; + tmp = (void *)strDevicePath; #endif iBufSize = 0; /* silence "unused" warning on linux/osx */ diff --git a/src/lib/adapter/USBCECAdapterDetection.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.h similarity index 97% rename from src/lib/adapter/USBCECAdapterDetection.h rename to src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.h index 9b6c624..dfccd65 100644 --- a/src/lib/adapter/USBCECAdapterDetection.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.h @@ -31,8 +31,6 @@ * http://www.pulse-eight.net/ */ -#include "../../../include/cectypes.h" - namespace CEC { class CUSBCECAdapterDetection diff --git a/src/lib/adapter/USBCECAdapterMessage.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp similarity index 98% rename from src/lib/adapter/USBCECAdapterMessage.cpp rename to src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp index 8ef5662..f213c1d 100644 --- a/src/lib/adapter/USBCECAdapterMessage.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp @@ -30,8 +30,11 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "USBCECAdapterMessage.h" -#include "../LibCEC.h" + +#include "lib/LibCEC.h" +#include "lib/platform/util/StdString.h" using namespace CEC; using namespace PLATFORM; @@ -91,7 +94,7 @@ CCECAdapterMessage::CCECAdapterMessage(const cec_command &command, uint8_t iLine lineTimeout = iLineTimeout; } -CStdString CCECAdapterMessage::ToString(void) const +std::string CCECAdapterMessage::ToString(void) const { CStdString strMsg; if (Size() == 0) @@ -130,7 +133,7 @@ CStdString CCECAdapterMessage::ToString(void) const } } - return strMsg; + return std::string(strMsg.c_str()); } const char *CCECAdapterMessage::ToString(cec_adapter_messagecode msgCode) diff --git a/src/lib/adapter/USBCECAdapterMessage.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h similarity index 87% rename from src/lib/adapter/USBCECAdapterMessage.h rename to src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h index 4d571b1..e4fedce 100644 --- a/src/lib/adapter/USBCECAdapterMessage.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h @@ -31,24 +31,10 @@ * http://www.pulse-eight.net/ */ -#include "../platform/util/StdString.h" -#include "../platform/util/buffer.h" -#include "../platform/threads/mutex.h" -#include "../../../include/cectypes.h" +#include "lib/adapter/AdapterCommunication.h" namespace CEC { - typedef enum cec_adapter_message_state - { - ADAPTER_MESSAGE_STATE_UNKNOWN = 0, /**< the initial state */ - ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT, /**< waiting in the send queue of the adapter, or timed out */ - ADAPTER_MESSAGE_STATE_SENT, /**< sent and waiting on an ACK */ - ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED, /**< sent, but failed to ACK */ - ADAPTER_MESSAGE_STATE_SENT_ACKED, /**< sent, and ACK received */ - ADAPTER_MESSAGE_STATE_INCOMING, /**< received from another device */ - ADAPTER_MESSAGE_STATE_ERROR /**< an error occured */ - } cec_adapter_message_state; - class CCECAdapterMessage { public: @@ -67,7 +53,7 @@ namespace CEC /*! * @return the message as human readable string. */ - CStdString ToString(void) const; + std::string ToString(void) const; /*! * @brief Translate the messagecode into a human readable string. diff --git a/src/lib/adapter/USBCECAdapterMessageQueue.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp similarity index 94% rename from src/lib/adapter/USBCECAdapterMessageQueue.cpp rename to src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp index 847115a..c713eea 100644 --- a/src/lib/adapter/USBCECAdapterMessageQueue.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp @@ -30,10 +30,14 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "USBCECAdapterMessageQueue.h" + #include "USBCECAdapterCommunication.h" -#include "../platform/sockets/socket.h" -#include "../LibCEC.h" +#include "USBCECAdapterMessage.h" +#include "lib/platform/sockets/socket.h" +#include "lib/LibCEC.h" +#include "lib/platform/util/StdString.h" using namespace CEC; using namespace PLATFORM; @@ -212,11 +216,20 @@ bool CCECAdapterMessageQueueEntry::MessageReceivedResponse(const CCECAdapterMess return true; } +CCECAdapterMessageQueue::CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com) : + PLATFORM::CThread(), + m_com(com), + m_iNextMessage(0) +{ + m_incomingAdapterMessage = new CCECAdapterMessage; + m_currentCECFrame.Clear(); +} CCECAdapterMessageQueue::~CCECAdapterMessageQueue(void) { Clear(); StopThread(0); + delete m_incomingAdapterMessage; } void CCECAdapterMessageQueue::Clear(void) @@ -264,7 +277,7 @@ void CCECAdapterMessageQueue::MessageReceived(const CCECAdapterMessage &msg) { /* the message wasn't handled */ bool bIsError(m_com->HandlePoll(msg)); - m_com->m_callback->GetLib()->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString()); + m_com->m_callback->GetLib()->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString().c_str()); /* push this message to the current frame */ if (!bIsError && msg.PushToCecCommand(m_currentCECFrame)) @@ -286,19 +299,19 @@ void CCECAdapterMessageQueue::AddData(uint8_t *data, size_t iLen) bool bFullMessage(false); { CLockObject lock(m_mutex); - bFullMessage = m_incomingAdapterMessage.PushReceivedByte(data[iPtr]); + bFullMessage = m_incomingAdapterMessage->PushReceivedByte(data[iPtr]); } if (bFullMessage) { /* a full message was received */ CCECAdapterMessage newMessage; - newMessage.packet = m_incomingAdapterMessage.packet; + newMessage.packet = m_incomingAdapterMessage->packet; MessageReceived(newMessage); /* clear the current message */ CLockObject lock(m_mutex); - m_incomingAdapterMessage.Clear(); + m_incomingAdapterMessage->Clear(); } } } diff --git a/src/lib/adapter/USBCECAdapterMessageQueue.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h similarity index 95% rename from src/lib/adapter/USBCECAdapterMessageQueue.h rename to src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h index 44c930b..6e325a7 100644 --- a/src/lib/adapter/USBCECAdapterMessageQueue.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h @@ -31,14 +31,15 @@ * http://www.pulse-eight.net/ */ -#include "USBCECAdapterMessage.h" -#include "../platform/threads/threads.h" +#include "lib/platform/threads/threads.h" +#include "lib/platform/util/buffer.h" #include namespace CEC { class CUSBCECAdapterCommunication; class CCECAdapterMessageQueue; + class CCECAdapterMessage; class CCECAdapterMessageQueueEntry { @@ -133,14 +134,7 @@ namespace CEC * @param com The communication handler callback to use. * @param iQueueSize The outgoing message queue size. */ - CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com) : - PLATFORM::CThread(), - m_com(com), - m_iNextMessage(0) - { - m_currentCECFrame.Clear(); - } - + CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com); virtual ~CCECAdapterMessageQueue(void); /*! @@ -176,7 +170,7 @@ namespace CEC std::map m_messages; /**< the outgoing message queue */ PLATFORM::SyncedBuffer m_writeQueue; /**< the queue for messages that are to be written */ uint64_t m_iNextMessage; /**< the index of the next message */ - CCECAdapterMessage m_incomingAdapterMessage; /**< the current incoming message that's being assembled */ + CCECAdapterMessage *m_incomingAdapterMessage; /**< the current incoming message that's being assembled */ cec_command m_currentCECFrame; /**< the current incoming CEC command that's being assembled */ }; } diff --git a/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp b/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp new file mode 100644 index 0000000..5e1efd4 --- /dev/null +++ b/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp @@ -0,0 +1,422 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" + +#if defined(HAVE_RPI_API) +#include "RPiCECAdapterCommunication.h" + +extern "C" { +#include +} + +#include "lib/CECTypeUtils.h" +#include "lib/LibCEC.h" +#include "lib/platform/util/StdString.h" +#include "RPiCECAdapterMessageQueue.h" + +using namespace CEC; +using namespace PLATFORM; + +#define LIB_CEC m_callback->GetLib() + +static bool g_bHostInited = false; + +// callback for the RPi CEC service +void rpi_cec_callback(void *callback_data, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4) +{ + if (callback_data) + static_cast(callback_data)->OnDataReceived(p0, p1, p2, p3, p4); +} + +CRPiCECAdapterCommunication::CRPiCECAdapterCommunication(IAdapterCommunicationCallback *callback) : + IAdapterCommunication(callback), + m_logicalAddress(CECDEVICE_UNKNOWN), + m_bLogicalAddressChanged(false) +{ + m_queue = new CRPiCECAdapterMessageQueue(this); +} + +CRPiCECAdapterCommunication::~CRPiCECAdapterCommunication(void) +{ + delete(m_queue); + Close(); +} + +const char *ToString(const VC_CEC_ERROR_T error) +{ + switch(error) + { + case VC_CEC_SUCCESS: + return "success"; + case VC_CEC_ERROR_NO_ACK: + return "no ack"; + case VC_CEC_ERROR_SHUTDOWN: + return "shutdown"; + case VC_CEC_ERROR_BUSY: + return "device is busy"; + case VC_CEC_ERROR_NO_LA: + return "no logical address"; + case VC_CEC_ERROR_NO_PA: + return "no physical address"; + case VC_CEC_ERROR_NO_TOPO: + return "no topology"; + case VC_CEC_ERROR_INVALID_FOLLOWER: + return "invalid follower"; + case VC_CEC_ERROR_INVALID_ARGUMENT: + return "invalid arg"; + default: + return "unknown"; + } +} + +bool CRPiCECAdapterCommunication::IsInitialised(void) +{ + CLockObject lock(m_mutex); + return m_bInitialised; +} + +void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) +{ + VC_CEC_NOTIFY_T reason = (VC_CEC_NOTIFY_T)CEC_CB_REASON(header); + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "received data: header:%08X p0:%08X p1:%08X p2:%08X p3:%08X reason:%x", header, p0, p1, p2, p3, reason); + + switch (reason) + { + case VC_CEC_RX: + // CEC data received + { + // translate into a VC_CEC_MESSAGE_T + VC_CEC_MESSAGE_T message; + vc_cec_param2message(header, p0, p1, p2, p3, &message); + + // translate to a cec_command + cec_command command; + cec_command::Format(command, + (cec_logical_address)message.initiator, + (cec_logical_address)message.follower, + (cec_opcode)CEC_CB_OPCODE(p0)); + + // copy parameters + for (uint8_t iPtr = 1; iPtr < message.length; iPtr++) + command.PushBack(message.payload[iPtr]); + + // send to libCEC + m_callback->OnCommandReceived(command); + } + break; + case VC_CEC_TX: + { + // handle response to a command that was sent earlier + m_queue->MessageReceived((cec_opcode)CEC_CB_OPCODE(p0), (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_CB_RC(header)); + } + break; + case VC_CEC_BUTTON_PRESSED: + { + // translate into a cec_command + cec_command command; + cec_command::Format(command, (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_OPCODE_USER_CONTROL_PRESSED); + command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0)); + + // send to libCEC + m_callback->OnCommandReceived(command); + } + break; + case VC_CEC_BUTTON_RELEASE: + { + // translate into a cec_command + cec_command command; + cec_command::Format(command, (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_OPCODE_USER_CONTROL_RELEASE); + command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0)); + + // send to libCEC + m_callback->OnCommandReceived(command); + } + break; + case VC_CEC_LOGICAL_ADDR: + { + CLockObject lock(m_mutex); + if (CEC_CB_RC(header) == VCHIQ_SUCCESS) + { + m_bLogicalAddressChanged = true; + m_logicalAddress = (cec_logical_address)(p0 & 0xF); + LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address changed to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress); + } + else + { + m_logicalAddress = CECDEVICE_BROADCAST; + LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to change the logical address, reset to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress); + } + m_logicalAddressCondition.Signal(); + } + break; + case VC_CEC_TOPOLOGY: + case VC_CEC_REMOTE_PRESSED: + case VC_CEC_REMOTE_RELEASE: + break; + default: + LIB_CEC->AddLog(CEC_LOG_DEBUG, "ignoring unknown reason %x", reason); + break; + } +} + +int CRPiCECAdapterCommunication::InitHostCEC(void) +{ + VCHIQ_INSTANCE_T vchiq_instance; + int iResult; + + if ((iResult = vchiq_initialise(&vchiq_instance)) != VCHIQ_SUCCESS) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vchiq_initialise failed (%d)", __FUNCTION__, iResult); + CStdString strError; + strError.Format("%s - vchiq_initialise failed (%d)", __FUNCTION__, iResult); + m_strError = strError; + return iResult; + } + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vchiq_initialise succeeded", __FUNCTION__); + + if ((iResult = vchi_initialise(&m_vchi_instance)) != VCHIQ_SUCCESS) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vchi_initialise failed (%d)", __FUNCTION__, iResult); + CStdString strError; + strError.Format("%s - vchi_initialise failed (%d)", __FUNCTION__, iResult); + m_strError = strError; + return iResult; + } + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vchi_initialise succeeded", __FUNCTION__); + + vchiq_instance = (VCHIQ_INSTANCE_T)m_vchi_instance; + + m_vchi_connection = vchi_create_connection(single_get_func_table(), + vchi_mphi_message_driver_func_table()); + + if ((iResult = vchi_connect(&m_vchi_connection, 1, m_vchi_instance)) != VCHIQ_SUCCESS) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vchi_connect failed (%d)", __FUNCTION__, iResult); + CStdString strError; + strError.Format("%s - vchi_connect failed (%d)", __FUNCTION__, iResult); + m_strError = strError; + return iResult; + } + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vchi_connect succeeded", __FUNCTION__); + + return VCHIQ_SUCCESS; +} + +bool CRPiCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool UNUSED(bSkipChecks) /* = false */, bool bStartListening) +{ + Close(); + + if (InitHostCEC() != VCHIQ_SUCCESS) + return false; + + if (bStartListening) + { + // enable passive mode + vc_cec_set_passive(true); + + // register the callback + vc_cec_register_callback(((CECSERVICE_CALLBACK_T)rpi_cec_callback), (void*)this); + + // release previous LA + vc_cec_release_logical_address(); + if (!m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged, iTimeoutMs)) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to release the previous LA"); + return false; + } + + // register LA "freeuse" + if (RegisterLogicalAddress(CECDEVICE_FREEUSE)) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vc_cec initialised", __FUNCTION__); + CLockObject lock(m_mutex); + m_bInitialised = true; + } + else + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec could not be initialised", __FUNCTION__); + } + + return true; +} + +uint16_t CRPiCECAdapterCommunication::GetPhysicalAddress(void) +{ + uint16_t iPA(CEC_INVALID_PHYSICAL_ADDRESS); + if (!IsInitialised()) + return iPA; + + if (vc_cec_get_physical_address(&iPA) == VCHIQ_SUCCESS) + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - physical address = %04x", __FUNCTION__, iPA); + else + { + LIB_CEC->AddLog(CEC_LOG_WARNING, "%s - failed to get the physical address", __FUNCTION__); + iPA = CEC_INVALID_PHYSICAL_ADDRESS; + } + + return iPA; +} + +void CRPiCECAdapterCommunication::Close(void) +{ + { + CLockObject lock(m_mutex); + if (m_bInitialised) + m_bInitialised = false; + else + return; + } + UnregisterLogicalAddress(); + + // disable passive mode + vc_cec_set_passive(false); + + if (!g_bHostInited) + { + g_bHostInited = false; + bcm_host_deinit(); + } +} + +std::string CRPiCECAdapterCommunication::GetError(void) const +{ + std::string strError(m_strError); + return strError; +} + +cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool bIsReply) +{ + // ensure that the source LA is registered + if (!RegisterLogicalAddress(data.initiator)) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to register logical address %s (%X)", CCECTypeUtils::ToString(data.initiator), data.initiator); + return (data.initiator == data.destination) ? ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED : ADAPTER_MESSAGE_STATE_ERROR; + } + + if (!data.opcode_set && data.initiator == data.destination) + { + // registration of the logical address would have failed + return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; + } + + return m_queue->Write(data, bIsReply) ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED; +} + +uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void) +{ + return VC_CECSERVICE_VER; +} + +cec_logical_address CRPiCECAdapterCommunication::GetLogicalAddress(void) +{ + { + CLockObject lock(m_mutex); + if (m_logicalAddress != CECDEVICE_UNKNOWN) + return m_logicalAddress; + } + + CEC_AllDevices_T address; + return (vc_cec_get_logical_address(&address) == VCHIQ_SUCCESS) ? + (cec_logical_address)address : CECDEVICE_UNKNOWN; +} + +bool CRPiCECAdapterCommunication::UnregisterLogicalAddress(void) +{ + CLockObject lock(m_mutex); + if (m_logicalAddress == CECDEVICE_UNKNOWN || + m_logicalAddress == CECDEVICE_BROADCAST) + return true; + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - releasing previous logical address", __FUNCTION__); + m_bLogicalAddressChanged = false; + + vc_cec_release_logical_address(); + + return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged); +} + +bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_address address) +{ + { + CLockObject lock(m_mutex); + if (m_logicalAddress == address) + return true; + } + + if (!UnregisterLogicalAddress()) + return false; + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - registering address %x", __FUNCTION__, address); + + CLockObject lock(m_mutex); + m_bLogicalAddressChanged = false; + vc_cec_poll_address((CEC_AllDevices_T)address); + + // register the new LA + int iRetval = vc_cec_set_logical_address((CEC_AllDevices_T)address, (CEC_DEVICE_TYPE_T)CCECTypeUtils::GetType(address), CEC_VENDOR_ID_BROADCOM); + if (iRetval != VCHIQ_SUCCESS) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec_set_logical_address(%X) returned %s (%d)", __FUNCTION__, address, ToString((VC_CEC_ERROR_T)iRetval), iRetval); + return false; + } + + return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged); +} + +cec_logical_addresses CRPiCECAdapterCommunication::GetLogicalAddresses(void) +{ + cec_logical_addresses addresses; addresses.Clear(); + cec_logical_address current = GetLogicalAddress(); + if (current != CECDEVICE_UNKNOWN) + addresses.Set(current); + + return addresses; +} + +bool CRPiCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses) +{ + // the current generation RPi only supports 1 LA, so just ensure that the primary address is registered + return SupportsSourceLogicalAddress(addresses.primary) && + RegisterLogicalAddress(addresses.primary); +} + +void CRPiCECAdapterCommunication::InitHost(void) +{ + if (!g_bHostInited) + { + g_bHostInited = true; + bcm_host_init(); + } +} + +#endif diff --git a/src/lib/adapter/RPi/RPiCECAdapterCommunication.h b/src/lib/adapter/RPi/RPiCECAdapterCommunication.h new file mode 100644 index 0000000..530aec1 --- /dev/null +++ b/src/lib/adapter/RPi/RPiCECAdapterCommunication.h @@ -0,0 +1,107 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#if defined(HAVE_RPI_API) + +#include "lib/adapter/AdapterCommunication.h" +#include "lib/platform/threads/mutex.h" + +extern "C" { +#include +#include +} + +namespace CEC +{ + class CRPiCECAdapterMessageQueue; + + class CRPiCECAdapterCommunication : public IAdapterCommunication + { + public: + /*! + * @brief Create a new USB-CEC communication handler. + * @param callback The callback to use for incoming CEC commands. + */ + CRPiCECAdapterCommunication(IAdapterCommunicationCallback *callback); + virtual ~CRPiCECAdapterCommunication(void); + + /** @name IAdapterCommunication implementation */ + ///{ + bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true); + void Close(void); + bool IsOpen(void) { return m_bInitialised; }; + std::string GetError(void) const; + cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply); + + bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; }; + bool StartBootloader(void) { return false; }; + bool SetLogicalAddresses(const cec_logical_addresses &addresses); + cec_logical_addresses GetLogicalAddresses(void); + bool PingAdapter(void) { return m_bInitialised; }; + uint16_t GetFirmwareVersion(void); + uint32_t GetFirmwareBuildDate(void) { return 0; }; + bool IsRunningLatestFirmware(void) { return true; }; + bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; }; + bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; }; + std::string GetPortName(void) { std::string strReturn("RPI"); return strReturn; }; + uint16_t GetPhysicalAddress(void); + bool SetControlledMode(bool UNUSED(controlled)) { return true; }; + cec_vendor_id GetVendorId(void) { return CEC_VENDOR_BROADCOM; } + bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address < CECDEVICE_BROADCAST; } + ///} + + bool IsInitialised(void); + void OnDataReceived(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4); + + static void InitHost(void); + + private: + cec_logical_address GetLogicalAddress(void); + bool UnregisterLogicalAddress(void); + bool RegisterLogicalAddress(const cec_logical_address address); + int InitHostCEC(void); + + bool m_bInitialised; /**< true when the connection is initialised, false otherwise */ + std::string m_strError; /**< current error message */ + CRPiCECAdapterMessageQueue *m_queue; + cec_logical_address m_logicalAddress; + + bool m_bLogicalAddressChanged; + PLATFORM::CCondition m_logicalAddressCondition; + PLATFORM::CMutex m_mutex; + VCHI_INSTANCE_T m_vchi_instance; + VCHI_CONNECTION_T * m_vchi_connection; + }; +}; + +#endif diff --git a/src/lib/adapter/RPi/RPiCECAdapterDetection.cpp b/src/lib/adapter/RPi/RPiCECAdapterDetection.cpp new file mode 100644 index 0000000..818d5ed --- /dev/null +++ b/src/lib/adapter/RPi/RPiCECAdapterDetection.cpp @@ -0,0 +1,59 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" + +#if defined(HAVE_RPI_API) +#include "RPiCECAdapterDetection.h" + +extern "C" { +#include +#include +} + +using namespace CEC; + +bool CRPiCECAdapterDetection::FindAdapter(void) +{ + uint8_t iResult; + + VCHI_INSTANCE_T vchiq_instance; + if ((iResult = vchi_initialise(&vchiq_instance)) != VCHIQ_SUCCESS) + return false; + + if ((iResult = vchi_connect(NULL, 0, vchiq_instance)) != VCHIQ_SUCCESS) + return false; + + return true; +} + +#endif diff --git a/src/lib/adapter/RPi/RPiCECAdapterDetection.h b/src/lib/adapter/RPi/RPiCECAdapterDetection.h new file mode 100644 index 0000000..34f2234 --- /dev/null +++ b/src/lib/adapter/RPi/RPiCECAdapterDetection.h @@ -0,0 +1,41 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +namespace CEC +{ + class CRPiCECAdapterDetection + { + public: + static bool FindAdapter(void); + }; +} diff --git a/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp b/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp new file mode 100644 index 0000000..df9a374 --- /dev/null +++ b/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.cpp @@ -0,0 +1,209 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" + +#if defined(HAVE_RPI_API) +#include "RPiCECAdapterMessageQueue.h" + +// use vc_cec_send_message2() if defined and vc_cec_send_message() if not +//#define RPI_USE_SEND_MESSAGE2 + +#include "RPiCECAdapterCommunication.h" +#include "lib/LibCEC.h" +#include "lib/CECTypeUtils.h" +#include "lib/platform/util/StdString.h" + +extern "C" { +#include +#include +} + +using namespace std; +using namespace CEC; +using namespace PLATFORM; + +#define LIB_CEC m_com->m_callback->GetLib() + +CRPiCECAdapterMessageQueueEntry::CRPiCECAdapterMessageQueueEntry(CRPiCECAdapterMessageQueue *queue, const cec_command &command) : + m_queue(queue), + m_command(command), + m_retval(VC_CEC_ERROR_NO_ACK), + m_bSucceeded(false) +{ + +} + +void CRPiCECAdapterMessageQueueEntry::Broadcast(void) +{ + CLockObject lock(m_mutex); + m_condition.Broadcast(); +} + +bool CRPiCECAdapterMessageQueueEntry::MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response) +{ + if ((!m_command.opcode_set || m_command.opcode == opcode) && + m_command.initiator == initiator && + m_command.destination == destination) + { + CLockObject lock(m_mutex); + m_retval = response; + m_bSucceeded = true; + m_condition.Signal(); + return true; + } + + return false; +} + +bool CRPiCECAdapterMessageQueueEntry::Wait(uint32_t iTimeout) +{ + bool bReturn(false); + /* wait until we receive a signal when the tranmission succeeded */ + { + CLockObject lock(m_mutex); + bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout); + m_bWaiting = false; + + if (bReturn) + bReturn = m_retval == VCHIQ_SUCCESS; + } + return bReturn; +} + +bool CRPiCECAdapterMessageQueueEntry::IsWaiting(void) +{ + CLockObject lock(m_mutex); + return m_bWaiting; +} + +void CRPiCECAdapterMessageQueue::Clear(void) +{ + CLockObject lock(m_mutex); + m_messages.clear(); +} + +void CRPiCECAdapterMessageQueue::MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response) +{ + bool bHandled(false); + CLockObject lock(m_mutex); + /* send the received message to each entry in the queue until it is handled */ + for (map::iterator it = m_messages.begin(); !bHandled && it != m_messages.end(); it++) + bHandled = it->second->MessageReceived(opcode, initiator, destination, response); + + if (!bHandled) + LIB_CEC->AddLog(CEC_LOG_WARNING, "unhandled response received"); +} + +bool CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool bIsReply) +{ + CRPiCECAdapterMessageQueueEntry *entry = new CRPiCECAdapterMessageQueueEntry(this, command); + uint64_t iEntryId(0); + /* add to the wait for ack queue */ + { + CLockObject lock(m_mutex); + iEntryId = m_iNextMessage++; + m_messages.insert(make_pair(iEntryId, entry)); + } + +#if defined(RPI_USE_SEND_MESSAGE2) + VC_CEC_MESSAGE_T message; + message.initiator = (CEC_AllDevices_T)command.initiator; + message.follower = (CEC_AllDevices_T)command.destination; + message.length = 1; + + if (command.opcode_set) + { + message.length += 1; + message.payload[0] = command.opcode; + + message.length += command.parameters.size; + for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) + message.payload[iPtr + 1] = command.parameters.At(iPtr); + } + + CStdString strDump; + strDump.Format("len = %d, payload = %X%X", message.length, (int)message.initiator, (int)message.follower); + for (uint8_t iPtr = 0; iPtr < message.length - 1; iPtr++) + strDump.AppendFormat(":%02X", message.payload[iPtr]); + LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); + + int iReturn = vc_cec_send_message2(&message); +#else + uint8_t payload[32]; + uint32_t iLength(0); + + if (command.opcode_set) + { + iLength += 1; + payload[0] = command.opcode; + + iLength += command.parameters.size; + for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) + payload[iPtr + 1] = command.parameters.At(iPtr); + } + + CStdString strDump; + strDump.Format("len = %d, payload = %X%X", iLength, (int)command.initiator, (int)command.destination); + for (uint8_t iPtr = 0; iPtr < iLength; iPtr++) + strDump.AppendFormat(":%02X", payload[iPtr]); + LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str()); + + int iReturn = vc_cec_send_message((uint32_t)command.destination, (uint8_t*)&payload, iLength, bIsReply); +#endif + + if (iReturn != VCHIQ_SUCCESS) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending command '%s' failed (%d)", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL", iReturn); + delete (entry); + return false; + } + + bool bReturn(true); + if (entry) + { + if (!entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT)) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", command.opcode_set ? CCECTypeUtils::ToString(command.opcode) : "POLL"); + bReturn = false; + } + + CLockObject lock(m_mutex); + m_messages.erase(iEntryId); + delete entry; + } + + return bReturn; +} + +#endif + diff --git a/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.h b/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.h new file mode 100644 index 0000000..35d2859 --- /dev/null +++ b/src/lib/adapter/RPi/RPiCECAdapterMessageQueue.h @@ -0,0 +1,117 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "lib/platform/util/buffer.h" +#include + +namespace CEC +{ + class CRPiCECAdapterCommunication; + class CRPiCECAdapterMessageQueue; + + class CRPiCECAdapterMessageQueueEntry + { + public: + CRPiCECAdapterMessageQueueEntry(CRPiCECAdapterMessageQueue *queue, const cec_command &command); + virtual ~CRPiCECAdapterMessageQueueEntry(void) {} + + /*! + * @brief Signal waiting threads + */ + void Broadcast(void); + + bool MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response); + + /*! + * @brief Wait for a response to this command. + * @param iTimeout The timeout to use while waiting. + * @return True when a response was received before the timeout passed, false otherwise. + */ + bool Wait(uint32_t iTimeout); + + /*! + * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise. + */ + bool IsWaiting(void); + + /*! + * @return The command that was sent in human readable form. + */ + const char *ToString(void) const { return "CEC transmission"; } + + CRPiCECAdapterMessageQueue * m_queue; + bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */ + PLATFORM::CCondition m_condition; /**< the condition to wait on */ + PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */ + cec_command m_command; + uint32_t m_retval; + bool m_bSucceeded; + }; + + class CRPiCECAdapterMessageQueue + { + friend class CRPiCECAdapterMessageQueueEntry; + + public: + /*! + * @brief Create a new message queue. + * @param com The communication handler callback to use. + * @param iQueueSize The outgoing message queue size. + */ + CRPiCECAdapterMessageQueue(CRPiCECAdapterCommunication *com) : + m_com(com), + m_iNextMessage(0) + { + } + + virtual ~CRPiCECAdapterMessageQueue(void) + { + Clear(); + } + + /*! + * @brief Signal and delete everything in the queue + */ + void Clear(void); + + void MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response); + + bool Write(const cec_command &command, bool bIsReply); + + private: + CRPiCECAdapterCommunication * m_com; /**< the communication handler */ + PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */ + std::map m_messages; /**< the outgoing message queue */ + uint64_t m_iNextMessage; /**< the index of the next message */ + }; +}; diff --git a/src/lib/devices/CECAudioSystem.cpp b/src/lib/devices/CECAudioSystem.cpp index 7824451..91a3e99 100644 --- a/src/lib/devices/CECAudioSystem.cpp +++ b/src/lib/devices/CECAudioSystem.cpp @@ -30,11 +30,13 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECAudioSystem.h" -#include "../CECProcessor.h" -#include "../implementations/CECCommandHandler.h" -#include "../LibCEC.h" -#include "../CECTypeUtils.h" + +#include "lib/CECProcessor.h" +#include "lib/implementations/CECCommandHandler.h" +#include "lib/LibCEC.h" +#include "lib/CECTypeUtils.h" using namespace CEC; using namespace PLATFORM; @@ -76,7 +78,7 @@ bool CCECAudioSystem::SetSystemAudioModeStatus(const cec_system_audio_status mod return false; } -bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest) +bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest, bool bIsReply) { uint8_t state; { @@ -85,10 +87,10 @@ bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest) state = m_audioStatus; } - return m_handler->TransmitAudioStatus(m_iLogicalAddress, dest, state); + return m_handler->TransmitAudioStatus(m_iLogicalAddress, dest, state, bIsReply); } -bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest) +bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest, bool bIsReply) { cec_system_audio_status state; { @@ -97,10 +99,10 @@ bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest) state = m_systemAudioStatus; } - return m_handler->TransmitSetSystemAudioMode(m_iLogicalAddress, dest, state); + return m_handler->TransmitSetSystemAudioMode(m_iLogicalAddress, dest, state, bIsReply); } -bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest) +bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest, bool bIsReply) { cec_system_audio_status state; { @@ -109,7 +111,7 @@ bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest) state = m_systemAudioStatus; } - return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state); + return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state, bIsReply); } uint8_t CCECAudioSystem::VolumeUp(const cec_logical_address source, bool bSendRelease /* = true */) diff --git a/src/lib/devices/CECAudioSystem.h b/src/lib/devices/CECAudioSystem.h index e2e3cd2..7950311 100644 --- a/src/lib/devices/CECAudioSystem.h +++ b/src/lib/devices/CECAudioSystem.h @@ -43,9 +43,9 @@ namespace CEC bool SetAudioStatus(uint8_t status); bool SetSystemAudioModeStatus(const cec_system_audio_status mode); - bool TransmitAudioStatus(cec_logical_address dest); - bool TransmitSetSystemAudioMode(cec_logical_address dest); - bool TransmitSystemAudioModeStatus(cec_logical_address dest); + bool TransmitAudioStatus(cec_logical_address dest, bool bIsReply); + bool TransmitSetSystemAudioMode(cec_logical_address dest, bool bIsReply); + bool TransmitSystemAudioModeStatus(cec_logical_address dest, bool bIsReply); uint8_t VolumeUp(const cec_logical_address source, bool bSendRelease = true); uint8_t VolumeDown(const cec_logical_address source, bool bSendRelease = true); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 91dd835..5b3e2cb 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -30,17 +30,19 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECBusDevice.h" -#include "../CECProcessor.h" -#include "../CECClient.h" -#include "../implementations/ANCommandHandler.h" -#include "../implementations/CECCommandHandler.h" -#include "../implementations/SLCommandHandler.h" -#include "../implementations/VLCommandHandler.h" -#include "../LibCEC.h" -#include "../CECTypeUtils.h" -#include "../platform/util/timeutils.h" -#include "../platform/util/util.h" + +#include "lib/CECProcessor.h" +#include "lib/CECClient.h" +#include "lib/implementations/ANCommandHandler.h" +#include "lib/implementations/CECCommandHandler.h" +#include "lib/implementations/SLCommandHandler.h" +#include "lib/implementations/VLCommandHandler.h" +#include "lib/LibCEC.h" +#include "lib/CECTypeUtils.h" +#include "lib/platform/util/timeutils.h" +#include "lib/platform/util/util.h" #include "CECAudioSystem.h" #include "CECPlaybackDevice.h" @@ -95,10 +97,7 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */) { bool bInitHandler(false); { - CTryLockObject lock(m_mutex); - if (!lock.IsLocked()) - return false; - + CLockObject lock(m_mutex); CLockObject handlerLock(m_handlerMutex); if (m_iHandlerUseCount > 0) return false; @@ -311,7 +310,7 @@ bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool return bReturn; } -bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination) +bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination, bool bIsReply) { cec_version version; { @@ -321,7 +320,7 @@ bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination) } MarkBusy(); - bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version); + bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version, bIsReply); MarkReady(); return bReturn; } @@ -380,7 +379,7 @@ bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, boo return bReturn; } -bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination) +bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination, bool bIsReply) { bool bReturn(false); cec_menu_language language; @@ -407,20 +406,20 @@ bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destinatio else { LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang); - bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang); + bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang, bIsReply); } MarkReady(); return bReturn; } -bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage) +bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage, bool bIsReply) { bool bReturn(false); if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING)) { LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage); MarkBusy(); - bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage); + bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage, bIsReply); MarkReady(); } return bReturn; @@ -478,7 +477,7 @@ bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWa return bReturn; } -bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination) +bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination, bool bIsReply) { CStdString strDeviceName; { @@ -488,7 +487,7 @@ bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination) } MarkBusy(); - bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName); + bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName, bIsReply); MarkReady(); return bReturn; } @@ -553,7 +552,7 @@ bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, return bReturn; } -bool CCECBusDevice::TransmitPhysicalAddress(void) +bool CCECBusDevice::TransmitPhysicalAddress(bool bIsReply) { uint16_t iPhysicalAddress; cec_device_type type; @@ -568,7 +567,7 @@ bool CCECBusDevice::TransmitPhysicalAddress(void) } MarkBusy(); - bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type); + bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type, bIsReply); MarkReady(); return bReturn; } @@ -628,7 +627,7 @@ bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool return bReturn; } -bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination) +bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination, bool bIsReply) { cec_power_status state; { @@ -638,7 +637,7 @@ bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination) } MarkBusy(); - bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state); + bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state, bIsReply); MarkReady(); return bReturn; } @@ -704,7 +703,7 @@ bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bW return bReturn; } -bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */) +bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort, bool bIsReply) { bool bReturn(false); uint64_t iVendorId; @@ -726,7 +725,7 @@ bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool else { LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId); - bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId); + bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId, bIsReply); } MarkReady(); return bReturn; @@ -757,7 +756,7 @@ cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bo return status; } -void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus) +void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */) { { CLockObject lock(m_mutex); @@ -769,7 +768,7 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus) SetPowerStatus (CEC_POWER_STATUS_ON); SetVendorId (CEC_VENDOR_UNKNOWN); SetMenuState (CEC_MENU_STATE_ACTIVATED); - SetCecVersion (CEC_VERSION_1_3A); + SetCecVersion (libCECSpecVersion); SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS); MarkAsInactiveSource(); m_iLastActive = 0; @@ -816,7 +815,7 @@ void CCECBusDevice::ResetDeviceStatus(void) m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN; } -bool CCECBusDevice::TransmitPoll(const cec_logical_address dest) +bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bIsReply) { bool bReturn(false); cec_logical_address destination(dest); @@ -829,7 +828,7 @@ bool CCECBusDevice::TransmitPoll(const cec_logical_address dest) MarkBusy(); LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest); - bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination); + bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, bIsReply); LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent"); CLockObject lock(m_mutex); @@ -884,7 +883,7 @@ void CCECBusDevice::SetMenuState(const cec_menu_state state) } } -bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest) +bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest, bool bIsReply) { cec_menu_state menuState; { @@ -894,7 +893,7 @@ bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest) } MarkBusy(); - bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState); + bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState, bIsReply); MarkReady(); return bReturn; } @@ -990,7 +989,7 @@ void CCECBusDevice::MarkAsInactiveSource(void) } } -bool CCECBusDevice::TransmitActiveSource(void) +bool CCECBusDevice::TransmitActiveSource(bool bIsReply) { bool bSendActiveSource(false); uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS); @@ -1020,7 +1019,7 @@ bool CCECBusDevice::TransmitActiveSource(void) if (bSendActiveSource) { MarkBusy(); - bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress); + bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress, bIsReply); MarkReady(); } @@ -1279,14 +1278,14 @@ void CCECBusDevice::MarkReady(void) --m_iHandlerUseCount; } -bool CCECBusDevice::TryLogicalAddress(void) +bool CCECBusDevice::TryLogicalAddress(cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName()); - if (!TransmitPoll(m_iLogicalAddress)) + if (!TransmitPoll(m_iLogicalAddress, false)) { LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName()); - SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC); + SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC, libCECSpecVersion); return true; } diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 89fb690..4e21553 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -31,11 +31,10 @@ * http://www.pulse-eight.net/ */ -#include "../../../include/cectypes.h" #include #include -#include "../platform/threads/mutex.h" -#include "../platform/util/StdString.h" +#include "lib/platform/threads/mutex.h" +#include "lib/platform/util/StdString.h" namespace CEC { @@ -167,61 +166,61 @@ namespace CEC virtual cec_version GetCecVersion(const cec_logical_address initiator, bool bUpdate = false); virtual void SetCecVersion(const cec_version newVersion); virtual bool RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse = true); - virtual bool TransmitCECVersion(const cec_logical_address destination); + virtual bool TransmitCECVersion(const cec_logical_address destination, bool bIsReply); virtual cec_menu_language & GetMenuLanguage(const cec_logical_address initiator, bool bUpdate = false); virtual void SetMenuLanguage(const char *strLanguage); virtual void SetMenuLanguage(const cec_menu_language &menuLanguage); virtual bool RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse = true); - virtual bool TransmitSetMenuLanguage(const cec_logical_address destination); + virtual bool TransmitSetMenuLanguage(const cec_logical_address destination, bool bIsReply); - virtual bool TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage); + virtual bool TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage, bool bIsReply); virtual CStdString GetCurrentOSDName(void); virtual CStdString GetOSDName(const cec_logical_address initiator, bool bUpdate = false); virtual void SetOSDName(CStdString strName); virtual bool RequestOSDName(const cec_logical_address source, bool bWaitForResponse = true); - virtual bool TransmitOSDName(const cec_logical_address destination); + virtual bool TransmitOSDName(const cec_logical_address destination, bool bIsReply); virtual uint16_t GetCurrentPhysicalAddress(void); virtual bool HasValidPhysicalAddress(void); virtual uint16_t GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate = false); virtual bool SetPhysicalAddress(uint16_t iNewAddress); virtual bool RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse = true); - virtual bool TransmitPhysicalAddress(void); + virtual bool TransmitPhysicalAddress(bool bIsReply); virtual cec_power_status GetCurrentPowerStatus(void); virtual cec_power_status GetPowerStatus(const cec_logical_address initiator, bool bUpdate = false); virtual void SetPowerStatus(const cec_power_status powerStatus); virtual bool RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse = true); - virtual bool TransmitPowerState(const cec_logical_address destination); + virtual bool TransmitPowerState(const cec_logical_address destination, bool bIsReply); virtual cec_vendor_id GetCurrentVendorId(void); virtual cec_vendor_id GetVendorId(const cec_logical_address initiator, bool bUpdate = false); virtual const char * GetVendorName(const cec_logical_address initiator, bool bUpdate = false); virtual bool SetVendorId(uint64_t iVendorId); virtual bool RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse = true); - virtual bool TransmitVendorID(const cec_logical_address destination, bool bSendAbort = true); + virtual bool TransmitVendorID(const cec_logical_address destination, bool bSendAbort, bool bIsReply); virtual cec_bus_device_status GetCurrentStatus(void) { return GetStatus(false, true); } virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false); - virtual void SetDeviceStatus(const cec_bus_device_status newStatus); + virtual void SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion = CEC_VERSION_1_4); virtual void ResetDeviceStatus(void); - virtual bool TransmitPoll(const cec_logical_address destination); + virtual bool TransmitPoll(const cec_logical_address destination, bool bIsReply); virtual void HandlePoll(const cec_logical_address destination); virtual void HandlePollFrom(const cec_logical_address initiator); virtual bool HandleReceiveFailed(void); virtual cec_menu_state GetMenuState(const cec_logical_address initiator); virtual void SetMenuState(const cec_menu_state state); - virtual bool TransmitMenuState(const cec_logical_address destination); + virtual bool TransmitMenuState(const cec_logical_address destination, bool bIsReply); 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 void MarkAsInactiveSource(void); - virtual bool TransmitActiveSource(void); + virtual bool TransmitActiveSource(bool bIsReply); virtual bool TransmitImageViewOn(void); virtual bool TransmitInactiveSource(void); virtual bool TransmitPendingActiveSourceCommands(void); @@ -230,7 +229,7 @@ namespace CEC virtual bool PowerOn(const cec_logical_address initiator); virtual bool Standby(const cec_logical_address initiator); - virtual bool TryLogicalAddress(void); + virtual bool TryLogicalAddress(cec_version libCECSpecVersion = CEC_VERSION_1_4); CCECClient * GetClient(void); void SignalOpcode(cec_opcode opcode); diff --git a/src/lib/devices/CECDeviceMap.cpp b/src/lib/devices/CECDeviceMap.cpp index 3c70603..a21b2b4 100644 --- a/src/lib/devices/CECDeviceMap.cpp +++ b/src/lib/devices/CECDeviceMap.cpp @@ -30,13 +30,15 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECDeviceMap.h" + #include "CECAudioSystem.h" #include "CECPlaybackDevice.h" #include "CECRecordingDevice.h" #include "CECTuner.h" #include "CECTV.h" -#include "../CECProcessor.h" +#include "lib/CECProcessor.h" using namespace std; using namespace CEC; diff --git a/src/lib/devices/CECDeviceMap.h b/src/lib/devices/CECDeviceMap.h index 128f574..d4af816 100644 --- a/src/lib/devices/CECDeviceMap.h +++ b/src/lib/devices/CECDeviceMap.h @@ -31,7 +31,6 @@ * http://www.pulse-eight.net/ */ -#include "../../../include/cectypes.h" #include #include diff --git a/src/lib/devices/CECPlaybackDevice.cpp b/src/lib/devices/CECPlaybackDevice.cpp index 1beed4f..ac5371e 100644 --- a/src/lib/devices/CECPlaybackDevice.cpp +++ b/src/lib/devices/CECPlaybackDevice.cpp @@ -30,11 +30,13 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECPlaybackDevice.h" -#include "../implementations/CECCommandHandler.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" -#include "../CECTypeUtils.h" + +#include "lib/implementations/CECCommandHandler.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" +#include "lib/CECTypeUtils.h" using namespace CEC; using namespace PLATFORM; @@ -81,7 +83,7 @@ void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode) } } -bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest) +bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest, bool bIsReply) { cec_deck_info state; { @@ -90,7 +92,7 @@ bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest) state = m_deckStatus; } - return m_handler->TransmitDeckStatus(m_iLogicalAddress, dest, state); + return m_handler->TransmitDeckStatus(m_iLogicalAddress, dest, state, bIsReply); } void CCECPlaybackDevice::ResetDeviceStatus(void) diff --git a/src/lib/devices/CECPlaybackDevice.h b/src/lib/devices/CECPlaybackDevice.h index c21bf30..d12c150 100644 --- a/src/lib/devices/CECPlaybackDevice.h +++ b/src/lib/devices/CECPlaybackDevice.h @@ -47,7 +47,7 @@ namespace CEC void SetDeckStatus(cec_deck_info deckStatus); void SetDeckControlMode(cec_deck_control_mode mode); - bool TransmitDeckStatus(cec_logical_address dest); + bool TransmitDeckStatus(cec_logical_address dest, bool bIsReply); virtual void ResetDeviceStatus(void); diff --git a/src/lib/devices/CECRecordingDevice.cpp b/src/lib/devices/CECRecordingDevice.cpp index 2a82902..8b1d575 100644 --- a/src/lib/devices/CECRecordingDevice.cpp +++ b/src/lib/devices/CECRecordingDevice.cpp @@ -30,6 +30,7 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECRecordingDevice.h" using namespace CEC; diff --git a/src/lib/devices/CECTV.cpp b/src/lib/devices/CECTV.cpp index b26dbdc..2f852ae 100644 --- a/src/lib/devices/CECTV.cpp +++ b/src/lib/devices/CECTV.cpp @@ -30,6 +30,7 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECTV.h" using namespace CEC; diff --git a/src/lib/devices/CECTuner.cpp b/src/lib/devices/CECTuner.cpp index 4721c1a..2de4a1f 100644 --- a/src/lib/devices/CECTuner.cpp +++ b/src/lib/devices/CECTuner.cpp @@ -30,6 +30,7 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECTuner.h" using namespace CEC; diff --git a/src/lib/implementations/ANCommandHandler.cpp b/src/lib/implementations/ANCommandHandler.cpp index 8eccf88..648f4a0 100644 --- a/src/lib/implementations/ANCommandHandler.cpp +++ b/src/lib/implementations/ANCommandHandler.cpp @@ -30,11 +30,13 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "ANCommandHandler.h" -#include "../devices/CECBusDevice.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" -#include "../CECClient.h" + +#include "lib/devices/CECBusDevice.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" +#include "lib/CECClient.h" using namespace CEC; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index ffe78b8..46edf98 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -30,15 +30,17 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECCommandHandler.h" -#include "../devices/CECBusDevice.h" -#include "../devices/CECAudioSystem.h" -#include "../devices/CECPlaybackDevice.h" -#include "../CECClient.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" -#include "../CECTypeUtils.h" -#include "../platform/util/util.h" + +#include "lib/devices/CECBusDevice.h" +#include "lib/devices/CECAudioSystem.h" +#include "lib/devices/CECPlaybackDevice.h" +#include "lib/CECClient.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" +#include "lib/CECTypeUtils.h" +#include "lib/platform/util/util.h" using namespace CEC; using namespace std; @@ -267,7 +269,7 @@ int CCECCommandHandler::HandleGetCecVersion(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitCECVersion(command.initiator)) + if (device && device->TransmitCECVersion(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -280,7 +282,7 @@ 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 && device->TransmitAudioStatus(command.initiator)) + if (device && device->TransmitAudioStatus(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -293,7 +295,7 @@ 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 && device->TransmitDeckStatus(command.initiator)) + if (device && device->TransmitDeckStatus(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -306,7 +308,7 @@ int CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitPowerState(command.initiator)) + if (device && device->TransmitPowerState(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -319,7 +321,7 @@ int CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitVendorID(command.initiator)) + if (device && device->TransmitVendorID(command.initiator, true, true)) return COMMAND_HANDLED; } @@ -331,7 +333,7 @@ int CCECCommandHandler::HandleGiveOSDName(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitOSDName(command.initiator)) + if (device && device->TransmitOSDName(command.initiator, true)) return COMMAND_HANDLED; } @@ -343,7 +345,7 @@ int CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitPhysicalAddress()) + if (device && device->TransmitPhysicalAddress(true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -356,7 +358,7 @@ int CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitSetMenuLanguage(command.initiator)) + if (device && device->TransmitSetMenuLanguage(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -369,7 +371,7 @@ int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &comma if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination)); - if (device && device->TransmitSystemAudioModeStatus(command.initiator)) + if (device && device->TransmitSystemAudioModeStatus(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -379,7 +381,14 @@ int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &comma int CCECCommandHandler::HandleImageViewOn(const cec_command &command) { - m_processor->GetDevice(command.initiator)->MarkAsActiveSource(); + CCECBusDevice *device = GetDevice(command.destination); + if (device && (device->GetCurrentStatus() == CEC_DEVICE_STATUS_PRESENT || + device->GetCurrentStatus() == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)) + { + if (device->GetCurrentPowerStatus() == CEC_POWER_STATUS_STANDBY || + device->GetCurrentPowerStatus() == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY) + device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); + } return COMMAND_HANDLED; } @@ -404,7 +413,7 @@ int CCECCommandHandler::HandleMenuRequest(const cec_command &command) device->SetMenuState(CEC_MENU_STATE_DEACTIVATED); } } - if (device->TransmitMenuState(command.initiator)) + if (device->TransmitMenuState(command.initiator, true)) return COMMAND_HANDLED; } return CEC_ABORT_REASON_INVALID_OPERAND; @@ -467,7 +476,7 @@ int CCECCommandHandler::HandleRequestActiveSource(const cec_command &command) vector devices; for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++) - devices[iDevicePtr]->TransmitActiveSource(); + devices[iDevicePtr]->TransmitActiveSource(true); } return COMMAND_HANDLED; @@ -589,13 +598,13 @@ int CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command) CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress); if (newActiveDevice) newActiveDevice->MarkAsActiveSource(); - if (device->TransmitSetSystemAudioMode(command.initiator)) + if (device->TransmitSetSystemAudioMode(command.initiator, true)) return COMMAND_HANDLED; } else { device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF); - if (device->TransmitSetSystemAudioMode(command.initiator)) + if (device->TransmitSetSystemAudioMode(command.initiator, true)) return COMMAND_HANDLED; } } @@ -809,7 +818,7 @@ bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiato cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON); - return Transmit(command); + return Transmit(command, false, false); } bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -817,7 +826,7 @@ bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, c cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY); - return Transmit(command); + return Transmit(command, false, false); } bool CCECCommandHandler::TransmitRequestActiveSource(const cec_logical_address iInitiator, bool bWaitForResponse /* = true */) @@ -825,7 +834,7 @@ bool CCECCommandHandler::TransmitRequestActiveSource(const cec_logical_address i cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REQUEST_ACTIVE_SOURCE); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -833,7 +842,7 @@ bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iIn cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -841,7 +850,7 @@ bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address i cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -849,7 +858,7 @@ bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iIniti cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -857,7 +866,7 @@ bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_addres cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -865,7 +874,7 @@ bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iI cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -873,26 +882,26 @@ bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInit cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } -bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) +bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion) +bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION); command.parameters.PushBack((uint8_t)cecVersion); - return Transmit(command); + return Transmit(command, false, bIsReply); } bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) @@ -902,29 +911,29 @@ bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iIniti command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF); command.parameters.PushBack(iPhysicalAddress & 0xFF); - return Transmit(command); + return Transmit(command, false, false); } -bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState) +bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS); command.parameters.PushBack((uint8_t)menuState); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName) +bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, std::string strDeviceName, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_NAME); for (size_t iPtr = 0; iPtr < strDeviceName.length(); iPtr++) command.parameters.PushBack(strDeviceName.at(iPtr)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage) +bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_STRING); @@ -936,10 +945,10 @@ bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, for (size_t iPtr = 0; iPtr < iLen; iPtr++) command.parameters.PushBack(strMessage[iPtr]); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type) +bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS); @@ -947,10 +956,10 @@ bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInit command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF)); command.parameters.PushBack((uint8_t) (type)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3]) +bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3], bool bIsReply) { cec_command command; command.Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_SET_MENU_LANGUAGE); @@ -958,27 +967,27 @@ bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInit command.parameters.PushBack((uint8_t) lang[1]); command.parameters.PushBack((uint8_t) lang[2]); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination) +bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_NONE); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state) +bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS); command.parameters.PushBack((uint8_t) state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId) +bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID); @@ -987,53 +996,58 @@ bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state) +bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS); command.parameters.PushBack(state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state) +bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE); command.parameters.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetStreamPath(uint16_t iStreamPath) +bool CCECCommandHandler::TransmitSetStreamPath(uint16_t iStreamPath, bool bIsReply) { + if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH"); + return false; + } cec_command command; cec_command::Format(command, m_busDevice->GetLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_SET_STREAM_PATH); command.parameters.PushBack((uint8_t) ((iStreamPath >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) (iStreamPath & 0xFF)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state) +bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS); command.parameters.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state) +bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS); command.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false, bIsReply); } bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */) @@ -1042,7 +1056,7 @@ bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED); command.parameters.PushBack((uint8_t)key); - return Transmit(command, !bWait); + return Transmit(command, !bWait, false); } bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */) @@ -1050,10 +1064,10 @@ bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE); - return Transmit(command, !bWait); + return Transmit(command, !bWait, false); } -bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* = false */) +bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait, bool bIsReply) { bool bReturn(false); cec_opcode expectedResponse(cec_command::GetResponseOpcode(command.opcode)); @@ -1070,7 +1084,7 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* = uint8_t iTries(0), iMaxTries(!command.opcode_set ? 1 : m_iTransmitRetries + 1); while (!bReturn && ++iTries <= iMaxTries && !m_busDevice->IsUnsupportedFeature(command.opcode)) { - if ((bReturn = m_processor->Transmit(command)) == true) + if ((bReturn = m_processor->Transmit(command, bIsReply)) == true) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted"); if (bExpectResponse) @@ -1120,15 +1134,15 @@ bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = f // switch sources (if allowed) if (!bActiveSourceFailed && bSourceSwitchAllowed) { - bActiveSourceFailed = !m_busDevice->TransmitActiveSource() || - !m_busDevice->TransmitMenuState(CECDEVICE_TV); + bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false) || + !m_busDevice->TransmitMenuState(CECDEVICE_TV, false); // update the deck status for playback devices if (!bActiveSourceFailed) { CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice(); if (playbackDevice && SendDeckStatusUpdateOnActiveSource()) - bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV); + bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV, false); } } diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index bc42128..45e3522 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -31,10 +31,9 @@ * http://www.pulse-eight.net/ */ -#include "../../../include/cectypes.h" #include -#include "../platform/threads/mutex.h" -#include "../platform/util/StdString.h" +#include +#include "lib/platform/threads/mutex.h" namespace CEC { @@ -74,24 +73,24 @@ namespace CEC virtual bool TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true); virtual bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true); virtual bool TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true); - virtual bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress); - virtual bool TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion); + virtual bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply); + virtual bool TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion, bool bIsReply); virtual bool TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress); - virtual bool TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState); - virtual bool TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName); - virtual bool TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage); - virtual bool TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type); - virtual bool TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3]); - virtual bool TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination); - virtual bool TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state); - virtual bool TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId); - virtual bool TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state); - virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state); - virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state); - virtual bool TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state); + virtual bool TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState, bool bIsReply); + virtual bool TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, std::string strDeviceName, bool bIsReply); + virtual bool TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage, bool bIsReply); + virtual bool TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type, bool bIsReply); + virtual bool TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3], bool bIsReply); + virtual bool TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bIsReply); + virtual bool TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state, bool bIsReply); + virtual bool TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId, bool bIsReply); + virtual bool TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state, bool bIsReply); + virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply); + virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply); + virtual bool TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state, bool bIsReply); virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait = true); virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true); - virtual bool TransmitSetStreamPath(uint16_t iStreamPath); + virtual bool TransmitSetStreamPath(uint16_t iStreamPath, bool bIsReply); virtual bool SendDeckStatusUpdateOnActiveSource(void) const { return m_bOPTSendDeckStatusUpdateOnActiveSource; }; virtual void ScheduleActivateSource(uint64_t iDelay); @@ -146,7 +145,7 @@ namespace CEC virtual bool SetVendorId(const cec_command &command); virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress); - virtual bool Transmit(cec_command &command, bool bSuppressWait = false); + virtual bool Transmit(cec_command &command, bool bSuppressWait, bool bIsReply); virtual bool SourceSwitchAllowed(void) { return true; } diff --git a/src/lib/implementations/RLCommandHandler.cpp b/src/lib/implementations/RLCommandHandler.cpp index 5653137..f1f936a 100644 --- a/src/lib/implementations/RLCommandHandler.cpp +++ b/src/lib/implementations/RLCommandHandler.cpp @@ -30,10 +30,13 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "RLCommandHandler.h" -#include "../devices/CECBusDevice.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" + +#include "lib/platform/util/timeutils.h" +#include "lib/devices/CECBusDevice.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" using namespace CEC; using namespace PLATFORM; @@ -67,7 +70,7 @@ bool CRLCommandHandler::InitHandler(void) if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) { /* send the vendor id */ - primary->TransmitVendorID(CECDEVICE_BROADCAST); + primary->TransmitVendorID(CECDEVICE_BROADCAST, false, false); } } diff --git a/src/lib/implementations/RLCommandHandler.h b/src/lib/implementations/RLCommandHandler.h index ec9edd9..446c91b 100644 --- a/src/lib/implementations/RLCommandHandler.h +++ b/src/lib/implementations/RLCommandHandler.h @@ -32,7 +32,6 @@ */ #include "CECCommandHandler.h" -#include "../platform/util/timeutils.h" namespace CEC { diff --git a/src/lib/implementations/SLCommandHandler.cpp b/src/lib/implementations/SLCommandHandler.cpp index 222fc95..32902c2 100644 --- a/src/lib/implementations/SLCommandHandler.cpp +++ b/src/lib/implementations/SLCommandHandler.cpp @@ -30,11 +30,14 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "SLCommandHandler.h" -#include "../devices/CECBusDevice.h" -#include "../devices/CECPlaybackDevice.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" + +#include "lib/platform/util/timeutils.h" +#include "lib/devices/CECBusDevice.h" +#include "lib/devices/CECPlaybackDevice.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" using namespace CEC; using namespace PLATFORM; @@ -97,10 +100,10 @@ bool CSLCommandHandler::InitHandler(void) { /* start as 'in transition standby->on' */ primary->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); - primary->TransmitPowerState(CECDEVICE_TV); + primary->TransmitPowerState(CECDEVICE_TV, false); /* send the vendor id */ - primary->TransmitVendorID(CECDEVICE_BROADCAST); + primary->TransmitVendorID(CECDEVICE_BROADCAST, false, false); } } @@ -124,7 +127,7 @@ int CSLCommandHandler::HandleActiveSource(const cec_command &command) CLockObject lock(m_SLMutex); m_bActiveSourceSent = false; } - primary->TransmitPowerState(CECDEVICE_TV); + primary->TransmitPowerState(CECDEVICE_TV, false); } return COMMAND_HANDLED; @@ -149,7 +152,7 @@ int CSLCommandHandler::HandleDeviceVendorId(const cec_command &command) cec_command response; cec_command::Format(response, initiator, command.initiator, CEC_OPCODE_FEATURE_ABORT); - Transmit(response); + Transmit(response, false, true); return COMMAND_HANDLED; } } @@ -203,7 +206,7 @@ void CSLCommandHandler::TransmitVendorCommand0205(const cec_logical_address iSou response.PushBack(SL_COMMAND_UNKNOWN_02); response.PushBack(SL_COMMAND_TYPE_HDDRECORDER); - Transmit(response); + Transmit(response, false, true); } void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command) @@ -217,12 +220,12 @@ void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command) SetSLInitialised(); device->MarkAsActiveSource(); device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); - device->TransmitPowerState(command.initiator); + device->TransmitPowerState(command.initiator, true); CEvent::Sleep(2000); device->SetPowerStatus(CEC_POWER_STATUS_ON); - device->TransmitPowerState(command.initiator); - device->TransmitPhysicalAddress(); + device->TransmitPowerState(command.initiator, false); + device->TransmitPhysicalAddress(false); { CLockObject lock(m_SLMutex); m_bActiveSourceSent = false; @@ -237,7 +240,7 @@ void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &comm if (device) { device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); - device->TransmitPowerState(command.initiator); + device->TransmitPowerState(command.initiator, true); device->SetPowerStatus(CEC_POWER_STATUS_ON); } } @@ -257,7 +260,7 @@ void CSLCommandHandler::TransmitVendorCommandSetDeviceMode(const cec_logical_add cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND); response.PushBack(SL_COMMAND_SET_DEVICE_MODE); response.PushBack((uint8_t)type); - Transmit(response); + Transmit(response, false, true); } int CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command) @@ -273,14 +276,14 @@ int CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command) device->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG); if (command.parameters[0] == CEC_STATUS_REQUEST_ON) { - device->TransmitDeckStatus(command.initiator); + device->TransmitDeckStatus(command.initiator, true); if (!ActiveSourceSent()) ActivateSource(); return COMMAND_HANDLED; } else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE) { - device->TransmitDeckStatus(command.initiator); + device->TransmitDeckStatus(command.initiator, true); return COMMAND_HANDLED; } @@ -294,7 +297,7 @@ int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) CCECBusDevice *device = GetDevice(command.destination); if (device && device->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON) { - device->TransmitPowerState(command.initiator); + device->TransmitPowerState(command.initiator, true); device->SetPowerStatus(CEC_POWER_STATUS_ON); } else @@ -302,7 +305,7 @@ int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) if (!ActiveSourceSent()) { device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); - device->TransmitPowerState(command.initiator); + device->TransmitPowerState(command.initiator, true); ActivateSource(); } else if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0) @@ -314,13 +317,13 @@ int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) m_bActiveSourceSent = false; } device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); - device->TransmitPowerState(command.initiator); + device->TransmitPowerState(command.initiator, true); device->SetPowerStatus(CEC_POWER_STATUS_ON); m_resetPowerState.Init(5000); } else { - device->TransmitPowerState(command.initiator); + device->TransmitPowerState(command.initiator, true); m_resetPowerState.Init(5000); } } @@ -349,8 +352,8 @@ 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) { - m_processor->GetPrimaryDevice()->TransmitPowerState(command.initiator); - m_processor->GetPrimaryDevice()->TransmitVendorID(CECDEVICE_BROADCAST, false); + m_processor->GetPrimaryDevice()->TransmitPowerState(command.initiator, false); + m_processor->GetPrimaryDevice()->TransmitVendorID(CECDEVICE_BROADCAST, false, false); } return CCECCommandHandler::HandleFeatureAbort(command); @@ -403,12 +406,12 @@ bool CSLCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_ cec_command command; if (!m_bSLEnabled) - TransmitVendorID(CECDEVICE_TV, CEC_VENDOR_LG); + TransmitVendorID(CECDEVICE_TV, CEC_VENDOR_LG, false); cec_command::Format(command, CECDEVICE_TV, iDestination, CEC_OPCODE_VENDOR_COMMAND); command.PushBack(SL_COMMAND_POWER_ON); command.PushBack(0); - return Transmit(command); + return Transmit(command, false, false); } return CCECCommandHandler::PowerOn(iInitiator, iDestination); diff --git a/src/lib/implementations/SLCommandHandler.h b/src/lib/implementations/SLCommandHandler.h index 8c6902d..8cc64f1 100644 --- a/src/lib/implementations/SLCommandHandler.h +++ b/src/lib/implementations/SLCommandHandler.h @@ -32,7 +32,6 @@ */ #include "CECCommandHandler.h" -#include "../platform/util/timeutils.h" namespace CEC { @@ -67,7 +66,7 @@ namespace CEC 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 TransmitMenuState(const cec_logical_address UNUSED(iInitiator), const cec_logical_address UNUSED(iDestination), cec_menu_state UNUSED(menuState), bool UNUSED(bIsReply)) { return true; } bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); void ResetSLState(void); diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index 97d06a2..e78f942 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -30,13 +30,15 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "VLCommandHandler.h" -#include "../devices/CECBusDevice.h" -#include "../devices/CECPlaybackDevice.h" -#include "../devices/CECTV.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" -#include "../CECClient.h" + +#include "lib/devices/CECBusDevice.h" +#include "lib/devices/CECPlaybackDevice.h" +#include "lib/devices/CECTV.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" +#include "lib/CECClient.h" #define VL_POWER_CHANGE 0x20 #define VL_POWERED_UP 0x00 @@ -200,7 +202,7 @@ int CVLCommandHandler::HandleVendorCommand(const cec_command &command) uint8_t iResponseData[] = {0x10, 0x02, 0xFF, 0xFF, 0x00, 0x05, 0x05, 0x45, 0x55, 0x5c, 0x58, 0x32}; response.PushArray(12, iResponseData); - Transmit(response, true); + Transmit(response, false, true); return COMMAND_HANDLED; } diff --git a/src/lib/platform/adl/adl-edid.cpp b/src/lib/platform/adl/adl-edid.cpp index 368b86b..c69c813 100644 --- a/src/lib/platform/adl/adl-edid.cpp +++ b/src/lib/platform/adl/adl-edid.cpp @@ -30,6 +30,7 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "adl-edid.h" // for dlsym and friends diff --git a/src/lib/platform/adl/adl-edid.h b/src/lib/platform/adl/adl-edid.h index 10b76c9..e6b1b04 100644 --- a/src/lib/platform/adl/adl-edid.h +++ b/src/lib/platform/adl/adl-edid.h @@ -33,8 +33,8 @@ #define HAS_ADL_EDID_PARSER -#include "../os.h" -#include "../util/edid.h" +#include "lib/platform/os.h" +#include "lib/platform/util/edid.h" #if !defined(__WINDOWS__) #include "adl_sdk.h" diff --git a/src/lib/platform/nvidia/nv-edid.cpp b/src/lib/platform/nvidia/nv-edid.cpp index 0c0bbd6..3de7754 100644 --- a/src/lib/platform/nvidia/nv-edid.cpp +++ b/src/lib/platform/nvidia/nv-edid.cpp @@ -30,6 +30,9 @@ * http://www.pulse-eight.net/ */ +#include "env.h" + +#include "lib/platform/os.h" #include "nv-edid.h" using namespace PLATFORM; @@ -46,7 +49,7 @@ uint16_t CNVEdidParser::GetPhysicalAddress(void) char buf[4096]; memset(buf, 0, sizeof(buf)); int iPtr(0); - char c(0); + int c(0); while (c != EOF) { c = fgetc(fp); diff --git a/src/lib/platform/nvidia/nv-edid.h b/src/lib/platform/nvidia/nv-edid.h index 81f10ce..a9ba940 100644 --- a/src/lib/platform/nvidia/nv-edid.h +++ b/src/lib/platform/nvidia/nv-edid.h @@ -33,8 +33,7 @@ #define HAS_NVIDIA_EDID_PARSER -#include "../os.h" -#include "../util/edid.h" +#include "lib/platform/util/edid.h" namespace PLATFORM { diff --git a/src/lib/platform/os.h b/src/lib/platform/os.h index 60e02d6..70e603c 100644 --- a/src/lib/platform/os.h +++ b/src/lib/platform/os.h @@ -31,7 +31,6 @@ * http://www.pulse-eight.net/ */ - #ifdef UNUSED #elif defined(__GNUC__) #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) diff --git a/src/lib/platform/posix/os-edid.cpp b/src/lib/platform/posix/os-edid.cpp index 1a346dc..05ce9fa 100644 --- a/src/lib/platform/posix/os-edid.cpp +++ b/src/lib/platform/posix/os-edid.cpp @@ -30,7 +30,8 @@ * http://www.pulse-eight.net/ */ -#include "../util/edid.h" +#include "env.h" +#include "lib/platform/util/edid.h" using namespace PLATFORM; diff --git a/src/lib/platform/posix/os-socket.h b/src/lib/platform/posix/os-socket.h index 036be3f..7539aab 100644 --- a/src/lib/platform/posix/os-socket.h +++ b/src/lib/platform/posix/os-socket.h @@ -32,8 +32,8 @@ */ -#include "../os.h" -#include "../util/timeutils.h" +#include "lib/platform/os.h" +#include "lib/platform/util/timeutils.h" #include #include #include diff --git a/src/lib/platform/posix/serialport.cpp b/src/lib/platform/posix/serialport.cpp index 3764a15..c1b3b22 100644 --- a/src/lib/platform/posix/serialport.cpp +++ b/src/lib/platform/posix/serialport.cpp @@ -30,12 +30,12 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" +#include "env.h" #include #include -#include "../sockets/serialport.h" -#include "../util/baudrate.h" -#include "../posix/os-socket.h" +#include "lib/platform/sockets/serialport.h" +#include "lib/platform/util/baudrate.h" +#include "lib/platform/posix/os-socket.h" #if defined(__APPLE__) || defined(__FreeBSD__) #ifndef XCASE @@ -58,6 +58,9 @@ inline bool RemoveLock(const char *strDeviceName) { #if !defined(__APPLE__) && !defined(__FreeBSD__) return dev_unlock(strDeviceName, 0) == 0; + #else + void *tmp = (void*)strDeviceName; // silence unused warning + return true; #endif } diff --git a/src/lib/platform/posix/serversocket.cpp b/src/lib/platform/posix/serversocket.cpp index dce13d3..30d80ee 100644 --- a/src/lib/platform/posix/serversocket.cpp +++ b/src/lib/platform/posix/serversocket.cpp @@ -30,9 +30,9 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" -#include "../sockets/tcp.h" -#include "../sockets/serversocket.h" +#include "env.h" +#include "lib/platform/sockets/tcp.h" +#include "lib/platform/sockets/serversocket.h" using namespace std; using namespace PLATFORM; @@ -103,10 +103,10 @@ bool CTcpServerSocket::IsOpen(void) return m_socket != INVALID_SOCKET_VALUE; } -CStdString CTcpServerSocket::GetError(void) +std::string CTcpServerSocket::GetError(void) { - CStdString strError; - strError = m_strError.IsEmpty() && m_iError != 0 ? strerror(m_iError) : m_strError; + std::string strError; + strError = m_strError.empty() && m_iError != 0 ? strerror(m_iError) : m_strError; return strError; } @@ -115,9 +115,9 @@ int CTcpServerSocket::GetErrorNumber(void) return m_iError; } -CStdString CTcpServerSocket::GetName(void) +std::string CTcpServerSocket::GetName(void) { - CStdString strName("localhost"); + std::string strName("localhost"); return strName; } diff --git a/src/lib/platform/sockets/serialport.h b/src/lib/platform/sockets/serialport.h index eed05a0..cb78b37 100644 --- a/src/lib/platform/sockets/serialport.h +++ b/src/lib/platform/sockets/serialport.h @@ -31,8 +31,8 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" -#include "../util/buffer.h" +#include "lib/platform/os.h" +#include "lib/platform/util/buffer.h" #include #include @@ -69,7 +69,7 @@ namespace PLATFORM class CSerialSocket : public CCommonSocket { public: - CSerialSocket(const CStdString &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : + CSerialSocket(const std::string &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : CCommonSocket(INVALID_SERIAL_SOCKET_VALUE, strName), #ifdef __WINDOWS__ m_iCurrentReadTimeout(MAXDWORD), @@ -114,7 +114,7 @@ namespace PLATFORM class CSerialPort : public CProtectedSocket { public: - CSerialPort(const CStdString &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : + CSerialPort(const std::string &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : CProtectedSocket (new CSerialSocket(strName, iBaudrate, iDatabits, iStopbits, iParity)) {} virtual ~CSerialPort(void) {} }; diff --git a/src/lib/platform/sockets/serversocket.h b/src/lib/platform/sockets/serversocket.h index edc7fcd..0aa51eb 100644 --- a/src/lib/platform/sockets/serversocket.h +++ b/src/lib/platform/sockets/serversocket.h @@ -50,9 +50,9 @@ namespace PLATFORM virtual bool IsOpen(void) = 0; ssize_t Write(void* data, size_t len) { (void) data; (void) len; return EINVAL; } ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) { (void) data; (void) len; (void) iTimeoutMs; return EINVAL; } - virtual CStdString GetError(void) = 0; + virtual std::string GetError(void) = 0; virtual int GetErrorNumber(void) = 0; - virtual CStdString GetName(void) = 0; + virtual std::string GetName(void) = 0; virtual ISocket* Accept(void) = 0; }; @@ -72,9 +72,9 @@ namespace PLATFORM virtual void Close(void); virtual void Shutdown(void); virtual bool IsOpen(void); - virtual CStdString GetError(void); + virtual std::string GetError(void); virtual int GetErrorNumber(void); - virtual CStdString GetName(void); + virtual std::string GetName(void); virtual ISocket* Accept(void); @@ -84,7 +84,7 @@ namespace PLATFORM protected: uint16_t m_iPort; tcp_socket_t m_socket; - CStdString m_strError; + std::string m_strError; int m_iError; }; } diff --git a/src/lib/platform/sockets/socket.h b/src/lib/platform/sockets/socket.h index f56d515..e894172 100644 --- a/src/lib/platform/sockets/socket.h +++ b/src/lib/platform/sockets/socket.h @@ -31,15 +31,16 @@ * http://www.pulse-eight.net/ */ -#include "../threads/mutex.h" -#include "../util/StdString.h" +#include "lib/platform/threads/mutex.h" #if defined(__WINDOWS__) -#include "../windows/os-socket.h" +#include "lib/platform/windows/os-socket.h" #else -#include "../posix/os-socket.h" +#include "lib/platform/posix/os-socket.h" #endif +#include + // Common socket operations namespace PLATFORM @@ -56,26 +57,26 @@ namespace PLATFORM virtual bool IsOpen(void) = 0; virtual ssize_t Write(void* data, size_t len) = 0; virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) = 0; - virtual CStdString GetError(void) = 0; + virtual std::string GetError(void) = 0; virtual int GetErrorNumber(void) = 0; - virtual CStdString GetName(void) = 0; + virtual std::string GetName(void) = 0; }; template class CCommonSocket : public ISocket { public: - CCommonSocket(_SType initialSocketValue, const CStdString &strName) : + CCommonSocket(_SType initialSocketValue, const std::string &strName) : m_socket(initialSocketValue), m_strName(strName), m_iError(0) {} virtual ~CCommonSocket(void) {} - virtual CStdString GetError(void) + virtual std::string GetError(void) { - CStdString strError; - strError = m_strError.IsEmpty() && m_iError != 0 ? strerror(m_iError) : m_strError; + std::string strError; + strError = m_strError.empty() && m_iError != 0 ? strerror(m_iError) : m_strError; return strError; } @@ -84,17 +85,17 @@ namespace PLATFORM return m_iError; } - virtual CStdString GetName(void) + virtual std::string GetName(void) { - CStdString strName; + std::string strName; strName = m_strName; return strName; } protected: _SType m_socket; - CStdString m_strError; - CStdString m_strName; + std::string m_strError; + std::string m_strName; int m_iError; CMutex m_mutex; }; @@ -182,9 +183,9 @@ namespace PLATFORM return iReturn; } - virtual CStdString GetError(void) + virtual std::string GetError(void) { - CStdString strError; + std::string strError; CLockObject lock(m_mutex); strError = m_socket ? m_socket->GetError() : ""; return strError; @@ -196,9 +197,9 @@ namespace PLATFORM return m_socket ? m_socket->GetErrorNumber() : -EINVAL; } - virtual CStdString GetName(void) + virtual std::string GetName(void) { - CStdString strName; + std::string strName; CLockObject lock(m_mutex); strName = m_socket ? m_socket->GetName() : ""; return strName; diff --git a/src/lib/platform/sockets/tcp.h b/src/lib/platform/sockets/tcp.h index 1693354..1dad499 100644 --- a/src/lib/platform/sockets/tcp.h +++ b/src/lib/platform/sockets/tcp.h @@ -40,7 +40,7 @@ namespace PLATFORM class CTcpSocket : public CCommonSocket { public: - CTcpSocket(const CStdString &strHostname, uint16_t iPort) : + CTcpSocket(const std::string &strHostname, uint16_t iPort) : CCommonSocket(INVALID_SOCKET_VALUE, strHostname), m_iPort(iPort) {} @@ -165,7 +165,7 @@ namespace PLATFORM class CTcpConnection : public CProtectedSocket { public: - CTcpConnection(const CStdString &strHostname, uint16_t iPort) : + CTcpConnection(const std::string &strHostname, uint16_t iPort) : CProtectedSocket (new CTcpSocket(strHostname, iPort)) {} virtual ~CTcpConnection(void) {} }; diff --git a/src/lib/platform/threads/mutex.h b/src/lib/platform/threads/mutex.h index 6fc57d1..00953db 100644 --- a/src/lib/platform/threads/mutex.h +++ b/src/lib/platform/threads/mutex.h @@ -31,15 +31,15 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" +#include "lib/platform/os.h" #if defined(__WINDOWS__) -#include "../windows/os-threads.h" +#include "lib/platform/windows/os-threads.h" #else -#include "../posix/os-threads.h" +#include "lib/platform/posix/os-threads.h" #endif -#include "../util/timeutils.h" +#include "lib/platform/util/timeutils.h" namespace PLATFORM { diff --git a/src/lib/platform/util/StdString.h b/src/lib/platform/util/StdString.h index 496dae7..63b3bf1 100644 --- a/src/lib/platform/util/StdString.h +++ b/src/lib/platform/util/StdString.h @@ -1,5 +1,5 @@ #pragma once -#include "../os.h" +#include "lib/platform/os.h" #include #include #include diff --git a/src/lib/platform/util/buffer.h b/src/lib/platform/util/buffer.h index aa658ee..4b57a29 100644 --- a/src/lib/platform/util/buffer.h +++ b/src/lib/platform/util/buffer.h @@ -31,7 +31,7 @@ * http://www.pulse-eight.net/ */ -#include "../threads/mutex.h" +#include "lib/platform/threads/mutex.h" #include namespace PLATFORM diff --git a/src/lib/platform/util/edid.h b/src/lib/platform/util/edid.h index 1db4f99..148728e 100644 --- a/src/lib/platform/util/edid.h +++ b/src/lib/platform/util/edid.h @@ -31,7 +31,7 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" +#include "lib/platform/os.h" #include "StdString.h" namespace PLATFORM diff --git a/src/lib/platform/util/timeutils.h b/src/lib/platform/util/timeutils.h index 5f2d27a..e95c10d 100644 --- a/src/lib/platform/util/timeutils.h +++ b/src/lib/platform/util/timeutils.h @@ -31,7 +31,8 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" +#include "env.h" +#include "lib/platform/os.h" #if defined(__APPLE__) #include @@ -39,6 +40,7 @@ #elif defined(__WINDOWS__) #include #else +#include #include #endif diff --git a/src/lib/platform/windows/dlfcn-win32.cpp b/src/lib/platform/windows/dlfcn-win32.cpp index 5839921..38bafd8 100644 --- a/src/lib/platform/windows/dlfcn-win32.cpp +++ b/src/lib/platform/windows/dlfcn-win32.cpp @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "env.h" #include #include diff --git a/src/lib/platform/windows/os-edid.cpp b/src/lib/platform/windows/os-edid.cpp index 2678392..d956ee8 100644 --- a/src/lib/platform/windows/os-edid.cpp +++ b/src/lib/platform/windows/os-edid.cpp @@ -30,7 +30,8 @@ * http://www.pulse-eight.net/ */ -#include "../util/edid.h" +#include "env.h" +#include "lib/platform/util/edid.h" #include "windows.h" #include "setupapi.h" diff --git a/src/lib/platform/windows/os-socket.h b/src/lib/platform/windows/os-socket.h index 5174cba..0c38555 100644 --- a/src/lib/platform/windows/os-socket.h +++ b/src/lib/platform/windows/os-socket.h @@ -31,8 +31,8 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" -#include "../util/timeutils.h" +#include "lib/platform/os.h" +#include "lib/platform/util/timeutils.h" #include #include @@ -181,7 +181,9 @@ namespace PLATFORM tv.tv_usec = 1000 * (long)(iTimeoutMs % 1000); FD_ZERO(&fd_read); + #pragma warning(disable:4127) /* disable 'conditional expression is constant' */ FD_SET(socket, &fd_read); + #pragma warning(default:4127) if (select((int)socket + 1, &fd_read, NULL, NULL, &tv) == 0) { @@ -270,8 +272,10 @@ namespace PLATFORM FD_ZERO(&fd_write); FD_ZERO(&fd_except); + #pragma warning(disable:4127) /* disable 'conditional expression is constant' */ FD_SET(socket, &fd_write); FD_SET(socket, &fd_except); + #pragma warning(default:4127) int iPollResult = select(sizeof(socket)*8, NULL, &fd_write, &fd_except, &tv); if (iPollResult == 0) diff --git a/src/lib/platform/windows/os-threads.cpp b/src/lib/platform/windows/os-threads.cpp index 7c06d41..6a06dd2 100644 --- a/src/lib/platform/windows/os-threads.cpp +++ b/src/lib/platform/windows/os-threads.cpp @@ -30,7 +30,7 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" +#include "env.h" #include "os-threads.h" using namespace PLATFORM; diff --git a/src/lib/platform/windows/os-threads.h b/src/lib/platform/windows/os-threads.h index 47101dc..091e962 100644 --- a/src/lib/platform/windows/os-threads.h +++ b/src/lib/platform/windows/os-threads.h @@ -31,6 +31,8 @@ * http://www.pulse-eight.net/ */ +#include + namespace PLATFORM { #define thread_t HANDLE diff --git a/src/lib/platform/windows/os-types.h b/src/lib/platform/windows/os-types.h index 9b0dca0..2fc6269 100644 --- a/src/lib/platform/windows/os-types.h +++ b/src/lib/platform/windows/os-types.h @@ -49,7 +49,6 @@ #include #include #include -#include typedef SOCKET tcp_socket_t; #define INVALID_SOCKET_VALUE INVALID_SOCKET diff --git a/src/lib/platform/windows/serialport.cpp b/src/lib/platform/windows/serialport.cpp index 96e743f..ad7f871 100644 --- a/src/lib/platform/windows/serialport.cpp +++ b/src/lib/platform/windows/serialport.cpp @@ -30,14 +30,15 @@ * http://www.pulse-eight.net/ */ -#include "../sockets/serialport.h" -#include "../util/baudrate.h" -#include "../util/timeutils.h" +#include "env.h" +#include "lib/platform/sockets/serialport.h" +#include "lib/platform/util/baudrate.h" +#include "lib/platform/util/timeutils.h" using namespace std; using namespace PLATFORM; -void FormatWindowsError(int iErrorCode, CStdString &strMessage) +void FormatWindowsError(int iErrorCode, std::string &strMessage) { if (iErrorCode != ERROR_SUCCESS) { @@ -119,7 +120,7 @@ bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) if (IsOpen()) return false; - CStdString strComPath = "\\\\.\\" + m_strName; + std::string strComPath = "\\\\.\\" + m_strName; CLockObject lock(m_mutex); m_socket = CreateFile(strComPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (m_socket == INVALID_HANDLE_VALUE) diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index fe3f893..97bdcc6 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -30,7 +30,8 @@ * http://www.pulse-eight.net/ */ -#include "../../include/cec.h" +#include "../env.h" +#include "../include/cec.h" #include #include @@ -40,12 +41,13 @@ #include #include "../lib/platform/os.h" #include "../lib/implementations/CECCommandHandler.h" +#include "../lib/platform/util/StdString.h" using namespace CEC; using namespace std; using namespace PLATFORM; -#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_1_7_1; +#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_1_8_0; #include @@ -221,7 +223,7 @@ void ListDevices(ICECAdapter *parser) { time_t buildTime = (time_t)config.iFirmwareBuildDate; strDeviceInfo.AppendFormat("firmware build date: %s", asctime(gmtime(&buildTime))); - strDeviceInfo = strDeviceInfo.Left((int)strDeviceInfo.length() - 1); // strip \n added by asctime + strDeviceInfo = strDeviceInfo.Left(strDeviceInfo.length() > 1 ? (unsigned)(strDeviceInfo.length() - 1) : 0); // strip \n added by asctime strDeviceInfo.append(" +0000"); } } @@ -253,6 +255,7 @@ void ShowHelpCommandLine(const char* strExec) " on devices on startup and power them off on exit." << endl << " -o --osd-name {osd name} Use a custom osd name." << endl << " -m --monitor Start a monitor-only client." << endl << + " -i --info Shows information about how libCEC was compiled." << endl << " [COM PORT] The com port to connect to. If no COM" << endl << " port is given, the client tries to connect to the" << endl << " first device that is detected." << endl << @@ -1007,6 +1010,24 @@ bool ProcessCommandLineArguments(int argc, char *argv[]) } ++iArgPtr; } + else if (!strcmp(argv[iArgPtr], "--info") || + !strcmp(argv[iArgPtr], "-i")) + { + if (g_cecLogLevel == -1) + g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR; + ICECAdapter *parser = LibCecInitialise(&g_config); + if (parser) + { + CStdString strMessage; + strMessage.Format("libCEC version: %s", parser->ToString((cec_server_version)g_config.serverVersion)); + if (g_config.serverVersion >= CEC_SERVER_VERSION_1_7_2) + strMessage.AppendFormat(", %s", parser->GetLibInfo()); + PrintToStdOut(strMessage.c_str()); + UnloadLibCec(parser); + parser = NULL; + } + bReturn = false; + } else if (!strcmp(argv[iArgPtr], "--list-devices") || !strcmp(argv[iArgPtr], "-l")) { @@ -1144,6 +1165,9 @@ int main (int argc, char *argv[]) return 1; } + // init video on targets that need this + parser->InitVideoStandalone(); + if (!g_bSingleCommand) { CStdString strLog;