cec: call SetControlledMode(false) as last command when closing the connection in...
[deb_libcec.git] / src / lib / adapter / USBCECAdapterCommunication.cpp
index 0134751d31b2b05f8eb4f88f3320ff9b09fba686..f56bdf4b1f029a233cce849e74df727ba905918f 100644 (file)
@@ -40,14 +40,35 @@ using namespace std;
 using namespace CEC;
 using namespace PLATFORM;
 
+void *CUSBCECAdapterProcessor::Process(void)
+{
+  cec_command command;
+  while (!IsStopped())
+  {
+    if (m_inBuffer.Pop(command))
+      m_callback->OnCommandReceived(command);
+    Sleep(5);
+  }
+
+  return NULL;
+}
+
+void CUSBCECAdapterProcessor::AddCommand(cec_command command)
+{
+  m_inBuffer.Push(command);
+}
+
 CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate /* = 38400 */) :
     m_port(NULL),
     m_processor(processor),
+    m_bHasData(false),
     m_iLineTimeout(0),
     m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN),
     m_lastInitiator(CECDEVICE_UNKNOWN),
     m_bNextIsEscaped(false),
-    m_bGotStart(false)
+    m_bGotStart(false),
+    m_messageProcessor(NULL),
+    m_bInitialised(false)
 {
   m_port = new PLATFORM::CSerialPort(strPort, iBaudRate);
 }
@@ -55,69 +76,133 @@ CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(CCECProcessor *processo
 CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
 {
   Close();
-
-  if (m_port)
-  {
-    delete m_port;
-    m_port = NULL;
-  }
 }
 
-bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */)
 {
+  bool bReturn(false);
   uint64_t iNow = GetTimeMs();
-  uint64_t iTimeout = iNow + iTimeoutMs;
+  uint64_t iTarget = iTimeoutMs > 0 ? iNow + iTimeoutMs : iNow + CEC_DEFAULT_TRANSMIT_WAIT;
 
-  CLockObject lock(m_mutex);
+  /* try to ping the adapter */
+  bool bPinged(false);
+  unsigned iPingTry(0);
+  while (iNow < iTarget && (bPinged = PingAdapter()) == false)
+  {
+    CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
+    CEvent::Sleep(500);
+    iNow = GetTimeMs();
+  }
 
-  if (!m_port)
+  /* try to read the firmware version */
+  m_iFirmwareVersion = CEC_FW_VERSION_UNKNOWN;
+  unsigned iFwVersionTry(0);
+  while (bPinged && iNow < iTarget && (m_iFirmwareVersion = GetFirmwareVersion()) == CEC_FW_VERSION_UNKNOWN && iFwVersionTry < 3)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
-    return false;
+    CLibCEC::AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", ++iFwVersionTry);
+    CEvent::Sleep(500);
+    iNow = GetTimeMs();
   }
 
-  if (IsOpen())
+  if (m_iFirmwareVersion == CEC_FW_VERSION_UNKNOWN)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "port is already open");
-    return true;
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1");
+    m_iFirmwareVersion = 1;
   }
 
-  CStdString strError;
-  bool bConnected(false);
-  while (!bConnected && iNow < iTimeout)
+  if (m_iFirmwareVersion >= 2)
   {
-    if ((bConnected = m_port->Open(iTimeout)) == false)
+    /* try to set controlled mode */
+    unsigned iControlledTry(0);
+    bool bControlled(false);
+    while (iNow < iTarget && (bControlled = SetControlledMode(true)) == false)
     {
-      strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
-      Sleep(250);
+      CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
+      CEvent::Sleep(500);
       iNow = GetTimeMs();
     }
+    bReturn = bControlled;
   }
+  else
+    bReturn = true;
 
