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
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 ===
===============================================================================
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
[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"])
+
+## 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"])
+
+## 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"
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")
+
+ ## 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])
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+#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*)
AC_CHECK_HEADER(mach/mach_time.h,,AC_MSG_ERROR($msg_required_header_missing))
features="$features\n Pulse-Eight CEC Adapter detection :\tno"
fi
+## 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))
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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
+
--- /dev/null
+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"
+}
+
--- /dev/null
+#!/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
+
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@
#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;
m_lib->AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with support for the Pulse-Eight USB-CEC Adapter");
#endif
-#if !defined(HAVE_P8_USB)
+#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
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_P8_USB)
+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB)
return NULL;
#endif
}
void CAdapterFactory::InitVideoStandalone(void)
{
+#if defined(HAVE_RPI_API)
+ CRPiCECAdapterCommunication::InitHost();
+#endif
}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_RPI_API)
+#include "RPiCECAdapterCommunication.h"
+
+extern "C" {
+#include <bcm_host.h>
+}
+
+#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<CRPiCECAdapterCommunication *>(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
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#if defined(HAVE_RPI_API)
+
+#include "lib/adapter/AdapterCommunication.h"
+#include "lib/platform/threads/mutex.h"
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+}
+
+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<bool> m_logicalAddressCondition;
+ PLATFORM::CMutex m_mutex;
+ VCHI_INSTANCE_T m_vchi_instance;
+ VCHI_CONNECTION_T * m_vchi_connection;
+ };
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_RPI_API)
+#include "RPiCECAdapterDetection.h"
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+}
+
+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
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+namespace CEC
+{
+ class CRPiCECAdapterDetection
+ {
+ public:
+ static bool FindAdapter(void);
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "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 <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq.h>
+}
+
+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<uint64_t, CRPiCECAdapterMessageQueueEntry *>::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
+
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "lib/platform/util/buffer.h"
+#include <map>
+
+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<bool> 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<uint64_t, CRPiCECAdapterMessageQueueEntry *> m_messages; /**< the outgoing message queue */
+ uint64_t m_iNextMessage; /**< the index of the next message */
+ };
+};