cec: ensure that the ackmask is always set to 0 when closing the connection and that...
[deb_libcec.git] / src / lib / CECProcessor.cpp
index a76f1980dba888c6ac18679f189c4508da44a662..f9d21346f2dbceaec74dfa2862df5808fbb6cd97 100644 (file)
@@ -66,7 +66,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const libcec_configuration *co
     m_busDevices[CECDEVICE_TV]->ReplaceHandler(false);
 }
 
-CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types, uint16_t iPhysicalAddress, cec_client_version clientVersion) :
+CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types, uint16_t iPhysicalAddress) :
     m_bInitialised(false),
     m_communication(NULL),
     m_controller(controller),
@@ -78,7 +78,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, con
   m_configuration.Clear();
 
   // client version < 1.5.0
-  m_configuration.clientVersion    = clientVersion;
+  m_configuration.clientVersion    = CEC_CLIENT_VERSION_PRE_1_5;
   snprintf(m_configuration.strDeviceName, 13, "%s", strDeviceName);
   m_configuration.deviceTypes      = types;
   m_configuration.iPhysicalAddress = iPhysicalAddress;
@@ -136,6 +136,8 @@ CCECProcessor::~CCECProcessor(void)
 
 void CCECProcessor::Close(void)
 {
+  StopThread(false);
+  SetInitialised(false);
   StopThread();
 
   CLockObject lock(m_mutex);
@@ -228,8 +230,6 @@ bool CCECProcessor::Initialise(void)
   else if (m_configuration.iPhysicalAddress == 0 && (bReturn = SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort, true)) == false)
     CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set HDMI port %d on %s (%x)", m_configuration.iHDMIPort, ToString(m_configuration.baseDevice), (uint8_t)m_configuration.baseDevice);
 
-  PowerOnDevices();
-
   SetInitialised(bReturn);
   CLibCEC::ConfigurationChanged(m_configuration);
 
@@ -440,11 +440,14 @@ void *CCECProcessor::Process(void)
 
   while (!IsStopped() && m_communication->IsOpen())
   {
-    ReplaceHandlers();
-    if (m_commandBuffer.Pop(command))
-      ParseCommand(command);
+    if (IsInitialised())
+    {
+      ReplaceHandlers();
+      if (m_commandBuffer.Pop(command))
+        ParseCommand(command);
 
-    m_controller->CheckKeypressTimeout();
+      m_controller->CheckKeypressTimeout();
+    }
     Sleep(5);
   }
 
@@ -507,6 +510,7 @@ void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
 
 bool CCECProcessor::SetActiveView(void)
 {
+  CLibCEC::AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
   return SetActiveSource(m_configuration.deviceTypes.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_configuration.deviceTypes[0]);
 }
 
@@ -545,10 +549,14 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true *
 bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
 {
   bool bReturn(false);
-  CLockObject lock(m_mutex);
 
-  m_configuration.baseDevice = iBaseDevice;
-  m_configuration.iHDMIPort = iPort;
+  {
+    CLockObject lock(m_mutex);
+    m_configuration.baseDevice = iBaseDevice;
+    m_configuration.iHDMIPort = iPort;
+    m_configuration.bAutodetectAddress = false;
+  }
+
   if (!IsRunning() && !bForce)
     return true;
 
@@ -557,9 +565,7 @@ bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort,
   uint16_t iPhysicalAddress(0);
   if (iBaseDevice > CECDEVICE_TV)
   {
-    lock.Unlock();
     iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
-    lock.Lock();
   }
 
   if (iPhysicalAddress < 0xffff)
@@ -579,10 +585,7 @@ bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort,
   if (!bReturn)
     CLibCEC::AddLog(CEC_LOG_ERROR, "failed to set the physical address");
   else
-  {
-    lock.Unlock();
     SetPhysicalAddress(iPhysicalAddress);
-  }
 
   return bReturn;
 }