-  if (!bConnected)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, strError);
-    return false;
+    CLockObject lock(m_mutex);
+    m_bInitialised = bReturn;
   }
 
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+  return bReturn;
+}
+
+bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */, bool bSkipChecks /* = false */)
+{
+  uint64_t iNow = GetTimeMs();
+  uint64_t iTimeout = iNow + iTimeoutMs;
 
-  //clear any input bytes
-  uint8_t buff[1024];
-  while (m_port->Read(buff, 1024, 100) > 0)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
-    Sleep(250);
+    CLockObject lock(m_mutex);
+
+    if (!m_port)
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
+      return false;
+    }
+
+    if (IsOpen())
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "port is already open");
+      return true;
+    }
+
+    m_callback = cb;
+    CStdString strError;
+    bool bConnected(false);
+    while (!bConnected && iNow < iTimeout)
+    {
+      if ((bConnected = m_port->Open(iTimeout)) == false)
+      {
+        strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
+        Sleep(250);
+        iNow = GetTimeMs();
+      }
+    }
+
+    if (!bConnected)
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, strError);
+      return false;
+    }
+
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+
+    if (!bSkipChecks)
+    {
+      //clear any input bytes
+      uint8_t buff[1024];
+      while (m_port->Read(buff, 1024, 100) > 0)
+      {
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
+        Sleep(250);
+      }
+    }
   }
 
-  if (CreateThread())
+  if (!bSkipChecks && !CheckAdapter())
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
-    return true;
+    CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+    return false;
   }
   else
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+    if (CreateThread())
+    {
+      CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
+      return true;
+    }
+    else
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+    }
   }
 
   return false;
@@ -125,23 +210,56 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */)
 
 void CUSBCECAdapterCommunication::Close(void)
 {
-  CLockObject lock(m_mutex);
-  m_rcvCondition.Broadcast();
   StopThread();
 }
 
 void *CUSBCECAdapterCommunication::Process(void)
 {
+  m_messageProcessor = new CUSBCECAdapterProcessor(m_callback);
+  m_messageProcessor->CreateThread();
+
+  cec_command command;
+  command.Clear();
+  bool bCommandReceived(false);
   while (!IsStopped())
   {
-    ReadFromDevice(50);
-    Sleep(5);
-    WriteNextCommand();
+    {
+      CLockObject lock(m_mutex);
+      ReadFromDevice(50);
+      bCommandReceived = m_callback && Read(command, 0) && m_bInitialised;
+    }
+
+    /* push the next command to the callback method if there is one */
+    if (!IsStopped() && bCommandReceived)
+      m_messageProcessor->AddCommand(command);
+
+    if (!IsStopped())
+    {
+      Sleep(5);
+      WriteNextCommand();
+    }
   }
 
+  /* stop the message processor */
+  m_messageProcessor->StopThread();
+  delete m_messageProcessor;
+
+  /* notify all threads that are waiting on messages to be sent */
   CCECAdapterMessage *msg(NULL);
-  if (m_outBuffer.Pop(msg))
-    msg->condition.Broadcast();
+  while (m_outBuffer.Pop(msg))
+    msg->event.Broadcast();
+
+  /* set the ackmask to 0 before closing the connection */
+  SetAckMaskInternal(0, true);
+
+  if (m_iFirmwareVersion >= 2)
+    SetControlledMode(false);
+
+  if (m_port)
+  {
+    delete m_port;
+    m_port = NULL;
+  }
 
   return NULL;
 }
@@ -149,6 +267,8 @@ void *CUSBCECAdapterCommunication::Process(void)
 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);
+  if (!IsRunning())
+    return retVal;
 
   CCECAdapterMessage *output = new CCECAdapterMessage(data);
 
@@ -177,41 +297,25 @@ 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);
+  data->event.Wait(5000);
 
-  if (data->state != ADAPTER_MESSAGE_STATE_SENT)
-  {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "command was not sent");
-  }
-  else if (data->expectControllerAck)
+  if ((data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT_ACKED) ||
+      (!data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT))
   {
-    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
-  {
-    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)
 {
+  if (!IsRunning())
+    return false;
+
   CCECAdapterMessage msg;
   if (Read(msg, iTimeout))
   {
@@ -234,15 +338,16 @@ 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, m_bHasData, iTimeout))
       return false;
     m_inBuffer.Pop(buf);
+    m_bHasData = !m_inBuffer.IsEmpty();
   }
 
   if (buf)
   {
     msg.packet = buf->packet;
-    msg.state = msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
+    msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
     delete buf;
     return true;
   }
