cec: receive and send full cec_commands, not CCECAdapterMessages in CAdapterCommunica...
authorLars Op den Kamp <lars@opdenkamp.eu>
Tue, 31 Jan 2012 23:05:40 +0000 (00:05 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Wed, 1 Feb 2012 01:26:38 +0000 (02:26 +0100)
13 files changed:
include/cectypes.h
project/libcec.vcxproj
project/libcec.vcxproj.filters
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/Makefile.am
src/lib/adapter/AdapterCommunication.h
src/lib/adapter/USBCECAdapterCommunication.cpp [moved from src/lib/adapter/AdapterCommunication.cpp with 62% similarity]
src/lib/adapter/USBCECAdapterCommunication.h [new file with mode: 0644]
src/lib/adapter/USBCECAdapterDetection.cpp [moved from src/lib/adapter/AdapterDetection.cpp with 98% similarity]
src/lib/adapter/USBCECAdapterDetection.h [moved from src/lib/adapter/AdapterDetection.h with 97% similarity]
src/lib/adapter/USBCECAdapterMessage.h [moved from src/lib/adapter/AdapterMessage.h with 96% similarity]

index 36057eb1f53d046b5c6212a5b63736bcd3f63b67..ddbd79fdef1da68a2638011dacd222ffd1efea1e 100644 (file)
@@ -874,7 +874,6 @@ typedef struct cec_logical_addresses
 #endif
 } cec_logical_addresses;
 
-
 typedef int (CEC_CDECL* CBCecLogMessageType)(void *param, const CEC::cec_log_message &);
 typedef int (CEC_CDECL* CBCecKeyPressType)(void *param, const cec_keypress &key);
 typedef int (CEC_CDECL* CBCecCommandType)(void *param, const cec_command &command);
index d667d14be4dae736396e05eb25acb3c13a821637..0ca4ccafb3ab20a0f107c9d12ab500fb0e46d127 100644 (file)
@@ -24,8 +24,9 @@
     <ClInclude Include="..\include\cecloader.h" />
     <ClInclude Include="..\include\cectypes.h" />
     <ClInclude Include="..\src\lib\adapter\AdapterCommunication.h" />
-    <ClInclude Include="..\src\lib\adapter\AdapterDetection.h" />
-    <ClInclude Include="..\src\lib\adapter\AdapterMessage.h" />
+    <ClInclude Include="..\src\lib\adapter\USBCECAdapterCommunication.h" />
+    <ClInclude Include="..\src\lib\adapter\USBCECAdapterDetection.h" />
+    <ClInclude Include="..\src\lib\adapter\USBCECAdapterMessage.h" />
     <ClInclude Include="..\src\lib\CECProcessor.h" />
     <ClInclude Include="..\src\lib\devices\CECAudioSystem.h" />
     <ClInclude Include="..\src\lib\devices\CECBusDevice.h" />
@@ -54,8 +55,8 @@
     <ClInclude Include="..\src\lib\platform\windows\stdint.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\src\lib\adapter\AdapterCommunication.cpp" />
-    <ClCompile Include="..\src\lib\adapter\AdapterDetection.cpp" />
+    <ClCompile Include="..\src\lib\adapter\USBCECAdapterCommunication.cpp" />
+    <ClCompile Include="..\src\lib\adapter\USBCECAdapterDetection.cpp" />
     <ClCompile Include="..\src\lib\CECProcessor.cpp" />
     <ClCompile Include="..\src\lib\devices\CECAudioSystem.cpp" />
     <ClCompile Include="..\src\lib\devices\CECBusDevice.cpp" />
index 37865049c307ba9d3da1a69cb0c4bb49399066af..a85f501934f38b3a36245e205f3f472b60a3412b 100644 (file)
     <ClInclude Include="..\src\lib\devices\CECTV.h">
       <Filter>devices</Filter>
     </ClInclude>
-    <ClInclude Include="..\src\lib\adapter\AdapterCommunication.h">
-      <Filter>adapter</Filter>
-    </ClInclude>
-    <ClInclude Include="..\src\lib\adapter\AdapterDetection.h">
-      <Filter>adapter</Filter>
-    </ClInclude>
-    <ClInclude Include="..\src\lib\adapter\AdapterMessage.h">
-      <Filter>adapter</Filter>
-    </ClInclude>
     <ClInclude Include="..\src\lib\platform\os.h">
       <Filter>platform</Filter>
     </ClInclude>
     <ClInclude Include="..\src\lib\platform\windows\stdint.h">
       <Filter>platform\windows</Filter>
     </ClInclude>
+    <ClInclude Include="..\src\lib\adapter\AdapterCommunication.h">
+      <Filter>adapter</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\lib\adapter\USBCECAdapterCommunication.h">
+      <Filter>adapter</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\lib\adapter\USBCECAdapterDetection.h">
+      <Filter>adapter</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\lib\adapter\USBCECAdapterMessage.h">
+      <Filter>adapter</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\src\lib\CECProcessor.cpp" />
     <ClCompile Include="..\src\lib\devices\CECTV.cpp">
       <Filter>devices</Filter>
     </ClCompile>