@@ -657,6 +660,11 @@ bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpda
   {
     CLockObject lock(m_mutex);
     m_configuration.iPhysicalAddress = iPhysicalAddress;
+    if (m_configuration.bAutodetectAddress)
+    {
+      m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+      m_configuration.iHDMIPort = 0;
+    }
 
     if (!m_logicalAddresses.IsEmpty())
     {
@@ -850,13 +858,22 @@ bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
 
 bool CCECProcessor::Transmit(const cec_command &data)
 {
+  if (m_logicalAddresses[(uint8_t)data.destination])
+  {
+    CLibCEC::AddLog(CEC_LOG_WARNING, "not sending data to myself!");
+    return false;
+  }
+
   cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
   {
     CLockObject lock(m_mutex);
     LogOutput(data);
     m_iLastTransmission = GetTimeMs();
-    if (!m_communication)
+    if (!m_communication || !IsInitialised())
+    {
+      CLibCEC::AddLog(CEC_LOG_ERROR, "cannot transmit command: connection closed");
       return false;
+    }
     uint8_t iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
     retVal = m_communication->Write(data, iMaxTries, m_iLineTimeout, m_iRetryLineTimeout);
   }
@@ -944,6 +961,21 @@ bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bW
   return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
 }
 
+bool CCECProcessor::EnablePhysicalAddressDetection(void)
+{
+  CLibCEC::AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
+  uint16_t iPhysicalAddress = m_communication->GetPhysicalAddress();
+  if (iPhysicalAddress != 0)
+  {
+    m_configuration.bAutodetectAddress = 1;
+    m_configuration.iPhysicalAddress = iPhysicalAddress;
+    m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+    m_configuration.iHDMIPort = 0;
+    return SetPhysicalAddress(iPhysicalAddress);
+  }
+  return false;
+}
+
 bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
 {
   if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
@@ -1406,34 +1438,69 @@ bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
 
 bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
 {
-  bool bNeedsReinit(false);
+       bool bReinit(false);
   CCECBusDevice *primary = IsRunning() ? GetPrimaryDevice() : NULL;
-  m_configuration.clientVersion        = configuration->clientVersion;
+       cec_device_type oldPrimaryType = primary ? primary->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE;
+  m_configuration.clientVersion  = configuration->clientVersion;
 
   // client version 1.5.0
 
   // device types
-  bNeedsReinit |= IsRunning () && m_configuration.deviceTypes != configuration->deviceTypes;
+  bool bDeviceTypeChanged = IsRunning () && m_configuration.deviceTypes != configuration->deviceTypes;
   m_configuration.deviceTypes = configuration->deviceTypes;
 
+  // autodetect address
+  uint16_t iPhysicalAddress = IsRunning() && configuration->bAutodetectAddress ? m_communication->GetPhysicalAddress() : 0;
+  bool bPhysicalAutodetected = IsRunning() && configuration->bAutodetectAddress && iPhysicalAddress != m_configuration.iPhysicalAddress && iPhysicalAddress != 0;
+  if (bPhysicalAutodetected)
+  {
+    m_configuration.iPhysicalAddress = iPhysicalAddress;
+    m_configuration.bAutodetectAddress = true;
+  }
+  else
+  {
+    m_configuration.bAutodetectAddress = false;
+  }
+
   // physical address
-  bNeedsReinit |= IsRunning() && m_configuration.iPhysicalAddress != configuration->iPhysicalAddress;
-  m_configuration.iPhysicalAddress = configuration->iPhysicalAddress;
+  bool bPhysicalAddressChanged(false);
+  if (!bPhysicalAutodetected)
+  {
+    bPhysicalAddressChanged = IsRunning() && m_configuration.iPhysicalAddress != configuration->iPhysicalAddress;
+    m_configuration.iPhysicalAddress = configuration->iPhysicalAddress;
+  }
 
   // base device
-  bNeedsReinit |= IsRunning() && m_configuration.baseDevice != configuration->baseDevice;
-  m_configuration.baseDevice = configuration->baseDevice;
+  bool bHdmiPortChanged(false);
+  if (!bPhysicalAutodetected && !bPhysicalAddressChanged)
+  {
+    bHdmiPortChanged = IsRunning() && m_configuration.baseDevice != configuration->baseDevice;
+    m_configuration.baseDevice = configuration->baseDevice;
+  }
+  else
+  {
+    m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+  }
 
   // hdmi port
-  bNeedsReinit |= IsRunning() && m_configuration.iHDMIPort != configuration->iHDMIPort;
-  m_configuration.iHDMIPort = configuration->iHDMIPort;
+  if (!bPhysicalAutodetected && !bPhysicalAddressChanged)
+  {
+    bHdmiPortChanged |= IsRunning() && m_configuration.iHDMIPort != configuration->iHDMIPort;
+    m_configuration.iHDMIPort = configuration->iHDMIPort;
+  }
+  else
+  {
+    m_configuration.iHDMIPort = 0;
+  }
+
+       bReinit = bPhysicalAddressChanged || bHdmiPortChanged || bDeviceTypeChanged || bPhysicalAutodetected;
 
   // device name
   snprintf(m_configuration.strDeviceName, 13, "%s", configuration->strDeviceName);
   if (primary && !primary->GetOSDName().Equals(m_configuration.strDeviceName))
   {
     primary->SetOSDName(m_configuration.strDeviceName);
-    if (!bNeedsReinit && IsRunning())
+    if (!bReinit && IsRunning())
       primary->TransmitOSDName(CECDEVICE_TV);
   }
 
@@ -1448,7 +1515,7 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   if (m_configuration.wakeDevices != configuration->wakeDevices)
   {
     m_configuration.wakeDevices = configuration->wakeDevices;
-    if (!bNeedsReinit && IsRunning())
+    if (!bReinit && IsRunning())
       PowerOnDevices();
   }
 
@@ -1462,11 +1529,14 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   if (m_configuration.deviceTypes.IsEmpty())
     m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
 
-  if (bNeedsReinit)
+  if (bReinit)
   {
-    SetInitialised(false);
-    m_logicalAddresses.Clear();
-    return Initialise();
+               if (bDeviceTypeChanged)
+                       return ChangeDeviceType(oldPrimaryType, m_configuration.deviceTypes[0]);
+               else if (bPhysicalAddressChanged)
+                       return SetPhysicalAddress(m_configuration.iPhysicalAddress);
+    else
+      return SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort);
   }
 
   return true;
@@ -1478,6 +1548,7 @@ bool CCECProcessor::GetCurrentConfiguration(libcec_configuration *configuration)
   configuration->clientVersion        = m_configuration.clientVersion;
   snprintf(configuration->strDeviceName, 13, "%s", m_configuration.strDeviceName);
   configuration->deviceTypes          = m_configuration.deviceTypes;
+  configuration->bAutodetectAddress   = m_configuration.bAutodetectAddress;
   configuration->iPhysicalAddress     = m_configuration.iPhysicalAddress;
   configuration->baseDevice           = m_configuration.baseDevice;
   configuration->iHDMIPort            = m_configuration.iHDMIPort;