@@ -280,11 +385,9 @@ bool CUSBCECAdapterCommunication::StartBootloader(void)
 
 bool CUSBCECAdapterCommunication::PingAdapter(void)
 {
-  bool bReturn(false);
-  if (!IsRunning())
-    return bReturn;
-
+  CLockObject lock(m_mutex);
   CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping");
+
   CCECAdapterMessage *output = new CCECAdapterMessage;
 
   output->PushBack(MSGSTART);
@@ -292,11 +395,16 @@ bool CUSBCECAdapterCommunication::PingAdapter(void)
   output->PushBack(MSGEND);
   output->isTransmission = false;
 
-  if ((bReturn = Write(output)) == false)
-    CLibCEC::AddLog(CEC_LOG_ERROR, "could not ping the adapter");
+  SendMessageToAdapter(output);
+  bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
   delete output;
+  if (!bWriteOk)
+  {
+    CLibCEC::AddLog(CEC_LOG_ERROR, "could not ping the adapter");
+    return false;
+  }
 
-  return bReturn;
+  return true;
 }
 
 bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
@@ -307,6 +415,7 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
   if (msg.IsEmpty())
     return bEom;
 
+  CLockObject adapterLock(m_mutex);
   switch(msg.Message())
   {
   case MSGCODE_FRAME_START:
@@ -340,7 +449,6 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
         m_currentframe.PushBack(msg[1]);
         m_currentframe.eom = msg.IsEOM();
       }
-      bEom = msg.IsEOM();
     }
     break;
   default:
@@ -348,17 +456,16 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
   }
 
   CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
-  return bEom;
+  return msg.IsEOM();
 }
 
 uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
 {
   uint16_t iReturn(m_iFirmwareVersion);
-  if (!IsRunning())
-    return iReturn;
 
   if (iReturn == CEC_FW_VERSION_UNKNOWN)
   {
+    CLockObject lock(m_mutex);
     CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
     CCECAdapterMessage *output = new CCECAdapterMessage;
 
@@ -369,15 +476,30 @@ uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
     output->expectControllerAck = false;
 
     SendMessageToAdapter(output);
+    bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT;
     delete output;
+    if (!bWriteOk)
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "could not request the firmware version");
+      return iReturn;
+    }
 
+    Sleep(250); // TODO ReadFromDevice() isn't waiting for the timeout to pass on win32
+    ReadFromDevice(CEC_DEFAULT_TRANSMIT_WAIT, 5 /* start + msgcode + 2 bytes for fw version + end */);
     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 (Read(input, 0))
+    {
+      if (input.Message() != MSGCODE_FIRMWARE_VERSION || input.Size() != 3)
+        CLibCEC::AddLog(CEC_LOG_ERROR, "invalid firmware version (size = %d, message = %d)", input.Size(), input.Message());
+      else
+      {
+        m_iFirmwareVersion = (input[1] << 8 | input[2]);
+        iReturn = m_iFirmwareVersion;
+      }
+    }
     else
     {
-      m_iFirmwareVersion = (input[1] << 8 | input[2]);
-      iReturn = m_iFirmwareVersion;
+      CLibCEC::AddLog(CEC_LOG_ERROR, "no firmware version received");
     }
   }
 
@@ -410,11 +532,14 @@ bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
 }
 
 bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
+{
+  return SetAckMaskInternal(iMask, false);
+}
+
+bool CUSBCECAdapterCommunication::SetAckMaskInternal(uint16_t iMask, bool bWriteDirectly /* = false */)
 {
   bool bReturn(false);
-  CStdString strLog;
-  strLog.Format("setting ackmask to %2x", iMask);
-  CLibCEC::AddLog(CEC_LOG_DEBUG, strLog.c_str());
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
 
   CCECAdapterMessage *output = new CCECAdapterMessage;
 
@@ -425,13 +550,41 @@ bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
   output->PushBack(MSGEND);
   output->isTransmission = false;
 
-  if ((bReturn = Write(output)) == false)
+  if (bWriteDirectly)
+    SendMessageToAdapter(output);
+  else if ((bReturn = Write(output)) == false)
     CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the ackmask");
   delete output;
 
   return bReturn;
 }
 