-    <ClCompile Include="..\src\lib\adapter\AdapterCommunication.cpp">
-      <Filter>adapter</Filter>
+    <ClCompile Include="..\src\lib\platform\windows\serialport.cpp">
+      <Filter>platform\windows</Filter>
     </ClCompile>
-    <ClCompile Include="..\src\lib\adapter\AdapterDetection.cpp">
+    <ClCompile Include="..\src\lib\adapter\USBCECAdapterCommunication.cpp">
       <Filter>adapter</Filter>
     </ClCompile>
-    <ClCompile Include="..\src\lib\platform\windows\serialport.cpp">
-      <Filter>platform\windows</Filter>
+    <ClCompile Include="..\src\lib\adapter\USBCECAdapterDetection.cpp">
+      <Filter>adapter</Filter>
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
index 6faf72c5e5b8ae3e8890024184da2115e9bf8d32..57704bdba531e571f8db1babbede3680ef167834 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "CECProcessor.h"
 
-#include "adapter/AdapterMessage.h"
+#include "adapter/USBCECAdapterCommunication.h"
 #include "devices/CECBusDevice.h"
 #include "devices/CECAudioSystem.h"
 #include "devices/CECPlaybackDevice.h"
@@ -52,7 +52,6 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec
     m_bInitialised(false),
     m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
     m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
-    m_lastInitiator(CECDEVICE_UNKNOWN),
     m_strDeviceName(strDeviceName),
     m_communication(NULL),
     m_controller(controller),
@@ -139,7 +138,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
     return bReturn;
   }
 
-  m_communication = new CAdapterCommunication(this, strPort, iBaudRate);
+  m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
 
   /* check for an already opened connection */
   if (m_communication->IsOpen())
@@ -420,17 +419,13 @@ void *CCECProcessor::Process(void)
   {
     ReplaceHandlers();
     command.Clear();
-    msg.Clear();
 
     {
       CLockObject lock(m_mutex);
       if (m_commandBuffer.Pop(command))
         bParseFrame = true;
-      else if (m_communication->IsOpen() && m_communication->Read(msg, 50))
-      {
-        if ((bParseFrame = (ParseMessage(msg) && !IsStopped())) == true)
-          command = m_currentframe;
-      }
+      else if (m_communication->IsOpen() && m_communication->Read(command, 50))
+        bParseFrame = true;
     }
 
     if (bParseFrame)
@@ -856,53 +851,23 @@ bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
 
 bool CCECProcessor::Transmit(const cec_command &data)
 {
-  bool bReturn(false);
-  LogOutput(data);
-
-  CCECAdapterMessage *output = new CCECAdapterMessage(data);
-
-  /* set the number of retries */
-  if (data.opcode == CEC_OPCODE_NONE)
-    output->maxTries = 1;
-  else if (data.initiator != CECDEVICE_BROADCAST)
-    output->maxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
-
-  bReturn = Transmit(output);
-
-  /* set to "not present" on failed ack */
-  if (output->state == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED &&
-      output->Destination() != CECDEVICE_BROADCAST)
-    m_busDevices[output->Destination()]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
-
-  delete output;
-  return bReturn;
-}
-
-bool CCECProcessor::Transmit(CCECAdapterMessage *output)
-{
-  bool bReturn(false);
-  CLockObject lock(m_mutex);
+  cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
   {
-    if (!m_communication)
-      return bReturn;
-
+    CLockObject lock(m_mutex);
+    LogOutput(data);
     m_iLastTransmission = GetTimeMs();
-    m_communication->SetLineTimeout(m_iStandardLineTimeout);
-    output->tries = 0;
-
-    do
-    {
-      if (output->tries > 0)
-        m_communication->SetLineTimeout(m_iRetryLineTimeout);
-      bReturn = m_communication->Write(output);
-      if (!bReturn)
-        Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
-    }while (!bReturn && output->transmit_timeout > 0 && output->NeedsRetry() && ++output->tries < output->maxTries);
+    if (!m_communication)
+      return false;
+    uint8_t iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
+    retVal = m_communication->Write(data, iMaxTries, m_iLineTimeout, m_iRetryLineTimeout);
   }
 
-  m_communication->SetLineTimeout(m_iStandardLineTimeout);
+  /* set to "not present" on failed ack */
+  if (retVal == ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED &&
+      data.destination != CECDEVICE_BROADCAST)
+    m_busDevices[data.destination]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
 
-  return bReturn;
+  return retVal == ADAPTER_MESSAGE_STATE_SENT_ACKED;
 }
 
 void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
@@ -918,57 +883,6 @@ void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode
   Transmit(command);
 }
 
-bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
-{
-  bool bEom(false);
-  bool bIsError(msg.IsError());
-
-  if (msg.IsEmpty())
-    return bEom;
-
-  switch(msg.Message())
-  {
-  case MSGCODE_FRAME_START:
-    {
-      m_currentframe.Clear();
-      if (msg.Size() >= 2)
-      {
-        m_currentframe.initiator   = msg.Initiator();
-        m_currentframe.destination = msg.Destination();
-        m_currentframe.ack         = msg.IsACK();
-        m_currentframe.eom         = msg.IsEOM();
-      }
-      if (m_currentframe.ack == 0x1)
-      {
-        m_lastInitiator = m_currentframe.initiator;
-        m_busDevices[m_lastInitiator]->GetHandler()->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
-      }
-    }
-    break;
-  case MSGCODE_RECEIVE_FAILED:
-    {
-      if (m_lastInitiator != CECDEVICE_UNKNOWN)
-        bIsError = m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
-    }
-    break;
-  case MSGCODE_FRAME_DATA:
-    {
-      if (msg.Size() >= 2)
-      {
-        m_currentframe.PushBack(msg[1]);
-        m_currentframe.eom = msg.IsEOM();
-      }
-      bEom = msg.IsEOM();
-    }
-    break;
-  default:
-    break;
-  }
-
-  CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
-  return bEom;
-}
-
 void CCECProcessor::ParseCommand(cec_command &command)
 {
   CStdString dataStr;
@@ -1433,11 +1347,9 @@ bool CCECProcessor::PingAdapter(void)
 void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
 {
   m_busDevices[initiator]->GetHandler()->HandlePoll(initiator, destination);
-  m_lastInitiator = initiator;
 }
 
-bool CCECProcessor::HandleReceiveFailed(void)
+bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
 {
-  return m_lastInitiator != CECDEVICE_UNKNOWN &&
-      !m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
+  return !m_busDevices[initiator]->GetHandler()->HandleReceiveFailed();
 }
index a78c41f9309c9518ad4d4809eddc0597ad758ed3..133a70b1b00ac12cbca3443aab17a73d5818d70a 100644 (file)
 
 #include <string>
 #include <cectypes.h>
-#include "adapter/AdapterCommunication.h"
+#include "platform/threads/threads.h"
 #include "platform/util/buffer.h"
 
-class CSerialPort;
-
 namespace CEC
 {
   class CLibCEC;
-  class CAdapterCommunication;
+  class IAdapterCommunication;
   class CCECBusDevice;
 
   class CCECProcessor : public PLATFORM::CThread
@@ -114,7 +112,6 @@ namespace CEC
       const char *ToString(const cec_vendor_id vendor);
 
       virtual bool Transmit(const cec_command &data);
-      virtual bool Transmit(CCECAdapterMessage *output);
       virtual void TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
 
       virtual bool ChangeDeviceType(cec_device_type from, cec_device_type to);
@@ -124,7 +121,7 @@ namespace CEC
       virtual bool StartBootloader(void);
       virtual bool PingAdapter(void);
       virtual void HandlePoll(cec_logical_address initiator, cec_logical_address destination);
-      virtual bool HandleReceiveFailed(void);
+      virtual bool HandleReceiveFailed(cec_logical_address initiator);
 
       CCECBusDevice *  m_busDevices[16];
       PLATFORM::CMutex m_transmitMutex;
@@ -144,21 +141,18 @@ namespace CEC
       bool FindLogicalAddressAudioSystem(void);
 
       void LogOutput(const cec_command &data);
-      bool ParseMessage(const CCECAdapterMessage &msg);
       void ParseCommand(cec_command &command);
 
       bool                                m_bStarted;
       bool                                m_bInitialised;
       uint8_t                             m_iHDMIPort;
       cec_logical_address                 m_iBaseDevice;
-      cec_command                         m_currentframe;
       cec_logical_addresses               m_logicalAddresses;
-      cec_logical_address                 m_lastInitiator;
       std::string                         m_strDeviceName;
       cec_device_type_list                m_types;
       PLATFORM::CMutex                    m_mutex;
       PLATFORM::CCondition                m_startCondition;
-      CAdapterCommunication*              m_communication;
+      IAdapterCommunication *             m_communication;
       CLibCEC*                            m_controller;
       bool                                m_bMonitor;
       PLATFORM::SyncedBuffer<cec_command> m_commandBuffer;
index 0048fb20d52f19f254c42a55ba0de47dfc4295b4..2562cfd7026df0d957b903a5633a15cde9ad1f2a 100644 (file)
@@ -32,8 +32,7 @@
 
 #include "LibCEC.h"
 
-#include "adapter/AdapterCommunication.h"
-#include "adapter/AdapterDetection.h"
+#include "adapter/USBCECAdapterDetection.h"
 #include "CECProcessor.h"
 #include "devices/CECBusDevice.h"
 #include "platform/util/timeutils.h"
@@ -112,7 +111,7 @@ int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const ch
     strDebug.Format("trying to autodetect all CEC adapters");
   AddLog(CEC_LOG_DEBUG, strDebug);
 
-  return CAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
+  return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
 }
 
 bool CLibCEC::PingAdapter(void)
index cd20766bbaa11b3fc27a9be65cfa0b2095514619..5df7c60021140b6a677ab0190956f5a8d93d172e 100644 (file)
@@ -11,8 +11,8 @@ pkgconfig_DATA = libcec.pc
 libcec_la_SOURCES = CECProcessor.cpp \
                     LibCEC.cpp \
                     LibCECC.cpp \
-                    adapter/AdapterCommunication.cpp \
-                    adapter/AdapterDetection.cpp \
+                    adapter/USBCECAdapterCommunication.cpp \
+                    adapter/USBCECAdapterDetection.cpp \
                     devices/CECAudioSystem.cpp \
                     devices/CECBusDevice.cpp \
                     devices/CECPlaybackDevice.cpp \
index 54f30cef3265b8ff32d43b0f6f3f236e3632d38c..cec8501a0c3e22a051fee4e3709dd758281577bf 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
-#include <cectypes.h>
-#include "../platform/threads/threads.h"
-#include "../platform/util/buffer.h"
 #include "../platform/util/StdString.h"
 
-namespace PLATFORM
-{
-  class ISocket;
-}
-
 namespace CEC
 {
-  class CCECProcessor;
-  class CCECAdapterMessage;
+  typedef enum cec_adapter_message_state
+  {
+    ADAPTER_MESSAGE_STATE_UNKNOWN = 0,          /**< the initial state */
+    ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT,   /**< waiting in the send queue of the adapter, or timed out */
+    ADAPTER_MESSAGE_STATE_SENT,                 /**< sent and waiting on an ACK */
+    ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED,       /**< sent, but failed to ACK */
+    ADAPTER_MESSAGE_STATE_SENT_ACKED,           /**< sent, and ACK received */
+    ADAPTER_MESSAGE_STATE_INCOMING,             /**< received from another device */
+    ADAPTER_MESSAGE_STATE_ERROR                 /**< an error occured */
+  } cec_adapter_message_state;
 
-  class CAdapterCommunication : private PLATFORM::CThread
+  class IAdapterCommunication
   {
   public:
-    CAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
-    virtual ~CAdapterCommunication();
+    /*!
+     * @brief Open a connection to the CEC adapter
+     * @param iTimeoutMs Connection timeout in ms
+     * @return True when connected, false otherwise
+     */
+    virtual bool Open(uint32_t iTimeoutMs = 10000) = 0;
+
+    /*!
+     * @brief Close an open connection
+     */
+    virtual void Close(void) = 0;
+
+    /*!
+     * @return True when the connection is open, false otherwise
+     */
+    virtual bool IsOpen(void) = 0;
+
+    /*!
+     * @return The last error message, or an empty string if there was none
+     */
+    virtual CStdString GetError(void) const = 0;
+
+    /*!
+     * @brief Reads one cec_command from the adapter
+     * @param command The command that will be read (output)
+     * @param iTimeout The read timeout
+     * @return True when a command has been read, false otherwise.
+     */
+    virtual bool Read(cec_command &command, uint32_t iTimeout) = 0;
 
-    bool Open(uint32_t iTimeoutMs = 10000);
-    bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000);
-    bool Write(CCECAdapterMessage *data);
-    void Close(void);
-    bool IsOpen(void);
-    CStdString GetError(void) const;
+    /*!
+     * @brief Write a cec_command to the adapter
+     * @param data The command to write
+     * @param iMaxTries The maximum number of tries
+     * @param iLineTimeout The line timeout for the first try
+     * @param iRetryLineTimeout The line timeout for each next try
+     * @return The last state of the transmitted command
+     */
+    virtual cec_adapter_message_state Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout = 3, uint8_t iRetryLineTimeout = 3) = 0;
 
-    void *Process(void);
+    /*!
+     * @brief Change the current line timeout on the CEC bus
+     * @param iTimeout The new timeout
+     * @return True when set, false otherwise
+     */
+    virtual bool SetLineTimeout(uint8_t iTimeout) = 0;
 
-    bool SetLineTimeout(uint8_t iTimeout);
-    bool StartBootloader(void);
-    bool SetAckMask(uint16_t iMask);
-    bool PingAdapter(void);
-    uint16_t GetFirmwareVersion(void);
+    /*!
+     * @brief Put the device in bootloader mode (which will disrupt CEC communication when it succeeds)
+     * @return True when the bootloader command has been sent, false otherwise.
+     */
+    virtual bool StartBootloader(void) = 0;
 
-    bool WaitForAck(CCECAdapterMessage &message);
+    /*!
+     * @brief Change the ACK-mask of the device, the mask for logical addresses to which the CEC device should ACK
+     * @param iMask The new mask
+     * @return True when set, false otherwise.
+     */
+    virtual bool SetAckMask(uint16_t iMask) = 0;
 
-  private:
-    void SendMessageToAdapter(CCECAdapterMessage *msg);
-    void WriteNextCommand(void);
-    void AddData(uint8_t *data, size_t iLen);
-    bool ReadFromDevice(uint32_t iTimeout);
+    /*!
+     * @brief Check whether the CEC adapter responds
+     * @return True when the ping was sent and acked, false otherwise.
+     */
+    virtual bool PingAdapter(void) = 0;
 
-    PLATFORM::ISocket *                          m_port;
-    CCECProcessor *                              m_processor;
-    PLATFORM::SyncedBuffer<uint8_t>              m_inBuffer;
-    PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_outBuffer;
-    PLATFORM::CMutex                             m_mutex;
-    PLATFORM::CCondition                         m_rcvCondition;
-    uint8_t                                      m_iLineTimeout;
-    uint16_t                                     m_iFirmwareVersion;
+    /*!
+     * @return The firmware version of this CEC adapter.
+     */
+    virtual uint16_t GetFirmwareVersion(void) = 0;
   };
 };
