remove all pre-v2.0 compatibility checks
[deb_libcec.git] / src / lib / CECProcessor.cpp
index b4445f42f921881edb6361d57f45a7498c62136f..824744cc061d9e52bfd11c69099508d050b81575 100644 (file)
@@ -63,13 +63,17 @@ CCECProcessor::CCECProcessor(CLibCEC *libcec) :
     m_iStandardLineTimeout(3),
     m_iRetryLineTimeout(3),
     m_iLastTransmission(0),
-    m_bMonitor(true)
+    m_bMonitor(true),
+    m_addrAllocator(NULL),
+    m_bStallCommunication(false)
 {
   m_busDevices = new CCECDeviceMap(this);
 }
 
 CCECProcessor::~CCECProcessor(void)
 {
+  m_bStallCommunication = false;
+  DELETE_AND_NULL(m_addrAllocator);
   Close();
   DELETE_AND_NULL(m_busDevices);
 }
@@ -100,6 +104,8 @@ void CCECProcessor::Close(void)
   SetCECInitialised(false);
 
   // stop the processor
+  StopThread(-1);
+  m_inBuffer.Broadcast();
   StopThread();
 
   // close the connection
@@ -218,7 +224,7 @@ void *CCECProcessor::Process(void)
     if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME))
       ProcessCommand(command);
 
-    if (CECInitialised())
+    if (CECInitialised() && !IsStopped())
     {
       // check clients for keypress timeouts
       m_libcec->CheckKeypressTimeout();
@@ -410,6 +416,9 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
     }
   }
 
+  // wait until we finished allocating a new LA if it got lost
+  while (m_bStallCommunication) Sleep(5);
+
   {
     CLockObject lock(m_mutex);
     m_iLastTransmission = GetTimeMs();
@@ -430,7 +439,9 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
     iLineTimeout = m_iRetryLineTimeout;
   }
 
-  return adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  return bIsReply ?
+      adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED || adapterState == ADAPTER_MESSAGE_STATE_SENT || adapterState == ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT :
+      adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
 }
 
 void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
@@ -642,6 +653,54 @@ CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const
   return CCECBusDevice::AsTuner(m_busDevices->At(address));
 }
 
+bool CCECProcessor::AllocateLogicalAddresses(CCECClient* client)
+{
+  libcec_configuration &configuration = *client->GetConfiguration();
+
+  // mark as unregistered
+  client->SetRegistered(false);
+
+  // unregister this client from the old addresses
+  CECDEVICEVEC devices;
+  m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    // remove client entry
+    CLockObject lock(m_mutex);
+    m_clients.erase((*it)->GetLogicalAddress());
+  }
+
+  // find logical addresses for this client
+  if (!client->AllocateLogicalAddresses())
+  {
+    m_libcec->AddLog(CEC_LOG_ERROR, "failed to find a free logical address for the client");
+    return false;
+  }
+
+  // register this client on the new addresses
+  devices.clear();
+  m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    // set the physical address of the device at this LA
+    if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+      (*it)->SetPhysicalAddress(configuration.iPhysicalAddress);
+
+    // replace a previous client
+    CLockObject lock(m_mutex);
+    m_clients.erase((*it)->GetLogicalAddress());
+    m_clients.insert(make_pair<cec_logical_address, CCECClient *>((*it)->GetLogicalAddress(), client));
+  }
+
+  // set the new ackmask
+  SetLogicalAddresses(GetLogicalAddresses());
+
+  // resume outgoing communication
+  m_bStallCommunication = false;
+
+  return true;
+}
+
 bool CCECProcessor::RegisterClient(CCECClient *client)
 {
   if (!client)
@@ -649,7 +708,13 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
 
   libcec_configuration &configuration = *client->GetConfiguration();
 
-  if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_3 && configuration.bMonitorOnly == 1)
+  if (configuration.clientVersion < CEC_CLIENT_VERSION_2_0_0)
+  {
+    m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: client version %s is no longer supported", ToString((cec_client_version)configuration.clientVersion));
+    return false;
+  }
+
+  if (configuration.bMonitorOnly == 1)
     return true;
 
   if (!CECInitialised())
