cec: split up CEC processing and the public interface. removed obsolete methods from...
[deb_libcec.git] / src / lib / CECProcessor.cpp
similarity index 54%
rename from src/lib/CECParser.cpp
rename to src/lib/CECProcessor.cpp
index a86da1a58f3411c7e23193ddb852cd971209e48e..f3b89c3e3fe7e2e1382767430e063ad5e3451c06 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
-#include "CECParser.h"
+#include "CECProcessor.h"
 
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <sys/stat.h>
+#include "AdapterCommunication.h"
+#include "LibCEC.h"
 #include "util/StdString.h"
-#include "libPlatform/serialport.h"
-#include "util/threads.h"
 #include "util/timeutils.h"
-#include "CECDetect.h"
-#include "AdapterCommunication.h"
 
 using namespace CEC;
 using namespace std;
 
-#define CEC_MAX_RETRY 5
-#define CEC_BUTTON_TIMEOUT 500
-
-/*!
- * ICECDevice implementation
- */
-//@{
-CCECParser::CCECParser(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
-    m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
     m_physicaladdress(iPhysicalAddress),
     m_iLogicalAddress(iLogicalAddress),
-    m_strDeviceName(strDeviceName)
+    m_strDeviceName(strDeviceName),
+    m_communication(serComm),
+    m_controller(controller)
 {
-  m_communication = new CAdapterCommunication(this);
 }
 
-CCECParser::~CCECParser(void)
+CCECProcessor::~CCECProcessor(void)
 {
-  Close();
-  m_communication->Close();
-  delete m_communication;
+  StopThread();
+  m_communication = NULL;
+  m_controller = NULL;
 }
 
-bool CCECParser::Open(const char *strPort, int iTimeoutMs /* = 10000 */)
+bool CCECProcessor::Start(void)
 {
-  if (!m_communication)
-    return false;
-
-  if (m_communication->IsOpen())
-  {
-    AddLog(CEC_LOG_ERROR, "connection already open");
+  if (!m_communication || !m_communication->IsOpen())
     return false;
-  }
-
-  if (!m_communication->Open(strPort, 38400, iTimeoutMs))
-  {
-    AddLog(CEC_LOG_ERROR, "could not open a connection");
-    return false;
-  }
 
   if (!SetLogicalAddress(m_iLogicalAddress))
   {
-    AddLog(CEC_LOG_ERROR, "could not set the logical address");
+    m_controller->AddLog(CEC_LOG_ERROR, "could not set the logical address");
     return false;
   }
 
   if (CreateThread())
     return true;
   else
-    AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+    m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
 
   return false;
 }
 
-void CCECParser::Close(void)
+void *CCECProcessor::Process(void)
 {
-  StopThread();
-}
-
-void *CCECParser::Process(void)
-{
-  AddLog(CEC_LOG_DEBUG, "processor thread started");
+  m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
 
-  int64_t now = GetTimeMs();
   while (!m_bStop)
   {
     bool bParseFrame(false);
@@ -124,103 +92,48 @@ void *CCECParser::Process(void)
     if (bParseFrame)
       ParseCurrentFrame();
 
-    now = GetTimeMs();
-    CheckKeypressTimeout(now);
+    m_controller->CheckKeypressTimeout();
     CCondition::Sleep(50);
   }
 
-  AddLog(CEC_LOG_DEBUG, "processor thread terminated");
+  m_controller->AddLog(CEC_LOG_DEBUG, "processor thread terminated");
   return NULL;
 }
 
-bool CCECParser::Ping(void)
-{
-  if (!IsRunning())
-    return false;
-
-  AddLog(CEC_LOG_DEBUG, "sending ping");
-  cec_frame output;
-  output.push_back(MSGSTART);
-  PushEscaped(output, MSGCODE_PING);
-  output.push_back(MSGEND);
-
-  if (!TransmitFormatted(output, false))
-  {
-    AddLog(CEC_LOG_ERROR, "could not send ping command");
-    return false;
-  }
-
-  AddLog(CEC_LOG_DEBUG, "ping tranmitted");
-
-  // TODO check for pong
-  return true;
-}
-
-bool CCECParser::StartBootloader(void)
-{
-  if (!IsRunning())
-    return false;
-
-  AddLog(CEC_LOG_DEBUG, "starting the bootloader");
-  cec_frame output;
-  output.push_back(MSGSTART);
-  PushEscaped(output, MSGCODE_START_BOOTLOADER);
-  output.push_back(MSGEND);
-
-  if (!TransmitFormatted(output, false))
-  {
-    AddLog(CEC_LOG_ERROR, "could not start the bootloader");
-    return false;
-  }
-
-  AddLog(CEC_LOG_DEBUG, "bootloader start command transmitted");
-  return true;
-}
-
-uint8_t CCECParser::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */)
-{
-  return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
-}
-
-bool CCECParser::PowerOffDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
-{
-  return StandbyDevices(address);
-}
-
-bool CCECParser::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
+bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
 {
   if (!IsRunning())
     return false;
 
   CStdString strLog;
   strLog.Format("powering on devices with logical address %d", (int8_t)address);
-  AddLog(CEC_LOG_DEBUG, strLog.c_str());
+  m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
   cec_frame frame;
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_TEXT_VIEW_ON);
   return Transmit(frame);
 }
 