similarity index 62%
rename from src/lib/adapter/AdapterCommunication.cpp
rename to src/lib/adapter/USBCECAdapterCommunication.cpp
index c0f9ea165a98ebb1823a3cd6248cebf0309c22d3..0134751d31b2b05f8eb4f88f3320ff9b09fba686 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
-#include "AdapterCommunication.h"
-
-#include "AdapterMessage.h"
-#include "../CECProcessor.h"
+#include "USBCECAdapterCommunication.h"
 #include "../platform/sockets/serialport.h"
 #include "../platform/util/timeutils.h"
 #include "../LibCEC.h"
+#include "../CECProcessor.h"
 
 using namespace std;
 using namespace CEC;
 using namespace PLATFORM;
 
-CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate /* = 38400 */) :
+CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate /* = 38400 */) :
     m_port(NULL),
     m_processor(processor),
     m_iLineTimeout(0),
-    m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN)
+    m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN),
+    m_lastInitiator(CECDEVICE_UNKNOWN),
+    m_bNextIsEscaped(false),
+    m_bGotStart(false)
 {
   m_port = new PLATFORM::CSerialPort(strPort, iBaudRate);
 }
 
-CAdapterCommunication::~CAdapterCommunication(void)
+CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
 {
   Close();
 
@@ -62,7 +63,7 @@ CAdapterCommunication::~CAdapterCommunication(void)
   }
 }
 
