cec: added an IAdapterCommunicationCallback interface an use a callback method to...
authorLars Op den Kamp <lars@opdenkamp.eu>
Thu, 2 Feb 2012 11:58:53 +0000 (12:58 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 2 Feb 2012 13:37:50 +0000 (14:37 +0100)
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/adapter/AdapterCommunication.h
src/lib/adapter/USBCECAdapterCommunication.cpp
src/lib/adapter/USBCECAdapterCommunication.h

index faa8d8c27cdf182682903b46748615f5473279f8..f1686d64251e0a8074a34d22f1f98bd7b2e0136b 100644 (file)
@@ -150,7 +150,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
   bool bConnected(false), bPinged(false), bControlled(false);
 
   /* open a new connection */
-  while (iNow < iTarget && (bConnected = m_communication->Open(iTimeoutMs)) == false)
+  while (iNow < iTarget && (bConnected = m_communication->Open(this, iTimeoutMs)) == false)
   {
     CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
     Sleep(500);
@@ -410,32 +410,25 @@ void CCECProcessor::ReplaceHandlers(void)
     m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
 }
 
+bool CCECProcessor::OnCommandReceived(const cec_command &command)
+{
+  m_commandBuffer.Push(command);
+  return true;
+}
+
 void *CCECProcessor::Process(void)
 {
-  bool        bParseCommand(false);
   cec_command command;
   CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
 
-  while (!IsStopped())
+  while (!IsStopped() && m_communication->IsOpen())
   {
     ReplaceHandlers();
-    command.Clear();
-
-    {
-      CLockObject lock(m_mutex);
-      if (m_commandBuffer.Pop(command))
-        bParseCommand = true;
-      else if (m_communication->IsOpen() && m_communication->Read(command, 50))
-        bParseCommand = true;
-    }
-
-    if (bParseCommand)
+    if (m_commandBuffer.Pop(command))
       ParseCommand(command);
-    bParseCommand = false;
-
-    Sleep(5);
 
     m_controller->CheckKeypressTimeout();
+    Sleep(5);
   }
 
   if (m_communication)
@@ -888,7 +881,7 @@ void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode
   Transmit(command);
 }
 
-void CCECProcessor::ParseCommand(cec_command &command)
+void CCECProcessor::ParseCommand(const cec_command &command)
 {
   CStdString dataStr;
   dataStr.Format(">> %1x%1x:%02x", command.initiator, command.destination, command.opcode);
index 487f1224e23154d5dbae299ac37eee6ea108d6c8..c6d278f09a5eb2c14cf3762559c0b97e3a76f03d 100644 (file)
@@ -35,6 +35,7 @@
 #include <cectypes.h>
 #include "platform/threads/threads.h"
 #include "platform/util/buffer.h"
+#include "adapter/AdapterCommunication.h"
 
 namespace CEC
 {
@@ -42,7 +43,7 @@ namespace CEC
   class IAdapterCommunication;
   class CCECBusDevice;
 
-  class CCECProcessor : public PLATFORM::CThread
+  class CCECProcessor : public PLATFORM::CThread, public IAdapterCommunicationCallback
   {
     public:
       CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
@@ -52,6 +53,8 @@ namespace CEC
       virtual bool Start(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000);
       virtual void *Process(void);
 
+      virtual bool                  OnCommandReceived(const cec_command &command);
+
       virtual bool                  IsMonitoring(void) const { return m_bMonitor; }
       virtual CCECBusDevice *       GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const;
       virtual CCECBusDevice *       GetDeviceByType(cec_device_type type) const;
@@ -140,7 +143,7 @@ namespace CEC
       bool FindLogicalAddressAudioSystem(void);
 
       void LogOutput(const cec_command &data);
-      void ParseCommand(cec_command &command);
+      void ParseCommand(const cec_command &command);
 
       bool                                m_bInitialised;
       uint8_t                             m_iHDMIPort;
index 36a9bb1d434356bd304afc86119f35347e6af0c4..9762926cc10a23e0561b96914c13b2ba4fac2aa8 100644 (file)
@@ -46,15 +46,27 @@ namespace CEC
     ADAPTER_MESSAGE_STATE_ERROR                 /**< an error occured */
   } cec_adapter_message_state;
 
-  class IAdapterCommunication
+  struct IAdapterCommunicationCallback
+  {
+  public:
+    /*!
+     * @brief Callback method for IAdapterCommunication, called when a new cec_command is received
+     * @param command The command that has been received
+     * @return True when it was handled by this listener, false otherwise.
+     */
+    virtual bool OnCommandReceived(const cec_command &command) = 0;
+  };
+
+  struct IAdapterCommunication
   {
   public:
     /*!
      * @brief Open a connection to the CEC adapter
+     * @param cb The callback struct. if set to NULL, the Read() method has to be used to read commands. if set, OnCommandReceived() will be called for each command that was received
      * @param iTimeoutMs Connection timeout in ms
      * @return True when connected, false otherwise
      */
-    virtual bool Open(uint32_t iTimeoutMs = 10000) = 0;
+    virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000) = 0;
 
     /*!
      * @brief Close an open connection
index 12b8eacde7f70b2197656cf78d8a6cd7c33576d5..a27765c6651eedf4df027c17d40c5f6d23748bd2 100644 (file)
@@ -57,7 +57,7 @@ CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
   Close();
 }
 
-bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */)
 {
   uint64_t iNow = GetTimeMs();
   uint64_t iTimeout = iNow + iTimeoutMs;
@@ -76,6 +76,7 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
     return true;
   }
 
+  m_callback = cb;
   CStdString strError;
   bool bConnected(false);
   while (!bConnected && iNow < iTimeout)
@@ -126,9 +127,15 @@ void CUSBCECAdapterCommunication::Close(void)
 
 void *CUSBCECAdapterCommunication::Process(void)
 {
+  cec_command command;
   while (!IsStopped())
   {
     ReadFromDevice(50);
+
+    /* push the next command to the callback method if there is one */
+    if (m_callback && Read(command, 0))
+      m_callback->OnCommandReceived(command);
+
     Sleep(5);
     WriteNextCommand();
   }
@@ -177,37 +184,19 @@ cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &
 
 bool CUSBCECAdapterCommunication::Write(CCECAdapterMessage *data)
 {
-  bool bReturn(false);
-
   CLockObject lock(data->mutex);
   data->state = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
   m_outBuffer.Push(data);
   data->condition.Wait(data->mutex);
 
-  if (data->state != ADAPTER_MESSAGE_STATE_SENT)
-  {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "command was not sent");
-  }
-  else if (data->expectControllerAck)
-  {
-    bReturn = WaitForAck(*data);
-    if (bReturn)
-    {
-      if (data->isTransmission)
-        data->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
-    }
-    else
-    {
-      data->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
-    }
-  }
-  else
+  if ((data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT_ACKED) ||
+      (!data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT))
   {
-    bReturn = true;
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "command was not %s", data->state == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED ? "acked" : "sent");
+    return false;
   }
 
-  return bReturn;
+  return true;
 }
 
 bool CUSBCECAdapterCommunication::Read(cec_command &command, uint32_t iTimeout)
@@ -234,7 +223,7 @@ bool CUSBCECAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeou
 
   if (!m_inBuffer.Pop(buf))
   {
-    if (!m_rcvCondition.Wait(m_mutex, iTimeout))
+    if (iTimeout == 0 || !m_rcvCondition.Wait(m_mutex, iTimeout))
       return false;
     m_inBuffer.Pop(buf);
   }
@@ -368,16 +357,23 @@ uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
     output->isTransmission = false;
     output->expectControllerAck = false;
 
-    SendMessageToAdapter(output);
+    bool bWriteOk = Write(output);
     delete output;
-
-    CCECAdapterMessage input;
-    if (!Read(input, CEC_DEFAULT_TRANSMIT_WAIT) || input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3)
-      CLibCEC::AddLog(CEC_LOG_ERROR, "no or invalid firmware version (size = %d, message = %d)", input.Size(), input.Message());
+    if (!bWriteOk)
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "could not request the firmware version");
+    }
     else
     {
-      m_iFirmwareVersion = (input[1] << 8 | input[2]);
-      iReturn = m_iFirmwareVersion;
+      ReadFromDevice(CEC_DEFAULT_TRANSMIT_WAIT, 5 /* start + msgcode + 2 bytes for fw version + end */);
+      CCECAdapterMessage input;
+      if (!Read(input, 0) || input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3)
+        CLibCEC::AddLog(CEC_LOG_ERROR, "no or invalid firmware version (size = %d, message = %d)", input.Size(), input.Message());
+      else
+      {
+        m_iFirmwareVersion = (input[1] << 8 | input[2]);
+        iReturn = m_iFirmwareVersion;
+      }
     }
   }
 
