cec: hold a lock when changing the ackmask in CUSBCECAdapterCommunication::Open
[deb_libcec.git] / src / lib / adapter / USBCECAdapterCommunication.cpp
index 70eddb84c0cb4755cada60539bf67460194f05fd..d6d9b5c0fab383d2023f5a62ddee1a129fda80d6 100644 (file)
@@ -35,6 +35,7 @@
 #include "USBCECAdapterMessageQueue.h"
 #include "../platform/sockets/serialport.h"
 #include "../platform/util/timeutils.h"
+#include "../platform/util/util.h"
 #include "../LibCEC.h"
 #include "../CECProcessor.h"
 
@@ -65,14 +66,22 @@ CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCa
   for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
     m_bWaitingForAck[iPtr] = false;
   m_port = new CSerialPort(strPort, iBaudRate);
+  m_commands = new CUSBCECAdapterCommands(this);
 }
 
 CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
 {
   Close();
-  delete m_commands;
-  delete m_adapterMessageQueue;
-  delete m_port;
+  DELETE_AND_NULL(m_commands);
+  DELETE_AND_NULL(m_adapterMessageQueue);
+  DELETE_AND_NULL(m_port);
+}
+
+void CUSBCECAdapterCommunication::ResetMessageQueue(void)
+{
+  DELETE_AND_NULL(m_adapterMessageQueue);
+  m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
+  m_adapterMessageQueue->CreateThread();
 }
 
 bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
@@ -95,15 +104,7 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
       return true;
     }
 
-    /* adapter commands */
-    if (!m_commands)
-      m_commands = new CUSBCECAdapterCommands(this);
-
-    if (!m_adapterMessageQueue)
-    {
-      m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
-      m_adapterMessageQueue->CreateThread();
-    }
+    ResetMessageQueue();
 
     /* try to open the connection */
     CStdString strError;
@@ -144,6 +145,9 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
     ClearInputBytes();
   }
 
+  // always start by setting the ackmask to 0, to clear previous values
+  SetAckMask(0);
+
   if (!CreateThread())
   {
     bConnectionOpened = false;
@@ -195,10 +199,7 @@ void CUSBCECAdapterCommunication::Close(void)
   m_adapterMessageQueue->Clear();
 
   /* stop and delete the ping thread */
-  if (m_pingThread)
-    m_pingThread->StopThread(0);
-  delete m_pingThread;
-  m_pingThread = NULL;
+  DELETE_AND_NULL(m_pingThread);
 
   /* close and delete the com port connection */
   if (m_port)
@@ -341,7 +342,8 @@ bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
   {
     LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
     message->state = ADAPTER_MESSAGE_STATE_ERROR;
-    Close();
+    // this will trigger an alert in the reader thread
+    m_port->Close();
     return false;
   }
 
@@ -486,7 +488,7 @@ bool CUSBCECAdapterCommunication::StartBootloader(void)
 {
   if (m_port->IsOpen() && m_commands->StartBootloader())
   {
-    Close();
+    m_port->Close();
     return true;
   }
   return false;
@@ -494,11 +496,15 @@ bool CUSBCECAdapterCommunication::StartBootloader(void)
 
 bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
 {
-  if (m_iAckMask == iMask)
-    return true;
+  {
+    CLockObject lock(m_mutex);
+    if (m_iAckMask == iMask)
+      return true;
+  }
 
   if (IsOpen() && m_commands->SetAckMask(iMask))
   {
+    CLockObject lock(m_mutex);
     m_iAckMask = iMask;
     return true;
   }
@@ -509,6 +515,7 @@ bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
 
 uint16_t CUSBCECAdapterCommunication::GetAckMask(void)
 {
+  CLockObject lock(m_mutex);
   return m_iAckMask;
 }