-bool CAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
 {
   uint64_t iNow = GetTimeMs();
   uint64_t iTimeout = iNow + iTimeoutMs;
@@ -122,14 +123,14 @@ bool CAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
   return false;
 }
 
-void CAdapterCommunication::Close(void)
+void CUSBCECAdapterCommunication::Close(void)
 {
   CLockObject lock(m_mutex);
   m_rcvCondition.Broadcast();
   StopThread();
 }
 
-void *CAdapterCommunication::Process(void)
+void *CUSBCECAdapterCommunication::Process(void)
 {
   while (!IsStopped())
   {
@@ -145,7 +146,36 @@ void *CAdapterCommunication::Process(void)
   return NULL;
 }
 
-bool CAdapterCommunication::Write(CCECAdapterMessage *data)
+cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout /* = 3 */, uint8_t iRetryLineTimeout /* = 3 */)
+{
+  cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
+
+  CCECAdapterMessage *output = new CCECAdapterMessage(data);
+
+  /* set the number of retries */
+  if (data.opcode == CEC_OPCODE_NONE) //TODO
+    output->maxTries = 1;
+  else if (data.initiator != CECDEVICE_BROADCAST)
+    output->maxTries = iMaxTries;
+
+  output->lineTimeout = iLineTimeout;
+  output->retryTimeout = iRetryLineTimeout;
+  output->tries = 0;
+
+  bool bRetry(true);
+  while (bRetry && ++output->tries < output->maxTries)
+  {
+    bRetry = (!Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
+    if (bRetry)
+      Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+  }
+  retVal = output->state;
+
+  delete output;
+  return retVal;
+}
+
+bool CUSBCECAdapterCommunication::Write(CCECAdapterMessage *data)
 {
   bool bReturn(false);
 
@@ -180,69 +210,53 @@ bool CAdapterCommunication::Write(CCECAdapterMessage *data)
   return bReturn;
 }
 
-bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::Read(cec_command &command, uint32_t iTimeout)
 {
-  CLockObject lock(m_mutex);
-
-  msg.Clear();
-  uint64_t iNow = GetTimeMs();
-  uint64_t iTarget = iNow + iTimeout;
-  bool bGotFullMessage(false);
-  bool bNextIsEscaped(false);
-  bool bGotStart(false);
-
-  while(!bGotFullMessage && iNow < iTarget)
+  CCECAdapterMessage msg;
+  if (Read(msg, iTimeout))
   {
-    uint8_t buf = 0;
-    if (!m_inBuffer.Pop(buf))
+    if (ParseMessage(msg))
     {
-      if (!m_rcvCondition.Wait(m_mutex, (uint32_t) (iTarget - iNow)))
-        return false;
+      command = m_currentframe;
+      m_currentframe.Clear();
+      return true;
     }
+  }
+  return false;
+}
 
-    if (!bGotStart)
-    {
-      if (buf == MSGSTART)
-        bGotStart = true;
-      continue;
-    }
-    else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove
-    {
-      if (msg.Size() > 0)
-        CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
-      msg.Clear();
-      bGotStart = true;
-    }
+bool CUSBCECAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
+{
+  CLockObject lock(m_mutex);
 
-    if (buf == MSGEND)
-    {
-      bGotFullMessage = true;
-    }
-    else if (bNextIsEscaped)
-    {
-      msg.PushBack(buf + (uint8_t)ESCOFFSET);
-      bNextIsEscaped = false;
-    }
-    else if (buf == MSGESC)
-      bNextIsEscaped = true;
-    else
-      msg.PushBack(buf);
-  }
+  msg.Clear();
+  CCECAdapterMessage *buf(NULL);
 
-  if (bGotFullMessage)
-    msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
+  if (!m_inBuffer.Pop(buf))
+  {
+    if (!m_rcvCondition.Wait(m_mutex, iTimeout))
+      return false;
+    m_inBuffer.Pop(buf);
+  }
 
-  return bGotFullMessage;
+  if (buf)
+  {
+    msg.packet = buf->packet;
+    msg.state = msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
+    delete buf;
+    return true;
+  }
+  return false;
 }
 