@@ -463,16 +459,13 @@ bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
   uint8_t iPacketsLeft(message.Size() / 4);
 
   int64_t iNow = GetTimeMs();
-  int64_t iTargetTime = iNow + message.transmit_timeout;
+  int64_t iTargetTime = iNow + (message.transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : message.transmit_timeout);
 
-  while (!bTransmitSucceeded && !bError && (message.transmit_timeout == 0 || iNow < iTargetTime))
+  while (!bTransmitSucceeded && !bError && iNow < iTargetTime)
   {
+    ReadFromDevice(50);
     CCECAdapterMessage msg;
-    int32_t iWait = (int32_t)(iTargetTime - iNow);
-    if (iWait <= 5 || message.transmit_timeout <= 5)
-      iWait = CEC_DEFAULT_TRANSMIT_WAIT;
-
-    if (!Read(msg, iWait))
+    if (!Read(msg, 0))
     {
       iNow = GetTimeMs();
       continue;
@@ -526,6 +519,10 @@ bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
     }
   }
 
+  message.state = bTransmitSucceeded && !bError ?
+      ADAPTER_MESSAGE_STATE_SENT_ACKED :
+      ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+
   return bTransmitSucceeded && !bError;
 }
 
@@ -572,15 +569,17 @@ void CUSBCECAdapterCommunication::AddData(uint8_t *data, size_t iLen)
   }
 }
 
-bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
 {
   ssize_t iBytesRead;
   uint8_t buff[256];
   if (!m_port)
     return false;
+  if (iSize > 256)
+    iSize = 256;
 
   CLockObject lock(m_mutex);
-  iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
+  iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
   if (iBytesRead < 0 || iBytesRead > 256)
   {
     CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
@@ -612,6 +611,12 @@ void CUSBCECAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
   {
     CLibCEC::AddLog(CEC_LOG_DEBUG, "command sent");
     msg->state = ADAPTER_MESSAGE_STATE_SENT;
+
+    if (msg->expectControllerAck)
+    {
+      if (!WaitForAck(*msg))
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
+    }
   }
   msg->condition.Signal();
 }
index 8cada4dbe0fd1259b13bf68cf6044f7a97958c61..ee8593fb583b641c81baaad75349cc8c5dd9fe5c 100644 (file)
@@ -52,7 +52,7 @@ namespace CEC
     CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
     virtual ~CUSBCECAdapterCommunication();
 
-    virtual bool Open(uint32_t iTimeoutMs = 10000);
+    virtual bool Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs = 10000);
     virtual void Close(void);
     virtual bool IsOpen(void);
     virtual CStdString GetError(void) const;
@@ -75,7 +75,7 @@ namespace CEC
     void SendMessageToAdapter(CCECAdapterMessage *msg);
     void WriteNextCommand(void);
     void AddData(uint8_t *data, size_t iLen);
-    bool ReadFromDevice(uint32_t iTimeout);
+    bool ReadFromDevice(uint32_t iTimeout, size_t iSize = 256);
     bool WaitForAck(CCECAdapterMessage &message);
 
     PLATFORM::ISocket *                          m_port;
@@ -91,5 +91,6 @@ namespace CEC
     CCECAdapterMessage                           m_currentAdapterMessage;
     bool                                         m_bNextIsEscaped;
     bool                                         m_bGotStart;
+    IAdapterCommunicationCallback *              m_callback;
   };
 };