cec: move WaitForTransmissionSucceeded() to CAdapterCommunication and wait for MSGCOD...
[deb_libcec.git] / src / lib / adapter / AdapterCommunication.cpp
index 4a136ab113f4bef0a8e1fcdd83b19506d49f7eb1..821a4f2aa276e919e3156d521b2114bd53b5248c 100644 (file)
@@ -140,9 +140,30 @@ void *CAdapterCommunication::Process(void)
 
 bool CAdapterCommunication::Write(CCECAdapterMessage *data)
 {
-  data->state = ADAPTER_MESSAGE_STATE_WAITING;
+  bool bReturn(false);
+
+  CLockObject lock(data->mutex);
+  data->state = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
   m_outBuffer.Push(data);
-  return true;
+  data->condition.Wait(data->mutex);
+
+  if (data->state != ADAPTER_MESSAGE_STATE_SENT)
+  {
+    m_processor->AddLog(CEC_LOG_ERROR, "command was not sent");
+  }
+  if (WaitForTransmitSucceeded(data))
+  {
+    if (data->isTransmission)
+      data->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+    bReturn = true;
+  }
+  else
+  {
+    data->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+    m_processor->AddLog(CEC_LOG_DEBUG, "did not receive ack");
+  }
+
+  return bReturn;
 }
 
 bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
@@ -195,7 +216,7 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
   }
 
   if (bGotFullMessage)
-    msg.state = ADAPTER_MESSAGE_STATE_RECEIVED;
+    msg.state = ADAPTER_MESSAGE_STATE_INCOMING;
 
   return bGotFullMessage;
 }
@@ -217,11 +238,10 @@ bool CAdapterCommunication::StartBootloader(void)
   output->PushBack(MSGSTART);
   output->PushEscaped(MSGCODE_START_BOOTLOADER);
   output->PushBack(MSGEND);
+  output->isTransmission = false;
 
-  CLockObject lock(output->mutex);
-  if (Write(output))
-    output->condition.Wait(output->mutex);
-  bReturn = output->state == ADAPTER_MESSAGE_STATE_SENT;
+  if ((bReturn = Write(output)) == false)
+    m_processor->AddLog(CEC_LOG_ERROR, "could not start the bootloader");
   delete output;
 
   return bReturn;
@@ -239,11 +259,10 @@ bool CAdapterCommunication::PingAdapter(void)
   output->PushBack(MSGSTART);
   output->PushEscaped(MSGCODE_PING);
   output->PushBack(MSGEND);
+  output->isTransmission = false;
 
-  CLockObject lock(output->mutex);
-  if (Write(output))
-    output->condition.Wait(output->mutex);
-  bReturn = output->state == ADAPTER_MESSAGE_STATE_SENT;
+  if ((bReturn = Write(output)) == false)
+    m_processor->AddLog(CEC_LOG_ERROR, "could not ping the adapter");
   delete output;
 
   return bReturn;
@@ -261,6 +280,7 @@ bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
     output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME);
     output->PushEscaped(iTimeout);
     output->PushBack(MSGEND);
+    output->isTransmission = false;
 
     if ((bReturn = Write(output)) == false)
       m_processor->AddLog(CEC_LOG_ERROR, "could not set the idletime");
@@ -270,11 +290,102 @@ bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
   return bReturn;
 }
 
+bool CAdapterCommunication::SetAckMask(uint16_t iMask)
+{
+  bool bReturn(false);
+  CStdString strLog;
+  strLog.Format("setting ackmask to %2x", iMask);
+  m_processor->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+
+  CCECAdapterMessage *output = new CCECAdapterMessage;
+
+  output->PushBack(MSGSTART);
+  output->PushEscaped(MSGCODE_SET_ACK_MASK);
+  output->PushEscaped(iMask >> 8);
+  output->PushEscaped((uint8_t)iMask);
+  output->PushBack(MSGEND);
+  output->isTransmission = false;
+
+  if ((bReturn = Write(output)) == false)
+    m_processor->AddLog(CEC_LOG_ERROR, "could not set the ackmask");
+  delete output;
+
+  return bReturn;
+}
+
 bool CAdapterCommunication::IsOpen(void)
 {
   return !IsStopped() && m_port->IsOpen() && IsRunning();
 }
 
+bool CAdapterCommunication::WaitForTransmitSucceeded(CCECAdapterMessage *message)
+{
+  bool bError(false);
+  bool bTransmitSucceeded(false);
+  uint8_t iPacketsLeft(message->Size() / 4);
+
+  int64_t iNow = GetTimeMs();
+  int64_t iTargetTime = iNow + message->transmit_timeout;
+
+  while (!bTransmitSucceeded && !bError && (message->transmit_timeout == 0 || iNow < iTargetTime))
+  {
+    CCECAdapterMessage msg;
+
+    if (!Read(msg, message->transmit_timeout > 0 ? (int32_t)(iTargetTime - iNow) : 1000))
+    {
+      iNow = GetTimeMs();
+      continue;
+    }
+
+    if (msg.Message() == MSGCODE_FRAME_START && msg.IsACK())
+    {
+      m_processor->HandlePoll(msg.Initiator(), msg.Destination());
+      iNow = GetTimeMs();
+      continue;
+    }
+
+    if (msg.Message() == MSGCODE_RECEIVE_FAILED &&
+        m_processor->HandleReceiveFailed())
+    {
+      iNow = GetTimeMs();
+      continue;
+    }
+
+    bError = msg.IsError();
+    if (bError)
+    {
+      message->reply = msg.Message();
+      m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+    }
+    else
+    {
+      switch(msg.Message())
+      {
+      case MSGCODE_COMMAND_ACCEPTED:
+        m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+        if (iPacketsLeft > 0)
+          iPacketsLeft--;
+        if (!message->isTransmission && iPacketsLeft == 0)
+          bTransmitSucceeded = true;
+        break;
+      case MSGCODE_TRANSMIT_SUCCEEDED:
+        m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+        bTransmitSucceeded = (iPacketsLeft == 0);
+        bError = !bTransmitSucceeded;
+        message->reply = MSGCODE_TRANSMIT_SUCCEEDED;
+        break;
+      default:
+        // ignore other data while waiting
+        break;
+      }
+
+      iNow = GetTimeMs();
+    }
+  }
+
+  return bTransmitSucceeded && !bError;
+}
+
 void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen)
 {
   CLockObject lock(m_mutex);