aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2010-02-11 12:31:59 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2010-02-11 12:31:59 +0100
commitdc006860c4e4b2e496290d8f751da8355f9f85e5 (patch)
tree2f9a934552251d2c6b32401f75076309aeccf9c9
parentecbb54811ccbf0e1c79a737c70ddbf37a2c15aa9 (diff)
Symbian: Let SymbianDeviceManager handle TrkDevice leases.
...making use of a shared device by all clients. Detect device removal by delaying the WM_DEVICE event handling. Introduce Acquire/Release mechanism to SymbianDeviceManager and let acquire() fail if the device is in use, thus preventing starting 'run' while debugging is active, etc. Handle "Device removed" (unplugging of cable) signal by closing the device and adding handlers to the clients, stabilize TrkDevice against it. Remove communication type from the run configuration parameters (now handled by SymbianDeviceManager). Working towards keeping the Trk-connection always open and a giving the target pane a meaningful tooltip. For the moment, pass on tooltips from device manager additional information (Trk version and such as determined by the launcher).
-rw-r--r--src/plugins/coreplugin/eventfilteringmainwindow.cpp39
-rw-r--r--src/plugins/coreplugin/eventfilteringmainwindow.h15
-rw-r--r--src/plugins/debugger/debuggermanager.cpp1
-rw-r--r--src/plugins/debugger/debuggermanager.h1
-rw-r--r--src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp13
-rw-r--r--src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h1
-rw-r--r--src/plugins/debugger/gdb/trkgdbadapter.cpp121
-rw-r--r--src/plugins/debugger/gdb/trkgdbadapter.h11
-rw-r--r--src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp133
-rw-r--r--src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h14
-rw-r--r--src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp15
-rw-r--r--src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp13
-rw-r--r--src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h1
-rw-r--r--src/plugins/qt4projectmanager/qt4target.cpp29
-rw-r--r--src/shared/symbianutils/launcher.cpp60
-rw-r--r--src/shared/symbianutils/launcher.h13
-rw-r--r--src/shared/symbianutils/symbiandevicemanager.cpp176
-rw-r--r--src/shared/symbianutils/symbiandevicemanager.h47
-rw-r--r--src/shared/symbianutils/trkdevice.cpp77
-rw-r--r--src/shared/symbianutils/trkdevice.h4
20 files changed, 566 insertions, 218 deletions
diff --git a/src/plugins/coreplugin/eventfilteringmainwindow.cpp b/src/plugins/coreplugin/eventfilteringmainwindow.cpp
index 12a4e820de..3b75faef2b 100644
--- a/src/plugins/coreplugin/eventfilteringmainwindow.cpp
+++ b/src/plugins/coreplugin/eventfilteringmainwindow.cpp
@@ -33,21 +33,50 @@
#include <windows.h>
#endif
-#include <QtDebug>
+#include <QtCore/QtDebug>
+#include <QtCore/QEvent>
+#include <QtCore/QCoreApplication>
-using namespace Core::Internal;
+namespace Core {
+namespace Internal {
-EventFilteringMainWindow::EventFilteringMainWindow()
+/* The notification signal is delayed by using a custom event
+ * as otherwise device removal is not detected properly
+ * (devices are still present in the registry. */
+
+class DeviceNotifyEvent : public QEvent {
+public:
+ explicit DeviceNotifyEvent(int id) : QEvent(static_cast<QEvent::Type>(id)) {}
+};
+
+EventFilteringMainWindow::EventFilteringMainWindow() :
+ m_deviceEventId(QEvent::registerEventType(QEvent::User + 2))
{
}
#ifdef Q_OS_WIN
+bool EventFilteringMainWindow::event(QEvent *event)
+{
+ if (event->type() == m_deviceEventId) {
+ event->accept();
+ emit deviceChange();
+ return true;
+ }
+ return QMainWindow::event(event);
+}
+
bool EventFilteringMainWindow::winEvent(MSG *msg, long *result)
{
if (msg->message == WM_DEVICECHANGE) {
- emit deviceChange();
- *result = TRUE;
+ if (msg->wParam & 0x7 /* DBT_DEVNODES_CHANGED */) {
+ *result = TRUE;
+ QCoreApplication::postEvent(this, new DeviceNotifyEvent(m_deviceEventId));
+ }
}
return false;
}
#endif
+
+} // namespace Internal
+} // namespace Core
+
diff --git a/src/plugins/coreplugin/eventfilteringmainwindow.h b/src/plugins/coreplugin/eventfilteringmainwindow.h
index f43eb7596e..c3b8f18418 100644
--- a/src/plugins/coreplugin/eventfilteringmainwindow.h
+++ b/src/plugins/coreplugin/eventfilteringmainwindow.h
@@ -32,6 +32,10 @@
#include <QtGui/QMainWindow>
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
namespace Core {
namespace Internal {
@@ -46,14 +50,17 @@ class EventFilteringMainWindow : public QMainWindow
public:
EventFilteringMainWindow();
+signals:
+ void deviceChange();
+
#ifdef Q_OS_WIN
protected:
- bool winEvent(MSG *message, long *result);
+ virtual bool winEvent(MSG *message, long *result);
+ virtual bool event(QEvent *event);
#endif
-signals:
- void deviceChange();
-
+private:
+ const int m_deviceEventId;
};
} // Internal
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 6827448946..f44f5761f4 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -224,7 +224,6 @@ const char *DebuggerManager::stateName(int s)
DebuggerStartParameters::DebuggerStartParameters()
: attachPID(-1),
useTerminal(false),
- remoteChannelType(-1),
toolChainType(ProjectExplorer::ToolChain::UNKNOWN),
startMode(NoStartMode)
{}
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 7a884976a2..782dec318f 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -118,7 +118,6 @@ public:
QString crashParameter; // for AttachCrashedExternal
// for remote debugging
QString remoteChannel;
- int remoteChannelType;
QString remoteArchitecture;
QString symbolFileName;
QString serverStartScript;
diff --git a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp
index 41856d8014..043f8a1aac 100644
--- a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp
+++ b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp
@@ -31,6 +31,7 @@
#include "bluetoothlistener.h"
#include "debuggermanager.h"
#include "trkoptions.h"
+#include "trkdevice.h"
namespace Debugger {
namespace Internal {
@@ -51,18 +52,16 @@ trk::BluetoothListener *S60DebuggerBluetoothStarter::createListener()
trk::PromptStartCommunicationResult
S60DebuggerBluetoothStarter::startCommunication(const TrkDevicePtr &trkDevice,
- int communicationType,
QWidget *msgBoxParent,
QString *errorMessage)
{
// Bluetooth?
- if (communicationType == TrkOptions::BlueTooth) {
- S60DebuggerBluetoothStarter bluetoothStarter(trkDevice);
- return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
+ if (trkDevice->serialFrame()) {
+ BaseCommunicationStarter serialStarter(trkDevice);
+ return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage);
}
- // Serial
- BaseCommunicationStarter serialStarter(trkDevice);
- return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage);
+ S60DebuggerBluetoothStarter bluetoothStarter(trkDevice);
+ return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
}
} // namespace Internal
diff --git a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h
index c97088c245..6a7d2cdb08 100644
--- a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h
+++ b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h
@@ -47,7 +47,6 @@ class S60DebuggerBluetoothStarter : public trk::AbstractBluetoothStarter
public:
static trk::PromptStartCommunicationResult
startCommunication(const TrkDevicePtr &trkDevice,
- int communicationType,
QWidget *msgBoxParent,
QString *errorMessage);
diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp
index 74a7145996..2d2db0e15d 100644
--- a/src/plugins/debugger/gdb/trkgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp
@@ -32,6 +32,7 @@
#include "launcher.h"
#include "trkoptions.h"
#include "trkoptionspage.h"
+#include "symbiandevicemanager.h"
#include "s60debuggerbluetoothstarter.h"
#include "bluetoothlistener_gui.h"
@@ -239,9 +240,8 @@ void Snapshot::insertMemory(const MemoryRange &range, const QByteArray &ba)
TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
AbstractGdbAdapter(engine),
m_options(options),
- m_overrideTrkDeviceType(-1),
m_running(false),
- m_trkDevice(new trk::TrkDevice),
+ m_deviceFromSymbianDeviceManager(false),
m_gdbAckMode(true),
m_verbose(0)
{
@@ -259,16 +259,8 @@ TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
#endif
m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
- connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
- this, SLOT(handleTrkResult(trk::TrkResult)));
- connect(m_trkDevice.data(), SIGNAL(error(QString)),
- this, SLOT(handleTrkError(QString)));
-
setVerbose(theDebuggerBoolSetting(VerboseLog));
- m_trkDevice->setSerialFrame(effectiveTrkDeviceType() != TrkOptions::BlueTooth);
- connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
- this, SLOT(trkLogMessage(QString)));
connect(theDebuggerAction(VerboseLog), SIGNAL(valueChanged(QVariant)),
this, SLOT(setVerbose(QVariant)));
}
@@ -287,23 +279,8 @@ void TrkGdbAdapter::setVerbose(const QVariant &value)
void TrkGdbAdapter::setVerbose(int verbose)
{
m_verbose = verbose;
- m_trkDevice->setVerbose(m_verbose);
-}
-
-QString TrkGdbAdapter::effectiveTrkDevice() const
-{
- if (!m_overrideTrkDevice.isEmpty())
- return m_overrideTrkDevice;
- if (m_options->mode == TrkOptions::BlueTooth)
- return m_options->blueToothDevice;
- return m_options->serialPort;
-}
-
-int TrkGdbAdapter::effectiveTrkDeviceType() const
-{
- if (m_overrideTrkDeviceType >= 0)
- return m_overrideTrkDeviceType;
- return m_options->mode;
+ if (!m_trkDevice.isNull())
+ m_trkDevice->setVerbose(m_verbose);
}
void TrkGdbAdapter::trkLogMessage(const QString &msg)
@@ -1726,14 +1703,66 @@ void TrkGdbAdapter::interruptInferior()
sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting...");
}
+void TrkGdbAdapter::trkDeviceRemoved(const SymbianUtils::SymbianDevice &dev)
+{
+ if (state() != DebuggerNotReady && m_deviceFromSymbianDeviceManager
+ && !m_trkDevice.isNull() && m_trkDevice->port() == dev.portName()) {
+ const QString message = QString::fromLatin1("Device '%1' has been disconnected.").arg(dev.friendlyName());
+ logMessage(message);
+ emit adapterCrashed(message);
+ }
+}
+
+bool TrkGdbAdapter::initializeDevice(const QString &remoteChannel, QString *errorMessage)
+{
+ m_deviceFromSymbianDeviceManager = false;
+ if (remoteChannel.isEmpty()) {
+ // Obtain device from settings page
+ m_trkDevice = TrkDevicePtr(new TrkDevice);
+ m_trkDevice->setPort(m_options->mode == TrkOptions::BlueTooth ?
+ m_options->blueToothDevice : m_options->serialPort);
+ m_trkDevice->setSerialFrame(m_options->mode != TrkOptions::BlueTooth);
+ } else {
+ // Run config: Acquire from device manager.
+ m_trkDevice = SymbianUtils::SymbianDeviceManager::instance()->acquireDevice(remoteChannel);
+ if (m_trkDevice.isNull()) {
+ *errorMessage = tr("Unable to acquire a device on '%1'. It appears to be in use.").arg(remoteChannel);
+ return false;
+ }
+ connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)),
+ this, SLOT(trkDeviceRemoved(SymbianUtils::SymbianDevice)));
+ m_deviceFromSymbianDeviceManager = true;
+ }
+ connect(m_trkDevice.data(), SIGNAL(messageReceived(trk::TrkResult)),
+ this, SLOT(handleTrkResult(trk::TrkResult)));
+ connect(m_trkDevice.data(), SIGNAL(error(QString)),
+ this, SLOT(handleTrkError(QString)));
+ connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
+ this, SLOT(trkLogMessage(QString)));
+ m_trkDevice->setVerbose(m_verbose);
+
+ // Prompt the user to start communication
+ const trk::PromptStartCommunicationResult src =
+ S60DebuggerBluetoothStarter::startCommunication(m_trkDevice,
+ 0, errorMessage);
+ switch (src) {
+ case trk::PromptStartCommunicationConnected:
+ break;
+ case trk::PromptStartCommunicationCanceled:
+ *errorMessage = tr("Canceled");
+ return false;
+ case trk::PromptStartCommunicationError:
+ return false;
+ }
+ return true;
+}
+
void TrkGdbAdapter::startAdapter()
{
m_snapshot.fullReset();
// Retrieve parameters
const DebuggerStartParameters &parameters = startParameters();
- m_overrideTrkDevice = parameters.remoteChannel;
- m_overrideTrkDeviceType = parameters.remoteChannelType;
m_remoteExecutable = parameters.executable;
m_remoteArguments = parameters.processArgs;
m_symbolFile = parameters.symbolFileName;
@@ -1750,23 +1779,16 @@ void TrkGdbAdapter::startAdapter()
setState(AdapterStarting);
debugMessage(_("TRYING TO START ADAPTER"));
logMessage(QLatin1String("### Starting TrkGdbAdapter"));
- m_trkDevice->setPort(effectiveTrkDevice());
- m_trkDevice->setSerialFrame(effectiveTrkDeviceType() != TrkOptions::BlueTooth);
+
// Prompt the user to start communication
QString message;
-
- const trk::PromptStartCommunicationResult src =
- S60DebuggerBluetoothStarter::startCommunication(m_trkDevice,
- effectiveTrkDeviceType(),
- 0, &message);
- switch (src) {
- case trk::PromptStartCommunicationConnected:
- break;
- case trk::PromptStartCommunicationCanceled:
- emit adapterStartFailed(message, QString());
- return;
- case trk::PromptStartCommunicationError:
- emit adapterStartFailed(message, TrkOptionsPage::settingsId());
+ if (!initializeDevice(parameters.remoteChannel, &message)) {
+ if (message.isEmpty()) {
+ emit adapterStartFailed(QString(), QString());
+ } else {
+ logMessage(message);
+ emit adapterStartFailed(message, TrkOptionsPage::settingsId());
+ }
return;
}
@@ -2099,7 +2121,16 @@ void TrkGdbAdapter::handleDirectStep3(const TrkResult &result)
void TrkGdbAdapter::cleanup()
{
- m_trkDevice->close();
+ if (!m_trkDevice.isNull()) {
+ m_trkDevice->close();
+ if (m_deviceFromSymbianDeviceManager) {
+ m_trkDevice->disconnect(this);
+ SymbianUtils::SymbianDeviceManager::instance()->releaseDevice(m_trkDevice->port());
+ m_deviceFromSymbianDeviceManager = false;
+ }
+ m_trkDevice = TrkDevicePtr();
+ }
+
delete m_gdbServer;
m_gdbServer = 0;
}
diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h
index 222955aaf0..1bfe0b9117 100644
--- a/src/plugins/debugger/gdb/trkgdbadapter.h
+++ b/src/plugins/debugger/gdb/trkgdbadapter.h
@@ -47,6 +47,9 @@
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
+namespace SymbianUtils {
+class SymbianDevice;
+}
namespace Debugger {
namespace Internal {
@@ -160,8 +163,6 @@ signals:
private:
const TrkOptionsPtr m_options;
- QString m_overrideTrkDevice;
- int m_overrideTrkDeviceType;
QString m_gdbServerName; // 127.0.0.1:(2222+uid)
@@ -180,6 +181,7 @@ public:
private:
void startAdapter();
+ bool initializeDevice(const QString &remoteChannel, QString *errorMessage);
void startInferior();
void startInferiorPhase2();
void interruptInferior();
@@ -258,8 +260,10 @@ private:
QByteArray trkStepRangeMessage();
QByteArray trkDeleteProcessMessage();
QByteArray trkInterruptMessage();
+ Q_SLOT void trkDeviceRemoved(const SymbianUtils::SymbianDevice &);
QSharedPointer<trk::TrkDevice> m_trkDevice;
+ bool m_deviceFromSymbianDeviceManager;
QString m_adapterFailMessage;
//
@@ -299,9 +303,6 @@ private:
QHash<int, GdbCommand> m_gdbCookieForToken;
- QString effectiveTrkDevice() const;
- int effectiveTrkDeviceType() const;
-
// Debuggee state
trk::Session m_session; // global-ish data (process id, target information)
Snapshot m_snapshot; // local-ish data (memory and registers)
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
index 582576b1fc..5493e50b3d 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
@@ -112,10 +112,8 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QStri
m_cachedTargetInformationValid(false),
#ifdef Q_OS_WIN
m_serialPortName(QLatin1String("COM5")),
- m_communicationType(SymbianUtils::SerialPortCommunication),
#else
m_serialPortName(QLatin1String(SymbianUtils::SymbianDeviceManager::linuxBlueToothDeviceRootC) + QLatin1Char('0')),
- m_communicationType(SymbianUtils::BlueToothCommunication),
#endif
m_signingMode(SignSelf)
{
@@ -127,7 +125,6 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRu
m_proFilePath(source->m_proFilePath),
m_cachedTargetInformationValid(false),
m_serialPortName(source->m_serialPortName),
- m_communicationType(source->m_communicationType),
m_signingMode(source->m_signingMode),
m_customSignaturePath(source->m_customSignaturePath),
m_customKeyPath(source->m_customKeyPath)
@@ -202,7 +199,6 @@ QVariantMap S60DeviceRunConfiguration::toMap() const
map.insert(QLatin1String(CUSTOM_SIGNATURE_PATH_KEY), m_customSignaturePath);
map.insert(QLatin1String(CUSTOM_KEY_PATH_KEY), m_customKeyPath);
map.insert(QLatin1String(SERIAL_PORT_NAME_KEY), m_serialPortName);
- map.insert(QLatin1String(COMMUNICATION_TYPE_KEY), m_communicationType);
map.insert(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY), m_commandLineArguments);
return map;
@@ -217,7 +213,6 @@ bool S60DeviceRunConfiguration::fromMap(const QVariantMap &map)
m_customSignaturePath = map.value(QLatin1String(CUSTOM_SIGNATURE_PATH_KEY)).toString();
m_customKeyPath = map.value(QLatin1String(CUSTOM_KEY_PATH_KEY)).toString();
m_serialPortName = map.value(QLatin1String(SERIAL_PORT_NAME_KEY)).toString().trimmed();
- m_communicationType = map.value(QLatin1String(COMMUNICATION_TYPE_KEY)).toInt();
m_commandLineArguments = map.value(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY)).toStringList();
return RunConfiguration::fromMap(map);
@@ -237,16 +232,6 @@ void S60DeviceRunConfiguration::setSerialPortName(const QString &name)
emit serialPortNameChanged();
}
-int S60DeviceRunConfiguration::communicationType() const
-{
- return m_communicationType;
-}
-
-void S60DeviceRunConfiguration::setCommunicationType(int t)
-{
- m_communicationType = t;
-}
-
QString S60DeviceRunConfiguration::targetName() const
{
const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
@@ -485,6 +470,8 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat
m_toolChain(ProjectExplorer::ToolChain::INVALID),
m_makesis(new QProcess(this)),
m_signsis(0),
+ m_releaseDeviceAfterLauncherFinish(false),
+ m_handleDeviceRemoval(true),
m_launcher(0)
{
// connect for automatically reporting the "finished deploy" state to the progress manager
@@ -507,7 +494,6 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat
m_toolChain = s60runConfig->toolChainType();
m_serialPortName = s60runConfig->serialPortName();
m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
- m_communicationType = s60runConfig->communicationType();
m_targetName = s60runConfig->targetName();
m_baseFileName = s60runConfig->basePackageFilePath();
m_commandLineArguments = s60runConfig->commandLineArguments();
@@ -553,7 +539,7 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat
m_packageFile = QFileInfo(m_packageFilePath).fileName();
if (debug)
qDebug() << "S60DeviceRunControlBase" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
- << m_serialPortName << m_communicationType << m_workingDirectory;
+ << m_serialPortName << m_workingDirectory;
}
S60DeviceRunControlBase::~S60DeviceRunControlBase()
@@ -564,6 +550,11 @@ S60DeviceRunControlBase::~S60DeviceRunControlBase()
}
}
+void S60DeviceRunControlBase::setReleaseDeviceAfterLauncherFinish(bool v)
+{
+ m_releaseDeviceAfterLauncherFinish = v;
+}
+
void S60DeviceRunControlBase::start()
{
m_deployProgress = new QFutureInterface<void>;
@@ -739,55 +730,59 @@ void S60DeviceRunControlBase::signsisProcessFinished()
}
}
+
void S60DeviceRunControlBase::startDeployment()
{
- m_launcher = new trk::Launcher();
- connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
- connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
- connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice()));
- connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(printCreateFileFailed(QString,QString)));
- connect(m_launcher, SIGNAL(canNotWriteFile(QString,QString)), this, SLOT(printWriteFileFailed(QString,QString)));
- connect(m_launcher, SIGNAL(canNotCloseFile(QString,QString)), this, SLOT(printCloseFileFailed(QString,QString)));
- connect(m_launcher, SIGNAL(installingStarted()), this, SLOT(printInstallingNotice()));
- connect(m_launcher, SIGNAL(canNotInstall(QString,QString)), this, SLOT(printInstallFailed(QString,QString)));
- connect(m_launcher, SIGNAL(installingFinished()), this, SLOT(printInstallingFinished()));
- connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(printCopyProgress(int)));
- connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
- connect(m_launcher, SIGNAL(processStopped(uint,uint,uint,QString)),
- this, SLOT(processStopped(uint,uint,uint,QString)));
-
- //TODO sisx destination and file path user definable
- m_launcher->setTrkServerName(m_serialPortName);
- m_launcher->setSerialFrame(m_communicationType == SymbianUtils::SerialPortCommunication);
- if (!m_commandLineArguments.isEmpty())
- m_launcher->setCommandLineArgs(m_commandLineArguments);
- const QString copySrc(m_baseFileName + ".sisx");
- const QString copyDst = QString("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName());
- const QString runFileName = QString("C:\\sys\\bin\\%1.exe").arg(m_targetName);
- m_launcher->setCopyFileName(copySrc, copyDst);
- m_launcher->setInstallFileName(copyDst);
- initLauncher(runFileName, m_launcher);
- emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(copySrc), m_serialPortFriendlyName));
QString errorMessage;
- // Prompt the user to start up the Blue tooth connection
- const trk::PromptStartCommunicationResult src =
+ bool success = false;
+ do {
+ connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)),
+ this, SLOT(deviceRemoved(SymbianUtils::SymbianDevice)));
+ m_launcher = trk::Launcher::acquireFromDeviceManager(m_serialPortName, 0, &errorMessage);
+ if (!m_launcher)
+ break;
+
+ connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
+ connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
+ connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice()));
+ connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(printCreateFileFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(canNotWriteFile(QString,QString)), this, SLOT(printWriteFileFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(canNotCloseFile(QString,QString)), this, SLOT(printCloseFileFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(installingStarted()), this, SLOT(printInstallingNotice()));
+ connect(m_launcher, SIGNAL(canNotInstall(QString,QString)), this, SLOT(printInstallFailed(QString,QString)));
+ connect(m_launcher, SIGNAL(installingFinished()), this, SLOT(printInstallingFinished()));
+ connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(printCopyProgress(int)));
+ connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
+ connect(m_launcher, SIGNAL(processStopped(uint,uint,uint,QString)),
+ this, SLOT(processStopped(uint,uint,uint,QString)));
+
+ //TODO sisx destination and file path user definable
+ if (!m_commandLineArguments.isEmpty())
+ m_launcher->setCommandLineArgs(m_commandLineArguments);
+ const QString copySrc(m_baseFileName + QLatin1String(".sisx"));
+ const QString copyDst = QString::fromLatin1("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName());
+ const QString runFileName = QString::fromLatin1("C:\\sys\\bin\\%1.exe").arg(m_targetName);
+ m_launcher->setCopyFileName(copySrc, copyDst);
+ m_launcher->setInstallFileName(copyDst);
+ initLauncher(runFileName, m_launcher);
+ emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(copySrc), m_serialPortFriendlyName));
+ // Prompt the user to start up the Blue tooth connection
+ const trk::PromptStartCommunicationResult src =
S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
- m_communicationType, 0,
- &errorMessage);
- switch (src) {
- case trk::PromptStartCommunicationConnected:
- break;
- case trk::PromptStartCommunicationCanceled:
- case trk::PromptStartCommunicationError:
- error(this, errorMessage);
- stop();
- emit finished();
- return;
- };
+ 0, &errorMessage);
+ if (src != trk::PromptStartCommunicationConnected)
+ break;
+ if (!m_launcher->startServer(&errorMessage)) {
+ errorMessage = tr("Could not connect to phone on port '%1': %2\n"
+ "Check if the phone is connected and App TRK is running.").arg(m_serialPortName, errorMessage);
+ break;
+ }
+ success = true;
+ } while (false);
- if (!m_launcher->startServer(&errorMessage)) {
- error(this, tr("Could not connect to phone on port '%1': %2\n"
- "Check if the phone is connected and App TRK is running.").arg(m_serialPortName, errorMessage));
+ if (!success) {
+ if (!errorMessage.isEmpty())
+ error(this, errorMessage);
stop();
emit finished();
}
@@ -845,6 +840,10 @@ void S60DeviceRunControlBase::printInstallFailed(const QString &filename, const
void S60DeviceRunControlBase::launcherFinished()
{
+ if (m_releaseDeviceAfterLauncherFinish) {
+ m_handleDeviceRemoval = false;
+ trk::Launcher::releaseToDeviceManager(m_launcher);
+ }
m_launcher->deleteLater();
m_launcher = 0;
handleLauncherFinished();
@@ -919,6 +918,14 @@ void S60DeviceRunControlBase::printApplicationOutput(const QString &output)
emit addToOutputWindowInline(this, output);
}
+void S60DeviceRunControlBase::deviceRemoved(const SymbianUtils::SymbianDevice &d)
+{
+ if (m_handleDeviceRemoval && d.portName() == m_serialPortName) {
+ error(this, tr("The device '%1' has been disconnected").arg(d.friendlyName()));
+ emit finished();
+ }
+}
+
bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
QString * /* settingsCategory */,
QString * /* settingsPage */) const
@@ -969,6 +976,7 @@ S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *ru
S60DeviceRunControlBase(runConfiguration),
m_startParams(new Debugger::DebuggerStartParameters)
{
+ setReleaseDeviceAfterLauncherFinish(true); // Debugger controls device after install
Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
S60DeviceRunConfiguration *rc = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
QTC_ASSERT(dm && rc, return);
@@ -981,7 +989,6 @@ S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *ru
m_startParams->remoteChannel = rc->serialPortName();
m_startParams->processArgs = rc->commandLineArguments();
- m_startParams->remoteChannelType = rc->communicationType();
m_startParams->startMode = Debugger::StartInternal;
m_startParams->toolChainType = rc->toolChainType();
@@ -1018,6 +1025,8 @@ void S60DeviceDebugRunControl::initLauncher(const QString &executable, trk::Laun
}
launcher->addStartupActions(trk::Launcher::ActionCopyInstall);
+ // Avoid close/open sequence in quick succession, which may cause crashs
+ launcher->setCloseDevice(false);
}
void S60DeviceDebugRunControl::handleLauncherFinished()
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
index 05afe277a0..3b5699095b 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
@@ -47,6 +47,10 @@ namespace Debugger {
class DebuggerStartParameters;
}
+namespace SymbianUtils {
+class SymbianDevice;
+}
+
namespace Qt4ProjectManager {
namespace Internal {
@@ -75,9 +79,6 @@ public:
QString serialPortName() const;
void setSerialPortName(const QString &name);
- // See SymbianDeviceManager
- int communicationType() const;
- void setCommunicationType(int t);
QString targetName() const;
QString basePackageFilePath() const;
@@ -126,7 +127,6 @@ private:
QString m_packageTemplateFileName;
bool m_cachedTargetInformationValid;
QString m_serialPortName;
- int m_communicationType;
SigningMode m_signingMode;
QString m_customSignaturePath;
QString m_customKeyPath;
@@ -179,9 +179,11 @@ protected:
virtual bool checkConfiguration(QString *errorMessage,
QString *settingsCategory,
QString *settingsPage) const;
+ void setReleaseDeviceAfterLauncherFinish(bool);
protected slots:
void printApplicationOutput(const QString &output);
+ void deviceRemoved(const SymbianUtils::SymbianDevice &);
private slots:
void processStopped(uint pc, uint pid, uint tid, const QString& reason);
@@ -213,7 +215,6 @@ private:
ProjectExplorer::ToolChain::ToolChainType m_toolChain;
QString m_serialPortName;
QString m_serialPortFriendlyName;
- int m_communicationType;
QString m_targetName;
QString m_baseFileName;
QStringList m_commandLineArguments;
@@ -232,7 +233,8 @@ private:
QProcess *m_signsis;
QString m_makesisTool;
QString m_packageFile;
-
+ bool m_releaseDeviceAfterLauncherFinish;
+ bool m_handleDeviceRemoval;
QFutureInterface<void> *m_deployProgress;
trk::Launcher *m_launcher;
};
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp
index e496b174eb..2d23a7260d 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp
@@ -244,7 +244,6 @@ void S60DeviceRunConfigurationWidget::setSerialPort(int index)
{
const SymbianUtils::SymbianDevice d = device(index);
m_runConfiguration->setSerialPortName(d.portName());
- m_runConfiguration->setCommunicationType(d.type());
m_deviceInfoButton->setEnabled(index >= 0);
clearDeviceInfo();
}
@@ -321,17 +320,21 @@ void S60DeviceRunConfigurationWidget::updateDeviceInfo()
setDeviceInfoLabel(tr("Connecting..."));
// Do a launcher run with the ping protocol. Prompt to connect and
// go asynchronous afterwards to pop up launch trk box if a timeout occurs.
- m_infoLauncher = new trk::Launcher(trk::Launcher::ActionPingOnly, QSharedPointer<trk::TrkDevice>(), this);
- connect(m_infoLauncher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
+ QString message;
const SymbianUtils::SymbianDevice commDev = currentDevice();
+ m_infoLauncher = trk::Launcher::acquireFromDeviceManager(commDev.portName(), this, &message);
+ if (!m_infoLauncher) {
+ setDeviceInfoLabel(message, true);
+ return;
+ }
+ connect(m_infoLauncher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
+
m_infoLauncher->setSerialFrame(commDev.type() == SymbianUtils::SerialPortCommunication);
m_infoLauncher->setTrkServerName(commDev.portName());
// Prompt user
- QString message;
const trk::PromptStartCommunicationResult src =
S60RunConfigBluetoothStarter::startCommunication(m_infoLauncher->trkDevice(),
- commDev.type(), this,
- &message);
+ this, &message);
switch (src) {
case trk::PromptStartCommunicationConnected:
break;
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp
index 9bd6e2a60f..e0cd4fb926 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp
@@ -30,6 +30,7 @@
#include "s60runconfigbluetoothstarter.h"
#include "bluetoothlistener.h"
#include "symbiandevicemanager.h"
+#include "trkdevice.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
@@ -53,18 +54,16 @@ trk::BluetoothListener *S60RunConfigBluetoothStarter::createListener()
trk::PromptStartCommunicationResult
S60RunConfigBluetoothStarter::startCommunication(const TrkDevicePtr &trkDevice,
- int communicationType,
QWidget *msgBoxParent,
QString *errorMessage)
{
// Bluetooth?
- if (communicationType == SymbianUtils::BlueToothCommunication) {
- S60RunConfigBluetoothStarter bluetoothStarter(trkDevice);
- return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
+ if (trkDevice->serialFrame()) {
+ BaseCommunicationStarter serialStarter(trkDevice);
+ return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage);
}
- // Serial
- BaseCommunicationStarter serialStarter(trkDevice);
- return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage);
+ S60RunConfigBluetoothStarter bluetoothStarter(trkDevice);
+ return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
}
} // namespace Internal
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h
index 67822af348..b293f73536 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h
+++ b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h
@@ -49,7 +49,6 @@ public:
// passing on the right messages.
static trk::PromptStartCommunicationResult
startCommunication(const TrkDevicePtr &trkDevice,
- int communicationType,
QWidget *msgBoxParent,
QString *errorMessage);
diff --git a/src/plugins/qt4projectmanager/qt4target.cpp b/src/plugins/qt4projectmanager/qt4target.cpp
index 497a9d17e9..11feec2c3b 100644
--- a/src/plugins/qt4projectmanager/qt4target.cpp
+++ b/src/plugins/qt4projectmanager/qt4target.cpp
@@ -413,13 +413,7 @@ void Qt4Target::slotUpdateDeviceInformation()
void Qt4Target::updateToolTipAndIcon()
{
- S60DeviceRunConfiguration *deviceRc(qobject_cast<S60DeviceRunConfiguration *>(activeRunConfiguration()));
- if (!deviceRc) {
- setToolTip(QString());
- setIcon(iconForId(id()));
- } else {
- QString friendlyPortName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(
- deviceRc->serialPortName());
+ if (const S60DeviceRunConfiguration *s60DeviceRc = qobject_cast<S60DeviceRunConfiguration *>(activeRunConfiguration())) {
QPixmap pixmap(Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
@@ -429,16 +423,25 @@ void Qt4Target::updateToolTipAndIcon()
(Core::Constants::TARGET_ICON_SIZE-actualSize.height())/2,
icon.pixmap(Core::Constants::TARGET_ICON_SIZE));
- if (!friendlyPortName.isEmpty()) {
- // device connected
- setToolTip(tr("<b>Device:</b> %1").arg(friendlyPortName));
- painter.drawPixmap(Core::Constants::TARGET_ICON_SIZE - m_connectedPixmap.width(),
- m_connectedPixmap.height(), m_connectedPixmap);
- } else {
+ const SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance();
+ const int deviceIndex = sdm->findByPortName(s60DeviceRc->serialPortName());
+ if (deviceIndex == -1) {
setToolTip(tr("<b>Device:</b> Not connected"));
painter.drawPixmap(Core::Constants::TARGET_ICON_SIZE - m_disconnectedPixmap.width(),
m_disconnectedPixmap.height(), m_disconnectedPixmap);
+ } else {
+ // device connected
+ const SymbianUtils::SymbianDevice device = sdm->devices().at(deviceIndex);
+ const QString tooltip = device.additionalInformation().isEmpty() ?
+ tr("<b>Device:</b> %1").arg(device.friendlyName()) :
+ tr("<b>Device:</b> %1, %2").arg(device.friendlyName(), device.additionalInformation());
+ setToolTip(tooltip);
+ painter.drawPixmap(Core::Constants::TARGET_ICON_SIZE - m_connectedPixmap.width(),
+ m_connectedPixmap.height(), m_connectedPixmap);
}
setIcon(QIcon(pixmap));
+ return;
}
+ setToolTip(QString());
+ setIcon(iconForId(id()));
}
diff --git a/src/shared/symbianutils/launcher.cpp b/src/shared/symbianutils/launcher.cpp
index 6f521571f5..40ad9fb650 100644
--- a/src/shared/symbianutils/launcher.cpp
+++ b/src/shared/symbianutils/launcher.cpp
@@ -32,6 +32,7 @@
#include "trkutils_p.h"
#include "trkdevice.h"
#include "bluetoothlistener.h"
+#include "symbiandevicemanager.h"
#include <QtCore/QTimer>
#include <QtCore/QDateTime>
@@ -89,11 +90,11 @@ Launcher::Launcher(Actions startupActions,
{
d->m_startupActions = startupActions;
connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
- connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close()));
}
Launcher::~Launcher()
{
+ emit destroyed(d->m_device->port());
logMessage("Shutting down.\n");
delete d;
}
@@ -202,11 +203,6 @@ bool Launcher::startServer(QString *errorMessage)
}
if (!d->m_device->isOpen() && !d->m_device->open(errorMessage))
return false;
- if (d->m_closeDevice) {
- connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close()));
- } else {
- disconnect(this, SIGNAL(finished()), d->m_device.data(), 0);
- }
setState(Connecting);
// Set up the temporary 'waiting' state if we do not get immediate connection
QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk()));
@@ -254,6 +250,13 @@ void Launcher::logMessage(const QString &msg)
qDebug() << "LAUNCHER: " << qPrintable(msg);
}
+void Launcher::handleFinished()
+{
+ if (d->m_closeDevice)
+ d->m_device->close();
+ emit finished();
+}
+
void Launcher::terminate()
{
switch (state()) {
@@ -275,7 +278,7 @@ void Launcher::terminate()
case Connecting:
case WaitingForTrk:
setState(Disconnected);
- emit finished();
+ handleFinished();
break;
}
}
@@ -434,7 +437,7 @@ void Launcher::handleTrkVersion(const TrkResult &result)
if (result.errorCode() || result.data.size() < 5) {
if (d->m_startupActions == ActionPingOnly) {
setState(Disconnected);
- emit finished();
+ handleFinished();
}
return;
}
@@ -443,11 +446,13 @@ void Launcher::handleTrkVersion(const TrkResult &result)
d->m_session.trkAppVersion.protocolMajor = result.data.at(3);
d->m_session.trkAppVersion.protocolMinor = result.data.at(4);
setState(DeviceDescriptionReceived);
+ const QString msg = deviceDescription();
+ emit deviceDescriptionReceived(trkServerName(), msg);
// Ping mode: Log & Terminate
if (d->m_startupActions == ActionPingOnly) {
- qWarning("%s", qPrintable(deviceDescription()));
+ qWarning("%s", qPrintable(msg));
setState(Disconnected);
- emit finished();
+ handleFinished();
}
}
@@ -574,7 +579,7 @@ void Launcher::handleWaitForFinished(const TrkResult &result)
{
logMessage(" FINISHED: " + stringFromArray(result.data));
setState(Disconnected);
- emit finished();
+ handleFinished();
}
void Launcher::handleSupportMask(const TrkResult &result)
@@ -725,4 +730,37 @@ void Launcher::resumeProcess(uint pid, uint tid)
appendInt(&ba, tid, BigEndian);
d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
}
+
+// Acquire a device from SymbianDeviceManager, return 0 if not available.
+Launcher *Launcher::acquireFromDeviceManager(const QString &serverName,
+ QObject *parent,
+ QString *errorMessage)
+{
+ SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance();
+ const QSharedPointer<trk::TrkDevice> device = sdm->acquireDevice(serverName);
+ if (device.isNull()) {
+ *errorMessage = tr("Unable to acquire a device for port '%1'. It appears to be in use.").arg(serverName);
+ return 0;
+ }
+ // Wire release signal.
+ Launcher *rc = new Launcher(trk::Launcher::ActionPingOnly, device, parent);
+ connect(rc, SIGNAL(deviceDescriptionReceived(QString,QString)),
+ sdm, SLOT(setAdditionalInformation(QString,QString)));
+ connect(rc, SIGNAL(destroyed(QString)), sdm, SLOT(releaseDevice(QString)));
+ return rc;
+}
+
+// Preliminary release of device, disconnecting the signal.
+void Launcher::releaseToDeviceManager(Launcher *launcher)
+{
+ SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance();
+ // Disentangle launcher and its device, remove connection from destroyed
+ launcher->setCloseDevice(false);
+ TrkDevice *device = launcher->trkDevice().data();
+ launcher->disconnect(device);
+ device->disconnect(launcher);
+ launcher->disconnect(sdm);
+ sdm->releaseDevice(launcher->trkServerName());
+}
+
} // namespace trk
diff --git a/src/shared/symbianutils/launcher.h b/src/shared/symbianutils/launcher.h
index b9b68e400d..38f1bf77ce 100644
--- a/src/shared/symbianutils/launcher.h
+++ b/src/shared/symbianutils/launcher.h
@@ -96,6 +96,15 @@ public:
// becomes valid after successful execution of ActionPingOnly
QString deviceDescription(unsigned verbose = 0u) const;
+ // Acquire a device from SymbianDeviceManager, return 0 if not available.
+ // The device will be released on destruction.
+ static Launcher *acquireFromDeviceManager(const QString &serverName,
+ QObject *parent,
+ QString *errorMessage);
+ // Preliminary release of device, disconnecting the signal.
+ static void releaseToDeviceManager(Launcher *l);
+
+ // Create Trk message to start a process.
static QByteArray startProcessMessage(const QString &executable,
const QStringList &arguments);
// Parse a TrkNotifyStopped message
@@ -106,6 +115,7 @@ public:
static QString msgStopped(uint pid, uint tid, uint address, const QString &why);
signals:
+ void deviceDescriptionReceived(const QString &port, const QString &description);
void copyingStarted();
void canNotConnect(const QString &errorMessage);
void canNotCreateFile(const QString &filename, const QString &errorMessage);
@@ -122,6 +132,8 @@ signals:
void copyProgress(int percent);
void stateChanged(int);
void processStopped(uint pc, uint pid, uint tid, const QString& reason);
+ // Emitted by the destructor, for releasing devices of SymbianDeviceManager by name
+ void destroyed(const QString &serverName);
public slots:
void terminate();
@@ -154,6 +166,7 @@ private:
void copyFileToRemote();
void installRemotePackageSilently();
void startInferiorIfNeeded();
+ void handleFinished();
void logMessage(const QString &msg);
void setState(State s);
diff --git a/src/shared/symbianutils/symbiandevicemanager.cpp b/src/shared/symbianutils/symbiandevicemanager.cpp
index 89b2b91449..6d6d7cef30 100644
--- a/src/shared/symbianutils/symbiandevicemanager.cpp
+++ b/src/shared/symbianutils/symbiandevicemanager.cpp
@@ -28,6 +28,7 @@
**************************************************************************/
#include "symbiandevicemanager.h"
+#include "trkdevice.h"
#include <QtCore/QSettings>
#include <QtCore/QStringList>
@@ -36,6 +37,7 @@
#include <QtCore/QTextStream>
#include <QtCore/QSharedData>
#include <QtCore/QScopedPointer>
+#include <QtCore/QSignalMapper>
namespace SymbianUtils {
@@ -49,19 +51,51 @@ const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm";
// ------------- SymbianDevice
class SymbianDeviceData : public QSharedData {
public:
- SymbianDeviceData() : type(SerialPortCommunication) {}
+ SymbianDeviceData();
+ ~SymbianDeviceData();
+
+ inline bool isOpen() const { return !device.isNull() && device->isOpen(); }
+ void forcedClose();
QString portName;
QString friendlyName;
QString deviceDesc;
QString manufacturer;
+ QString additionalInformation;
+
DeviceCommunicationType type;
+ QSharedPointer<trk::TrkDevice> device;
+ bool deviceAcquired;
};
+SymbianDeviceData::SymbianDeviceData() :
+ type(SerialPortCommunication),
+ deviceAcquired(false)
+{
+}
+
+SymbianDeviceData::~SymbianDeviceData()
+{
+ forcedClose();
+}
+
+void SymbianDeviceData::forcedClose()
+{
+ // Close the device when unplugging. Should devices be in 'acquired' state,
+ // their owners should hit on write failures.
+ // Apart from the <shared item> destructor, also called by the devicemanager
+ // to ensure it also happens if other shared instances are still around.
+ if (isOpen()) {
+ if (deviceAcquired)
+ qWarning("Device on '%s' unplugged while an operation is in progress.",
+ qPrintable(portName));
+ device->close();
+ }
+}
+
SymbianDevice::SymbianDevice(SymbianDeviceData *data) :
m_data(data)
{
-
}
SymbianDevice::SymbianDevice() :
@@ -84,6 +118,11 @@ SymbianDevice::~SymbianDevice()
{
}
+void SymbianDevice::forcedClose()
+{
+ m_data->forcedClose();
+}
+
QString SymbianDevice::portName() const
{
return m_data->portName;
@@ -94,6 +133,49 @@ QString SymbianDevice::friendlyName() const
return m_data->friendlyName;
}
+QString SymbianDevice::additionalInformation() const
+{
+ return m_data->additionalInformation;
+}
+
+void SymbianDevice::setAdditionalInformation(const QString &a)
+{
+ m_data->additionalInformation = a;
+}
+
+SymbianDevice::TrkDevicePtr SymbianDevice::acquireDevice()
+{
+ if (debug)
+ qDebug() << "SymbianDevice::acquireDevice" << m_data->portName
+ << "acquired: " << m_data->deviceAcquired << " open: " << isOpen();
+ if (isNull() || m_data->deviceAcquired)
+ return TrkDevicePtr();
+ if (m_data->device.isNull()) {
+ m_data->device = TrkDevicePtr(new trk::TrkDevice);
+ m_data->device->setPort(m_data->portName);
+ m_data->device->setSerialFrame(m_data->type == SerialPortCommunication);
+ }
+ m_data->deviceAcquired = true;
+ return m_data->device;
+}
+
+void SymbianDevice::releaseDevice(TrkDevicePtr *ptr /* = 0 */)
+{
+ if (debug)
+ qDebug() << "SymbianDevice::releaseDevice" << m_data->portName
+ << " open: " << isOpen();
+ if (m_data->deviceAcquired) {
+ // Release if a valid pointer was passed in.
+ if (ptr && !ptr->isNull()) {
+ ptr->data()->disconnect();
+ *ptr = TrkDevicePtr();
+ }
+ m_data->deviceAcquired = false;
+ } else {
+ qWarning("Internal error: Attempt to release device that is not acquired.");
+ }
+}
+
QString SymbianDevice::deviceDesc() const
{
return m_data->deviceDesc;
@@ -111,7 +193,12 @@ DeviceCommunicationType SymbianDevice::type() const
bool SymbianDevice::isNull() const
{
- return !m_data->portName.isEmpty();
+ return m_data->portName.isEmpty();
+}
+
+bool SymbianDevice::isOpen() const
+{
+ return m_data->isOpen();
}
QString SymbianDevice::toString() const
@@ -146,7 +233,7 @@ int SymbianDevice::compare(const SymbianDevice &rhs) const
return 0;
}
-QDebug operator<<(QDebug d, const SymbianDevice &cd)
+SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd)
{
d.nospace() << cd.toString();
return d;
@@ -154,10 +241,11 @@ QDebug operator<<(QDebug d, const SymbianDevice &cd)
// ------------- SymbianDeviceManagerPrivate
struct SymbianDeviceManagerPrivate {
- SymbianDeviceManagerPrivate() : m_initialized(false) {}
+ SymbianDeviceManagerPrivate() : m_initialized(false), m_destroyReleaseMapper(0) {}
bool m_initialized;
SymbianDeviceManager::SymbianDeviceList m_devices;
+ QSignalMapper *m_destroyReleaseMapper;
};
SymbianDeviceManager::SymbianDeviceManager(QObject *parent) :
@@ -173,8 +261,7 @@ SymbianDeviceManager::~SymbianDeviceManager()
SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const
{
- if (!d->m_initialized)
- const_cast<SymbianDeviceManager*>(this)->update(false);
+ ensureInitialized();
return d->m_devices;
}
@@ -182,6 +269,7 @@ QString SymbianDeviceManager::toString() const
{
QString rc;
QTextStream str(&rc);
+ str << d->m_devices.size() << " devices:\n";
const int count = d->m_devices.size();
for (int i = 0; i < count; i++) {
str << '#' << i << ' ';
@@ -191,15 +279,37 @@ QString SymbianDeviceManager::toString() const
return rc;
}
+int SymbianDeviceManager::findByPortName(const QString &p) const
+{
+ ensureInitialized();
+ const int count = d->m_devices.size();
+ for (int i = 0; i < count; i++)
+ if (d->m_devices.at(i).portName() == p)
+ return i;
+ return -1;
+}
+
QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const
{
- if (!d->m_initialized)
- const_cast<SymbianDeviceManager*>(this)->update(false);
- foreach (const SymbianDevice &device, d->m_devices) {
- if (device.portName() == port)
- return device.friendlyName();
- }
- return QString();
+ const int idx = findByPortName(port);
+ return idx == -1 ? QString() : d->m_devices.at(idx).friendlyName();
+}
+
+SymbianDeviceManager::TrkDevicePtr
+ SymbianDeviceManager::acquireDevice(const QString &port)
+{
+ ensureInitialized();
+ const int idx = findByPortName(port);
+ if (idx == -1) {
+ qWarning("Attempt to acquire device '%s' that does not exist.", qPrintable(port));
+ if (debug)
+ qDebug() << *this;
+ return TrkDevicePtr();
+ }
+ const TrkDevicePtr rc = d->m_devices[idx].acquireDevice();
+ if (debug)
+ qDebug() << "SymbianDeviceManager::acquireDevice" << port << " returns " << !rc.isNull();
+ return rc;
}
void SymbianDeviceManager::update()
@@ -207,12 +317,38 @@ void SymbianDeviceManager::update()
update(true);
}
+void SymbianDeviceManager::releaseDevice(const QString &port)
+{
+ const int idx = findByPortName(port);
+ if (debug)
+ qDebug() << "SymbianDeviceManager::releaseDevice" << port << idx << sender();
+ if (idx != -1) {
+ d->m_devices[idx].releaseDevice();
+ } else {
+ qWarning("Attempt to release non-existing device %s.", qPrintable(port));
+ }
+}
+
+void SymbianDeviceManager::setAdditionalInformation(const QString &port, const QString &ai)
+{
+ const int idx = findByPortName(port);
+ if (idx != -1)
+ d->m_devices[idx].setAdditionalInformation(ai);
+}
+
+void SymbianDeviceManager::ensureInitialized() const
+{
+ if (!d->m_initialized) // Flag is set in update()
+ const_cast<SymbianDeviceManager*>(this)->update(false);
+}
+
void SymbianDeviceManager::update(bool emitSignals)
{
+ static int n = 0;
typedef SymbianDeviceList::iterator SymbianDeviceListIterator;
if (debug)
- qDebug(">SerialDeviceLister::update(%d)\n%s", int(emitSignals),
+ qDebug(">SerialDeviceLister::update(#%d, signals=%d)\n%s", n++, int(emitSignals),
qPrintable(toString()));
d->m_initialized = true;
@@ -220,8 +356,11 @@ void SymbianDeviceManager::update(bool emitSignals)
SymbianDeviceList newDevices = serialPorts() + blueToothDevices();
if (newDevices.size() > 1)
qStableSort(newDevices.begin(), newDevices.end());
- if (d->m_devices == newDevices) // Happy, nothing changed.
+ if (d->m_devices == newDevices) { // Happy, nothing changed.
+ if (debug)
+ qDebug("<SerialDeviceLister::update: unchanged\n");
return;
+ }
// Merge the lists and emit the respective added/removed signals, assuming
// no one can plug a different device on the same port at the speed of lightning
if (!d->m_devices.isEmpty()) {
@@ -230,7 +369,8 @@ void SymbianDeviceManager::update(bool emitSignals)
if (newDevices.contains(*oldIt)) {
++oldIt;
} else {
- const SymbianDevice toBeDeleted = *oldIt;
+ SymbianDevice toBeDeleted = *oldIt;
+ toBeDeleted.forcedClose();
oldIt = d->m_devices.erase(oldIt);
if (emitSignals)
emit deviceRemoved(toBeDeleted);
@@ -312,7 +452,7 @@ SymbianDeviceManager *SymbianDeviceManager::instance()
return symbianDeviceManager();
}
-QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm)
+SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm)
{
d.nospace() << sdm.toString();
return d;
diff --git a/src/shared/symbianutils/symbiandevicemanager.h b/src/shared/symbianutils/symbiandevicemanager.h
index 27305b5cb9..08ae401f86 100644
--- a/src/shared/symbianutils/symbiandevicemanager.h
+++ b/src/shared/symbianutils/symbiandevicemanager.h
@@ -34,12 +34,17 @@
#include <QtCore/QObject>
#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
class QDebug;
class QTextStream;
QT_END_NAMESPACE
+namespace trk {
+ class TrkDevice;
+}
+
namespace SymbianUtils {
struct SymbianDeviceManagerPrivate;
@@ -50,11 +55,16 @@ enum DeviceCommunicationType {
BlueToothCommunication = 1
};
-// SymbianDevice, explicitly shared.
+// SymbianDevice: Explicitly shared device data and a TrkDevice
+// instance that can be acquired (exclusively) for use.
+// A device removal from the manager will result in the
+// device being closed.
class SYMBIANUTILS_EXPORT SymbianDevice {
explicit SymbianDevice(SymbianDeviceData *data);
friend class SymbianDeviceManager;
public:
+ typedef QSharedPointer<trk::TrkDevice> TrkDevicePtr;
+
SymbianDevice();
SymbianDevice(const SymbianDevice &rhs);
SymbianDevice &operator=(const SymbianDevice &rhs);
@@ -65,6 +75,17 @@ public:
bool isNull() const;
QString portName() const;
QString friendlyName() const;
+ QString additionalInformation() const;
+ void setAdditionalInformation(const QString &);
+
+ // Acquire: Mark the device as 'out' and return a shared pointer
+ // unless it is already in use by another owner. The result should not
+ // be passed on further.
+ TrkDevicePtr acquireDevice();
+ // Give back a device and mark it as 'free'.
+ void releaseDevice(TrkDevicePtr *ptr = 0);
+
+ bool isOpen() const;
// Windows only.
QString deviceDesc() const;
@@ -74,10 +95,12 @@ public:
QString toString() const;
private:
+ void forcedClose();
+
QExplicitlySharedDataPointer<SymbianDeviceData> m_data;
};
-QDebug operator<<(QDebug d, const SymbianDevice &);
+SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &);
inline bool operator==(const SymbianDevice &d1, const SymbianDevice &d2)
{ return d1.compare(d2) == 0; }
@@ -88,13 +111,15 @@ inline bool operator<(const SymbianDevice &d1, const SymbianDevice &d2)
/* SymbianDeviceManager: Singleton that maintains a list of Symbian devices.
* and emits change signals.
- * On Windows, the update slot must be connected to a signal
- * emitted from an event handler listening for WM_DEVICECHANGE. */
+ * On Windows, the update slot must be connected to a [delayed] signal
+ * emitted from an event handler listening for WM_DEVICECHANGE.
+ * Device removal will result in the device being closed. */
class SYMBIANUTILS_EXPORT SymbianDeviceManager : public QObject
{
Q_OBJECT
public:
typedef QList<SymbianDevice> SymbianDeviceList;
+ typedef QSharedPointer<trk::TrkDevice> TrkDevicePtr;
static const char *linuxBlueToothDeviceRootC;
@@ -108,17 +133,25 @@ public:
SymbianDeviceList devices() const;
QString toString() const;
+ // Acquire a device for use. See releaseDevice().
+ TrkDevicePtr acquireDevice(const QString &port);
+
+ int findByPortName(const QString &p) const;
QString friendlyNameForPort(const QString &port) const;
public slots:
void update();
+ // Relase a device, make it available for further use.
+ void releaseDevice(const QString &port);
+ void setAdditionalInformation(const QString &port, const QString &ai);
signals:
- void deviceRemoved(const SymbianDevice &d);
- void deviceAdded(const SymbianDevice &d);
+ void deviceRemoved(const SymbianUtils::SymbianDevice &d);
+ void deviceAdded(const SymbianUtils::SymbianDevice &d);
void updated();
private:
+ void ensureInitialized() const;
void update(bool emitSignals);
SymbianDeviceList serialPorts() const;
SymbianDeviceList blueToothDevices() const;
@@ -126,7 +159,7 @@ private:
SymbianDeviceManagerPrivate *d;
};
-QDebug operator<<(QDebug d, const SymbianDeviceManager &);
+SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &);
} // namespace SymbianUtils
diff --git a/src/shared/symbianutils/trkdevice.cpp b/src/shared/symbianutils/trkdevice.cpp
index 6c5b8b2648..c9b1bb79ed 100644
--- a/src/shared/symbianutils/trkdevice.cpp
+++ b/src/shared/symbianutils/trkdevice.cpp
@@ -40,6 +40,7 @@
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QSharedPointer>
+#include <QtCore/QScopedPointer>
#include <QtCore/QMetaType>
#ifdef Q_OS_WIN
@@ -90,6 +91,11 @@ QString winErrorMessage(unsigned long error)
enum { verboseTrk = 0 };
+static inline QString msgAccessingClosedDevice(const QString &msg)
+{
+ return QString::fromLatin1("Error: Attempt to access device '%1', which is closed.").arg(msg);
+}
+
namespace trk {
///////////////////////////////////////////////////////////////////////
@@ -147,6 +153,7 @@ class TrkWriteQueue
Q_DISABLE_COPY(TrkWriteQueue)
public:
explicit TrkWriteQueue();
+ void clear();
// Enqueue messages.
void queueTrkMessage(byte code, TrkCallback callback,
@@ -196,13 +203,21 @@ TrkWriteQueue::TrkWriteQueue() :
{
}
+void TrkWriteQueue::clear()
+{
+ m_trkWriteToken = 0;
+ m_trkWriteBusy = false;
+ m_trkWriteQueue.clear();
+ m_writtenTrkMessages.clear();
+}
+
byte TrkWriteQueue::nextTrkWriteToken()
{
++m_trkWriteToken;
if (m_trkWriteToken == 0)
++m_trkWriteToken;
if (verboseTrk)
- qDebug() << "Write token: " << m_trkWriteToken;
+ qDebug() << "nextTrkWriteToken:" << m_trkWriteToken;
return m_trkWriteToken;
}
@@ -450,6 +465,7 @@ void WriterThread::terminate()
m_waitCondition.wakeAll();
wait();
m_terminate = false;
+ m_queue.clear();
}
#ifdef Q_OS_WIN
@@ -580,6 +596,8 @@ class ReaderThreadBase : public QThread
Q_DISABLE_COPY(ReaderThreadBase)
public:
+ int bytesPending() const { return m_trkReadBuffer.size(); }
+
signals:
void messageReceived(const trk::TrkResult &result, const QByteArray &rawData);
@@ -865,8 +883,8 @@ struct TrkDevicePrivate
TrkDevicePrivate();
QSharedPointer<DeviceContext> deviceContext;
- QSharedPointer<WriterThread> writerThread;
- QSharedPointer<ReaderThread> readerThread;
+ QScopedPointer<WriterThread> writerThread;
+ QScopedPointer<ReaderThread> readerThread;
QByteArray trkReadBuffer;
int verbose;
@@ -905,14 +923,14 @@ TrkDevice::~TrkDevice()
bool TrkDevice::open(QString *errorMessage)
{
- if (d->verbose)
+ if (d->verbose || verboseTrk)
qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame();
+ if (isOpen())
+ return true;
if (d->port.isEmpty()) {
*errorMessage = QLatin1String("Internal error: No port set on TrkDevice");
return false;
}
-
- close();
#ifdef Q_OS_WIN
const QString fullPort = QLatin1String("\\\\.\\") + d->port;
d->deviceContext->device = CreateFile(reinterpret_cast<const WCHAR*>(fullPort.utf16()),
@@ -963,7 +981,7 @@ bool TrkDevice::open(QString *errorMessage)
return false;
}
#endif
- d->readerThread = QSharedPointer<ReaderThread>(new ReaderThread(d->deviceContext));
+ d->readerThread.reset(new ReaderThread(d->deviceContext));
connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
Qt::QueuedConnection);
connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)),
@@ -971,18 +989,22 @@ bool TrkDevice::open(QString *errorMessage)
Qt::QueuedConnection);
d->readerThread->start();
- d->writerThread = QSharedPointer<WriterThread>(new WriterThread(d->deviceContext));
+ d->writerThread.reset(new WriterThread(d->deviceContext));
connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
Qt::QueuedConnection);
d->writerThread->start();
- if (d->verbose)
- qDebug() << "Opened" << d->port;
+ if (d->verbose || verboseTrk)
+ qDebug() << "Opened" << d->port << d->readerThread.data() << d->writerThread.data();
return true;
}
void TrkDevice::close()
{
+ if (verboseTrk)
+ qDebug() << "close" << d->port << " is open: " << isOpen()
+ << " read pending " << (d->readerThread.isNull() ? 0 : d->readerThread->bytesPending())
+ << sender();
if (!isOpen())
return;
if (d->readerThread)
@@ -998,6 +1020,7 @@ void TrkDevice::close()
#else
d->deviceContext->file.close();
#endif
+
if (d->verbose)
emitLogMessage("Close");
}
@@ -1018,6 +1041,8 @@ QString TrkDevice::port() const
void TrkDevice::setPort(const QString &p)
{
+ if (verboseTrk)
+ qDebug() << "setPort" << p;
d->port = p;
}
@@ -1033,6 +1058,8 @@ bool TrkDevice::serialFrame() const
void TrkDevice::setSerialFrame(bool f)
{
+ if (verboseTrk)
+ qDebug() << "setSerialFrame" << f;
d->deviceContext->serialFrame = f;
}
@@ -1048,12 +1075,14 @@ void TrkDevice::setVerbose(int b)
void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData)
{
- d->writerThread->slotHandleResult(result);
- if (d->verbose > 1)
- qDebug() << "Received: " << result.toString();
- emit messageReceived(result);
- if (!rawData.isEmpty())
- emit rawDataReceived(rawData);
+ if (isOpen()) { // Might receive bytes after closing due to queued connections.
+ d->writerThread->slotHandleResult(result);
+ if (d->verbose > 1)
+ qDebug() << "Received: " << result.toString();
+ emit messageReceived(result);
+ if (!rawData.isEmpty())
+ emit rawDataReceived(rawData);
+ }
}
void TrkDevice::emitError(const QString &s)
@@ -1066,12 +1095,18 @@ void TrkDevice::emitError(const QString &s)
void TrkDevice::sendTrkMessage(byte code, TrkCallback callback,
const QByteArray &data, const QVariant &cookie)
{
+ if (!isOpen()) {
+ emitError(msgAccessingClosedDevice(d->port));
+ return;
+ }
if (!d->writerThread.isNull()) {
if (d->verbose > 1) {
- QByteArray msg = "Sending: ";
+ QByteArray msg = "Sending: 0x";
msg += QByteArray::number(code, 16);
msg += ": ";
msg += stringFromArray(data).toLatin1();
+ if (cookie.isValid())
+ msg += " Cookie: " + cookie.toString().toLatin1();
qDebug("%s", msg.data());
}
d->writerThread->queueTrkMessage(code, callback, data, cookie);
@@ -1080,12 +1115,20 @@ void TrkDevice::sendTrkMessage(byte code, TrkCallback callback,
void TrkDevice::sendTrkInitialPing()
{
+ if (!isOpen()) {
+ emitError(msgAccessingClosedDevice(d->port));
+ return;
+ }
if (!d->writerThread.isNull())
d->writerThread->queueTrkInitialPing();
}
bool TrkDevice::sendTrkAck(byte token)
{
+ if (!isOpen()) {
+ emitError(msgAccessingClosedDevice(d->port));
+ return false;
+ }
if (d->writerThread.isNull())
return false;
// The acknowledgement must not be queued!
diff --git a/src/shared/symbianutils/trkdevice.h b/src/shared/symbianutils/trkdevice.h
index 763b60ff25..531b40c300 100644
--- a/src/shared/symbianutils/trkdevice.h
+++ b/src/shared/symbianutils/trkdevice.h
@@ -57,7 +57,9 @@ struct TrkDevicePrivate;
* for queueing messages with a notification callback. If the message receives
* an ACK, the callback is invoked.
* The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronization.
- * The respective message will not be sent, the callback is just invoked. */
+ * The respective message will not be sent, the callback is just invoked.
+ * Note that calling open/close in quick succession can cause crashes
+ * due to the use of queused signals. */
enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f };