-bool CCECParser::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
 {
   if (!IsRunning())
     return false;
 
   CStdString strLog;
   strLog.Format("putting all devices with logical address %d in standby mode", (int8_t)address);
-  AddLog(CEC_LOG_DEBUG, strLog.c_str());
+  m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
   cec_frame frame;
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_STANDBY);
   return Transmit(frame);
 }
 
-bool CCECParser::SetActiveView(void)
+bool CCECProcessor::SetActiveView(void)
 {
   if (!IsRunning())
     return false;
 
-  AddLog(CEC_LOG_DEBUG, "setting active view");
+  m_controller->AddLog(CEC_LOG_DEBUG, "setting active view");
   cec_frame frame;
   frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
   frame.push_back(CEC_OPCODE_ACTIVE_SOURCE);
@@ -229,12 +142,12 @@ bool CCECParser::SetActiveView(void)
   return Transmit(frame);
 }
 
-bool CCECParser::SetInactiveView(void)
+bool CCECProcessor::SetInactiveView(void)
 {
   if (!IsRunning())
     return false;
 
-  AddLog(CEC_LOG_DEBUG, "setting inactive view");
+  m_controller->AddLog(CEC_LOG_DEBUG, "setting inactive view");
   cec_frame frame;
   frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
   frame.push_back(CEC_OPCODE_INACTIVE_SOURCE);
@@ -243,25 +156,78 @@ bool CCECParser::SetInactiveView(void)
   return Transmit(frame);
 }
 
-bool CCECParser::GetNextLogMessage(cec_log_message *message)
+bool CCECProcessor::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
 {
-  return m_logBuffer.Pop(*message);
+  CStdString txStr = "transmit ";
+  for (unsigned int i = 0; i < data.size(); i++)
+    txStr.AppendFormat(" %02x", data[i]);
+  m_controller->AddLog(CEC_LOG_DEBUG, txStr.c_str());
+
+  if (data.empty())
+  {
+    m_controller->AddLog(CEC_LOG_WARNING, "transmit buffer is empty");
+    return false;
+  }
+
+  cec_frame output;
+
+  //set ack polarity to high when transmitting to the broadcast address
+  //set ack polarity low when transmitting to any other address
+  output.push_back(MSGSTART);
+  CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_ACK_POLARITY);
+
+  if ((data[0] & 0xF) == 0xF)
+    CAdapterCommunication::PushEscaped(output, CEC_TRUE);
+  else
+    CAdapterCommunication::PushEscaped(output, CEC_FALSE);
+
+  output.push_back(MSGEND);
+
+  for (unsigned int i = 0; i < data.size(); i++)
+  {
+    output.push_back(MSGSTART);
+
+    if (i == data.size() - 1)
+      CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_EOM);
+    else
+      CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT);
+
+    CAdapterCommunication::PushEscaped(output, data[i]);
+
+    output.push_back(MSGEND);
+  }
+
+  return TransmitFormatted(output, bWaitForAck);
 }
 
