[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / peripherals / bus / PeripheralBus.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "PeripheralBus.h"
22 #include "peripherals/Peripherals.h"
23 #include "utils/Variant.h"
24 #include "utils/log.h"
25 #include "FileItem.h"
26
27 using namespace std;
28 using namespace PERIPHERALS;
29
30 #define PERIPHERAL_DEFAULT_RESCAN_INTERVAL 1000
31
32 bool PeripheralScanResult::operator ==(const PeripheralScanResult &right) const
33 {
34   return m_iVendorId == right.m_iVendorId &&
35       m_iProductId == right.m_iProductId &&
36       m_type == right.m_type &&
37       m_strLocation.Equals(right.m_strLocation);
38 }
39
40 bool PeripheralScanResult::operator !=(const PeripheralScanResult &right) const
41 {
42   return !(*this == right);
43 }
44
45 bool PeripheralScanResult::operator ==(const CPeripheral &right) const
46 {
47   return m_iVendorId == right.VendorId() &&
48       m_iProductId == right.ProductId() &&
49       m_type == right.Type() &&
50       m_strLocation.Equals(right.Location());
51 }
52
53 bool PeripheralScanResult::operator !=(const CPeripheral &right) const
54 {
55   return !(*this == right);
56 }
57
58 bool PeripheralScanResults::GetDeviceOnLocation(const CStdString &strLocation, PeripheralScanResult *result) const
59 {
60   bool bReturn(false);
61
62   for (unsigned int iDevicePtr = 0; iDevicePtr < m_results.size(); iDevicePtr++)
63   {
64     if (m_results.at(iDevicePtr).m_strLocation == strLocation)
65     {
66       *result = m_results.at(iDevicePtr);
67       bReturn = true;
68       break;
69     }
70   }
71
72   return bReturn;
73 }
74
75 bool PeripheralScanResults::ContainsResult(const PeripheralScanResult &result) const
76 {
77   bool bReturn(false);
78
79   for (unsigned int iDevicePtr = 0; iDevicePtr < m_results.size(); iDevicePtr++)
80   {
81     if (m_results.at(iDevicePtr) == result)
82     {
83       bReturn = true;
84       break;
85     }
86   }
87
88   return bReturn;
89 }
90
91 CPeripheralBus::CPeripheralBus(CPeripherals *manager, PeripheralBusType type) :
92     CThread("XBMC Peripherals"),
93     m_iRescanTime(PERIPHERAL_DEFAULT_RESCAN_INTERVAL),
94     m_bInitialised(false),
95     m_bIsStarted(false),
96     m_bNeedsPolling(true),
97     m_manager(manager),
98     m_type(type),
99     m_triggerEvent(true)
100 {
101 }
102
103 void CPeripheralBus::OnDeviceAdded(const CStdString &strLocation)
104 {
105   ScanForDevices();
106 }
107
108 void CPeripheralBus::OnDeviceChanged(const CStdString &strLocation)
109 {
110   ScanForDevices();
111 }
112
113 void CPeripheralBus::OnDeviceRemoved(const CStdString &strLocation)
114 {
115   ScanForDevices();
116 }
117
118 void CPeripheralBus::Clear(void)
119 {
120   if (m_bNeedsPolling)
121   {
122     m_bStop = true;
123     m_triggerEvent.Set();
124     StopThread(true);
125   }
126
127   CSingleLock lock(m_critSection);
128   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
129     delete m_peripherals.at(iPeripheralPtr);
130   m_peripherals.clear();
131 }
132
133 void CPeripheralBus::UnregisterRemovedDevices(const PeripheralScanResults &results)
134 {
135   CSingleLock lock(m_critSection);
136   vector<CPeripheral *> removedPeripherals;
137   for (int iDevicePtr = (int) m_peripherals.size() - 1; iDevicePtr >= 0; iDevicePtr--)
138   {
139     CPeripheral *peripheral = m_peripherals.at(iDevicePtr);
140     PeripheralScanResult updatedDevice;
141     if (!results.GetDeviceOnLocation(peripheral->Location(), &updatedDevice) ||
142         updatedDevice != *peripheral)
143     {
144       /* device removed */
145       removedPeripherals.push_back(peripheral);
146       m_peripherals.erase(m_peripherals.begin() + iDevicePtr);
147     }
148   }
149   lock.Leave();
150
151   for (unsigned int iDevicePtr = 0; iDevicePtr < removedPeripherals.size(); iDevicePtr++)
152   {
153     CPeripheral *peripheral = removedPeripherals.at(iDevicePtr);
154     vector<PeripheralFeature> features;
155     peripheral->GetFeatures(features);
156     bool peripheralHasFeatures = features.size() > 1 || (features.size() == 1 && features.at(0) != FEATURE_UNKNOWN);
157     if (peripheral->Type() != PERIPHERAL_UNKNOWN || peripheralHasFeatures)
158     {
159       CLog::Log(LOGNOTICE, "%s - device removed from %s/%s: %s (%s:%s)", __FUNCTION__, PeripheralTypeTranslator::TypeToString(peripheral->Type()), peripheral->Location().c_str(), peripheral->DeviceName().c_str(), peripheral->VendorIdAsString(), peripheral->ProductIdAsString());
160       peripheral->OnDeviceRemoved();
161     }
162
163     m_manager->OnDeviceDeleted(*this, *peripheral);
164     delete peripheral;
165   }
166 }
167
168 void CPeripheralBus::RegisterNewDevices(const PeripheralScanResults &results)
169 {
170   CSingleLock lock(m_critSection);
171   for (unsigned int iResultPtr = 0; iResultPtr < results.m_results.size(); iResultPtr++)
172   {
173     PeripheralScanResult result = results.m_results.at(iResultPtr);
174     if (!HasPeripheral(result.m_strLocation))
175       g_peripherals.CreatePeripheral(*this, result.m_type, result.m_strLocation, result.m_iVendorId, result.m_iProductId);
176   }
177 }
178
179 bool CPeripheralBus::ScanForDevices(void)
180 {
181   bool bReturn(false);
182
183   PeripheralScanResults results;
184   if (PerformDeviceScan(results))
185   {
186     UnregisterRemovedDevices(results);
187     RegisterNewDevices(results);
188
189     bReturn = true;
190   }
191
192   m_bInitialised = true;
193   return bReturn;
194 }
195
196 bool CPeripheralBus::HasFeature(const PeripheralFeature feature) const
197 {
198   bool bReturn(false);
199   CSingleLock lock(m_critSection);
200   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
201   {
202     if (m_peripherals.at(iPeripheralPtr)->HasFeature(feature))
203     {
204       bReturn = true;
205       break;
206     }
207   }
208   return bReturn;
209 }
210
211 void CPeripheralBus::GetFeatures(std::vector<PeripheralFeature> &features) const
212 {
213   CSingleLock lock(m_critSection);
214   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
215     m_peripherals.at(iPeripheralPtr)->GetFeatures(features);
216 }
217
218 CPeripheral *CPeripheralBus::GetPeripheral(const CStdString &strLocation) const
219 {
220   CPeripheral *peripheral(NULL);
221   CSingleLock lock(m_critSection);
222   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
223   {
224     if (m_peripherals.at(iPeripheralPtr)->Location() == strLocation)
225     {
226       peripheral = m_peripherals.at(iPeripheralPtr);
227       break;
228     }
229   }
230   return peripheral;
231 }
232
233 int CPeripheralBus::GetPeripheralsWithFeature(vector<CPeripheral *> &results, const PeripheralFeature feature) const
234 {
235   int iReturn(0);
236   CSingleLock lock(m_critSection);
237   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
238   {
239     if (m_peripherals.at(iPeripheralPtr)->HasFeature(feature))
240     {
241       results.push_back(m_peripherals.at(iPeripheralPtr));
242       ++iReturn;
243     }
244   }
245
246   return iReturn;
247 }
248
249 void CPeripheralBus::Process(void)
250 {
251   while (!m_bStop)
252   {
253     m_triggerEvent.Reset();
254
255     if (!ScanForDevices())
256       break;
257
258     if (!m_bStop)
259       m_triggerEvent.WaitMSec(m_iRescanTime);
260   }
261
262   m_bIsStarted = false;
263 }
264
265 bool CPeripheralBus::Initialise(void)
266 {
267   CSingleLock lock(m_critSection);
268   if (!m_bIsStarted)
269   {
270     /* do an initial scan of the bus */
271     m_bIsStarted = ScanForDevices();
272
273     if (m_bIsStarted && m_bNeedsPolling)
274     {
275       lock.Leave();
276       m_triggerEvent.Reset();
277       Create();
278       SetPriority(-1);
279     }
280   }
281
282   return m_bIsStarted;
283 }
284
285 void CPeripheralBus::Register(CPeripheral *peripheral)
286 {
287   if (!peripheral)
288     return;
289
290   CSingleLock lock(m_critSection);
291   if (!HasPeripheral(peripheral->Location()))
292   {
293     m_peripherals.push_back(peripheral);
294     CLog::Log(LOGNOTICE, "%s - new %s device registered on %s->%s: %s (%s:%s)", __FUNCTION__, PeripheralTypeTranslator::TypeToString(peripheral->Type()), PeripheralTypeTranslator::BusTypeToString(m_type), peripheral->Location().c_str(), peripheral->DeviceName().c_str(), peripheral->VendorIdAsString(), peripheral->ProductIdAsString());
295     lock.Leave();
296
297     m_manager->OnDeviceAdded(*this, *peripheral);
298   }
299 }
300
301 void CPeripheralBus::TriggerDeviceScan(void)
302 {
303   CSingleLock lock(m_critSection);
304   if (m_bNeedsPolling)
305   {
306     lock.Leave();
307     m_triggerEvent.Set();
308   }
309   else
310   {
311     lock.Leave();
312     ScanForDevices();
313   }
314 }
315
316 bool CPeripheralBus::HasPeripheral(const CStdString &strLocation) const
317 {
318   return (GetPeripheral(strLocation) != NULL);
319 }
320
321 void CPeripheralBus::GetDirectory(const CStdString &strPath, CFileItemList &items) const
322 {
323   CStdString strDevPath;
324   CSingleLock lock(m_critSection);
325   for (unsigned int iDevicePtr = 0; iDevicePtr < m_peripherals.size(); iDevicePtr++)
326   {
327     const CPeripheral *peripheral = m_peripherals.at(iDevicePtr);
328     if (peripheral->IsHidden())
329       continue;
330
331     CFileItemPtr peripheralFile(new CFileItem(peripheral->DeviceName()));
332     peripheralFile->SetPath(peripheral->FileLocation());
333     peripheralFile->SetProperty("vendor", peripheral->VendorIdAsString());
334     peripheralFile->SetProperty("product", peripheral->ProductIdAsString());
335     peripheralFile->SetProperty("bus", PeripheralTypeTranslator::BusTypeToString(peripheral->GetBusType()));
336     peripheralFile->SetProperty("location", peripheral->Location());
337     peripheralFile->SetProperty("class", PeripheralTypeTranslator::TypeToString(peripheral->Type()));
338     peripheralFile->SetProperty("version", peripheral->GetVersionInfo());
339     items.Add(peripheralFile);
340   }
341 }
342
343 CPeripheral *CPeripheralBus::GetByPath(const CStdString &strPath) const
344 {
345   CStdString strDevPath;
346   CSingleLock lock(m_critSection);
347   for (unsigned int iDevicePtr = 0; iDevicePtr < m_peripherals.size(); iDevicePtr++)
348   {
349     if (strPath.Equals(m_peripherals.at(iDevicePtr)->FileLocation()))
350       return m_peripherals.at(iDevicePtr);
351   }
352
353   return NULL;
354 }
355
356 size_t CPeripheralBus::GetNumberOfPeripherals() const
357 {
358   return m_peripherals.size();
359 }