cec: sync win32
[deb_libcec.git] / src / lib / adapter / AdapterCommunication.cpp
index a792a1d77071de9c9cb80cd3b395a429a69a605e..e143b08c3f9054e2a0e5b307df9e1600c4331c59 100644 (file)
@@ -33,8 +33,9 @@
 #include "AdapterCommunication.h"
 
 #include "AdapterMessage.h"
-#include "CECProcessor.h"
-#include "platform/serialport/serialport.h"
+#include "../CECProcessor.h"
+#include "../platform/serialport/serialport.h"
+#include "../LibCEC.h"
 
 using namespace std;
 using namespace CEC;
@@ -43,7 +44,8 @@ using namespace PLATFORM;
 CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor) :
     m_port(NULL),
     m_processor(processor),
-    m_iLineTimeout(0)
+    m_iLineTimeout(0),
+    m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN)
 {
   m_port = new PLATFORM::CSerialPort;
 }
@@ -68,13 +70,13 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38
 
   if (!m_port)
   {
-    m_processor->AddLog(CEC_LOG_ERROR, "port is NULL");
+    CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
     return false;
   }
 
   if (IsOpen())
   {
-    m_processor->AddLog(CEC_LOG_ERROR, "port is already open");
+    CLibCEC::AddLog(CEC_LOG_ERROR, "port is already open");
     return true;
   }
 
@@ -92,11 +94,11 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38
 
   if (!bConnected)
   {
-    m_processor->AddLog(CEC_LOG_ERROR, strError);
+    CLibCEC::AddLog(CEC_LOG_ERROR, strError);
     return false;
   }
 
-  m_processor->AddLog(CEC_LOG_DEBUG, "connection opened");
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened");
 
   //clear any input bytes
   uint8_t buff[1];
@@ -104,12 +106,12 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38
 
   if (CreateThread())
   {
-    m_processor->AddLog(CEC_LOG_DEBUG, "communication thread started");
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
     return true;
   }
   else
   {
-    m_processor->AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+    CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
   }
 
   return false;
@@ -140,9 +142,38 @@ 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)
+  {
+    CLibCEC::AddLog(CEC_LOG_ERROR, "command was not sent");
+  }
+
+  if (data->expectControllerAck)
+  {
+    bReturn = WaitForTransmitSucceeded(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;
+  }
+
+  return bReturn;
 }
 
 bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
@@ -174,7 +205,7 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
     else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove
     {
       if (msg.Size() > 0)
-        m_processor->AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+        CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
       msg.Clear();
       bGotStart = true;
     }
@@ -195,7 +226,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;
 }
@@ -211,17 +242,17 @@ bool CAdapterCommunication::StartBootloader(void)
   if (!IsRunning())
     return bReturn;
 
-  m_processor->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "starting the bootloader");
   CCECAdapterMessage *output = new CCECAdapterMessage;
 
   output->PushBack(MSGSTART);
   output->PushEscaped(MSGCODE_START_BOOTLOADER);
   output->PushBack(MSGEND);
+  output->isTransmission = false;
+  output->expectControllerAck = 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)
+    CLibCEC::AddLog(CEC_LOG_ERROR, "could not start the bootloader");
   delete output;
 
   return bReturn;
@@ -233,22 +264,54 @@ bool CAdapterCommunication::PingAdapter(void)
   if (!IsRunning())
     return bReturn;
 
-  m_processor->AddLog(CEC_LOG_DEBUG, "sending ping");
+  CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping");
   CCECAdapterMessage *output = new CCECAdapterMessage;
 
   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)
+    CLibCEC::AddLog(CEC_LOG_ERROR, "could not ping the adapter");
   delete output;
 
   return bReturn;
 }
 
+uint16_t CAdapterCommunication::GetFirmwareVersion(void)
+{
+  uint16_t iReturn(m_iFirmwareVersion);
+  if (!IsRunning())
+    return iReturn;
+
+  if (iReturn == CEC_FW_VERSION_UNKNOWN)
+  {
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
+    CCECAdapterMessage *output = new CCECAdapterMessage;
+
+    output->PushBack(MSGSTART);
+    output->PushEscaped(MSGCODE_FIRMWARE_VERSION);
+    output->PushBack(MSGEND);
+    output->isTransmission = false;
+    output->expectControllerAck = false;
+
+    SendMessageToAdapter(output);
+    delete output;
+
+    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");
+    else
+    {
+      m_iFirmwareVersion = (input[1] << 8 | input[2]);
+      iReturn = m_iFirmwareVersion;
+    }
+  }
+
+  return iReturn;
+}
+
 bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
 {
   bool bReturn(m_iLineTimeout != iTimeout);
@@ -261,15 +324,39 @@ 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");
+      CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the idletime");
     delete output;
   }
 
   return bReturn;
 }
 
+bool CAdapterCommunication::SetAckMask(uint16_t iMask)
+{
+  bool bReturn(false);
+  CStdString strLog;
+  strLog.Format("setting ackmask to %2x", iMask);
+  CLibCEC::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)
+    CLibCEC::AddLog(CEC_LOG_ERROR, "could not set the ackmask");
+  delete output;
+
+  return bReturn;
+}
+
 bool CAdapterCommunication::IsOpen(void)
 {
   return !IsStopped() && m_port->IsOpen() && IsRunning();
@@ -312,19 +399,21 @@ bool CAdapterCommunication::WaitForTransmitSucceeded(CCECAdapterMessage *message
     if (bError)
     {
       message->reply = msg.Message();
-      m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+      CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString());
     }
     else
     {
       switch(msg.Message())
       {
       case MSGCODE_COMMAND_ACCEPTED:
-        m_processor->AddLog(CEC_LOG_DEBUG, msg.ToString());
+        CLibCEC::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());
+        CLibCEC::AddLog(CEC_LOG_DEBUG, msg.ToString());
         bTransmitSucceeded = (iPacketsLeft == 0);
         bError = !bTransmitSucceeded;
         message->reply = MSGCODE_TRANSMIT_SUCCEEDED;
@@ -357,12 +446,13 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
   if (!m_port)
     return false;
 
+  CLockObject lock(m_mutex);
   iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
   if (iBytesRead < 0 || iBytesRead > 256)
   {
     CStdString strError;
     strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
-    m_processor->AddLog(CEC_LOG_ERROR, strError);
+    CLibCEC::AddLog(CEC_LOG_ERROR, strError);
     return false;
   }
   else if (iBytesRead > 0)
@@ -373,17 +463,18 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
 
 void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
 {
+  CLockObject adapterLock(m_mutex);
   CLockObject lock(msg->mutex);
   if (m_port->Write(msg->packet.data, msg->Size()) != (int32_t) msg->Size())
   {
     CStdString strError;
     strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
-    m_processor->AddLog(CEC_LOG_ERROR, strError);
+    CLibCEC::AddLog(CEC_LOG_ERROR, strError);
     msg->state = ADAPTER_MESSAGE_STATE_ERROR;
   }
   else
   {
-    m_processor->AddLog(CEC_LOG_DEBUG, "command sent");
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "command sent");
     msg->state = ADAPTER_MESSAGE_STATE_SENT;
   }
   msg->condition.Signal();