-CStdString CAdapterCommunication::GetError(void) const
+CStdString CUSBCECAdapterCommunication::GetError(void) const
 {
   CStdString strError;
   strError = m_port->GetError();
   return strError;
 }
 
-bool CAdapterCommunication::StartBootloader(void)
+bool CUSBCECAdapterCommunication::StartBootloader(void)
 {
   bool bReturn(false);
   if (!IsRunning())
@@ -264,7 +278,7 @@ bool CAdapterCommunication::StartBootloader(void)
   return bReturn;
 }
 
-bool CAdapterCommunication::PingAdapter(void)
+bool CUSBCECAdapterCommunication::PingAdapter(void)
 {
   bool bReturn(false);
   if (!IsRunning())
@@ -285,7 +299,59 @@ bool CAdapterCommunication::PingAdapter(void)
   return bReturn;
 }
 
-uint16_t CAdapterCommunication::GetFirmwareVersion(void)
+bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
+{
+  bool bEom(false);
+  bool bIsError(msg.IsError());
+
+  if (msg.IsEmpty())
+    return bEom;
+
+  switch(msg.Message())
+  {
+  case MSGCODE_FRAME_START:
+    {
+      m_currentframe.Clear();
+      if (msg.Size() >= 2)
+      {
+        m_currentframe.initiator   = msg.Initiator();
+        m_currentframe.destination = msg.Destination();
+        m_currentframe.ack         = msg.IsACK();
+        m_currentframe.eom         = msg.IsEOM();
+      }
+      if (m_currentframe.ack == 0x1)
+      {
+        m_lastInitiator = m_currentframe.initiator;
+        m_processor->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
+      }
+    }
+    break;
+  case MSGCODE_RECEIVE_FAILED:
+    {
+      m_currentframe.Clear();
+      if (m_lastInitiator != CECDEVICE_UNKNOWN)
+        bIsError = m_processor->HandleReceiveFailed(m_lastInitiator);
+    }
+    break;
+  case MSGCODE_FRAME_DATA:
+    {
+      if (msg.Size() >= 2)
+      {
+        m_currentframe.PushBack(msg[1]);
+        m_currentframe.eom = msg.IsEOM();
+      }
+      bEom = msg.IsEOM();
+    }
+    break;
+  default:
+    break;
+  }
+
+  CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
+  return bEom;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
 {
   uint16_t iReturn(m_iFirmwareVersion);
   if (!IsRunning())
@@ -318,29 +384,32 @@ uint16_t CAdapterCommunication::GetFirmwareVersion(void)
   return iReturn;
 }
 
-bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
+bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
 {
-  bool bReturn(m_iLineTimeout != iTimeout);
-
-  if (!bReturn)
-  {
-    CCECAdapterMessage *output = new CCECAdapterMessage;
-
-    output->PushBack(MSGSTART);
-    output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME);
-    output->PushEscaped(iTimeout);
-    output->PushBack(MSGEND);
-    output->isTransmission = false;
-
-    if ((bReturn = Write(output)) == false)
-      CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the idletime");
-    delete output;
-  }
-
-  return bReturn;
+  m_iLineTimeout = iTimeout;
+  return true;
+  //TODO
+//  bool bReturn(m_iLineTimeout != iTimeout);
+//
+//  if (!bReturn)
+//  {
+//    CCECAdapterMessage *output = new CCECAdapterMessage;
+//
+//    output->PushBack(MSGSTART);
+//    output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME);
+//    output->PushEscaped(iTimeout);
+//    output->PushBack(MSGEND);
+//    output->isTransmission = false;
+//
+//    if ((bReturn = Write(output)) == false)
+//      CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the idletime");
+//    delete output;
+//  }
+//
+//  return bReturn;
 }
 
