tools/runonphone/symbianutils/symbiandevicemanager.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    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 
   121     return m_data->type;
   205     return m_data->type;
   122 }
   206 }
   123 
   207 
   124 bool SymbianDevice::isNull() const
   208 bool SymbianDevice::isNull() const
   125 {
   209 {
   126     return !m_data->portName.isEmpty();
   210     return m_data->portName.isEmpty();
       
   211 }
       
   212 
       
   213 bool SymbianDevice::isOpen() const
       
   214 {
       
   215     return m_data->isOpen();
   127 }
   216 }
   128 
   217 
   129 QString SymbianDevice::toString() const
   218 QString SymbianDevice::toString() const
   130 {
   219 {
   131     QString rc;
   220     QString rc;
   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 }
   320 SymbianDeviceManager *SymbianDeviceManager::instance()
   478 SymbianDeviceManager *SymbianDeviceManager::instance()
   321 {
   479 {
   322     return symbianDeviceManager();
   480     return symbianDeviceManager();
   323 }
   481 }
   324 
   482 
   325 QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm)
   483 SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm)
   326 {
   484 {
   327     d.nospace() << sdm.toString();
   485     d.nospace() << sdm.toString();
   328     return d;
   486     return d;
   329 }
   487 }
   330 
   488