-bool CCECParser::GetNextKeypress(cec_keypress *key)
+bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
 {
-  return IsRunning() ? m_keyBuffer.Pop(*key) : false;
+  CStdString strLog;
+  strLog.Format("setting logical address to %d", iLogicalAddress);
+  m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
+
+  m_iLogicalAddress = iLogicalAddress;
+  return m_communication && m_communication->SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
 }
 
-bool CCECParser::GetNextCommand(cec_command *command)
+bool CCECProcessor::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */)
 {
-  return IsRunning() ? m_commandBuffer.Pop(*command) : false;
+  CLockObject lock(&m_mutex);
+  if (!m_communication || !m_communication->Write(data))
+    return false;
+
+  if (bWaitForAck && !WaitForAck())
+  {
+    m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ACK");
+    return false;
+  }
+
+  return true;
 }
-//@}
 
-void CCECParser::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
+void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
 {
-  AddLog(CEC_LOG_DEBUG, "transmitting abort message");
+  m_controller->AddLog(CEC_LOG_DEBUG, "transmitting abort message");
   cec_frame frame;
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_FEATURE_ABORT);
@@ -270,23 +236,23 @@ void CCECParser::TransmitAbort(cec_logical_address address, cec_opcode opcode, E
   Transmit(frame);
 }
 
-void CCECParser::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
+void CCECProcessor::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
 {
   cec_frame frame;
-  AddLog(CEC_LOG_NOTICE, "reporting CEC version as 1.3a");
+  m_controller->AddLog(CEC_LOG_NOTICE, "reporting CEC version as 1.3a");
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_CEC_VERSION);
   frame.push_back(CEC_VERSION_1_3A);
   Transmit(frame);
 }
 
-void CCECParser::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
+void CCECProcessor::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
 {
   cec_frame frame;
   if (bOn)
-    AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
   else
-    AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
 
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_REPORT_POWER_STATUS);
@@ -294,13 +260,13 @@ void CCECParser::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV *
   Transmit(frame);
 }
 
-void CCECParser::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
+void CCECProcessor::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
 {
   cec_frame frame;
   if (bActive)
-    AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
   else
-    AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
+    m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
 
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_MENU_STATUS);
@@ -308,19 +274,19 @@ void CCECParser::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV *
   Transmit(frame);
 }
 