-bool CAdapterCommunication::SetAckMask(uint16_t iMask)
+bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
 {
   bool bReturn(false);
   CStdString strLog;
@@ -363,12 +432,12 @@ bool CAdapterCommunication::SetAckMask(uint16_t iMask)
   return bReturn;
 }
 
-bool CAdapterCommunication::IsOpen(void)
+bool CUSBCECAdapterCommunication::IsOpen(void)
 {
   return !IsStopped() && m_port->IsOpen() && IsRunning();
 }
 
-bool CAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
+bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
 {
   bool bError(false);
   bool bTransmitSucceeded(false);
@@ -393,12 +462,14 @@ bool CAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
     if (msg.Message() == MSGCODE_FRAME_START && msg.IsACK())
     {
       m_processor->HandlePoll(msg.Initiator(), msg.Destination());
+      m_lastInitiator = msg.Initiator();
       iNow = GetTimeMs();
       continue;
     }
 
     if (msg.Message() == MSGCODE_RECEIVE_FAILED &&
-        m_processor->HandleReceiveFailed())
+        m_lastInitiator != CECDEVICE_UNKNOWN &&
+        m_processor->HandleReceiveFailed(m_lastInitiator))
     {
       iNow = GetTimeMs();
       continue;
@@ -439,16 +510,50 @@ bool CAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
   return bTransmitSucceeded && !bError;
 }
 
-void CAdapterCommunication::AddData(uint8_t *data, size_t iLen)
+void CUSBCECAdapterCommunication::AddData(uint8_t *data, size_t iLen)
 {
   CLockObject lock(m_mutex);
   for (size_t iPtr = 0; iPtr < iLen; iPtr++)
-    m_inBuffer.Push(data[iPtr]);
-
-  m_rcvCondition.Signal();
+  {
+    if (!m_bGotStart)
+    {
+      if (data[iPtr] == MSGSTART)
+        m_bGotStart = true;
+    }
+    else if (data[iPtr] == MSGSTART) //we found a msgstart before msgend, this is not right, remove
+    {
+      if (m_currentAdapterMessage.Size() > 0)
+        CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+      m_currentAdapterMessage.Clear();
+      m_bGotStart = true;
+    }
+    else if (data[iPtr] == MSGEND)
+    {
+      CCECAdapterMessage *newMessage = new CCECAdapterMessage;
+      newMessage->packet = m_currentAdapterMessage.packet;
+      m_inBuffer.Push(newMessage);
+      m_currentAdapterMessage.Clear();
+      m_bGotStart = false;
+      m_bNextIsEscaped = false;
+      m_rcvCondition.Signal();
+    }
+    else if (m_bNextIsEscaped)
+    {
+      m_currentAdapterMessage.PushBack(data[iPtr] + (uint8_t)ESCOFFSET);
+      m_bNextIsEscaped = false;
+    }
+    else if (data[iPtr] == MSGESC)
+    {
+      m_bNextIsEscaped = true;
+    }
+    else
+    {
+      m_currentAdapterMessage.PushBack(data[iPtr]);
+    }
+  }
 }
 
-bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
+bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
 {
   ssize_t iBytesRead;
   uint8_t buff[256];
@@ -470,10 +575,15 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
   return iBytesRead > 0;
 }
 
