From 24dd566c2a75900a5add19d9b5965ab04f7d6fd4 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Sat, 18 Feb 2012 02:50:34 +0100 Subject: [PATCH] cec: wait for multiple responses, not just for one. don't try to read and write at the same time --- src/lib/CECProcessor.cpp | 2 + .../adapter/USBCECAdapterCommunication.cpp | 3 +- src/lib/devices/CECBusDevice.cpp | 5 ++ src/lib/implementations/CECCommandHandler.cpp | 27 ++---- src/lib/implementations/CECCommandHandler.h | 84 +++++++++++++++++-- 5 files changed, 95 insertions(+), 26 deletions(-) diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 0dec343..9fc11fd 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -1316,6 +1316,8 @@ const char *CCECProcessor::ToString(const cec_opcode opcode) return "system audio mode status"; case CEC_OPCODE_SET_AUDIO_RATE: return "set audio rate"; + case CEC_OPCODE_NONE: + return "poll"; default: return "UNKNOWN"; } diff --git a/src/lib/adapter/USBCECAdapterCommunication.cpp b/src/lib/adapter/USBCECAdapterCommunication.cpp index 2d8957b..80670e4 100644 --- a/src/lib/adapter/USBCECAdapterCommunication.cpp +++ b/src/lib/adapter/USBCECAdapterCommunication.cpp @@ -391,6 +391,7 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg) if (msg.IsEmpty()) return bEom; + CLockObject adapterLock(m_mutex); switch(msg.Message()) { case MSGCODE_FRAME_START: @@ -663,7 +664,7 @@ void CUSBCECAdapterCommunication::AddData(uint8_t *data, size_t iLen) m_bGotStart = false; m_bNextIsEscaped = false; m_bHasData = true; - m_rcvCondition.Signal(); + m_rcvCondition.Broadcast(); } else if (m_bNextIsEscaped) { diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 8f679c3..845cb07 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -524,6 +524,8 @@ void CCECBusDevice::SetInactiveSource(void) { { CLockObject lock(m_mutex); + if (m_bActiveSource) + CLibCEC::AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress); m_bActiveSource = false; } @@ -901,7 +903,10 @@ bool CCECBusDevice::TransmitPowerState(cec_logical_address dest) { CLockObject lock(m_mutex); if (!IsActiveSource()) + { + CLibCEC::AddLog(CEC_LOG_NOTICE, "power state requested of %s (%X), but we are not the active source. setting power state to standby", GetLogicalAddressName(), m_iLogicalAddress); SetPowerStatus(CEC_POWER_STATUS_STANDBY); + } CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus)); state = m_powerStatus; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index f742fc9..d2fe2fd 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -48,17 +48,15 @@ CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) : m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT), m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES), m_bHandlerInited(false), - m_expectedResponse(CEC_OPCODE_NONE), - m_lastCommandSent(CEC_OPCODE_NONE), m_bOPTSendDeckStatusUpdateOnActiveSource(false), m_vendorId(CEC_VENDOR_UNKNOWN), - m_bRcvSignal(false) + m_waitForResponse(new CWaitForResponse) { } CCECCommandHandler::~CCECCommandHandler(void) { - m_condition.Broadcast(); + delete m_waitForResponse; } bool CCECCommandHandler::HandleCommand(const cec_command &command) @@ -189,16 +187,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) } if (bHandled) - { - CLockObject lock(m_receiveMutex); - if (m_expectedResponse == CEC_OPCODE_NONE || - m_expectedResponse == command.opcode || - (command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0 && command.parameters[0] == m_lastCommandSent)) - { - m_bRcvSignal = true; - m_condition.Signal(); - } - } + m_waitForResponse->Received((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode); return bHandled; } @@ -963,18 +952,16 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* { uint8_t iTries(0), iMaxTries(command.opcode == CEC_OPCODE_NONE ? 1 : m_iTransmitRetries + 1); CLockObject writeLock(m_processor->m_transmitMutex); - CLockObject receiveLock(m_receiveMutex); while (!bReturn && ++iTries <= iMaxTries) { - m_expectedResponse = expectedResponse; - m_lastCommandSent = command.opcode; - m_bRcvSignal = false; if ((bReturn = m_processor->Transmit(command)) == true) { CLibCEC::AddLog(CEC_LOG_DEBUG, "command transmitted"); if (bExpectResponse) - bReturn = m_condition.Wait(m_receiveMutex, m_bRcvSignal, m_iTransmitWait); - CLibCEC::AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received" : "expected response not received"); + { + bReturn = m_waitForResponse->Wait(expectedResponse); + CLibCEC::AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, m_processor->ToString(expectedResponse)); + } } } } diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index a1b1f96..2943ba3 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -33,6 +33,7 @@ #include "../../../include/cectypes.h" #include +#include #include "../platform/threads/mutex.h" #include "../platform/util/StdString.h" @@ -41,6 +42,83 @@ namespace CEC class CCECProcessor; class CCECBusDevice; + class CResponse + { + public: + CResponse(cec_opcode opcode) : + m_opcode(opcode){} + ~CResponse(void) + { + Broadcast(); + } + + bool Wait(uint32_t iTimeout) + { + return m_event.Wait(iTimeout); + } + + void Broadcast(void) + { + m_event.Broadcast(); + } + + private: + cec_opcode m_opcode; + PLATFORM::CEvent m_event; + }; + + class CWaitForResponse + { + public: + CWaitForResponse(void) {} + ~CWaitForResponse(void) + { + PLATFORM::CLockObject lock(m_mutex); + for (std::map::iterator it = m_waitingFor.begin(); it != m_waitingFor.end(); it++) + { + it->second->Broadcast(); + delete it->second; + } + m_waitingFor.clear(); + } + + bool Wait(cec_opcode opcode, uint32_t iTimeout = 2000) + { + CResponse *response = GetEvent(opcode); + return response ? response->Wait(iTimeout) : false; + } + + void Received(cec_opcode opcode) + { + CResponse *response = GetEvent(opcode); + if (response) + response->Broadcast(); + } + + private: + CResponse *GetEvent(cec_opcode opcode) + { + CResponse *retVal(NULL); + { + PLATFORM::CLockObject lock(m_mutex); + std::map::iterator it = m_waitingFor.find(opcode); + if (it != m_waitingFor.end()) + { + retVal = it->second; + } + else + { + retVal = new CResponse(opcode); + m_waitingFor[opcode] = retVal; + } + return retVal; + } + } + + PLATFORM::CMutex m_mutex; + std::map m_waitingFor; + }; + class CCECCommandHandler { public: @@ -136,12 +214,8 @@ namespace CEC int32_t m_iTransmitWait; int8_t m_iTransmitRetries; bool m_bHandlerInited; - cec_opcode m_expectedResponse; - cec_opcode m_lastCommandSent; bool m_bOPTSendDeckStatusUpdateOnActiveSource; cec_vendor_id m_vendorId; - PLATFORM::CMutex m_receiveMutex; - PLATFORM::CCondition m_condition; - volatile bool m_bRcvSignal; + CWaitForResponse *m_waitForResponse; }; }; -- 2.34.1