-void CCECParser::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
+void CCECProcessor::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
 {
-  AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
+  m_controller->AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
   TransmitAbort(address, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
 }
 
-void CCECParser::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
+void CCECProcessor::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
 {
   cec_frame frame;
   const char *osdname = m_strDeviceName.c_str();
   CStdString strLog;
   strLog.Format("reporting OSD name as %s", osdname);
-  AddLog(CEC_LOG_NOTICE, strLog.c_str());
+  m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
   frame.push_back(GetSourceDestination(address));
   frame.push_back(CEC_OPCODE_SET_OSD_NAME);
 
@@ -330,12 +296,12 @@ void CCECParser::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
   Transmit(frame);
 }
 
-void CCECParser::ReportPhysicalAddress(void)
+void CCECProcessor::ReportPhysicalAddress(void)
 {
   cec_frame frame;
   CStdString strLog;
   strLog.Format("reporting physical address as %04x", m_physicaladdress);
-  AddLog(CEC_LOG_NOTICE, strLog.c_str());
+  m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
   frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
   frame.push_back(CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
   frame.push_back((m_physicaladdress >> 8) & 0xFF);
@@ -344,10 +310,10 @@ void CCECParser::ReportPhysicalAddress(void)
   Transmit(frame);
 }
 
-void CCECParser::BroadcastActiveSource(void)
+void CCECProcessor::BroadcastActiveSource(void)
 {
   cec_frame frame;
-  AddLog(CEC_LOG_NOTICE, "broadcasting active source");
+  m_controller->AddLog(CEC_LOG_NOTICE, "broadcasting active source");
   frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
   frame.push_back(CEC_OPCODE_ACTIVE_SOURCE);
   frame.push_back((m_physicaladdress >> 8) & 0xFF);
@@ -355,69 +321,12 @@ void CCECParser::BroadcastActiveSource(void)
   Transmit(frame);
 }
 
-bool CCECParser::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */)
-{
-  CLockObject lock(&m_mutex);
-  if (!m_communication || !m_communication->Write(data))
-  {
-    return false;
-  }
-
-  CCondition::Sleep((int) data.size() * 24 /*data*/ + 5 /*start bit (4.5 ms)*/ + 50 /* to be on the safe side */);
-  if (bWaitForAck && !WaitForAck())
-  {
-    AddLog(CEC_LOG_DEBUG, "did not receive ACK");
-    return false;
-  }
-
-  return true;
-}
-
-bool CCECParser::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
+uint8_t CCECProcessor::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */) const
 {
-  CStdString txStr = "transmit ";
-  for (unsigned int i = 0; i < data.size(); i++)
-    txStr.AppendFormat(" %02x", data[i]);
-  AddLog(CEC_LOG_DEBUG, txStr.c_str());
-
-  if (data.empty())
-  {
-    AddLog(CEC_LOG_WARNING, "transmit buffer is empty");
-    return false;
-  }
-
-  cec_frame output;
-
-  //set ack polarity to high when transmitting to the broadcast address
-  //set ack polarity low when transmitting to any other address
-  output.push_back(MSGSTART);
-  PushEscaped(output, MSGCODE_TRANSMIT_ACK_POLARITY);
-
-  if ((data[0] & 0xF) == 0xF)
-    PushEscaped(output, CEC_TRUE);
-  else
-    PushEscaped(output, CEC_FALSE);
-
-  output.push_back(MSGEND);
-
-  for (unsigned int i = 0; i < data.size(); i++)
-  {
-    output.push_back(MSGSTART);
-
-    if (i == data.size() - 1)
-      PushEscaped(output, MSGCODE_TRANSMIT_EOM);
-    else
-      PushEscaped(output, MSGCODE_TRANSMIT);
-
-    PushEscaped(output, data[i]);
-
-    output.push_back(MSGEND);
-  }
-
-  return TransmitFormatted(output, bWaitForAck);
+  return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
 }
 
-bool CCECParser::WaitForAck(int iTimeout /* = 1000 */)
+bool CCECProcessor::WaitForAck(int iTimeout /* = 1000 */)
 {
   bool bGotAck(false);
   bool bError(false);
@@ -435,35 +344,35 @@ bool CCECParser::WaitForAck(int iTimeout /* = 1000 */)
       switch (iCode)
       {
       case MSGCODE_COMMAND_ACCEPTED:
-        AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
+        m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
         break;
       case MSGCODE_TRANSMIT_SUCCEEDED:
-        AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
+        m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
         // TODO
         bGotAck = true;
         break;
       case MSGCODE_RECEIVE_FAILED:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
         bError = true;
         break;
       case MSGCODE_COMMAND_REJECTED:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
         bError = true;
         break;
       case MSGCODE_TRANSMIT_FAILED_LINE:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
         bError = true;
         break;
       case MSGCODE_TRANSMIT_FAILED_ACK:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_ACK");
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_ACK");
         bError = true;
         break;
       case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA");
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA");
         bError = true;
         break;
       case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
-        AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
+        m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
         bError = true;
         break;
       default:
@@ -478,7 +387,7 @@ bool CCECParser::WaitForAck(int iTimeout /* = 1000 */)
   return bGotAck && !bError;
 }
 
-bool CCECParser::ParseMessage(cec_frame &msg)
+bool CCECProcessor::ParseMessage(cec_frame &msg)
 {
   bool bReturn(false);
 
@@ -493,7 +402,7 @@ bool CCECParser::ParseMessage(cec_frame &msg)
   switch(iCode)
   {
   case MSGCODE_NOTHING:
-    AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
+    m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
     break;
   case MSGCODE_TIMEOUT_ERROR:
   case MSGCODE_HIGH_ERROR:
@@ -510,7 +419,7 @@ bool CCECParser::ParseMessage(cec_frame &msg)
       uint32_t iTime = (msg.size() >= 7) ? (msg[3] << 24) | (msg[4] << 16) | (msg[5] << 8) | (msg[6]) : 0;
       logStr.AppendFormat(" line:%i", iLine);
       logStr.AppendFormat(" time:%u", iTime);
-      AddLog(CEC_LOG_WARNING, logStr.c_str());
+      m_controller->AddLog(CEC_LOG_WARNING, logStr.c_str());
     }
     break;
   case MSGCODE_FRAME_START:
@@ -525,7 +434,7 @@ bool CCECParser::ParseMessage(cec_frame &msg)
 
         m_currentframe.push_back(msg[1]);
       }
-      AddLog(CEC_LOG_DEBUG, logStr.c_str());
+      m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
     }
     break;
   case MSGCODE_FRAME_DATA:
@@ -537,7 +446,7 @@ bool CCECParser::ParseMessage(cec_frame &msg)
         logStr.AppendFormat(" %02x", iData);
         m_currentframe.push_back(iData);
       }
-      AddLog(CEC_LOG_DEBUG, logStr.c_str());
+      m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
     }
     if (bEom)
       bReturn = true;
@@ -549,7 +458,7 @@ bool CCECParser::ParseMessage(cec_frame &msg)
   return bReturn;
 }
 
-void CCECParser::ParseCurrentFrame(void)
+void CCECProcessor::ParseCurrentFrame(void)
 {
   uint8_t initiator = m_currentframe[0] >> 4;
   uint8_t destination = m_currentframe[0] & 0xF;
@@ -563,7 +472,7 @@ void CCECParser::ParseCurrentFrame(void)
     for (unsigned int i = 1; i < m_currentframe.size(); i++)
       dataStr.AppendFormat(" %02x", m_currentframe[i]);
   }
-  AddLog(CEC_LOG_DEBUG, dataStr.c_str());
+  m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str());
 
   if (m_currentframe.size() <= 1)
     return;
@@ -596,22 +505,19 @@ void CCECParser::ParseCurrentFrame(void)
     case CEC_OPCODE_USER_CONTROL_PRESSED:
       if (m_currentframe.size() > 2)
       {
-        AddKey();
+        m_controller->AddKey();
 
         if (m_currentframe[2] <= CEC_USER_CONTROL_CODE_MAX)
-        {
-          m_iCurrentButton = (cec_user_control_code) m_currentframe[2];
-          m_buttontime = GetTimeMs();
-        }
+          m_controller->SetCurrentButton((cec_user_control_code) m_currentframe[2]);
       }
       break;
     case CEC_OPCODE_USER_CONTROL_RELEASE:
-      AddKey();
+      m_controller->AddKey();
       break;
     default:
       cec_frame params = m_currentframe;
       params.erase(params.begin(), params.begin() + 2);
-      AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+      m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
       break;
     }
   }
@@ -628,7 +534,7 @@ void CCECParser::ParseCurrentFrame(void)
         int streamaddr = ((int)m_currentframe[2] << 8) | ((int)m_currentframe[3]);
         CStdString strLog;
         strLog.Format("%i requests stream path from physical address %04x", initiator, streamaddr);
-        AddLog(CEC_LOG_DEBUG, strLog.c_str());
+        m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
         if (streamaddr == m_physicaladdress)
           BroadcastActiveSource();
       }