-void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
+void CUSBCECAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
 {
   CLockObject adapterLock(m_mutex);
   CLockObject lock(msg->mutex);
+  if (msg->tries == 1)
+    SetLineTimeout(msg->lineTimeout);
+  else
+    SetLineTimeout(msg->retryTimeout);
+
   if (m_port->Write(msg->packet.data, msg->Size()) != (ssize_t) msg->Size())
   {
     CStdString strError;
@@ -489,7 +599,7 @@ void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
   msg->condition.Signal();
 }
 
-void CAdapterCommunication::WriteNextCommand(void)
+void CUSBCECAdapterCommunication::WriteNextCommand(void)
 {
   CCECAdapterMessage *msg(NULL);
   if (m_outBuffer.Pop(msg))
diff --git a/src/lib/adapter/USBCECAdapterCommunication.h b/src/lib/adapter/USBCECAdapterCommunication.h
new file mode 100644 (file)
index 0000000..7aa0350
--- /dev/null
@@ -0,0 +1,94 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 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       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include <cectypes.h>
+#include "../platform/threads/threads.h"
+#include "../platform/util/buffer.h"
+#include "AdapterCommunication.h"
+#include "USBCECAdapterMessage.h"
+
+namespace PLATFORM
+{
+  class ISocket;
+}
+
+namespace CEC
+{
+  class CCECProcessor;
+
+  class CUSBCECAdapterCommunication : public IAdapterCommunication, private PLATFORM::CThread
+  {
+  public:
+    CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400);
+    virtual ~CUSBCECAdapterCommunication();
+
+    virtual bool Open(uint32_t iTimeoutMs = 10000);
+    virtual void Close(void);
+    virtual bool IsOpen(void);
+    virtual CStdString GetError(void) const;
+
+    bool Read(cec_command &command, uint32_t iTimeout);
+    cec_adapter_message_state Write(const cec_command &data, uint8_t iMaxTries, uint8_t iLineTimeout = 3, uint8_t iRetryLineTimeout = 3);
+
+    virtual bool SetLineTimeout(uint8_t iTimeout);
+    virtual bool StartBootloader(void);
+    virtual bool SetAckMask(uint16_t iMask);
+    virtual bool PingAdapter(void);
+    virtual uint16_t GetFirmwareVersion(void);
+
+    void *Process(void);
+  private:
+    bool Write(CCECAdapterMessage *data);
+    bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000);
+    bool ParseMessage(const CCECAdapterMessage &msg);
+    void SendMessageToAdapter(CCECAdapterMessage *msg);
+    void WriteNextCommand(void);
+    void AddData(uint8_t *data, size_t iLen);
+    bool ReadFromDevice(uint32_t iTimeout);
+    bool WaitForAck(CCECAdapterMessage &message);
+
+    PLATFORM::ISocket *                          m_port;
+    CCECProcessor *                              m_processor;
+    PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_inBuffer;
+    PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_outBuffer;
+    PLATFORM::CMutex                             m_mutex;
+    PLATFORM::CCondition                         m_rcvCondition;
+    uint8_t                                      m_iLineTimeout;
+    uint16_t                                     m_iFirmwareVersion;
+    cec_command                                  m_currentframe;
+    cec_logical_address                          m_lastInitiator;
+    CCECAdapterMessage                           m_currentAdapterMessage;
+    bool                                         m_bNextIsEscaped;
+    bool                                         m_bGotStart;
+  };
+};
similarity index 98%
rename from src/lib/adapter/AdapterDetection.cpp
rename to src/lib/adapter/USBCECAdapterDetection.cpp
index 10b07493702f7feb3102141cc4605eb8183e42c6..0d9f8b3d9c04b19738f560be47d1cb57ae43f95b 100644 (file)
@@ -30,7 +30,7 @@
  *     http://www.pulse-eight.net/
  */
 
-#include "AdapterDetection.h"
+#include "USBCECAdapterDetection.h"
 #include "../platform/util/StdString.h"
 
 #if defined(__APPLE__)
@@ -112,7 +112,7 @@ bool FindComPort(CStdString &strLocation)
 }
 #endif
 
-uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
 {
   uint8_t iFound(0);
 
similarity index 97%
rename from src/lib/adapter/AdapterDetection.h
rename to src/lib/adapter/USBCECAdapterDetection.h
index 6478156c8bacacddfab66faf508babacfcd8dc44..45b641b476a47593938bec590e0097243bd7ff63 100644 (file)
@@ -35,7 +35,7 @@
 
 namespace CEC
 {
-  class CAdapterDetection
+  class CUSBCECAdapterDetection
   {
   public:
     static uint8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL); 
similarity index 96%
rename from src/lib/adapter/AdapterMessage.h
rename to src/lib/adapter/USBCECAdapterMessage.h
index 2ba59a1946d85f447c44a8977f2d6e0385e53eba..169c115dc4fdef55ca8b34637e3951ec089e36cb 100644 (file)
 
 namespace CEC
 {
-  typedef enum cec_adapter_message_state
-  {
-    ADAPTER_MESSAGE_STATE_UNKNOWN = 0,
-    ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT,
-    ADAPTER_MESSAGE_STATE_SENT,
-    ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED,
-    ADAPTER_MESSAGE_STATE_SENT_ACKED,
-    ADAPTER_MESSAGE_STATE_INCOMING,
-    ADAPTER_MESSAGE_STATE_ERROR
-  } cec_adapter_message_state;
-
-
   class CCECAdapterMessage
   {
   public:
@@ -265,6 +253,8 @@ namespace CEC
       reply               = MSGCODE_NOTHING;
       isTransmission      = true;
       expectControllerAck = true;
+      lineTimeout         = 3;
+      retryTimeout        = 3;
     }
 
     void Shift(uint8_t iShiftBy)
@@ -358,6 +348,8 @@ namespace CEC
     int32_t                   transmit_timeout;
     bool                      isTransmission;
     bool                      expectControllerAck;
+    uint8_t                   lineTimeout;
+    uint8_t                   retryTimeout;
     PLATFORM::CMutex          mutex;
     PLATFORM::CCondition      condition;
   };