@@ -684,36 +749,20 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
   // get the configuration from the client
   m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion));
 
-  // mark as uninitialised and unregistered
-  client->SetRegistered(false);
-  client->SetInitialised(false);
-
   // get the current ackmask, so we can restore it if polling fails
   cec_logical_addresses previousMask = GetLogicalAddresses();
 
+  // mark as uninitialised
+  client->SetInitialised(false);
+
   // find logical addresses for this client
-  if (!client->AllocateLogicalAddresses())
+  if (!AllocateLogicalAddresses(client))
   {
     m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types");
     SetLogicalAddresses(previousMask);
     return false;
   }
 
-  // register this client on the new addresses
-  CECDEVICEVEC devices;
-  m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
-  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
-  {
-               // set the physical address of the device at this LA
-    if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
-      (*it)->SetPhysicalAddress(configuration.iPhysicalAddress);
-
-    // replace a previous client
-    CLockObject lock(m_mutex);
-    m_clients.erase((*it)->GetLogicalAddress());
-    m_clients.insert(make_pair<cec_logical_address, CCECClient *>((*it)->GetLogicalAddress(), client));
-  }
-
   // get the settings from the rom
   if (configuration.bGetSettingsFromROM == 1)
   {
@@ -737,10 +786,8 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
   // mark the client as registered
   client->SetRegistered(true);
 
-  // set the new ack mask
-  bool bReturn = SetLogicalAddresses(GetLogicalAddresses()) &&
-      // and initialise the client
-      client->OnRegister();
+  // initialise the client
+  bool bReturn = client->OnRegister();
 
   // log the new registration
   CStdString strLog;
@@ -814,7 +861,7 @@ bool CCECProcessor::UnregisterClient(CCECClient *client)
 
 void CCECProcessor::UnregisterClients(void)
 {
-  m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering all CEC clients");
+  m_libcec->AddLog(CEC_LOG_DEBUG, "unregistering all CEC clients");
 
   vector<CCECClient *> clients = m_libcec->GetClients();
   for (vector<CCECClient *>::iterator client = clients.begin(); client != clients.end(); client++)
@@ -887,10 +934,42 @@ void CCECProcessor::SwitchMonitoring(bool bSwitchTo)
     UnregisterClients();
 }
 
-void CCECProcessor::HandleLogicalAddressLost(cec_logical_address address)
+void CCECProcessor::HandleLogicalAddressLost(cec_logical_address oldAddress)
 {
-  m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, re-registering the client");
-  CCECClient* client = GetClient(address);
+  // stall outgoing messages until we know our new LA
+  m_bStallCommunication = true;
+
+  m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, allocating a new address", oldAddress);
+  CCECClient* client = GetClient(oldAddress);
+  if (!client)
+    client = GetPrimaryClient();
   if (client)
-    RegisterClient(client);
+  {
+    if (m_addrAllocator)
+      while (m_addrAllocator->IsRunning()) Sleep(5);
+    delete m_addrAllocator;
+
+    m_addrAllocator = new CCECAllocateLogicalAddress(this, client);
+    m_addrAllocator->CreateThread();
+  }
+}
+
+uint16_t CCECProcessor::GetAdapterVendorId(void) const
+{
+  return m_communication ? m_communication->GetAdapterVendorId() : 0;
+}
+
+uint16_t CCECProcessor::GetAdapterProductId(void) const
+{
+  return m_communication ? m_communication->GetAdapterProductId() : 0;
+}
+
+CCECAllocateLogicalAddress::CCECAllocateLogicalAddress(CCECProcessor* processor, CCECClient* client) :
+    m_processor(processor),
+    m_client(client) { }
+
+void* CCECAllocateLogicalAddress::Process(void)
+{
+  m_processor->AllocateLogicalAddresses(m_client);
+  return NULL;
 }