@@ -637,136 +543,13 @@ void CCECParser::ParseCurrentFrame(void)
     {
       cec_frame params = m_currentframe;
       params.erase(params.begin(), params.begin() + 2);
-      AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+      m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
     }
   }
   else
   {
     CStdString strLog;
     strLog.Format("ignoring frame: destination: %u != %u", destination, (uint16_t)m_iLogicalAddress);
-    AddLog(CEC_LOG_DEBUG, strLog.c_str());
+    m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
   }
 }
-
-void CCECParser::PushEscaped(cec_frame &vec, uint8_t byte)
-{
-  if (byte >= MSGESC && byte != MSGSTART)
-  {
-    vec.push_back(MSGESC);
-    vec.push_back(byte - ESCOFFSET);
-  }
-  else
-  {
-    vec.push_back(byte);
-  }
-}
-
-void CCECParser::CheckKeypressTimeout(int64_t now)
-{
-  if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && now - m_buttontime > CEC_BUTTON_TIMEOUT)
-  {
-    AddKey();
-    m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
-  }
-}
-
-bool CCECParser::SetLogicalAddress(cec_logical_address iLogicalAddress)
-{
-  CStdString strLog;
-  strLog.Format("setting logical address to %d", iLogicalAddress);
-  AddLog(CEC_LOG_NOTICE, strLog.c_str());
-
-  m_iLogicalAddress = iLogicalAddress;
-  return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
-}
-
-bool CCECParser::SetAckMask(uint16_t iMask)
-{
-  CStdString strLog;
-  strLog.Format("setting ackmask to %2x", iMask);
-  AddLog(CEC_LOG_DEBUG, strLog.c_str());
-
-  cec_frame output;
-
-  output.push_back(MSGSTART);
-  PushEscaped(output, MSGCODE_SET_ACK_MASK);
-  PushEscaped(output, iMask >> 8);
-  PushEscaped(output, (uint8_t)iMask);
-  output.push_back(MSGEND);
-
-  if (!m_communication->Write(output))
-  {
-    AddLog(CEC_LOG_ERROR, "could not set the ackmask");
-    return false;
-  }
-
-  return true;
-}
-
-void CCECParser::AddLog(cec_log_level level, const string &strMessage)
-{
-  cec_log_message message;
-  message.level = level;
-  message.message.assign(strMessage.c_str());
-  m_logBuffer.Push(message);
-}
-
-void CCECParser::AddKey(void)
-{
-  if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
-  {
-    cec_keypress key;
-    key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
-    key.keycode = m_iCurrentButton;
-    m_keyBuffer.Push(key);
-    m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
-    m_buttontime = 0;
-  }
-}
-
-void CCECParser::AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters)
-{
-  cec_command command;
-  command.source       = source;
-  command.destination  = destination;
-  command.opcode       = opcode;
-  if (parameters)
-    command.parameters = *parameters;
-  if (m_commandBuffer.Push(command))
-  {
-    CStdString strDebug;
-    strDebug.Format("stored command '%d' in the command buffer. buffer size = %d", opcode, m_commandBuffer.Size());
-    AddLog(CEC_LOG_DEBUG, strDebug);
-  }
-  else
-  {
-    AddLog(CEC_LOG_WARNING, "command buffer is full");
-  }
-}
-
-int CCECParser::GetMinVersion(void)
-{
-  return CEC_MIN_VERSION;
-}
-
-int CCECParser::GetLibVersion(void)
-{
-  return CEC_LIB_VERSION;
-}
-
-int CCECParser::FindDevices(std::vector<cec_device> &deviceList, const char *strDevicePath /* = NULL */)
-{
-  CStdString strDebug;
-  if (strDevicePath)
-    strDebug.Format("trying to autodetect the com port for device path '%s'", strDevicePath);
-  else
-    strDebug.Format("trying to autodetect all CEC adapters");
-  AddLog(CEC_LOG_DEBUG, strDebug);
-
-  return CCECDetect::FindDevices(deviceList, strDevicePath);
-}
-
-DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress /*= CEC::CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
-{
-  return static_cast< void* > (new CCECParser(strDeviceName, iLogicalAddress, iPhysicalAddress));
-}