+
+bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
+{
+  CLockObject lock(m_mutex);
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off");
+
+  CCECAdapterMessage *output = new CCECAdapterMessage;
+
+  output->PushBack(MSGSTART);
+  output->PushEscaped(MSGCODE_SET_CONTROLLED);
+  output->PushEscaped(controlled);
+  output->PushBack(MSGEND);
+  output->isTransmission = false;
+
+  SendMessageToAdapter(output);
+  bool bWriteOk = output->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  delete output;
+  if (!bWriteOk)
+  {
+    CLibCEC::AddLog(CEC_LOG_ERROR, "could not set controlled mode");
+    return false;
+  }
+
+  return true;
+}
+
 bool CUSBCECAdapterCommunication::IsOpen(void)
 {
   return !IsStopped() && m_port->IsOpen() && IsRunning();
@@ -444,16 +597,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;
@@ -486,11 +636,11 @@ bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
       switch(msg.Message())
       {
       case MSGCODE_COMMAND_ACCEPTED:
-        CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString());
         if (iPacketsLeft > 0)
           iPacketsLeft--;
         if (!message.isTransmission && iPacketsLeft == 0)
           bTransmitSucceeded = true;
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - waiting for %d more", msg.ToString().c_str(), iPacketsLeft);
         break;
       case MSGCODE_TRANSMIT_SUCCEEDED:
         CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString());
@@ -507,6 +657,10 @@ bool CUSBCECAdapterCommunication::WaitForAck(CCECAdapterMessage &message)
     }
   }
 
+  message.state = bTransmitSucceeded && !bError ?
+      ADAPTER_MESSAGE_STATE_SENT_ACKED :
+      ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+
   return bTransmitSucceeded && !bError;
 }
 
@@ -535,7 +689,8 @@ void CUSBCECAdapterCommunication::AddData(uint8_t *data, size_t iLen)
       m_currentAdapterMessage.Clear();
       m_bGotStart = false;
       m_bNextIsEscaped = false;
-      m_rcvCondition.Signal();
+      m_bHasData = true;
+      m_rcvCondition.Broadcast();
     }
     else if (m_bNextIsEscaped)
     {
@@ -553,18 +708,21 @@ 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());
+    StopThread(false);
     return false;
   }
   else if (iBytesRead > 0)
@@ -578,7 +736,13 @@ bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
 void CUSBCECAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
 {
   CLockObject adapterLock(m_mutex);
-  CLockObject lock(msg->mutex);
+  if (!m_port->IsOpen())
+  {
+    CLibCEC::AddLog(CEC_LOG_ERROR, "error writing to serial port: the connection is closed");
+    msg->state = ADAPTER_MESSAGE_STATE_ERROR;
+    return;
+  }
+
   if (msg->tries == 1)
     SetLineTimeout(msg->lineTimeout);
   else
@@ -586,17 +750,21 @@ void CUSBCECAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
 
   if (m_port->Write(msg->packet.data, msg->Size()) != (ssize_t) msg->Size())
   {
-    CStdString strError;
-    strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
-    CLibCEC::AddLog(CEC_LOG_ERROR, strError);
+    CLibCEC::AddLog(CEC_LOG_ERROR, "error writing to serial port: %s", m_port->GetError().c_str());
     msg->state = ADAPTER_MESSAGE_STATE_ERROR;
   }
   else
   {
     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();
+  msg->event.Signal();
 }
 
 void CUSBCECAdapterCommunication::WriteNextCommand(void)
@@ -605,3 +773,10 @@ void CUSBCECAdapterCommunication::WriteNextCommand(void)
   if (m_outBuffer.Pop(msg))
     SendMessageToAdapter(msg);
 }
+
+CStdString CUSBCECAdapterCommunication::GetPortName(void)
+{
+  CStdString strName;
+  strName = m_port->GetName();
+  return strName;
+}