From e9de9629478f63b357b69314d7935c6539c3ad71 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Thu, 27 Oct 2011 00:59:40 +0200 Subject: [PATCH] cec: refactor CEC command handling. split up standard and non-standard CEC implementations. --- configure.ac | 2 +- include/cecloader.h | 4 +- src/lib/ANCommandHandler.cpp | 108 +++++++++++++++ src/lib/ANCommandHandler.h | 49 +++++++ src/lib/CECBusDevice.cpp | 112 +++++++++++++++ src/lib/CECBusDevice.h | 72 ++++++++++ src/lib/CECCommandHandler.cpp | 250 +++++++++++++++++++++++++++++++++ src/lib/CECCommandHandler.h | 67 +++++++++ src/lib/CECProcessor.cpp | 251 +++------------------------------- src/lib/CECProcessor.h | 19 +-- src/lib/LibCEC.cpp | 2 +- src/lib/LibCEC.h | 2 +- src/lib/Makefile.am | 8 ++ src/lib/SLCommandHandler.cpp | 41 ++++++ src/lib/SLCommandHandler.h | 44 ++++++ 15 files changed, 788 insertions(+), 243 deletions(-) create mode 100644 src/lib/ANCommandHandler.cpp create mode 100644 src/lib/ANCommandHandler.h create mode 100644 src/lib/CECBusDevice.cpp create mode 100644 src/lib/CECBusDevice.h create mode 100644 src/lib/CECCommandHandler.cpp create mode 100644 src/lib/CECCommandHandler.h create mode 100644 src/lib/SLCommandHandler.cpp create mode 100644 src/lib/SLCommandHandler.h diff --git a/configure.ac b/configure.ac index fd1eb01..b350c82 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([libcec], 0:7:0) +AC_INIT([libcec], 0:8:0) AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) AC_PROG_CXX diff --git a/include/cecloader.h b/include/cecloader.h index 7ae8b49..242d4fe 100644 --- a/include/cecloader.h +++ b/include/cecloader.h @@ -84,9 +84,9 @@ CEC::ICECAdapter *LoadLibCec(const char *strName, CEC::cec_logical_address iLogi if (!g_libCEC) { #if defined(__APPLE__) - cout << "cannot find " << (strLib ? strLib : "libcec.dylib") << endl; + cout << "cannot find " << (strLib ? strLib : "libcec.dylib") << dlerror() << endl; #else - cout << "cannot find " << (strLib ? strLib : "libcec.so") << endl; + cout << "cannot find " << (strLib ? strLib : "libcec.so") << dlerror() << endl; #endif return NULL; } diff --git a/src/lib/ANCommandHandler.cpp b/src/lib/ANCommandHandler.cpp new file mode 100644 index 0000000..575c4c3 --- /dev/null +++ b/src/lib/ANCommandHandler.cpp @@ -0,0 +1,108 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "ANCommandHandler.h" +#include "CECBusDevice.h" +#include "CECProcessor.h" +#include "util/StdString.h" + +using namespace CEC; + +CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) : + CCECCommandHandler(busDevice) +{ +} + +bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command) +{ + if (command.parameters.size > 0) + { + m_busDevice->GetProcessor()->AddKey(); + + uint8_t iButton = 0; + switch (command.parameters[0]) + { + case CEC_AN_USER_CONTROL_CODE_RETURN: + iButton = CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL; + break; + default: + break; + } + + if (iButton > 0 && iButton <= CEC_USER_CONTROL_CODE_MAX) + { + CStdString strLog; + strLog.Format("key pressed: %1x", iButton); + m_busDevice->AddLog(CEC_LOG_DEBUG, strLog); + + m_busDevice->GetProcessor()->SetCurrentButton((cec_user_control_code) command.parameters[0]); + } + } + + return true; +} + +bool CANCommandHandler::HandleCommand(const cec_command &command) +{ + bool bHandled(true); + if (command.destination == m_busDevice->GetMyLogicalAddress()) + { + switch(command.opcode) + { + case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN: + HandleVendorRemoteButtonDown(command); + break; + case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP: + HandleUserControlRelease(command); + break; + default: + bHandled = false; + break; + } + } + else if (command.destination == CECDEVICE_BROADCAST) + { + switch(command.opcode) + { + // TODO + default: + bHandled = false; + break; + } + } + + if (!bHandled) + bHandled = CCECCommandHandler::HandleCommand(command); + + return bHandled; +} diff --git a/src/lib/ANCommandHandler.h b/src/lib/ANCommandHandler.h new file mode 100644 index 0000000..d1729aa --- /dev/null +++ b/src/lib/ANCommandHandler.h @@ -0,0 +1,49 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "CECCommandHandler.h" + +namespace CEC +{ + class CANCommandHandler : public CCECCommandHandler + { + public: + CANCommandHandler(CCECBusDevice *busDevice); + virtual ~CANCommandHandler(void) {}; + + virtual bool HandleCommand(const cec_command &command); + + protected: + virtual bool HandleVendorRemoteButtonDown(const cec_command &command); + }; +}; diff --git a/src/lib/CECBusDevice.cpp b/src/lib/CECBusDevice.cpp new file mode 100644 index 0000000..bcd73cf --- /dev/null +++ b/src/lib/CECBusDevice.cpp @@ -0,0 +1,112 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "CECBusDevice.h" +#include "CECProcessor.h" +#include "ANCommandHandler.h" +#include "SLCommandHandler.h" + +using namespace CEC; + +CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress) : + m_iPhysicalAddress(iPhysicalAddress), + m_iLogicalAddress(iLogicalAddress), + m_processor(processor), + m_iVendorId(0), + m_iVendorClass(0) +{ + m_handler = new CCECCommandHandler(this); +} + +CCECBusDevice::~CCECBusDevice(void) +{ + delete m_handler; +} + +cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const +{ + return m_processor->GetLogicalAddress(); +} + +uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const +{ + return m_processor->GetPhysicalAddress(); +} + +void CCECBusDevice::AddLog(cec_log_level level, const CStdString &strMessage) +{ + m_processor->AddLog(level, strMessage); +} + +void CCECBusDevice::SetVendorId(uint16_t iVendorId, uint8_t iVendorClass /* = 0 */) +{ + delete m_handler; + m_iVendorId = iVendorId; + m_iVendorClass = iVendorClass; + + switch (iVendorId) + { + case CEC_VENDOR_SAMSUNG: + m_handler = new CANCommandHandler(this); + break; + case CEC_VENDOR_LG: + m_handler = new CSLCommandHandler(this); + break; + default: + m_handler = new CCECCommandHandler(this); + break; + } + + CStdString strLog; + strLog.Format("device %d: vendor = %s (%04x) class = %2x", m_iLogicalAddress, CECVendorIdToString(iVendorId), iVendorId, iVendorClass); + m_processor->AddLog(CEC_LOG_DEBUG, strLog.c_str()); +} + +bool CCECBusDevice::HandleCommand(const cec_command &command) +{ + CLockObject lock(&m_mutex); + m_handler->HandleCommand(command); + return true; +} + +const char *CCECBusDevice::CECVendorIdToString(const uint64_t iVendorId) +{ + switch (iVendorId) + { + case CEC_VENDOR_SAMSUNG: + return "Samsung"; + case CEC_VENDOR_LG: + return "LG"; + default: + return "Unknown"; + } +} diff --git a/src/lib/CECBusDevice.h b/src/lib/CECBusDevice.h new file mode 100644 index 0000000..b7ae7e9 --- /dev/null +++ b/src/lib/CECBusDevice.h @@ -0,0 +1,72 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "CECCommandHandler.h" +#include "platform/threads.h" +#include "util/StdString.h" + +namespace CEC +{ + class CCECProcessor; + + class CCECBusDevice + { + public: + CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0); + virtual ~CCECBusDevice(void); + + virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; } + virtual uint16_t GetPhysicalAddress(void) const { return m_iPhysicalAddress; } + + virtual cec_logical_address GetMyLogicalAddress(void) const; + virtual uint16_t GetMyPhysicalAddress(void) const; + + virtual void SetVendorId(uint16_t iVendorId, uint8_t iVendorClass = 0); + virtual bool HandleCommand(const cec_command &command); + + virtual void AddLog(cec_log_level level, const CStdString &strMessage); + virtual CCECProcessor *GetProcessor() const { return m_processor; } + virtual CCECCommandHandler *GetHandler(void) const { return m_handler; }; + + static const char *CECVendorIdToString(const uint64_t iVendorId); + + protected: + uint16_t m_iPhysicalAddress; + cec_logical_address m_iLogicalAddress; + CCECProcessor *m_processor; + CCECCommandHandler *m_handler; + uint64_t m_iVendorId; + uint8_t m_iVendorClass; + CMutex m_mutex; + }; +}; diff --git a/src/lib/CECCommandHandler.cpp b/src/lib/CECCommandHandler.cpp new file mode 100644 index 0000000..314313d --- /dev/null +++ b/src/lib/CECCommandHandler.cpp @@ -0,0 +1,250 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "CECCommandHandler.h" +#include "CECBusDevice.h" +#include "CECProcessor.h" + +using namespace CEC; + +CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) +{ + m_busDevice = busDevice; +} + +bool CCECCommandHandler::HandleCommand(const cec_command &command) +{ + bool bHandled(true); + + if (command.destination == m_busDevice->GetMyLogicalAddress()) + { + switch(command.opcode) + { + case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS: + HandleGivePhysicalAddress(command); + break; + case CEC_OPCODE_GIVE_OSD_NAME: + HandleGiveOSDName(command); + break; + case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID: + HandleGiveDeviceVendorId(command); + break; + case CEC_OPCODE_DEVICE_VENDOR_ID: + HandleDeviceVendorId(command); + break; + case CEC_OPCODE_VENDOR_COMMAND_WITH_ID: + HandleDeviceVendorCommandWithId(command); + break; + case CEC_OPCODE_GIVE_DECK_STATUS: + HandleGiveDeckStatus(command); + break; + case CEC_OPCODE_MENU_REQUEST: + HandleMenuRequest(command); + break; + case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS: + HandleGiveDevicePowerStatus(command); + break; + case CEC_OPCODE_GET_CEC_VERSION: + HandleGetCecVersion(command); + break; + case CEC_OPCODE_USER_CONTROL_PRESSED: + HandleUserControlPressed(command); + break; + case CEC_OPCODE_USER_CONTROL_RELEASE: + HandleUserControlRelease(command); + break; + default: + UnhandledCommand(command); + bHandled = false; + break; + } + } + else if (command.destination == CECDEVICE_BROADCAST) + { + CStdString strLog; + switch (command.opcode) + { + case CEC_OPCODE_REQUEST_ACTIVE_SOURCE: + HandleRequestActiveSource(command); + break; + case CEC_OPCODE_SET_STREAM_PATH: + HandleSetStreamPath(command); + break; + case CEC_OPCODE_ROUTING_CHANGE: + HandleRoutingChange(command); + break; + case CEC_OPCODE_DEVICE_VENDOR_ID: + HandleDeviceVendorId(command); + break; + case CEC_OPCODE_VENDOR_COMMAND_WITH_ID: + HandleDeviceVendorCommandWithId(command); + break; + default: + UnhandledCommand(command); + bHandled = false; + break; + } + } + else + { + CStdString strLog; + strLog.Format("ignoring frame: destination: %u != %u", command.destination, (uint8_t)m_busDevice->GetMyLogicalAddress()); + m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + bHandled = false; + } + + return bHandled; +} + +bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command) +{ + m_busDevice->GetProcessor()->ParseVendorId(command.initiator, command.parameters); + return true; +} + +bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command) +{ + m_busDevice->GetProcessor()->ParseVendorId(command.initiator, command.parameters); + return true; +} + +bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command) +{ + m_busDevice->GetProcessor()->ReportCECVersion(command.initiator); + return true; +} + +bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command) +{ + // need to support opcodes play and deck control before doing anything with this + m_busDevice->GetProcessor()->TransmitAbort(command.initiator, CEC_OPCODE_GIVE_DECK_STATUS); + return true; +} + +bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) +{ + m_busDevice->GetProcessor()->ReportPowerState(command.initiator); + return true; +} + +bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command) +{ + m_busDevice->GetProcessor()->ReportVendorID(command.initiator); + return true; +} + +bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command) +{ + m_busDevice->GetProcessor()->ReportOSDName(command.initiator); + return true; +} + +bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command) +{ + m_busDevice->GetProcessor()->ReportPhysicalAddress(); + return true; +} + +bool CCECCommandHandler::HandleMenuRequest(const cec_command &command) +{ + if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY) + m_busDevice->GetProcessor()->ReportMenuState(command.initiator); + return true; +} + +bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command) +{ + CStdString strLog; + strLog.Format(">> %i requests active source", (uint8_t) command.initiator); + m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + m_busDevice->GetProcessor()->BroadcastActiveSource(); + return true; +} + +bool CCECCommandHandler::HandleRoutingChange(const cec_command &command) +{ + if (command.parameters.size == 4) + { + uint16_t iOldAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); + uint16_t iNewAddress = ((uint16_t)command.parameters[2] << 8) | ((uint16_t)command.parameters[3]); + CStdString strLog; + strLog.Format(">> %i changed physical address from %04x to %04x", command.initiator, iOldAddress, iNewAddress); + m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + + m_busDevice->GetProcessor()->AddCommand(command); + } + return true; +} + +bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command) +{ + if (command.parameters.size >= 2) + { + int streamaddr = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); + CStdString strLog; + strLog.Format(">> %i requests stream path from physical address %04x", command.initiator, streamaddr); + m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + if (streamaddr == m_busDevice->GetMyPhysicalAddress()) + m_busDevice->GetProcessor()->BroadcastActiveSource(); + } + return true; +} + +bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command) +{ + if (command.parameters.size > 0) + { + m_busDevice->GetProcessor()->AddKey(); + + if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX) + { + CStdString strLog; + strLog.Format("key pressed: %1x", command.parameters[0]); + m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + + m_busDevice->GetProcessor()->SetCurrentButton((cec_user_control_code) command.parameters[0]); + } + } + return true; +} + +bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command) +{ + m_busDevice->GetProcessor()->AddKey(); + return true; +} + +void CCECCommandHandler::UnhandledCommand(const cec_command &command) +{ + m_busDevice->GetProcessor()->AddCommand(command);; +} diff --git a/src/lib/CECCommandHandler.h b/src/lib/CECCommandHandler.h new file mode 100644 index 0000000..7129b40 --- /dev/null +++ b/src/lib/CECCommandHandler.h @@ -0,0 +1,67 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 + +namespace CEC +{ + class CCECBusDevice; + + class CCECCommandHandler + { + public: + CCECCommandHandler(CCECBusDevice *busDevice); + virtual ~CCECCommandHandler(void) {}; + + virtual bool HandleCommand(const cec_command &command); + + protected: + bool HandleDeviceVendorCommandWithId(const cec_command &command); + bool HandleDeviceVendorId(const cec_command &command); + bool HandleGetCecVersion(const cec_command &command); + bool HandleGiveDeckStatus(const cec_command &command); + bool HandleGiveDevicePowerStatus(const cec_command &command); + bool HandleGiveDeviceVendorId(const cec_command &command); + bool HandleGiveOSDName(const cec_command &command); + bool HandleGivePhysicalAddress(const cec_command &command); + bool HandleMenuRequest(const cec_command &command); + bool HandleRequestActiveSource(const cec_command &command); + bool HandleRoutingChange(const cec_command &command); + bool HandleSetStreamPath(const cec_command &command); + bool HandleUserControlPressed(const cec_command &command); + bool HandleUserControlRelease(const cec_command &command); + void UnhandledCommand(const cec_command &command); + + CCECBusDevice *m_busDevice; + }; +}; diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index e324899..eae4c3c 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -33,6 +33,7 @@ #include "CECProcessor.h" #include "AdapterCommunication.h" +#include "CECBusDevice.h" #include "LibCEC.h" #include "util/StdString.h" #include "platform/timeutils.h" @@ -48,10 +49,8 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm m_controller(controller), m_bMonitor(false) { - for (uint8_t iPtr = 0; iPtr < 16; iPtr++) - m_vendorIds[iPtr] = CEC_VENDOR_UNKNOWN; - for (uint8_t iPtr = 0; iPtr < 16; iPtr++) - m_vendorClasses[iPtr] = (uint8_t) 0; + for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0); } CCECProcessor::~CCECProcessor(void) @@ -59,6 +58,7 @@ CCECProcessor::~CCECProcessor(void) StopThread(); m_communication = NULL; m_controller = NULL; + delete[] m_busDevices; } bool CCECProcessor::Start(void) @@ -533,246 +533,37 @@ void CCECProcessor::ParseVendorId(cec_logical_address device, const cec_datapack ((uint64_t)data[1] << 2) + (uint64_t)data[2]; - m_vendorIds[(uint8_t)device] = iVendorId; - m_vendorClasses[(uint8_t)device] = data.size >= 4 ? data[3] : 0; - - CStdString strLog; - strLog.Format("device %d: vendor = %s (%04x) class = %2x", (uint8_t)device, CECVendorIdToString(m_vendorIds[(uint8_t)device]), iVendorId, m_vendorClasses[(uint8_t)device]); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); + m_busDevices[(uint8_t)device]->SetVendorId(iVendorId, data.size >= 4 ? data[3] : 0); } -bool CCECProcessor::HandleANCommand(cec_command &command) +void CCECProcessor::ParseCommand(cec_command &command) { - bool bHandled(true); - if (command.destination == m_iLogicalAddress) - { - switch(command.opcode) - { - case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN: - if (command.parameters.size > 0) - { - m_controller->AddKey(); - - uint8_t iButton = 0; - switch (command.parameters[0]) - { - case CEC_AN_USER_CONTROL_CODE_RETURN: - iButton = CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL; - break; - default: - break; - } - - if (iButton > 0 && iButton <= CEC_USER_CONTROL_CODE_MAX) - { - CStdString strLog; - strLog.Format("key pressed: %1x", iButton); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - - m_controller->SetCurrentButton((cec_user_control_code) command.parameters[0]); - } - } - break; - case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP: - m_controller->AddKey(); - break; - default: - bHandled = false; - break; - } - } - else if (command.destination == CECDEVICE_BROADCAST) - { - switch(command.opcode) - { - // TODO - default: - bHandled = false; - break; - } - } - - if (!bHandled) - bHandled = HandleCecCommand(command); + CStdString dataStr; + dataStr.Format(">> received frame: %1x%1x:%02x", command.initiator, command.destination, command.opcode); + for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) + dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]); + m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str()); - return bHandled; + if (!m_bMonitor) + m_busDevices[(uint8_t)command.initiator]->HandleCommand(command); } -bool CCECProcessor::HandleSLCommand(cec_command &command) +void CCECProcessor::SetCurrentButton(cec_user_control_code iButtonCode) { - bool bHandled(true); - if (command.destination == m_iLogicalAddress) - { - switch(command.opcode) - { - // TODO - default: - bHandled = false; - break; - } - } - else if (command.destination == CECDEVICE_BROADCAST) - { - switch(command.opcode) - { - // TODO - default: - bHandled = false; - break; - } - } - - if (!bHandled) - bHandled = HandleCecCommand(command); - - return bHandled; + m_controller->SetCurrentButton(iButtonCode); } -bool CCECProcessor::HandleCecCommand(cec_command &command) +void CCECProcessor::AddCommand(const cec_command &command) { - bool bHandled(true); - - if (command.destination == m_iLogicalAddress) - { - switch(command.opcode) - { - case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS: - ReportPhysicalAddress(); - break; - case CEC_OPCODE_GIVE_OSD_NAME: - ReportOSDName(command.initiator); - break; - case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID: - ReportVendorID(command.initiator); - break; - case CEC_OPCODE_DEVICE_VENDOR_ID: - case CEC_OPCODE_VENDOR_COMMAND_WITH_ID: - ParseVendorId(command.initiator, command.parameters); - break; - case CEC_OPCODE_GIVE_DECK_STATUS: - // need to support opcodes play and deck control before doing anything with this - TransmitAbort(command.initiator, CEC_OPCODE_GIVE_DECK_STATUS); - break; - case CEC_OPCODE_MENU_REQUEST: - if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY) - ReportMenuState(command.initiator); - break; - case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS: - ReportPowerState(command.initiator); - break; - case CEC_OPCODE_GET_CEC_VERSION: - ReportCECVersion(command.initiator); - break; - case CEC_OPCODE_USER_CONTROL_PRESSED: - if (command.parameters.size > 0) - { - m_controller->AddKey(); - - if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX) - { - CStdString strLog; - strLog.Format("key pressed: %1x", command.parameters[0]); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - - m_controller->SetCurrentButton((cec_user_control_code) command.parameters[0]); - } - } - break; - case CEC_OPCODE_USER_CONTROL_RELEASE: - m_controller->AddKey(); - break; - default: - m_controller->AddCommand(command); - bHandled = false; - break; - } - } - else if (command.destination == CECDEVICE_BROADCAST) - { - CStdString strLog; - switch (command.opcode) - { - case CEC_OPCODE_REQUEST_ACTIVE_SOURCE: - strLog.Format(">> %i requests active source", (uint8_t) command.initiator); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - BroadcastActiveSource(); - break; - case CEC_OPCODE_SET_STREAM_PATH: - if (command.parameters.size >= 2) - { - int streamaddr = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); - strLog.Format(">> %i requests stream path from physical address %04x", command.initiator, streamaddr); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - if (streamaddr == m_iPhysicalAddress) - BroadcastActiveSource(); - } - break; - case CEC_OPCODE_ROUTING_CHANGE: - if (command.parameters.size == 4) - { - uint16_t iOldAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); - uint16_t iNewAddress = ((uint16_t)command.parameters[2] << 8) | ((uint16_t)command.parameters[3]); - strLog.Format(">> %i changed physical address from %04x to %04x", command.initiator, iOldAddress, iNewAddress); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - - m_controller->AddCommand(command); - } - break; - case CEC_OPCODE_DEVICE_VENDOR_ID: - case CEC_OPCODE_VENDOR_COMMAND_WITH_ID: - ParseVendorId(command.initiator, command.parameters); - break; - default: - m_controller->AddCommand(command); - bHandled = false; - break; - } - } - else - { - CStdString strLog; - strLog.Format("ignoring frame: destination: %u != %u", command.destination, (uint8_t)m_iLogicalAddress); - m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - bHandled = false; - } - - return bHandled; + m_controller->AddCommand(command); } -void CCECProcessor::ParseCommand(cec_command &command) +void CCECProcessor::AddKey(void) { - CStdString dataStr; - dataStr.Format(">> received frame: %1x%1x:%02x", command.initiator, command.destination, command.opcode); - for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) - dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]); - m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str()); - - if (!m_bMonitor) - { - switch(m_vendorIds[command.initiator]) - { - case CEC_VENDOR_LG: - HandleSLCommand(command); - break; - case CEC_VENDOR_SAMSUNG: - HandleANCommand(command); - break; - default: - HandleCecCommand(command); - break; - } - } + m_controller->AddKey(); } -const char *CCECProcessor::CECVendorIdToString(const uint64_t iVendorId) +void CCECProcessor::AddLog(cec_log_level level, const CStdString &strMessage) { - switch (iVendorId) - { - case CEC_VENDOR_SAMSUNG: - return "Samsung"; - case CEC_VENDOR_LG: - return "LG"; - default: - return "Unknown"; - } + m_controller->AddLog(level, strMessage); } diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 4e9d111..c9028a8 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -35,6 +35,7 @@ #include #include "platform/threads.h" #include "util/buffer.h" +#include "util/StdString.h" class CSerialPort; @@ -42,6 +43,7 @@ namespace CEC { class CLibCEC; class CAdapterCommunication; + class CCECBusDevice; class CCECProcessor : public CThread { @@ -62,9 +64,14 @@ namespace CEC virtual bool SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage); virtual bool SwitchMonitoring(bool bEnable); - static const char *CECVendorIdToString(const uint64_t iVendorId); + virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; } + virtual uint16_t GetPhysicalAddress(void) const { return m_iPhysicalAddress; } + + virtual void SetCurrentButton(cec_user_control_code iButtonCode); + virtual void AddCommand(const cec_command &command); + virtual void AddKey(void); + virtual void AddLog(cec_log_level level, const CStdString &strMessage); - protected: virtual bool TransmitFormatted(const cec_adapter_message &data, bool bWaitForAck = true); virtual void TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE); virtual void ReportCECVersion(cec_logical_address address = CECDEVICE_TV); @@ -74,16 +81,13 @@ namespace CEC virtual void ReportOSDName(cec_logical_address address = CECDEVICE_TV); virtual void ReportPhysicalAddress(void); virtual void BroadcastActiveSource(void); - virtual bool HandleANCommand(cec_command &command); - virtual bool HandleSLCommand(cec_command &command); - virtual bool HandleCecCommand(cec_command &command); + virtual void ParseVendorId(cec_logical_address device, const cec_datapacket &data); private: void LogOutput(const cec_command &data); bool WaitForAck(bool *bError, uint32_t iTimeout = 1000); void ParseMessage(cec_adapter_message &msg, bool *bError, bool *bTransmitSucceeded, bool *bEom, bool bProcessMessages = true); void ParseCommand(cec_command &command); - void ParseVendorId(cec_logical_address device, const cec_datapacket &data); cec_command m_currentframe; uint16_t m_iPhysicalAddress; @@ -93,8 +97,7 @@ namespace CEC CMutex m_mutex; CAdapterCommunication *m_communication; CLibCEC *m_controller; - uint64_t m_vendorIds[16]; - uint8_t m_vendorClasses[16]; + CCECBusDevice *m_busDevices[16]; bool m_bMonitor; }; }; diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 9742795..ecbc55a 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -229,7 +229,7 @@ void CLibCEC::AddKey(void) } } -void CLibCEC::AddCommand(cec_command &command) +void CLibCEC::AddCommand(const cec_command &command) { if (m_commandBuffer.Push(command)) { diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index 968d615..d0147d8 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -77,7 +77,7 @@ namespace CEC virtual void AddLog(cec_log_level level, const std::string &strMessage); virtual void AddKey(void); - virtual void AddCommand(cec_command &command); + virtual void AddCommand(const cec_command &command); virtual void CheckKeypressTimeout(void); virtual void SetCurrentButton(cec_user_control_code iButtonCode); diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index e3354e1..c608a67 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -12,11 +12,19 @@ libcec_la_SOURCES = AdapterCommunication.cpp \ AdapterCommunication.h \ AdapterDetection.cpp \ AdapterDetection.h \ + ANCommandHandler.cpp \ + ANCommandHandler.h \ + CECBusDevice.cpp \ + CECBusDevice.h \ + CECCommandHandler.cpp \ + CECCommandHandler.h \ CECProcessor.cpp \ CECProcessor.h \ LibCEC.cpp \ LibCEC.h \ LibCECC.cpp \ + SLCommandHandler.cpp \ + SLCommandHandler.h \ util/StdString.h \ platform/timeutils.h \ platform/baudrate.h \ diff --git a/src/lib/SLCommandHandler.cpp b/src/lib/SLCommandHandler.cpp new file mode 100644 index 0000000..7c216e9 --- /dev/null +++ b/src/lib/SLCommandHandler.cpp @@ -0,0 +1,41 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "SLCommandHandler.h" + +using namespace CEC; + +CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) : + CCECCommandHandler(busDevice) +{ +} diff --git a/src/lib/SLCommandHandler.h b/src/lib/SLCommandHandler.h new file mode 100644 index 0000000..e5edac5 --- /dev/null +++ b/src/lib/SLCommandHandler.h @@ -0,0 +1,44 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 "CECCommandHandler.h" + +namespace CEC +{ + class CSLCommandHandler : public CCECCommandHandler + { + public: + CSLCommandHandler(CCECBusDevice *busDevice); + virtual ~CSLCommandHandler(void) {}; + }; +}; -- 2.34.1