cec: wait for multiple responses, not just for one. don't try to read and write at...
authorLars Op den Kamp <lars@opdenkamp.eu>
Sat, 18 Feb 2012 01:50:34 +0000 (02:50 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Sat, 18 Feb 2012 01:52:57 +0000 (02:52 +0100)
src/lib/CECProcessor.cpp
src/lib/adapter/USBCECAdapterCommunication.cpp
src/lib/devices/CECBusDevice.cpp
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h

index 0dec343d1540342de65b555618a1b054b181c9e2..9fc11fdf30c3b97f16469e256e7339bd510d03c6 100644 (file)
@@ -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";
   }
index 2d8957b05e839004b6c7ce771d080448e9c478ef..80670e42f5c981f01bb2b1aff2c2d6c0fec345f6 100644 (file)
@@ -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)
     {
index 8f679c3973f317c319afb94b9726ee2d46b0d70d..845cb07d6426af2ab801fa7ba674a439c7628517 100644 (file)
@@ -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;
index f742fc9922b98bedefecb36314471326b5e64eb8..d2fe2fd9f742101948ceb97b08c5cbbab3a55fc6 100644 (file)
@@ -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));
+        }
       }
     }
   }
index a1b1f96fb90e2c16ff5c57f711d6af7703d8028a..2943ba39b3a17059491bc098a3414a3be18c8182 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "../../../include/cectypes.h"
 #include <vector>
+#include <map>
 #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<cec_opcode, CResponse*>::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<cec_opcode, CResponse*>::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<cec_opcode, CResponse*> 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<volatile bool &> m_condition;
-    volatile bool                         m_bRcvSignal;
+    CWaitForResponse                     *m_waitForResponse;
   };
 };