2 * Copyright (C) 2005-2011 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "Peripherals.h"
23 #include "bus/PeripheralBus.h"
24 #include "devices/PeripheralBluetooth.h"
25 #include "devices/PeripheralDisk.h"
26 #include "devices/PeripheralHID.h"
27 #include "devices/PeripheralNIC.h"
28 #include "devices/PeripheralNyxboard.h"
29 #include "devices/PeripheralTuner.h"
31 #include "devices/PeripheralCecAdapter.h"
33 #include "bus/PeripheralBusUSB.h"
34 #include "dialogs/GUIDialogPeripheralManager.h"
36 #include "threads/SingleLock.h"
37 #include "utils/log.h"
38 #include "utils/XMLUtils.h"
39 #include "settings/GUISettings.h"
40 #include "tinyXML/tinyxml.h"
41 #include "filesystem/Directory.h"
42 #include "guilib/GUIWindowManager.h"
43 #include "guilib/LocalizeStrings.h"
44 #include "dialogs/GUIDialogKaiToast.h"
45 #include "utils/StringUtils.h"
47 using namespace PERIPHERALS;
48 using namespace XFILE;
51 CPeripherals::CPeripherals(void)
53 CDirectory::Create("special://profile/peripheral_data");
58 CPeripherals::~CPeripherals(void)
63 CPeripherals &CPeripherals::Get(void)
65 static CPeripherals peripheralsInstance;
66 return peripheralsInstance;
69 void CPeripherals::Initialise(void)
71 CSingleLock lock(m_critSection);
76 /* load mappings from peripherals.xml */
79 #if defined(HAVE_PERIPHERAL_BUS_USB)
80 m_busses.push_back(new CPeripheralBusUSB(this));
83 /* initialise all known busses */
84 for (int iBusPtr = (int)m_busses.size() - 1; iBusPtr >= 0; iBusPtr--)
86 if (!m_busses.at(iBusPtr)->Initialise())
88 CLog::Log(LOGERROR, "%s - failed to initialise bus %s", __FUNCTION__, PeripheralTypeTranslator::BusTypeToString(m_busses.at(iBusPtr)->Type()));
89 delete m_busses.at(iBusPtr);
90 m_busses.erase(m_busses.begin() + iBusPtr);
94 m_bInitialised = true;
98 void CPeripherals::Clear(void)
100 CSingleLock lock(m_critSection);
101 /* delete busses and devices */
102 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
103 delete m_busses.at(iBusPtr);
106 /* delete mappings */
107 for (unsigned int iMappingPtr = 0; iMappingPtr < m_mappings.size(); iMappingPtr++)
108 m_mappings.at(iMappingPtr).m_settings.clear();
111 /* reset class state */
112 m_bIsStarted = false;
113 m_bInitialised = false;
116 void CPeripherals::TriggerDeviceScan(const PeripheralBusType type /* = PERIPHERAL_BUS_UNKNOWN */)
118 CSingleLock lock(m_critSection);
119 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
121 if (type == PERIPHERAL_BUS_UNKNOWN || m_busses.at(iBusPtr)->Type() == type)
123 m_busses.at(iBusPtr)->TriggerDeviceScan();
124 if (type != PERIPHERAL_BUS_UNKNOWN)
130 CPeripheralBus *CPeripherals::GetBusByType(const PeripheralBusType type) const
132 CPeripheralBus *bus(NULL);
134 CSingleLock lock(m_critSection);
135 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
137 if (m_busses.at(iBusPtr)->Type() == type)
139 bus = m_busses.at(iBusPtr);
147 CPeripheral *CPeripherals::GetPeripheralAtLocation(const CStdString &strLocation, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
149 CPeripheral *peripheral(NULL);
150 CSingleLock lock(m_critSection);
151 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
153 /* check whether the bus matches if a bus type other than unknown was passed */
154 if (busType != PERIPHERAL_BUS_UNKNOWN && m_busses.at(iBusPtr)->Type() != busType)
157 /* return the first device that matches */
158 if ((peripheral = m_busses.at(iBusPtr)->GetPeripheral(strLocation)) != NULL)
165 bool CPeripherals::HasPeripheralAtLocation(const CStdString &strLocation, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
167 return (GetPeripheralAtLocation(strLocation, busType) != NULL);
170 CPeripheralBus *CPeripherals::GetBusWithDevice(const CStdString &strLocation) const
172 CSingleLock lock(m_critSection);
173 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
175 /* return the first bus that matches */
176 if (m_busses.at(iBusPtr)->HasPeripheral(strLocation))
177 return m_busses.at(iBusPtr);
183 int CPeripherals::GetPeripheralsWithFeature(vector<CPeripheral *> &results, const PeripheralFeature feature, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
186 CSingleLock lock(m_critSection);
187 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
189 /* check whether the bus matches if a bus type other than unknown was passed */
190 if (busType != PERIPHERAL_BUS_UNKNOWN && m_busses.at(iBusPtr)->Type() != busType)
193 iReturn += m_busses.at(iBusPtr)->GetPeripheralsWithFeature(results, feature);
199 bool CPeripherals::HasPeripheralWithFeature(const PeripheralFeature feature, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
201 vector<CPeripheral *> dummy;
202 return (GetPeripheralsWithFeature(dummy, feature, busType) > 0);
205 CPeripheral *CPeripherals::CreatePeripheral(CPeripheralBus &bus, const PeripheralType type, const CStdString &strLocation, int iVendorId /* = 0 */, int iProductId /* = 0 */)
207 CPeripheral *peripheral = GetPeripheralAtLocation(strLocation, bus.Type());
209 /* only create a new device instances if there's no device at the given location */
212 /* check whether there's something mapped in peripherals.xml */
213 PeripheralType mappedType = type;
214 CStdString strDeviceName;
215 int iMappingPtr = GetMappingForDevice(bus, type, iVendorId, iProductId);
216 bool bHasMapping(iMappingPtr >= 0);
219 mappedType = m_mappings[iMappingPtr].m_mappedTo;
220 strDeviceName = m_mappings[iMappingPtr].m_strDeviceName;
224 /* don't create instances for devices that aren't mapped in peripherals.xml */
231 peripheral = new CPeripheralHID(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
235 peripheral = new CPeripheralNIC(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
238 case PERIPHERAL_DISK:
239 peripheral = new CPeripheralDisk(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
242 case PERIPHERAL_NYXBOARD:
243 peripheral = new CPeripheralNyxboard(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
246 case PERIPHERAL_TUNER:
247 peripheral = new CPeripheralTuner(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
250 case PERIPHERAL_BLUETOOTH:
251 peripheral = new CPeripheralBluetooth(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
256 peripheral = new CPeripheralCecAdapter(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
261 peripheral = new CPeripheral(type, bus.Type(), strLocation, strDeviceName, iVendorId, iProductId);
267 /* try to initialise the new peripheral
268 * Initialise() will make sure that each device is only initialised once */
269 if (peripheral->Initialise())
272 peripheral->SetHidden(true);
273 bus.Register(peripheral);
277 CLog::Log(LOGDEBUG, "%s - failed to initialise peripheral on '%s'", __FUNCTION__, strLocation.c_str());
287 void CPeripherals::OnDeviceAdded(const CPeripheralBus &bus, const CStdString &strLocation)
289 CGUIDialogPeripheralManager *dialog = (CGUIDialogPeripheralManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PERIPHERAL_MANAGER);
290 if (dialog && dialog->IsActive())
293 CPeripheral *peripheral = GetByPath(strLocation);
295 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(35005), peripheral->DeviceName());
298 void CPeripherals::OnDeviceDeleted(const CPeripheralBus &bus, const CStdString &strLocation)
300 CGUIDialogPeripheralManager *dialog = (CGUIDialogPeripheralManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PERIPHERAL_MANAGER);
301 if (dialog && dialog->IsActive())
304 CPeripheral *peripheral = GetByPath(strLocation);
306 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(35006), peripheral->DeviceName());
309 int CPeripherals::GetMappingForDevice(const CPeripheralBus &bus, const PeripheralType classType, int iVendorId, int iProductId) const
311 /* check all mappings in the order in which they are defined in peripherals.xml */
312 for (unsigned int iMappingPtr = 0; iMappingPtr < m_mappings.size(); iMappingPtr++)
314 PeripheralDeviceMapping mapping = m_mappings.at(iMappingPtr);
315 bool bBusMatch = (mapping.m_busType == PERIPHERAL_BUS_UNKNOWN || mapping.m_busType == bus.Type());
316 bool bVendorMatch = (mapping.m_iVendorId == 0 || mapping.m_iVendorId == iVendorId);
317 bool bProductMatch = (mapping.m_iProductId == 0 || mapping.m_iProductId == iProductId);
318 bool bClassMatch = (mapping.m_class == PERIPHERAL_UNKNOWN || mapping.m_class == classType);
320 if (bBusMatch && bVendorMatch && bProductMatch && bClassMatch)
322 CLog::Log(LOGDEBUG, "%s - device (%s:%s) mapped to %s (type = %s)", __FUNCTION__, PeripheralTypeTranslator::IntToHexString(iVendorId), PeripheralTypeTranslator::IntToHexString(iProductId), mapping.m_strDeviceName.c_str(), PeripheralTypeTranslator::TypeToString(mapping.m_mappedTo));
330 void CPeripherals::GetSettingsFromMapping(CPeripheral &peripheral) const
332 /* check all mappings in the order in which they are defined in peripherals.xml */
333 for (unsigned int iMappingPtr = 0; iMappingPtr < m_mappings.size(); iMappingPtr++)
335 const PeripheralDeviceMapping *mapping = &m_mappings.at(iMappingPtr);
336 bool bBusMatch = (mapping->m_busType == PERIPHERAL_BUS_UNKNOWN || mapping->m_busType == peripheral.GetBusType());
337 bool bVendorMatch = (mapping->m_iVendorId == 0 || mapping->m_iVendorId == peripheral.VendorId());
338 bool bProductMatch = (mapping->m_iProductId == 0 || mapping->m_iProductId == peripheral.ProductId());
339 bool bClassMatch = (mapping->m_class == PERIPHERAL_UNKNOWN || mapping->m_class == peripheral.Type());
341 if (bBusMatch && bVendorMatch && bProductMatch && bClassMatch)
343 for (map<CStdString, CSetting *>::const_iterator itr = mapping->m_settings.begin(); itr != mapping->m_settings.end(); itr++)
344 peripheral.AddSetting((*itr).first, (*itr).second);
349 bool CPeripherals::LoadMappings(void)
351 TiXmlDocument xmlDoc;
352 if (!xmlDoc.LoadFile("special://xbmc/system/peripherals.xml"))
354 CLog::Log(LOGWARNING, "%s - peripherals.xml does not exist", __FUNCTION__);
358 TiXmlElement *pRootElement = xmlDoc.RootElement();
359 if (strcmpi(pRootElement->Value(), "peripherals") != 0)
361 CLog::Log(LOGERROR, "%s - peripherals.xml does not contain <peripherals>", __FUNCTION__);
365 TiXmlElement *currentNode = pRootElement->FirstChildElement("peripheral");
368 PeripheralDeviceMapping mapping;
370 mapping.m_iVendorId = currentNode->Attribute("vendor") ? PeripheralTypeTranslator::HexStringToInt(currentNode->Attribute("vendor")) : 0;
371 mapping.m_iProductId = currentNode->Attribute("product") ? PeripheralTypeTranslator::HexStringToInt(currentNode->Attribute("product")) : 0;
372 mapping.m_busType = PeripheralTypeTranslator::GetBusTypeFromString(currentNode->Attribute("bus"));
373 mapping.m_class = PeripheralTypeTranslator::GetTypeFromString(currentNode->Attribute("class"));
374 mapping.m_strDeviceName = currentNode->Attribute("name") ? CStdString(currentNode->Attribute("name")) : StringUtils::EmptyString;
375 mapping.m_mappedTo = PeripheralTypeTranslator::GetTypeFromString(currentNode->Attribute("mapTo"));
376 GetSettingsFromMappingsFile(currentNode, mapping.m_settings);
378 m_mappings.push_back(mapping);
379 currentNode = currentNode->NextSiblingElement("peripheral");
385 void CPeripherals::GetSettingsFromMappingsFile(TiXmlElement *xmlNode, map<CStdString, CSetting *> &m_settings)
387 TiXmlElement *currentNode = xmlNode->FirstChildElement("setting");
390 CSetting *setting = NULL;
391 CStdString strKey(currentNode->Attribute("key"));
392 if (strKey.IsEmpty())
395 CStdString strSettingsType(currentNode->Attribute("type"));
396 int iLabelId = currentNode->Attribute("label") ? atoi(currentNode->Attribute("label")) : -1;
397 bool bConfigurable = (!currentNode->Attribute("configurable") ||
398 strcmp(currentNode->Attribute("configurable"), "") == 0 ||
399 (strcmp(currentNode->Attribute("configurable"), "no") != 0 &&
400 strcmp(currentNode->Attribute("configurable"), "false") != 0 &&
401 strcmp(currentNode->Attribute("configurable"), "0") != 0));
402 if (strSettingsType.Equals("bool"))
404 bool bValue = (strcmp(currentNode->Attribute("value"), "no") != 0 &&
405 strcmp(currentNode->Attribute("value"), "false") != 0 &&
406 strcmp(currentNode->Attribute("value"), "0") != 0);
407 setting = new CSettingBool(0, strKey, iLabelId, bValue, CHECKMARK_CONTROL);
409 else if (strSettingsType.Equals("int"))
411 int iValue = currentNode->Attribute("value") ? atoi(currentNode->Attribute("value")) : 0;
412 int iMin = currentNode->Attribute("min") ? atoi(currentNode->Attribute("min")) : 0;
413 int iStep = currentNode->Attribute("step") ? atoi(currentNode->Attribute("step")) : 0;
414 int iMax = currentNode->Attribute("max") ? atoi(currentNode->Attribute("max")) : 0;
415 CStdString strFormat(currentNode->Attribute("format"));
416 setting = new CSettingInt(0, strKey, iLabelId, iValue, iMin, iStep, iMax, SPIN_CONTROL_INT, strFormat);
418 else if (strSettingsType.Equals("float"))
420 float fValue = currentNode->Attribute("value") ? atof(currentNode->Attribute("value")) : 0;
421 float fMin = currentNode->Attribute("min") ? atof(currentNode->Attribute("min")) : 0;
422 float fStep = currentNode->Attribute("step") ? atof(currentNode->Attribute("step")) : 0;
423 float fMax = currentNode->Attribute("max") ? atof(currentNode->Attribute("max")) : 0;
424 setting = new CSettingFloat(0, strKey, iLabelId, fValue, fMin, fStep, fMax, SPIN_CONTROL_FLOAT);
428 CStdString strValue(currentNode->Attribute("value"));
429 setting = new CSettingString(0, strKey, iLabelId, strValue, EDIT_CONTROL_INPUT, !bConfigurable, -1);
432 //TODO add more types if needed
433 setting->SetVisible(bConfigurable);
434 m_settings[strKey] = setting;
435 currentNode = currentNode->NextSiblingElement("setting");
439 void CPeripherals::GetDirectory(const CStdString &strPath, CFileItemList &items) const
441 if (!strPath.Left(14).Equals("peripherals://"))
444 CStdString strPathCut = strPath.Right(strPath.length() - 14);
445 CStdString strBus = strPathCut.Left(strPathCut.Find('/'));
447 CSingleLock lock(m_critSection);
448 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
450 if (strBus.Equals("all") || strBus.Equals(PeripheralTypeTranslator::BusTypeToString(m_busses.at(iBusPtr)->Type())))
451 m_busses.at(iBusPtr)->GetDirectory(strPath, items);
455 CPeripheral *CPeripherals::GetByPath(const CStdString &strPath) const
457 if (!strPath.Left(14).Equals("peripherals://"))
460 CStdString strPathCut = strPath.Right(strPath.length() - 14);
461 CStdString strBus = strPathCut.Left(strPathCut.Find('/'));
463 CSingleLock lock(m_critSection);
464 for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
466 if (strBus.Equals(PeripheralTypeTranslator::BusTypeToString(m_busses.at(iBusPtr)->Type())))
467 return m_busses.at(iBusPtr)->GetByPath(strPath);