38 ** $QT_END_LICENSE$ |
38 ** $QT_END_LICENSE$ |
39 ** |
39 ** |
40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include "symbiandevicemanager.h" |
42 #include "symbiandevicemanager.h" |
|
43 #include "trkdevice.h" |
43 |
44 |
44 #include <QtCore/QSettings> |
45 #include <QtCore/QSettings> |
45 #include <QtCore/QStringList> |
46 #include <QtCore/QStringList> |
46 #include <QtCore/QFileInfo> |
47 #include <QtCore/QFileInfo> |
47 #include <QtCore/QtDebug> |
48 #include <QtCore/QtDebug> |
48 #include <QtCore/QTextStream> |
49 #include <QtCore/QTextStream> |
49 #include <QtCore/QSharedData> |
50 #include <QtCore/QSharedData> |
50 #include <QtCore/QScopedPointer> |
51 #include <QtCore/QScopedPointer> |
|
52 #include <QtCore/QSignalMapper> |
51 |
53 |
52 namespace SymbianUtils { |
54 namespace SymbianUtils { |
53 |
55 |
54 enum { debug = 0 }; |
56 enum { debug = 0 }; |
55 |
57 |
59 const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm"; |
61 const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm"; |
60 |
62 |
61 // ------------- SymbianDevice |
63 // ------------- SymbianDevice |
62 class SymbianDeviceData : public QSharedData { |
64 class SymbianDeviceData : public QSharedData { |
63 public: |
65 public: |
64 SymbianDeviceData() : type(SerialPortCommunication) {} |
66 SymbianDeviceData(); |
|
67 ~SymbianDeviceData(); |
|
68 |
|
69 inline bool isOpen() const { return !device.isNull() && device->isOpen(); } |
|
70 void forcedClose(); |
65 |
71 |
66 QString portName; |
72 QString portName; |
67 QString friendlyName; |
73 QString friendlyName; |
68 QString deviceDesc; |
74 QString deviceDesc; |
69 QString manufacturer; |
75 QString manufacturer; |
|
76 QString additionalInformation; |
|
77 |
70 DeviceCommunicationType type; |
78 DeviceCommunicationType type; |
|
79 QSharedPointer<trk::TrkDevice> device; |
|
80 bool deviceAcquired; |
71 }; |
81 }; |
|
82 |
|
83 SymbianDeviceData::SymbianDeviceData() : |
|
84 type(SerialPortCommunication), |
|
85 deviceAcquired(false) |
|
86 { |
|
87 } |
|
88 |
|
89 SymbianDeviceData::~SymbianDeviceData() |
|
90 { |
|
91 forcedClose(); |
|
92 } |
|
93 |
|
94 void SymbianDeviceData::forcedClose() |
|
95 { |
|
96 // Close the device when unplugging. Should devices be in 'acquired' state, |
|
97 // their owners should hit on write failures. |
|
98 // Apart from the <shared item> destructor, also called by the devicemanager |
|
99 // to ensure it also happens if other shared instances are still around. |
|
100 if (isOpen()) { |
|
101 if (deviceAcquired) |
|
102 qWarning("Device on '%s' unplugged while an operation is in progress.", |
|
103 qPrintable(portName)); |
|
104 device->close(); |
|
105 } |
|
106 } |
72 |
107 |
73 SymbianDevice::SymbianDevice(SymbianDeviceData *data) : |
108 SymbianDevice::SymbianDevice(SymbianDeviceData *data) : |
74 m_data(data) |
109 m_data(data) |
75 { |
110 { |
76 |
|
77 } |
111 } |
78 |
112 |
79 SymbianDevice::SymbianDevice() : |
113 SymbianDevice::SymbianDevice() : |
80 m_data(new SymbianDeviceData) |
114 m_data(new SymbianDeviceData) |
81 { |
115 { |
94 |
128 |
95 SymbianDevice::~SymbianDevice() |
129 SymbianDevice::~SymbianDevice() |
96 { |
130 { |
97 } |
131 } |
98 |
132 |
|
133 void SymbianDevice::forcedClose() |
|
134 { |
|
135 m_data->forcedClose(); |
|
136 } |
|
137 |
99 QString SymbianDevice::portName() const |
138 QString SymbianDevice::portName() const |
100 { |
139 { |
101 return m_data->portName; |
140 return m_data->portName; |
102 } |
141 } |
103 |
142 |
104 QString SymbianDevice::friendlyName() const |
143 QString SymbianDevice::friendlyName() const |
105 { |
144 { |
106 return m_data->friendlyName; |
145 return m_data->friendlyName; |
107 } |
146 } |
108 |
147 |
|
148 QString SymbianDevice::additionalInformation() const |
|
149 { |
|
150 return m_data->additionalInformation; |
|
151 } |
|
152 |
|
153 void SymbianDevice::setAdditionalInformation(const QString &a) |
|
154 { |
|
155 m_data->additionalInformation = a; |
|
156 } |
|
157 |
|
158 SymbianDevice::TrkDevicePtr SymbianDevice::acquireDevice() |
|
159 { |
|
160 if (debug) |
|
161 qDebug() << "SymbianDevice::acquireDevice" << m_data->portName |
|
162 << "acquired: " << m_data->deviceAcquired << " open: " << isOpen(); |
|
163 if (isNull() || m_data->deviceAcquired) |
|
164 return TrkDevicePtr(); |
|
165 if (m_data->device.isNull()) { |
|
166 m_data->device = TrkDevicePtr(new trk::TrkDevice); |
|
167 m_data->device->setPort(m_data->portName); |
|
168 m_data->device->setSerialFrame(m_data->type == SerialPortCommunication); |
|
169 } |
|
170 m_data->deviceAcquired = true; |
|
171 return m_data->device; |
|
172 } |
|
173 |
|
174 void SymbianDevice::releaseDevice(TrkDevicePtr *ptr /* = 0 */) |
|
175 { |
|
176 if (debug) |
|
177 qDebug() << "SymbianDevice::releaseDevice" << m_data->portName |
|
178 << " open: " << isOpen(); |
|
179 if (m_data->deviceAcquired) { |
|
180 if (m_data->device->isOpen()) |
|
181 m_data->device->clearWriteQueue(); |
|
182 // Release if a valid pointer was passed in. |
|
183 if (ptr && !ptr->isNull()) { |
|
184 ptr->data()->disconnect(); |
|
185 *ptr = TrkDevicePtr(); |
|
186 } |
|
187 m_data->deviceAcquired = false; |
|
188 } else { |
|
189 qWarning("Internal error: Attempt to release device that is not acquired."); |
|
190 } |
|
191 } |
|
192 |
109 QString SymbianDevice::deviceDesc() const |
193 QString SymbianDevice::deviceDesc() const |
110 { |
194 { |
111 return m_data->deviceDesc; |
195 return m_data->deviceDesc; |
112 } |
196 } |
113 |
197 |
156 if (const int frc = m_data->friendlyName.compare(rhs.m_data->friendlyName)) |
245 if (const int frc = m_data->friendlyName.compare(rhs.m_data->friendlyName)) |
157 return frc; |
246 return frc; |
158 return 0; |
247 return 0; |
159 } |
248 } |
160 |
249 |
161 QDebug operator<<(QDebug d, const SymbianDevice &cd) |
250 SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd) |
162 { |
251 { |
163 d.nospace() << cd.toString(); |
252 d.nospace() << cd.toString(); |
164 return d; |
253 return d; |
165 } |
254 } |
166 |
255 |
167 // ------------- SymbianDeviceManagerPrivate |
256 // ------------- SymbianDeviceManagerPrivate |
168 struct SymbianDeviceManagerPrivate { |
257 struct SymbianDeviceManagerPrivate { |
169 SymbianDeviceManagerPrivate() : m_initialized(false) {} |
258 SymbianDeviceManagerPrivate() : m_initialized(false), m_destroyReleaseMapper(0) {} |
170 |
259 |
171 bool m_initialized; |
260 bool m_initialized; |
172 SymbianDeviceManager::SymbianDeviceList m_devices; |
261 SymbianDeviceManager::SymbianDeviceList m_devices; |
|
262 QSignalMapper *m_destroyReleaseMapper; |
173 }; |
263 }; |
174 |
264 |
175 SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : |
265 SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : |
176 QObject(parent), |
266 QObject(parent), |
177 d(new SymbianDeviceManagerPrivate) |
267 d(new SymbianDeviceManagerPrivate) |
183 delete d; |
273 delete d; |
184 } |
274 } |
185 |
275 |
186 SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const |
276 SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const |
187 { |
277 { |
188 if (!d->m_initialized) |
278 ensureInitialized(); |
189 const_cast<SymbianDeviceManager*>(this)->update(false); |
|
190 return d->m_devices; |
279 return d->m_devices; |
191 } |
280 } |
192 |
281 |
193 QString SymbianDeviceManager::toString() const |
282 QString SymbianDeviceManager::toString() const |
194 { |
283 { |
195 QString rc; |
284 QString rc; |
196 QTextStream str(&rc); |
285 QTextStream str(&rc); |
|
286 str << d->m_devices.size() << " devices:\n"; |
197 const int count = d->m_devices.size(); |
287 const int count = d->m_devices.size(); |
198 for (int i = 0; i < count; i++) { |
288 for (int i = 0; i < count; i++) { |
199 str << '#' << i << ' '; |
289 str << '#' << i << ' '; |
200 d->m_devices.at(i).format(str); |
290 d->m_devices.at(i).format(str); |
201 str << '\n'; |
291 str << '\n'; |
202 } |
292 } |
203 return rc; |
293 return rc; |
204 } |
294 } |
205 |
295 |
|
296 int SymbianDeviceManager::findByPortName(const QString &p) const |
|
297 { |
|
298 ensureInitialized(); |
|
299 const int count = d->m_devices.size(); |
|
300 for (int i = 0; i < count; i++) |
|
301 if (d->m_devices.at(i).portName() == p) |
|
302 return i; |
|
303 return -1; |
|
304 } |
|
305 |
206 QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const |
306 QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const |
207 { |
307 { |
208 foreach (const SymbianDevice &device, d->m_devices) { |
308 const int idx = findByPortName(port); |
209 if (device.portName() == port) |
309 return idx == -1 ? QString() : d->m_devices.at(idx).friendlyName(); |
210 return device.friendlyName(); |
310 } |
211 } |
311 |
212 return QString(); |
312 SymbianDeviceManager::TrkDevicePtr |
|
313 SymbianDeviceManager::acquireDevice(const QString &port) |
|
314 { |
|
315 ensureInitialized(); |
|
316 const int idx = findByPortName(port); |
|
317 if (idx == -1) { |
|
318 qWarning("Attempt to acquire device '%s' that does not exist.", qPrintable(port)); |
|
319 if (debug) |
|
320 qDebug() << *this; |
|
321 return TrkDevicePtr(); |
|
322 } |
|
323 const TrkDevicePtr rc = d->m_devices[idx].acquireDevice(); |
|
324 if (debug) |
|
325 qDebug() << "SymbianDeviceManager::acquireDevice" << port << " returns " << !rc.isNull(); |
|
326 return rc; |
213 } |
327 } |
214 |
328 |
215 void SymbianDeviceManager::update() |
329 void SymbianDeviceManager::update() |
216 { |
330 { |
217 update(true); |
331 update(true); |
218 } |
332 } |
219 |
333 |
|
334 void SymbianDeviceManager::releaseDevice(const QString &port) |
|
335 { |
|
336 const int idx = findByPortName(port); |
|
337 if (debug) |
|
338 qDebug() << "SymbianDeviceManager::releaseDevice" << port << idx << sender(); |
|
339 if (idx != -1) { |
|
340 d->m_devices[idx].releaseDevice(); |
|
341 } else { |
|
342 qWarning("Attempt to release non-existing device %s.", qPrintable(port)); |
|
343 } |
|
344 } |
|
345 |
|
346 void SymbianDeviceManager::setAdditionalInformation(const QString &port, const QString &ai) |
|
347 { |
|
348 const int idx = findByPortName(port); |
|
349 if (idx != -1) |
|
350 d->m_devices[idx].setAdditionalInformation(ai); |
|
351 } |
|
352 |
|
353 void SymbianDeviceManager::ensureInitialized() const |
|
354 { |
|
355 if (!d->m_initialized) // Flag is set in update() |
|
356 const_cast<SymbianDeviceManager*>(this)->update(false); |
|
357 } |
|
358 |
220 void SymbianDeviceManager::update(bool emitSignals) |
359 void SymbianDeviceManager::update(bool emitSignals) |
221 { |
360 { |
|
361 static int n = 0; |
222 typedef SymbianDeviceList::iterator SymbianDeviceListIterator; |
362 typedef SymbianDeviceList::iterator SymbianDeviceListIterator; |
223 |
363 |
224 if (debug) |
364 if (debug) |
225 qDebug(">SerialDeviceLister::update(%d)\n%s", int(emitSignals), |
365 qDebug(">SerialDeviceLister::update(#%d, signals=%d)\n%s", n++, int(emitSignals), |
226 qPrintable(toString())); |
366 qPrintable(toString())); |
227 |
367 |
228 d->m_initialized = true; |
368 d->m_initialized = true; |
229 // Get ordered new list |
369 // Get ordered new list |
230 SymbianDeviceList newDevices = serialPorts() + blueToothDevices(); |
370 SymbianDeviceList newDevices = serialPorts() + blueToothDevices(); |
231 if (newDevices.size() > 1) |
371 if (newDevices.size() > 1) |
232 qStableSort(newDevices.begin(), newDevices.end()); |
372 qStableSort(newDevices.begin(), newDevices.end()); |
233 if (d->m_devices == newDevices) // Happy, nothing changed. |
373 if (d->m_devices == newDevices) { // Happy, nothing changed. |
|
374 if (debug) |
|
375 qDebug("<SerialDeviceLister::update: unchanged\n"); |
234 return; |
376 return; |
|
377 } |
235 // Merge the lists and emit the respective added/removed signals, assuming |
378 // Merge the lists and emit the respective added/removed signals, assuming |
236 // no one can plug a different device on the same port at the speed of lightning |
379 // no one can plug a different device on the same port at the speed of lightning |
237 if (!d->m_devices.isEmpty()) { |
380 if (!d->m_devices.isEmpty()) { |
238 // Find deleted devices |
381 // Find deleted devices |
239 for (SymbianDeviceListIterator oldIt = d->m_devices.begin(); oldIt != d->m_devices.end(); ) { |
382 for (SymbianDeviceListIterator oldIt = d->m_devices.begin(); oldIt != d->m_devices.end(); ) { |
240 if (newDevices.contains(*oldIt)) { |
383 if (newDevices.contains(*oldIt)) { |
241 ++oldIt; |
384 ++oldIt; |
242 } else { |
385 } else { |
243 const SymbianDevice toBeDeleted = *oldIt; |
386 SymbianDevice toBeDeleted = *oldIt; |
|
387 toBeDeleted.forcedClose(); |
244 oldIt = d->m_devices.erase(oldIt); |
388 oldIt = d->m_devices.erase(oldIt); |
245 if (emitSignals) |
389 if (emitSignals) |
246 emit deviceRemoved(toBeDeleted); |
390 emit deviceRemoved(toBeDeleted); |
247 } |
391 } |
248 } |
392 } |
299 SymbianDeviceList rc; |
443 SymbianDeviceList rc; |
300 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) |
444 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) |
301 // Bluetooth devices are created on connection. List the existing ones |
445 // Bluetooth devices are created on connection. List the existing ones |
302 // or at least the first one. |
446 // or at least the first one. |
303 const QString prefix = QLatin1String(linuxBlueToothDeviceRootC); |
447 const QString prefix = QLatin1String(linuxBlueToothDeviceRootC); |
304 const QString friendlyFormat = QLatin1String("Bluetooth device (%1)"); |
448 const QString blueToothfriendlyFormat = QLatin1String("Bluetooth device (%1)"); |
305 for (int d = 0; d < 4; d++) { |
449 for (int d = 0; d < 4; d++) { |
306 QScopedPointer<SymbianDeviceData> device(new SymbianDeviceData); |
450 QScopedPointer<SymbianDeviceData> device(new SymbianDeviceData); |
307 device->type = BlueToothCommunication; |
451 device->type = BlueToothCommunication; |
308 device->portName = prefix + QString::number(d); |
452 device->portName = prefix + QString::number(d); |
309 if (d == 0 || QFileInfo(device->portName).exists()) { |
453 if (d == 0 || QFileInfo(device->portName).exists()) { |
310 device->friendlyName = friendlyFormat.arg(device->portName); |
454 device->friendlyName = blueToothfriendlyFormat.arg(device->portName); |
311 rc.push_back(SymbianDevice(device.take())); |
455 rc.push_back(SymbianDevice(device.take())); |
|
456 } |
|
457 } |
|
458 // New kernel versions support /dev/ttyUSB0, /dev/ttyUSB1. Trk responds |
|
459 // on the latter (usually), try first. |
|
460 static const char *usbTtyDevices[] = { "/dev/ttyUSB1", "/dev/ttyUSB0" }; |
|
461 const int usbTtyCount = sizeof(usbTtyDevices)/sizeof(const char *); |
|
462 for (int d = 0; d < usbTtyCount; d++) { |
|
463 const QString ttyUSBDevice = QLatin1String(usbTtyDevices[d]); |
|
464 if (QFileInfo(ttyUSBDevice).exists()) { |
|
465 SymbianDeviceData *device = new SymbianDeviceData; |
|
466 device->type = SerialPortCommunication; |
|
467 device->portName = ttyUSBDevice; |
|
468 device->friendlyName = QString::fromLatin1("USB/Serial device (%1)").arg(device->portName); |
|
469 rc.push_back(SymbianDevice(device)); |
312 } |
470 } |
313 } |
471 } |
314 #endif |
472 #endif |
315 return rc; |
473 return rc; |
316 } |
474 } |