summaryrefslogtreecommitdiffstats
path: root/xbmc/peripherals/bus/PeripheralBus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/peripherals/bus/PeripheralBus.cpp')
-rw-r--r--xbmc/peripherals/bus/PeripheralBus.cpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/xbmc/peripherals/bus/PeripheralBus.cpp b/xbmc/peripherals/bus/PeripheralBus.cpp
new file mode 100644
index 0000000..59a4c61
--- /dev/null
+++ b/xbmc/peripherals/bus/PeripheralBus.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "PeripheralBus.h"
+
+#include "FileItem.h"
+#include "guilib/LocalizeStrings.h"
+#include "peripherals/Peripherals.h"
+#include "peripherals/devices/Peripheral.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+
+#include <mutex>
+
+using namespace PERIPHERALS;
+using namespace std::chrono_literals;
+
+namespace
+{
+constexpr auto PERIPHERAL_DEFAULT_RESCAN_INTERVAL = 5000ms;
+}
+
+CPeripheralBus::CPeripheralBus(const std::string& threadname,
+ CPeripherals& manager,
+ PeripheralBusType type)
+ : CThread(threadname.c_str()),
+ m_iRescanTime(PERIPHERAL_DEFAULT_RESCAN_INTERVAL),
+ m_bNeedsPolling(true),
+ m_manager(manager),
+ m_type(type),
+ m_triggerEvent(true)
+{
+}
+
+bool CPeripheralBus::InitializeProperties(CPeripheral& peripheral)
+{
+ return true;
+}
+
+void CPeripheralBus::OnDeviceAdded(const std::string& strLocation)
+{
+ ScanForDevices();
+}
+
+void CPeripheralBus::OnDeviceChanged(const std::string& strLocation)
+{
+ ScanForDevices();
+}
+
+void CPeripheralBus::OnDeviceRemoved(const std::string& strLocation)
+{
+ ScanForDevices();
+}
+
+void CPeripheralBus::Clear(void)
+{
+ if (m_bNeedsPolling)
+ {
+ StopThread(false);
+ m_triggerEvent.Set();
+ StopThread(true);
+ }
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ m_peripherals.clear();
+}
+
+void CPeripheralBus::UnregisterRemovedDevices(const PeripheralScanResults& results)
+{
+ PeripheralVector removedPeripherals;
+
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (int iDevicePtr = (int)m_peripherals.size() - 1; iDevicePtr >= 0; iDevicePtr--)
+ {
+ const PeripheralPtr& peripheral = m_peripherals.at(iDevicePtr);
+ PeripheralScanResult updatedDevice(m_type);
+ if (!results.GetDeviceOnLocation(peripheral->Location(), &updatedDevice) ||
+ *peripheral != updatedDevice)
+ {
+ /* device removed */
+ removedPeripherals.push_back(peripheral);
+ m_peripherals.erase(m_peripherals.begin() + iDevicePtr);
+ }
+ }
+ }
+
+ for (auto& peripheral : removedPeripherals)
+ {
+ std::vector<PeripheralFeature> features;
+ peripheral->GetFeatures(features);
+ bool peripheralHasFeatures =
+ features.size() > 1 || (features.size() == 1 && features.at(0) != FEATURE_UNKNOWN);
+ if (peripheral->Type() != PERIPHERAL_UNKNOWN || peripheralHasFeatures)
+ {
+ CLog::Log(LOGINFO, "{} - device removed from {}/{}: {} ({}:{})", __FUNCTION__,
+ PeripheralTypeTranslator::TypeToString(peripheral->Type()), peripheral->Location(),
+ peripheral->DeviceName(), peripheral->VendorIdAsString(),
+ peripheral->ProductIdAsString());
+ peripheral->OnDeviceRemoved();
+ }
+
+ m_manager.OnDeviceDeleted(*this, *peripheral);
+ }
+}
+
+void CPeripheralBus::RegisterNewDevices(const PeripheralScanResults& results)
+{
+ for (unsigned int iResultPtr = 0; iResultPtr < results.m_results.size(); iResultPtr++)
+ {
+ const PeripheralScanResult& result = results.m_results.at(iResultPtr);
+ if (!HasPeripheral(result.m_strLocation))
+ m_manager.CreatePeripheral(*this, result);
+ }
+}
+
+bool CPeripheralBus::ScanForDevices(void)
+{
+ bool bReturn(false);
+
+ PeripheralScanResults results;
+ if (PerformDeviceScan(results))
+ {
+ UnregisterRemovedDevices(results);
+ RegisterNewDevices(results);
+
+ m_manager.NotifyObservers(ObservableMessagePeripheralsChanged);
+
+ bReturn = true;
+ }
+
+ return bReturn;
+}
+
+bool CPeripheralBus::HasFeature(const PeripheralFeature feature) const
+{
+ bool bReturn(false);
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
+ {
+ if (m_peripherals.at(iPeripheralPtr)->HasFeature(feature))
+ {
+ bReturn = true;
+ break;
+ }
+ }
+ return bReturn;
+}
+
+void CPeripheralBus::GetFeatures(std::vector<PeripheralFeature>& features) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
+ m_peripherals.at(iPeripheralPtr)->GetFeatures(features);
+}
+
+PeripheralPtr CPeripheralBus::GetPeripheral(const std::string& strLocation) const
+{
+ PeripheralPtr result;
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (auto& peripheral : m_peripherals)
+ {
+ if (peripheral->Location() == strLocation)
+ {
+ result = peripheral;
+ break;
+ }
+ }
+ return result;
+}
+
+unsigned int CPeripheralBus::GetPeripheralsWithFeature(PeripheralVector& results,
+ const PeripheralFeature feature) const
+{
+ unsigned int iReturn = 0;
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (auto& peripheral : m_peripherals)
+ {
+ if (peripheral->HasFeature(feature))
+ {
+ results.push_back(peripheral);
+ ++iReturn;
+ }
+ }
+
+ return iReturn;
+}
+
+unsigned int CPeripheralBus::GetNumberOfPeripheralsWithId(const int iVendorId,
+ const int iProductId) const
+{
+ unsigned int iReturn = 0;
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (const auto& peripheral : m_peripherals)
+ {
+ if (peripheral->VendorId() == iVendorId && peripheral->ProductId() == iProductId)
+ iReturn++;
+ }
+
+ return iReturn;
+}
+
+void CPeripheralBus::Process(void)
+{
+ while (!m_bStop)
+ {
+ m_triggerEvent.Reset();
+
+ if (!ScanForDevices())
+ break;
+
+ // depending on bus implementation
+ // needsPolling can be set properly
+ // only after initial scan.
+ // if this is the case, bail out.
+ if (!m_bNeedsPolling)
+ break;
+
+ if (!m_bStop)
+ m_triggerEvent.Wait(m_iRescanTime);
+ }
+}
+
+void CPeripheralBus::Initialise(void)
+{
+ bool bNeedsPolling = false;
+
+ if (!IsRunning())
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ bNeedsPolling = m_bNeedsPolling;
+ }
+
+ if (bNeedsPolling)
+ {
+ m_triggerEvent.Reset();
+ Create();
+ SetPriority(ThreadPriority::BELOW_NORMAL);
+ }
+}
+
+void CPeripheralBus::Register(const PeripheralPtr& peripheral)
+{
+ if (!peripheral)
+ return;
+
+ bool bPeripheralAdded = false;
+
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (!HasPeripheral(peripheral->Location()))
+ {
+ m_peripherals.push_back(peripheral);
+ bPeripheralAdded = true;
+ }
+ }
+
+ if (bPeripheralAdded)
+ {
+ CLog::Log(LOGINFO, "{} - new {} device registered on {}->{}: {} ({}:{})", __FUNCTION__,
+ PeripheralTypeTranslator::TypeToString(peripheral->Type()),
+ PeripheralTypeTranslator::BusTypeToString(m_type), peripheral->Location(),
+ peripheral->DeviceName(), peripheral->VendorIdAsString(),
+ peripheral->ProductIdAsString());
+ m_manager.OnDeviceAdded(*this, *peripheral);
+ }
+}
+
+void CPeripheralBus::TriggerDeviceScan(void)
+{
+ bool bNeedsPolling;
+
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ bNeedsPolling = m_bNeedsPolling;
+ }
+
+ if (bNeedsPolling)
+ m_triggerEvent.Set();
+ else
+ ScanForDevices();
+}
+
+bool CPeripheralBus::HasPeripheral(const std::string& strLocation) const
+{
+ return (GetPeripheral(strLocation) != NULL);
+}
+
+void CPeripheralBus::GetDirectory(const std::string& strPath, CFileItemList& items) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (const auto& peripheral : m_peripherals)
+ {
+ if (peripheral->IsHidden())
+ continue;
+
+ CFileItemPtr peripheralFile(new CFileItem(peripheral->DeviceName()));
+ peripheralFile->SetPath(peripheral->FileLocation());
+ peripheralFile->SetProperty("vendor", peripheral->VendorIdAsString());
+ peripheralFile->SetProperty("product", peripheral->ProductIdAsString());
+ peripheralFile->SetProperty(
+ "bus", PeripheralTypeTranslator::BusTypeToString(peripheral->GetBusType()));
+ peripheralFile->SetProperty("location", peripheral->Location());
+ peripheralFile->SetProperty("class",
+ PeripheralTypeTranslator::TypeToString(peripheral->Type()));
+
+ std::string strVersion(peripheral->GetVersionInfo());
+ if (strVersion.empty())
+ strVersion = g_localizeStrings.Get(13205);
+
+ std::string strDetails = StringUtils::Format("{} {}", g_localizeStrings.Get(24051), strVersion);
+ if (peripheral->GetBusType() == PERIPHERAL_BUS_CEC && !peripheral->GetSettingBool("enabled"))
+ strDetails =
+ StringUtils::Format("{}: {}", g_localizeStrings.Get(126), g_localizeStrings.Get(13106));
+
+ peripheralFile->SetProperty("version", strVersion);
+ peripheralFile->SetLabel2(strDetails);
+ peripheralFile->SetArt("icon", peripheral->GetIcon());
+
+ items.Add(peripheralFile);
+ }
+}
+
+PeripheralPtr CPeripheralBus::GetByPath(const std::string& strPath) const
+{
+ PeripheralPtr result;
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ for (auto& peripheral : m_peripherals)
+ {
+ if (StringUtils::EqualsNoCase(strPath, peripheral->FileLocation()))
+ {
+ result = peripheral;
+ break;
+ }
+ }
+
+ return result;
+}
+
+unsigned int CPeripheralBus::GetNumberOfPeripherals() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return static_cast<unsigned int>(m_peripherals.size());
+}