cec: use the correct Sleep() method in CCECProcessor::OpenConnection(). the thread...
[deb_libcec.git] / src / lib / adapter / USBCECAdapterCommunication.cpp
index 32158de76513e32c7cce41c9b58a6488566318d5..5400325bb215ff2bf7a41c2e7245df5acaf0541f 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);
 }
@@ -99,10 +120,15 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = 10000 */
   else
     bReturn = true;
 
+  {
+    CLockObject lock(m_mutex);
+    m_bInitialised = bReturn;
+  }
+
   return bReturn;
 }
 
-bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */)
+bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32_t iTimeoutMs /* = 10000 */, bool bSkipChecks /* = false */)
 {
   uint64_t iNow = GetTimeMs();
   uint64_t iTimeout = iNow + iTimeoutMs;
@@ -143,21 +169,25 @@ bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32
 
     CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
 
-    //clear any input bytes
-    uint8_t buff[1024];
-    while (m_port->Read(buff, 1024, 100) > 0)
+    if (!bSkipChecks)
     {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "data received, clearing it");
-      Sleep(250);
+      //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 (!CheckAdapter())
+    if (!bSkipChecks && !CheckAdapter())
     {
       StopThread();
       CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+      return false;
     }
     else
     {
@@ -172,27 +202,28 @@ bool CUSBCECAdapterCommunication::Open(IAdapterCommunicationCallback *cb, uint32
 
 void CUSBCECAdapterCommunication::Close(void)
 {
-  SetAckMask(0);
-  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())
   {
     {
       CLockObject lock(m_mutex);
       ReadFromDevice(50);
-      bCommandReceived = m_callback && Read(command, 0);
+      bCommandReceived = m_callback && Read(command, 0) && m_bInitialised;
     }
 
     /* push the next command to the callback method if there is one */
     if (!IsStopped() && bCommandReceived)
-      m_callback->OnCommandReceived(command);
+      m_messageProcessor->AddCommand(command);
 
     if (!IsStopped())
     {
@@ -201,9 +232,17 @@ void *CUSBCECAdapterCommunication::Process(void)
     }
   }
 
+  /* 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_port)
   {
@@ -247,10 +286,9 @@ cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &
 
 bool CUSBCECAdapterCommunication::Write(CCECAdapterMessage *data)
 {
-  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->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT_ACKED) ||
       (!data->expectControllerAck && data->state != ADAPTER_MESSAGE_STATE_SENT))
@@ -289,9 +327,10 @@ bool CUSBCECAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeou
 
   if (!m_inBuffer.Pop(buf))
   {
-    if (iTimeout == 0 || !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)
@@ -362,6 +401,7 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
   if (msg.IsEmpty())
     return bEom;
 
+  CLockObject adapterLock(m_mutex);
   switch(msg.Message())
   {
   case MSGCODE_FRAME_START:
@@ -395,7 +435,6 @@ bool CUSBCECAdapterCommunication::ParseMessage(const CCECAdapterMessage &msg)
         m_currentframe.PushBack(msg[1]);
         m_currentframe.eom = msg.IsEOM();
       }
-      bEom = msg.IsEOM();
     }
     break;
   default:
@@ -403,7 +442,7 @@ 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)
@@ -481,6 +520,11 @@ 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);
   CLibCEC::AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
@@ -494,7 +538,9 @@ 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;
 
@@ -626,7 +672,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)
     {
@@ -658,6 +705,7 @@ bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize
   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)
@@ -671,7 +719,13 @@ bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize
 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
@@ -693,7 +747,7 @@ void CUSBCECAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
         CLibCEC::AddLog(CEC_LOG_DEBUG, "did not receive ack");
     }
   }
-  msg->condition.Signal();
+  msg->event.Signal();
 }
 
 void CUSBCECAdapterCommunication::WriteNextCommand(void)
@@ -702,3 +756,10 @@ void CUSBCECAdapterCommunication::WriteNextCommand(void)
   if (m_outBuffer.Pop(msg))
     SendMessageToAdapter(msg);
 }
+
+CStdString CUSBCECAdapterCommunication::GetPortName(void)
+{
+  CStdString strName;
+  strName = m_port->GetName();
+  return strName;
+}