From b64db02edf638da604a1b7042ff3af6347f228d4 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Tue, 27 Dec 2011 20:15:08 +0100 Subject: [PATCH] cec: don't replace a command handler when it's being used --- src/lib/CECProcessor.cpp | 10 ++- src/lib/CECProcessor.h | 2 + src/lib/devices/CECBusDevice.cpp | 76 ++++++++++++++----- src/lib/devices/CECBusDevice.h | 5 ++ src/lib/implementations/CECCommandHandler.cpp | 46 ++++++++--- src/lib/implementations/CECCommandHandler.h | 7 +- 6 files changed, 113 insertions(+), 33 deletions(-) diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 27bca69..63205f4 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -49,6 +49,7 @@ using namespace std; CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) : m_bStarted(false), + m_bInitialised(false), m_iHDMIPort(CEC_DEFAULT_HDMI_PORT), m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE), m_lastInitiator(CECDEVICE_UNKNOWN), @@ -69,6 +70,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) : m_bStarted(false), + m_bInitialised(false), m_iHDMIPort(CEC_DEFAULT_HDMI_PORT), m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE), m_strDeviceName(strDeviceName), @@ -176,8 +178,9 @@ bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, /* make the primary device the active source */ if (bReturn) { + m_bInitialised = true; m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true; - bReturn = m_busDevices[CECDEVICE_TV]->GetHandler()->InitHandler(); + bReturn = m_busDevices[CECDEVICE_TV]->InitHandler(); } if (bReturn) @@ -413,6 +416,7 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true * bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */) { bool bReturn(false); + CLockObject lock(&m_mutex); m_iBaseDevice = iBaseDevice; m_iHDMIPort = iPort; @@ -482,6 +486,7 @@ void CCECProcessor::LogOutput(const cec_command &data) bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress) { + CLockObject lock(&m_mutex); if (m_logicalAddresses.primary != iLogicalAddress) { CStdString strLog; @@ -511,6 +516,7 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress) { + CLockObject lock(&m_mutex); if (!m_logicalAddresses.IsEmpty()) { for (uint8_t iPtr = 0; iPtr < 15; iPtr++) @@ -604,7 +610,7 @@ CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const for (unsigned int iPtr = 0; iPtr < 16; iPtr++) { - if (m_busDevices[iPtr]->m_type == type) + if (m_busDevices[iPtr]->m_type == type && m_logicalAddresses[iPtr]) { device = m_busDevices[iPtr]; break; diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index e2705fd..9cb1bf9 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -78,6 +78,7 @@ namespace CEC virtual bool IsStarted(void) const { return m_bStarted; } virtual cec_logical_address GetActiveSource(void); virtual bool IsActiveSource(cec_logical_address iAddress); + virtual bool IsInitialised(void) const { return m_bInitialised; } virtual bool SetActiveView(void); virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED); @@ -147,6 +148,7 @@ namespace CEC void ParseCommand(cec_command &command); bool m_bStarted; + bool m_bInitialised; uint8_t m_iHDMIPort; cec_logical_address m_iBaseDevice; cec_command m_currentframe; diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 6279de9..1ea78d7 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -50,11 +50,13 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi m_powerStatus(CEC_POWER_STATUS_UNKNOWN), m_processor(processor), m_vendor(CEC_VENDOR_UNKNOWN), + m_bReplaceHandler(false), m_menuState(CEC_MENU_STATE_ACTIVATED), m_bActiveSource(false), m_iLastActive(0), m_cecVersion(CEC_VERSION_UNKNOWN), - m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN) + m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN), + m_handlerMutex(false) { m_handler = new CCECCommandHandler(this); @@ -90,6 +92,7 @@ bool CCECBusDevice::HandleCommand(const cec_command &command) } /* handle the command */ + ReplaceHandler(true); bHandled = m_handler->HandleCommand(command); /* change status to present */ @@ -117,7 +120,7 @@ bool CCECBusDevice::PowerOn(void) strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_DEBUG, strLog.c_str()); - if (m_handler->TransmitPowerOn(GetMyLogicalAddress(), m_iLogicalAddress)) + if (m_handler->TransmitImageViewOn(GetMyLogicalAddress(), m_iLogicalAddress)) { { CLockObject lock(&m_mutex); @@ -165,6 +168,7 @@ cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */) bool CCECBusDevice::RequestCecVersion(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) { CStdString strLog; @@ -194,6 +198,7 @@ cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */) bool CCECBusDevice::RequestMenuLanguage(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress) && !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE)) { @@ -229,6 +234,7 @@ CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */) bool CCECBusDevice::RequestOSDName(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress) && !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME)) { @@ -256,6 +262,7 @@ uint16_t CCECBusDevice::GetPhysicalAddress(bool bUpdate /* = false */) bool CCECBusDevice::RequestPhysicalAddress(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) { CStdString strLog; @@ -279,6 +286,7 @@ cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */) bool CCECBusDevice::RequestPowerStatus(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress) && !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS)) { @@ -303,6 +311,7 @@ cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */) bool CCECBusDevice::RequestVendorId(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) { CStdString strLog; @@ -558,41 +567,51 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) } } -bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */) +bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */) { - bool bVendorChanged(false); + CLockObject lock(&m_mutex); + CLockObject handlerLock(&m_handlerMutex); + if (m_vendor != m_handler->GetVendorId()) { - CLockObject lock(&m_mutex); - bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId); - m_vendor = (cec_vendor_id)iVendorId; + if (m_handler->InUse()) + return false; - if (bVendorChanged) - delete m_handler; + delete m_handler; - switch (iVendorId) + switch (m_vendor) { case CEC_VENDOR_SAMSUNG: - if (bVendorChanged) - m_handler = new CANCommandHandler(this); + m_handler = new CANCommandHandler(this); break; case CEC_VENDOR_LG: - if (bVendorChanged) - m_handler = new CSLCommandHandler(this); + m_handler = new CSLCommandHandler(this); break; case CEC_VENDOR_PANASONIC: - if (bVendorChanged) - m_handler = new CVLCommandHandler(this); + m_handler = new CVLCommandHandler(this); break; default: - if (bVendorChanged) - m_handler = new CCECCommandHandler(this); + m_handler = new CCECCommandHandler(this); break; } + + if (bInitHandler && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised()) + m_handler->InitHandler(); } - if (bVendorChanged && bInitHandler && m_handler->GetVendorId() != CEC_VENDOR_UNKNOWN) - m_handler->InitHandler(); + return true; +} + +bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */) +{ + bool bVendorChanged(false); + + { + CLockObject lock(&m_mutex); + bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId); + m_vendor = (cec_vendor_id)iVendorId; + ReplaceHandler(bInitHandler); + } CStdString strLog; strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor); @@ -631,7 +650,14 @@ bool CCECBusDevice::TransmitActiveSource(void) } } - return bSendActiveSource ? m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress) : false; + if (bSendActiveSource) + { + m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress); + m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV); + return true; + } + + return false; } bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest) @@ -814,4 +840,12 @@ void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode) { m_unsupportedFeatures.insert(opcode); } + +bool CCECBusDevice::InitHandler(void) +{ + CLockObject lock(&m_mutex); + ReplaceHandler(false); + return m_handler->InitHandler(); +} + //@} diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 0ca662a..30d8329 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -80,6 +80,7 @@ namespace CEC virtual void SetInactiveSource(void); virtual void SetActiveSource(void); virtual bool TryLogicalAddress(void); + virtual bool InitHandler(void); virtual void SetDeviceStatus(const cec_bus_device_status newStatus); virtual void SetPhysicalAddress(uint16_t iNewAddress); @@ -105,6 +106,8 @@ namespace CEC virtual bool TransmitKeyRelease(bool bWait = true); protected: + bool ReplaceHandler(bool bInitHandler = true); + bool RequestCecVersion(void); bool RequestMenuLanguage(void); bool RequestPowerStatus(void); @@ -124,6 +127,7 @@ namespace CEC CCECProcessor * m_processor; CCECCommandHandler * m_handler; cec_vendor_id m_vendor; + bool m_bReplaceHandler; cec_menu_state m_menuState; bool m_bActiveSource; uint64_t m_iLastActive; @@ -131,5 +135,6 @@ namespace CEC cec_bus_device_status m_deviceStatus; std::set m_unsupportedFeatures; CMutex m_mutex; + CMutex m_handlerMutex; }; }; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 23fd550..5da80a0 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -45,12 +45,15 @@ CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) : m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT), m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT), m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES), - m_bHandlerInited(false) + m_bHandlerInited(false), + m_iUseCounter(0) { } CCECCommandHandler::~CCECCommandHandler(void) { + CLockObject lock(&m_processor->m_transmitMutex); + CLockObject receiveLock(&m_receiveMutex); m_condition.Broadcast(); } @@ -58,6 +61,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) { bool bHandled(true), bHandlerChanged(false); + MarkBusy(); CStdString strLog; strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode); m_busDevice->AddLog(CEC_LOG_NOTICE, strLog); @@ -174,6 +178,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) m_condition.Signal(); } + MarkReady(); return bHandled; } @@ -704,7 +709,7 @@ bool CCECCommandHandler::HandleReceiveFailed(void) return true; } -bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination) +bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON); @@ -926,18 +931,23 @@ bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */) { + bool bReturn(false); command.transmit_timeout = m_iTransmitTimeout; - CLockObject writeLock(&m_processor->m_transmitMutex); - CLockObject receiveLock(&m_receiveMutex); - if (m_processor->Transmit(command)) { - if (bExpectResponse) - return m_condition.Wait(&m_receiveMutex, m_iTransmitWait); - return true; + CLockObject writeLock(&m_processor->m_transmitMutex); + CLockObject receiveLock(&m_receiveMutex); + ++m_iUseCounter; + if (m_processor->Transmit(command)) + { + bReturn = bExpectResponse ? + m_condition.Wait(&m_receiveMutex, m_iTransmitWait) : + true; + } + --m_iUseCounter; } - return false; + return bReturn; } bool CCECCommandHandler::InitHandler(void) @@ -957,3 +967,21 @@ bool CCECCommandHandler::InitHandler(void) } return true; } + +void CCECCommandHandler::MarkBusy(void) +{ + CLockObject receiveLock(&m_receiveMutex); + ++m_iUseCounter; +} + +bool CCECCommandHandler::MarkReady(void) +{ + CLockObject receiveLock(&m_receiveMutex); + return m_iUseCounter > 0 ? (--m_iUseCounter == 0) : true; +} + +bool CCECCommandHandler::InUse(void) +{ + CLockObject receiveLock(&m_receiveMutex); + return m_iUseCounter > 0; +} diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index 0469b31..9ced829 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -55,7 +55,7 @@ namespace CEC virtual bool InitHandler(void); virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; } - virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); + virtual bool TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination); @@ -80,6 +80,10 @@ namespace CEC 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 void MarkBusy(void); + virtual bool MarkReady(void); + virtual bool InUse(void); + protected: virtual bool HandleActiveSource(const cec_command &command); virtual bool HandleDeckControl(const cec_command &command); @@ -131,6 +135,7 @@ namespace CEC int32_t m_iTransmitWait; int8_t m_iTransmitRetries; bool m_bHandlerInited; + uint8_t m_iUseCounter; CMutex m_receiveMutex; CCondition m_condition; }; -- 2.34.1