cec: ensure that the ackmask is always set to 0 when closing the connection and that...
[deb_libcec.git] / src / lib / CECProcessor.cpp
index 20b8e059f329f210400fd9570af8c0c5f571fa25..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);
 
@@ -510,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]);
 }
 
@@ -548,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;
 
@@ -560,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)
@@ -582,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;
 }
@@ -660,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())
     {
@@ -853,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);
   }
@@ -947,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)
@@ -1410,9 +1439,6 @@ bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
 bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
 {
        bool bReinit(false);
-  bool bPhysicalAddressChanged(false);
-       bool bHdmiPortChanged(false);
-       bool bDeviceTypeChanged(false);
   CCECBusDevice *primary = IsRunning() ? GetPrimaryDevice() : NULL;
        cec_device_type oldPrimaryType = primary ? primary->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE;
   m_configuration.clientVersion  = configuration->clientVersion;
@@ -1420,22 +1446,54 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
   // client version 1.5.0
 
   // device types
-  bDeviceTypeChanged |= 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
-  bPhysicalAddressChanged |= 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
-  bHdmiPortChanged |= 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
-  bHdmiPortChanged |= 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;
+       bReinit = bPhysicalAddressChanged || bHdmiPortChanged || bDeviceTypeChanged || bPhysicalAutodetected;
 
   // device name
   snprintf(m_configuration.strDeviceName, 13, "%s", configuration->strDeviceName);
@@ -1477,7 +1535,7 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
                        return ChangeDeviceType(oldPrimaryType, m_configuration.deviceTypes[0]);
                else if (bPhysicalAddressChanged)
                        return SetPhysicalAddress(m_configuration.iPhysicalAddress);
-               else
+    else
       return SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort);
   }
 
@@ -1490,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;