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).
This commit is contained in:
Friedemann Kleint
2010-02-11 12:31:59 +01:00
parent ecbb54811c
commit dc006860c4
20 changed files with 568 additions and 220 deletions

View File

@@ -33,21 +33,50 @@
#include <windows.h> #include <windows.h>
#endif #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 #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) bool EventFilteringMainWindow::winEvent(MSG *msg, long *result)
{ {
if (msg->message == WM_DEVICECHANGE) { if (msg->message == WM_DEVICECHANGE) {
emit deviceChange(); if (msg->wParam & 0x7 /* DBT_DEVNODES_CHANGED */) {
*result = TRUE; *result = TRUE;
QCoreApplication::postEvent(this, new DeviceNotifyEvent(m_deviceEventId));
}
} }
return false; return false;
} }
#endif #endif
} // namespace Internal
} // namespace Core

View File

@@ -32,6 +32,10 @@
#include <QtGui/QMainWindow> #include <QtGui/QMainWindow>
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
namespace Core { namespace Core {
namespace Internal { namespace Internal {
@@ -46,14 +50,17 @@ class EventFilteringMainWindow : public QMainWindow
public: public:
EventFilteringMainWindow(); EventFilteringMainWindow();
#ifdef Q_OS_WIN
protected:
bool winEvent(MSG *message, long *result);
#endif
signals: signals:
void deviceChange(); void deviceChange();
#ifdef Q_OS_WIN
protected:
virtual bool winEvent(MSG *message, long *result);
virtual bool event(QEvent *event);
#endif
private:
const int m_deviceEventId;
}; };
} // Internal } // Internal

View File

@@ -224,7 +224,6 @@ const char *DebuggerManager::stateName(int s)
DebuggerStartParameters::DebuggerStartParameters() DebuggerStartParameters::DebuggerStartParameters()
: attachPID(-1), : attachPID(-1),
useTerminal(false), useTerminal(false),
remoteChannelType(-1),
toolChainType(ProjectExplorer::ToolChain::UNKNOWN), toolChainType(ProjectExplorer::ToolChain::UNKNOWN),
startMode(NoStartMode) startMode(NoStartMode)
{} {}

View File

@@ -118,7 +118,6 @@ public:
QString crashParameter; // for AttachCrashedExternal QString crashParameter; // for AttachCrashedExternal
// for remote debugging // for remote debugging
QString remoteChannel; QString remoteChannel;
int remoteChannelType;
QString remoteArchitecture; QString remoteArchitecture;
QString symbolFileName; QString symbolFileName;
QString serverStartScript; QString serverStartScript;

View File

@@ -31,6 +31,7 @@
#include "bluetoothlistener.h" #include "bluetoothlistener.h"
#include "debuggermanager.h" #include "debuggermanager.h"
#include "trkoptions.h" #include "trkoptions.h"
#include "trkdevice.h"
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -51,19 +52,17 @@ trk::BluetoothListener *S60DebuggerBluetoothStarter::createListener()
trk::PromptStartCommunicationResult trk::PromptStartCommunicationResult
S60DebuggerBluetoothStarter::startCommunication(const TrkDevicePtr &trkDevice, S60DebuggerBluetoothStarter::startCommunication(const TrkDevicePtr &trkDevice,
int communicationType,
QWidget *msgBoxParent, QWidget *msgBoxParent,
QString *errorMessage) QString *errorMessage)
{ {
// Bluetooth? // Bluetooth?
if (communicationType == TrkOptions::BlueTooth) { if (trkDevice->serialFrame()) {
S60DebuggerBluetoothStarter bluetoothStarter(trkDevice);
return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
}
// Serial
BaseCommunicationStarter serialStarter(trkDevice); BaseCommunicationStarter serialStarter(trkDevice);
return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage); return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage);
} }
S60DebuggerBluetoothStarter bluetoothStarter(trkDevice);
return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -47,7 +47,6 @@ class S60DebuggerBluetoothStarter : public trk::AbstractBluetoothStarter
public: public:
static trk::PromptStartCommunicationResult static trk::PromptStartCommunicationResult
startCommunication(const TrkDevicePtr &trkDevice, startCommunication(const TrkDevicePtr &trkDevice,
int communicationType,
QWidget *msgBoxParent, QWidget *msgBoxParent,
QString *errorMessage); QString *errorMessage);

View File

@@ -32,6 +32,7 @@
#include "launcher.h" #include "launcher.h"
#include "trkoptions.h" #include "trkoptions.h"
#include "trkoptionspage.h" #include "trkoptionspage.h"
#include "symbiandevicemanager.h"
#include "s60debuggerbluetoothstarter.h" #include "s60debuggerbluetoothstarter.h"
#include "bluetoothlistener_gui.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) : TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
AbstractGdbAdapter(engine), AbstractGdbAdapter(engine),
m_options(options), m_options(options),
m_overrideTrkDeviceType(-1),
m_running(false), m_running(false),
m_trkDevice(new trk::TrkDevice), m_deviceFromSymbianDeviceManager(false),
m_gdbAckMode(true), m_gdbAckMode(true),
m_verbose(0) m_verbose(0)
{ {
@@ -259,16 +259,8 @@ TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
#endif #endif
m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset); 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)); 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)), connect(theDebuggerAction(VerboseLog), SIGNAL(valueChanged(QVariant)),
this, SLOT(setVerbose(QVariant))); this, SLOT(setVerbose(QVariant)));
} }
@@ -287,25 +279,10 @@ void TrkGdbAdapter::setVerbose(const QVariant &value)
void TrkGdbAdapter::setVerbose(int verbose) void TrkGdbAdapter::setVerbose(int verbose)
{ {
m_verbose = verbose; m_verbose = verbose;
if (!m_trkDevice.isNull())
m_trkDevice->setVerbose(m_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;
}
void TrkGdbAdapter::trkLogMessage(const QString &msg) void TrkGdbAdapter::trkLogMessage(const QString &msg)
{ {
logMessage("TRK " + msg); logMessage("TRK " + msg);
@@ -1726,14 +1703,66 @@ void TrkGdbAdapter::interruptInferior()
sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting..."); 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() void TrkGdbAdapter::startAdapter()
{ {
m_snapshot.fullReset(); m_snapshot.fullReset();
// Retrieve parameters // Retrieve parameters
const DebuggerStartParameters &parameters = startParameters(); const DebuggerStartParameters &parameters = startParameters();
m_overrideTrkDevice = parameters.remoteChannel;
m_overrideTrkDeviceType = parameters.remoteChannelType;
m_remoteExecutable = parameters.executable; m_remoteExecutable = parameters.executable;
m_remoteArguments = parameters.processArgs; m_remoteArguments = parameters.processArgs;
m_symbolFile = parameters.symbolFileName; m_symbolFile = parameters.symbolFileName;
@@ -1750,23 +1779,16 @@ void TrkGdbAdapter::startAdapter()
setState(AdapterStarting); setState(AdapterStarting);
debugMessage(_("TRYING TO START ADAPTER")); debugMessage(_("TRYING TO START ADAPTER"));
logMessage(QLatin1String("### Starting TrkGdbAdapter")); logMessage(QLatin1String("### Starting TrkGdbAdapter"));
m_trkDevice->setPort(effectiveTrkDevice());
m_trkDevice->setSerialFrame(effectiveTrkDeviceType() != TrkOptions::BlueTooth);
// Prompt the user to start communication // Prompt the user to start communication
QString message; QString message;
if (!initializeDevice(parameters.remoteChannel, &message)) {
const trk::PromptStartCommunicationResult src = if (message.isEmpty()) {
S60DebuggerBluetoothStarter::startCommunication(m_trkDevice, emit adapterStartFailed(QString(), QString());
effectiveTrkDeviceType(), } else {
0, &message); logMessage(message);
switch (src) {
case trk::PromptStartCommunicationConnected:
break;
case trk::PromptStartCommunicationCanceled:
emit adapterStartFailed(message, QString());
return;
case trk::PromptStartCommunicationError:
emit adapterStartFailed(message, TrkOptionsPage::settingsId()); emit adapterStartFailed(message, TrkOptionsPage::settingsId());
}
return; return;
} }
@@ -2099,7 +2121,16 @@ void TrkGdbAdapter::handleDirectStep3(const TrkResult &result)
void TrkGdbAdapter::cleanup() void TrkGdbAdapter::cleanup()
{ {
if (!m_trkDevice.isNull()) {
m_trkDevice->close(); 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; delete m_gdbServer;
m_gdbServer = 0; m_gdbServer = 0;
} }

View File

@@ -47,6 +47,9 @@
#include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket> #include <QtNetwork/QTcpSocket>
namespace SymbianUtils {
class SymbianDevice;
}
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -160,8 +163,6 @@ signals:
private: private:
const TrkOptionsPtr m_options; const TrkOptionsPtr m_options;
QString m_overrideTrkDevice;
int m_overrideTrkDeviceType;
QString m_gdbServerName; // 127.0.0.1:(2222+uid) QString m_gdbServerName; // 127.0.0.1:(2222+uid)
@@ -180,6 +181,7 @@ public:
private: private:
void startAdapter(); void startAdapter();
bool initializeDevice(const QString &remoteChannel, QString *errorMessage);
void startInferior(); void startInferior();
void startInferiorPhase2(); void startInferiorPhase2();
void interruptInferior(); void interruptInferior();
@@ -258,8 +260,10 @@ private:
QByteArray trkStepRangeMessage(); QByteArray trkStepRangeMessage();
QByteArray trkDeleteProcessMessage(); QByteArray trkDeleteProcessMessage();
QByteArray trkInterruptMessage(); QByteArray trkInterruptMessage();
Q_SLOT void trkDeviceRemoved(const SymbianUtils::SymbianDevice &);
QSharedPointer<trk::TrkDevice> m_trkDevice; QSharedPointer<trk::TrkDevice> m_trkDevice;
bool m_deviceFromSymbianDeviceManager;
QString m_adapterFailMessage; QString m_adapterFailMessage;
// //
@@ -299,9 +303,6 @@ private:
QHash<int, GdbCommand> m_gdbCookieForToken; QHash<int, GdbCommand> m_gdbCookieForToken;
QString effectiveTrkDevice() const;
int effectiveTrkDeviceType() const;
// Debuggee state // Debuggee state
trk::Session m_session; // global-ish data (process id, target information) trk::Session m_session; // global-ish data (process id, target information)
Snapshot m_snapshot; // local-ish data (memory and registers) Snapshot m_snapshot; // local-ish data (memory and registers)

View File

@@ -112,10 +112,8 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QStri
m_cachedTargetInformationValid(false), m_cachedTargetInformationValid(false),
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
m_serialPortName(QLatin1String("COM5")), m_serialPortName(QLatin1String("COM5")),
m_communicationType(SymbianUtils::SerialPortCommunication),
#else #else
m_serialPortName(QLatin1String(SymbianUtils::SymbianDeviceManager::linuxBlueToothDeviceRootC) + QLatin1Char('0')), m_serialPortName(QLatin1String(SymbianUtils::SymbianDeviceManager::linuxBlueToothDeviceRootC) + QLatin1Char('0')),
m_communicationType(SymbianUtils::BlueToothCommunication),
#endif #endif
m_signingMode(SignSelf) m_signingMode(SignSelf)
{ {
@@ -127,7 +125,6 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRu
m_proFilePath(source->m_proFilePath), m_proFilePath(source->m_proFilePath),
m_cachedTargetInformationValid(false), m_cachedTargetInformationValid(false),
m_serialPortName(source->m_serialPortName), m_serialPortName(source->m_serialPortName),
m_communicationType(source->m_communicationType),
m_signingMode(source->m_signingMode), m_signingMode(source->m_signingMode),
m_customSignaturePath(source->m_customSignaturePath), m_customSignaturePath(source->m_customSignaturePath),
m_customKeyPath(source->m_customKeyPath) 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_SIGNATURE_PATH_KEY), m_customSignaturePath);
map.insert(QLatin1String(CUSTOM_KEY_PATH_KEY), m_customKeyPath); map.insert(QLatin1String(CUSTOM_KEY_PATH_KEY), m_customKeyPath);
map.insert(QLatin1String(SERIAL_PORT_NAME_KEY), m_serialPortName); 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); map.insert(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY), m_commandLineArguments);
return map; return map;
@@ -217,7 +213,6 @@ bool S60DeviceRunConfiguration::fromMap(const QVariantMap &map)
m_customSignaturePath = map.value(QLatin1String(CUSTOM_SIGNATURE_PATH_KEY)).toString(); m_customSignaturePath = map.value(QLatin1String(CUSTOM_SIGNATURE_PATH_KEY)).toString();
m_customKeyPath = map.value(QLatin1String(CUSTOM_KEY_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_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(); m_commandLineArguments = map.value(QLatin1String(COMMAND_LINE_ARGUMENTS_KEY)).toStringList();
return RunConfiguration::fromMap(map); return RunConfiguration::fromMap(map);
@@ -237,16 +232,6 @@ void S60DeviceRunConfiguration::setSerialPortName(const QString &name)
emit serialPortNameChanged(); emit serialPortNameChanged();
} }
int S60DeviceRunConfiguration::communicationType() const
{
return m_communicationType;
}
void S60DeviceRunConfiguration::setCommunicationType(int t)
{
m_communicationType = t;
}
QString S60DeviceRunConfiguration::targetName() const QString S60DeviceRunConfiguration::targetName() const
{ {
const_cast<S60DeviceRunConfiguration *>(this)->updateTarget(); const_cast<S60DeviceRunConfiguration *>(this)->updateTarget();
@@ -485,6 +470,8 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat
m_toolChain(ProjectExplorer::ToolChain::INVALID), m_toolChain(ProjectExplorer::ToolChain::INVALID),
m_makesis(new QProcess(this)), m_makesis(new QProcess(this)),
m_signsis(0), m_signsis(0),
m_releaseDeviceAfterLauncherFinish(false),
m_handleDeviceRemoval(true),
m_launcher(0) m_launcher(0)
{ {
// connect for automatically reporting the "finished deploy" state to the progress manager // 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_toolChain = s60runConfig->toolChainType();
m_serialPortName = s60runConfig->serialPortName(); m_serialPortName = s60runConfig->serialPortName();
m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName); m_serialPortFriendlyName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(m_serialPortName);
m_communicationType = s60runConfig->communicationType();
m_targetName = s60runConfig->targetName(); m_targetName = s60runConfig->targetName();
m_baseFileName = s60runConfig->basePackageFilePath(); m_baseFileName = s60runConfig->basePackageFilePath();
m_commandLineArguments = s60runConfig->commandLineArguments(); m_commandLineArguments = s60runConfig->commandLineArguments();
@@ -553,7 +539,7 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat
m_packageFile = QFileInfo(m_packageFilePath).fileName(); m_packageFile = QFileInfo(m_packageFilePath).fileName();
if (debug) if (debug)
qDebug() << "S60DeviceRunControlBase" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain) qDebug() << "S60DeviceRunControlBase" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
<< m_serialPortName << m_communicationType << m_workingDirectory; << m_serialPortName << m_workingDirectory;
} }
S60DeviceRunControlBase::~S60DeviceRunControlBase() S60DeviceRunControlBase::~S60DeviceRunControlBase()
@@ -564,6 +550,11 @@ S60DeviceRunControlBase::~S60DeviceRunControlBase()
} }
} }
void S60DeviceRunControlBase::setReleaseDeviceAfterLauncherFinish(bool v)
{
m_releaseDeviceAfterLauncherFinish = v;
}
void S60DeviceRunControlBase::start() void S60DeviceRunControlBase::start()
{ {
m_deployProgress = new QFutureInterface<void>; m_deployProgress = new QFutureInterface<void>;
@@ -739,9 +730,18 @@ void S60DeviceRunControlBase::signsisProcessFinished()
} }
} }
void S60DeviceRunControlBase::startDeployment() void S60DeviceRunControlBase::startDeployment()
{ {
m_launcher = new trk::Launcher(); QString errorMessage;
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(finished()), this, SLOT(launcherFinished()));
connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString))); connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice())); connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice()));
@@ -757,37 +757,32 @@ void S60DeviceRunControlBase::startDeployment()
this, SLOT(processStopped(uint,uint,uint,QString))); this, SLOT(processStopped(uint,uint,uint,QString)));
//TODO sisx destination and file path user definable //TODO sisx destination and file path user definable
m_launcher->setTrkServerName(m_serialPortName);
m_launcher->setSerialFrame(m_communicationType == SymbianUtils::SerialPortCommunication);
if (!m_commandLineArguments.isEmpty()) if (!m_commandLineArguments.isEmpty())
m_launcher->setCommandLineArgs(m_commandLineArguments); m_launcher->setCommandLineArgs(m_commandLineArguments);
const QString copySrc(m_baseFileName + ".sisx"); const QString copySrc(m_baseFileName + QLatin1String(".sisx"));
const QString copyDst = QString("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName()); const QString copyDst = QString::fromLatin1("C:\\Data\\%1.sisx").arg(QFileInfo(m_baseFileName).fileName());
const QString runFileName = QString("C:\\sys\\bin\\%1.exe").arg(m_targetName); const QString runFileName = QString::fromLatin1("C:\\sys\\bin\\%1.exe").arg(m_targetName);
m_launcher->setCopyFileName(copySrc, copyDst); m_launcher->setCopyFileName(copySrc, copyDst);
m_launcher->setInstallFileName(copyDst); m_launcher->setInstallFileName(copyDst);
initLauncher(runFileName, m_launcher); initLauncher(runFileName, m_launcher);
emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(copySrc), m_serialPortFriendlyName)); 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 // Prompt the user to start up the Blue tooth connection
const trk::PromptStartCommunicationResult src = const trk::PromptStartCommunicationResult src =
S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(), S60RunConfigBluetoothStarter::startCommunication(m_launcher->trkDevice(),
m_communicationType, 0, 0, &errorMessage);
&errorMessage); if (src != trk::PromptStartCommunicationConnected)
switch (src) {
case trk::PromptStartCommunicationConnected:
break; break;
case trk::PromptStartCommunicationCanceled:
case trk::PromptStartCommunicationError:
error(this, errorMessage);
stop();
emit finished();
return;
};
if (!m_launcher->startServer(&errorMessage)) { if (!m_launcher->startServer(&errorMessage)) {
error(this, tr("Could not connect to phone on port '%1': %2\n" 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)); "Check if the phone is connected and App TRK is running.").arg(m_serialPortName, errorMessage);
break;
}
success = true;
} while (false);
if (!success) {
if (!errorMessage.isEmpty())
error(this, errorMessage);
stop(); stop();
emit finished(); emit finished();
} }
@@ -845,6 +840,10 @@ void S60DeviceRunControlBase::printInstallFailed(const QString &filename, const
void S60DeviceRunControlBase::launcherFinished() void S60DeviceRunControlBase::launcherFinished()
{ {
if (m_releaseDeviceAfterLauncherFinish) {
m_handleDeviceRemoval = false;
trk::Launcher::releaseToDeviceManager(m_launcher);
}
m_launcher->deleteLater(); m_launcher->deleteLater();
m_launcher = 0; m_launcher = 0;
handleLauncherFinished(); handleLauncherFinished();
@@ -919,6 +918,14 @@ void S60DeviceRunControlBase::printApplicationOutput(const QString &output)
emit addToOutputWindowInline(this, 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 */, bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
QString * /* settingsCategory */, QString * /* settingsCategory */,
QString * /* settingsPage */) const QString * /* settingsPage */) const
@@ -969,6 +976,7 @@ S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *ru
S60DeviceRunControlBase(runConfiguration), S60DeviceRunControlBase(runConfiguration),
m_startParams(new Debugger::DebuggerStartParameters) m_startParams(new Debugger::DebuggerStartParameters)
{ {
setReleaseDeviceAfterLauncherFinish(true); // Debugger controls device after install
Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance(); Debugger::DebuggerManager *dm = Debugger::DebuggerManager::instance();
S60DeviceRunConfiguration *rc = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration); S60DeviceRunConfiguration *rc = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration);
QTC_ASSERT(dm && rc, return); QTC_ASSERT(dm && rc, return);
@@ -981,7 +989,6 @@ S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *ru
m_startParams->remoteChannel = rc->serialPortName(); m_startParams->remoteChannel = rc->serialPortName();
m_startParams->processArgs = rc->commandLineArguments(); m_startParams->processArgs = rc->commandLineArguments();
m_startParams->remoteChannelType = rc->communicationType();
m_startParams->startMode = Debugger::StartInternal; m_startParams->startMode = Debugger::StartInternal;
m_startParams->toolChainType = rc->toolChainType(); m_startParams->toolChainType = rc->toolChainType();
@@ -1018,6 +1025,8 @@ void S60DeviceDebugRunControl::initLauncher(const QString &executable, trk::Laun
} }
launcher->addStartupActions(trk::Launcher::ActionCopyInstall); launcher->addStartupActions(trk::Launcher::ActionCopyInstall);
// Avoid close/open sequence in quick succession, which may cause crashs
launcher->setCloseDevice(false);
} }
void S60DeviceDebugRunControl::handleLauncherFinished() void S60DeviceDebugRunControl::handleLauncherFinished()

View File

@@ -47,6 +47,10 @@ namespace Debugger {
class DebuggerStartParameters; class DebuggerStartParameters;
} }
namespace SymbianUtils {
class SymbianDevice;
}
namespace Qt4ProjectManager { namespace Qt4ProjectManager {
namespace Internal { namespace Internal {
@@ -75,9 +79,6 @@ public:
QString serialPortName() const; QString serialPortName() const;
void setSerialPortName(const QString &name); void setSerialPortName(const QString &name);
// See SymbianDeviceManager
int communicationType() const;
void setCommunicationType(int t);
QString targetName() const; QString targetName() const;
QString basePackageFilePath() const; QString basePackageFilePath() const;
@@ -126,7 +127,6 @@ private:
QString m_packageTemplateFileName; QString m_packageTemplateFileName;
bool m_cachedTargetInformationValid; bool m_cachedTargetInformationValid;
QString m_serialPortName; QString m_serialPortName;
int m_communicationType;
SigningMode m_signingMode; SigningMode m_signingMode;
QString m_customSignaturePath; QString m_customSignaturePath;
QString m_customKeyPath; QString m_customKeyPath;
@@ -179,9 +179,11 @@ protected:
virtual bool checkConfiguration(QString *errorMessage, virtual bool checkConfiguration(QString *errorMessage,
QString *settingsCategory, QString *settingsCategory,
QString *settingsPage) const; QString *settingsPage) const;
void setReleaseDeviceAfterLauncherFinish(bool);
protected slots: protected slots:
void printApplicationOutput(const QString &output); void printApplicationOutput(const QString &output);
void deviceRemoved(const SymbianUtils::SymbianDevice &);
private slots: private slots:
void processStopped(uint pc, uint pid, uint tid, const QString& reason); void processStopped(uint pc, uint pid, uint tid, const QString& reason);
@@ -213,7 +215,6 @@ private:
ProjectExplorer::ToolChain::ToolChainType m_toolChain; ProjectExplorer::ToolChain::ToolChainType m_toolChain;
QString m_serialPortName; QString m_serialPortName;
QString m_serialPortFriendlyName; QString m_serialPortFriendlyName;
int m_communicationType;
QString m_targetName; QString m_targetName;
QString m_baseFileName; QString m_baseFileName;
QStringList m_commandLineArguments; QStringList m_commandLineArguments;
@@ -232,7 +233,8 @@ private:
QProcess *m_signsis; QProcess *m_signsis;
QString m_makesisTool; QString m_makesisTool;
QString m_packageFile; QString m_packageFile;
bool m_releaseDeviceAfterLauncherFinish;
bool m_handleDeviceRemoval;
QFutureInterface<void> *m_deployProgress; QFutureInterface<void> *m_deployProgress;
trk::Launcher *m_launcher; trk::Launcher *m_launcher;
}; };

View File

@@ -244,7 +244,6 @@ void S60DeviceRunConfigurationWidget::setSerialPort(int index)
{ {
const SymbianUtils::SymbianDevice d = device(index); const SymbianUtils::SymbianDevice d = device(index);
m_runConfiguration->setSerialPortName(d.portName()); m_runConfiguration->setSerialPortName(d.portName());
m_runConfiguration->setCommunicationType(d.type());
m_deviceInfoButton->setEnabled(index >= 0); m_deviceInfoButton->setEnabled(index >= 0);
clearDeviceInfo(); clearDeviceInfo();
} }
@@ -321,17 +320,21 @@ void S60DeviceRunConfigurationWidget::updateDeviceInfo()
setDeviceInfoLabel(tr("Connecting...")); setDeviceInfoLabel(tr("Connecting..."));
// Do a launcher run with the ping protocol. Prompt to connect and // 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. // 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); QString message;
connect(m_infoLauncher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
const SymbianUtils::SymbianDevice commDev = currentDevice(); 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->setSerialFrame(commDev.type() == SymbianUtils::SerialPortCommunication);
m_infoLauncher->setTrkServerName(commDev.portName()); m_infoLauncher->setTrkServerName(commDev.portName());
// Prompt user // Prompt user
QString message;
const trk::PromptStartCommunicationResult src = const trk::PromptStartCommunicationResult src =
S60RunConfigBluetoothStarter::startCommunication(m_infoLauncher->trkDevice(), S60RunConfigBluetoothStarter::startCommunication(m_infoLauncher->trkDevice(),
commDev.type(), this, this, &message);
&message);
switch (src) { switch (src) {
case trk::PromptStartCommunicationConnected: case trk::PromptStartCommunicationConnected:
break; break;

View File

@@ -30,6 +30,7 @@
#include "s60runconfigbluetoothstarter.h" #include "s60runconfigbluetoothstarter.h"
#include "bluetoothlistener.h" #include "bluetoothlistener.h"
#include "symbiandevicemanager.h" #include "symbiandevicemanager.h"
#include "trkdevice.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
@@ -53,19 +54,17 @@ trk::BluetoothListener *S60RunConfigBluetoothStarter::createListener()
trk::PromptStartCommunicationResult trk::PromptStartCommunicationResult
S60RunConfigBluetoothStarter::startCommunication(const TrkDevicePtr &trkDevice, S60RunConfigBluetoothStarter::startCommunication(const TrkDevicePtr &trkDevice,
int communicationType,
QWidget *msgBoxParent, QWidget *msgBoxParent,
QString *errorMessage) QString *errorMessage)
{ {
// Bluetooth? // Bluetooth?
if (communicationType == SymbianUtils::BlueToothCommunication) { if (trkDevice->serialFrame()) {
S60RunConfigBluetoothStarter bluetoothStarter(trkDevice);
return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
}
// Serial
BaseCommunicationStarter serialStarter(trkDevice); BaseCommunicationStarter serialStarter(trkDevice);
return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage); return trk::promptStartSerial(serialStarter, msgBoxParent, errorMessage);
} }
S60RunConfigBluetoothStarter bluetoothStarter(trkDevice);
return trk::promptStartBluetooth(bluetoothStarter, msgBoxParent, errorMessage);
}
} // namespace Internal } // namespace Internal
} // namespace Qt4ProjectManager } // namespace Qt4ProjectManager

View File

@@ -49,7 +49,6 @@ public:
// passing on the right messages. // passing on the right messages.
static trk::PromptStartCommunicationResult static trk::PromptStartCommunicationResult
startCommunication(const TrkDevicePtr &trkDevice, startCommunication(const TrkDevicePtr &trkDevice,
int communicationType,
QWidget *msgBoxParent, QWidget *msgBoxParent,
QString *errorMessage); QString *errorMessage);

View File

@@ -413,13 +413,7 @@ void Qt4Target::slotUpdateDeviceInformation()
void Qt4Target::updateToolTipAndIcon() void Qt4Target::updateToolTipAndIcon()
{ {
S60DeviceRunConfiguration *deviceRc(qobject_cast<S60DeviceRunConfiguration *>(activeRunConfiguration())); if (const S60DeviceRunConfiguration *s60DeviceRc = qobject_cast<S60DeviceRunConfiguration *>(activeRunConfiguration())) {
if (!deviceRc) {
setToolTip(QString());
setIcon(iconForId(id()));
} else {
QString friendlyPortName = SymbianUtils::SymbianDeviceManager::instance()->friendlyNameForPort(
deviceRc->serialPortName());
QPixmap pixmap(Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE); QPixmap pixmap(Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE);
pixmap.fill(Qt::transparent); pixmap.fill(Qt::transparent);
QPainter painter(&pixmap); QPainter painter(&pixmap);
@@ -429,16 +423,25 @@ void Qt4Target::updateToolTipAndIcon()
(Core::Constants::TARGET_ICON_SIZE-actualSize.height())/2, (Core::Constants::TARGET_ICON_SIZE-actualSize.height())/2,
icon.pixmap(Core::Constants::TARGET_ICON_SIZE)); icon.pixmap(Core::Constants::TARGET_ICON_SIZE));
if (!friendlyPortName.isEmpty()) { const SymbianUtils::SymbianDeviceManager *sdm = SymbianUtils::SymbianDeviceManager::instance();
// device connected const int deviceIndex = sdm->findByPortName(s60DeviceRc->serialPortName());
setToolTip(tr("<b>Device:</b> %1").arg(friendlyPortName)); if (deviceIndex == -1) {
painter.drawPixmap(Core::Constants::TARGET_ICON_SIZE - m_connectedPixmap.width(),
m_connectedPixmap.height(), m_connectedPixmap);
} else {
setToolTip(tr("<b>Device:</b> Not connected")); setToolTip(tr("<b>Device:</b> Not connected"));
painter.drawPixmap(Core::Constants::TARGET_ICON_SIZE - m_disconnectedPixmap.width(), painter.drawPixmap(Core::Constants::TARGET_ICON_SIZE - m_disconnectedPixmap.width(),
m_disconnectedPixmap.height(), m_disconnectedPixmap); 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)); setIcon(QIcon(pixmap));
return;
} }
setToolTip(QString());
setIcon(iconForId(id()));
} }

View File

@@ -32,6 +32,7 @@
#include "trkutils_p.h" #include "trkutils_p.h"
#include "trkdevice.h" #include "trkdevice.h"
#include "bluetoothlistener.h" #include "bluetoothlistener.h"
#include "symbiandevicemanager.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
@@ -89,11 +90,11 @@ Launcher::Launcher(Actions startupActions,
{ {
d->m_startupActions = startupActions; d->m_startupActions = startupActions;
connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult))); 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() Launcher::~Launcher()
{ {
emit destroyed(d->m_device->port());
logMessage("Shutting down.\n"); logMessage("Shutting down.\n");
delete d; delete d;
} }
@@ -202,11 +203,6 @@ bool Launcher::startServer(QString *errorMessage)
} }
if (!d->m_device->isOpen() && !d->m_device->open(errorMessage)) if (!d->m_device->isOpen() && !d->m_device->open(errorMessage))
return false; 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); setState(Connecting);
// Set up the temporary 'waiting' state if we do not get immediate connection // Set up the temporary 'waiting' state if we do not get immediate connection
QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk())); QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk()));
@@ -254,6 +250,13 @@ void Launcher::logMessage(const QString &msg)
qDebug() << "LAUNCHER: " << qPrintable(msg); qDebug() << "LAUNCHER: " << qPrintable(msg);
} }
void Launcher::handleFinished()
{
if (d->m_closeDevice)
d->m_device->close();
emit finished();
}
void Launcher::terminate() void Launcher::terminate()
{ {
switch (state()) { switch (state()) {
@@ -275,7 +278,7 @@ void Launcher::terminate()
case Connecting: case Connecting:
case WaitingForTrk: case WaitingForTrk:
setState(Disconnected); setState(Disconnected);
emit finished(); handleFinished();
break; break;
} }
} }
@@ -434,7 +437,7 @@ void Launcher::handleTrkVersion(const TrkResult &result)
if (result.errorCode() || result.data.size() < 5) { if (result.errorCode() || result.data.size() < 5) {
if (d->m_startupActions == ActionPingOnly) { if (d->m_startupActions == ActionPingOnly) {
setState(Disconnected); setState(Disconnected);
emit finished(); handleFinished();
} }
return; return;
} }
@@ -443,11 +446,13 @@ void Launcher::handleTrkVersion(const TrkResult &result)
d->m_session.trkAppVersion.protocolMajor = result.data.at(3); d->m_session.trkAppVersion.protocolMajor = result.data.at(3);
d->m_session.trkAppVersion.protocolMinor = result.data.at(4); d->m_session.trkAppVersion.protocolMinor = result.data.at(4);
setState(DeviceDescriptionReceived); setState(DeviceDescriptionReceived);
const QString msg = deviceDescription();
emit deviceDescriptionReceived(trkServerName(), msg);
// Ping mode: Log & Terminate // Ping mode: Log & Terminate
if (d->m_startupActions == ActionPingOnly) { if (d->m_startupActions == ActionPingOnly) {
qWarning("%s", qPrintable(deviceDescription())); qWarning("%s", qPrintable(msg));
setState(Disconnected); setState(Disconnected);
emit finished(); handleFinished();
} }
} }
@@ -574,7 +579,7 @@ void Launcher::handleWaitForFinished(const TrkResult &result)
{ {
logMessage(" FINISHED: " + stringFromArray(result.data)); logMessage(" FINISHED: " + stringFromArray(result.data));
setState(Disconnected); setState(Disconnected);
emit finished(); handleFinished();
} }
void Launcher::handleSupportMask(const TrkResult &result) void Launcher::handleSupportMask(const TrkResult &result)
@@ -725,4 +730,37 @@ void Launcher::resumeProcess(uint pid, uint tid)
appendInt(&ba, tid, BigEndian); appendInt(&ba, tid, BigEndian);
d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); 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 } // namespace trk

View File

@@ -96,6 +96,15 @@ public:
// becomes valid after successful execution of ActionPingOnly // becomes valid after successful execution of ActionPingOnly
QString deviceDescription(unsigned verbose = 0u) const; 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, static QByteArray startProcessMessage(const QString &executable,
const QStringList &arguments); const QStringList &arguments);
// Parse a TrkNotifyStopped message // Parse a TrkNotifyStopped message
@@ -106,6 +115,7 @@ public:
static QString msgStopped(uint pid, uint tid, uint address, const QString &why); static QString msgStopped(uint pid, uint tid, uint address, const QString &why);
signals: signals:
void deviceDescriptionReceived(const QString &port, const QString &description);
void copyingStarted(); void copyingStarted();
void canNotConnect(const QString &errorMessage); void canNotConnect(const QString &errorMessage);
void canNotCreateFile(const QString &filename, const QString &errorMessage); void canNotCreateFile(const QString &filename, const QString &errorMessage);
@@ -122,6 +132,8 @@ signals:
void copyProgress(int percent); void copyProgress(int percent);
void stateChanged(int); void stateChanged(int);
void processStopped(uint pc, uint pid, uint tid, const QString& reason); 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: public slots:
void terminate(); void terminate();
@@ -154,6 +166,7 @@ private:
void copyFileToRemote(); void copyFileToRemote();
void installRemotePackageSilently(); void installRemotePackageSilently();
void startInferiorIfNeeded(); void startInferiorIfNeeded();
void handleFinished();
void logMessage(const QString &msg); void logMessage(const QString &msg);
void setState(State s); void setState(State s);

View File

@@ -28,6 +28,7 @@
**************************************************************************/ **************************************************************************/
#include "symbiandevicemanager.h" #include "symbiandevicemanager.h"
#include "trkdevice.h"
#include <QtCore/QSettings> #include <QtCore/QSettings>
#include <QtCore/QStringList> #include <QtCore/QStringList>
@@ -36,6 +37,7 @@
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QSharedData> #include <QtCore/QSharedData>
#include <QtCore/QScopedPointer> #include <QtCore/QScopedPointer>
#include <QtCore/QSignalMapper>
namespace SymbianUtils { namespace SymbianUtils {
@@ -49,19 +51,51 @@ const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm";
// ------------- SymbianDevice // ------------- SymbianDevice
class SymbianDeviceData : public QSharedData { class SymbianDeviceData : public QSharedData {
public: public:
SymbianDeviceData() : type(SerialPortCommunication) {} SymbianDeviceData();
~SymbianDeviceData();
inline bool isOpen() const { return !device.isNull() && device->isOpen(); }
void forcedClose();
QString portName; QString portName;
QString friendlyName; QString friendlyName;
QString deviceDesc; QString deviceDesc;
QString manufacturer; QString manufacturer;
QString additionalInformation;
DeviceCommunicationType type; 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) : SymbianDevice::SymbianDevice(SymbianDeviceData *data) :
m_data(data) m_data(data)
{ {
} }
SymbianDevice::SymbianDevice() : SymbianDevice::SymbianDevice() :
@@ -84,6 +118,11 @@ SymbianDevice::~SymbianDevice()
{ {
} }
void SymbianDevice::forcedClose()
{
m_data->forcedClose();
}
QString SymbianDevice::portName() const QString SymbianDevice::portName() const
{ {
return m_data->portName; return m_data->portName;
@@ -94,6 +133,49 @@ QString SymbianDevice::friendlyName() const
return m_data->friendlyName; 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 QString SymbianDevice::deviceDesc() const
{ {
return m_data->deviceDesc; return m_data->deviceDesc;
@@ -111,7 +193,12 @@ DeviceCommunicationType SymbianDevice::type() const
bool SymbianDevice::isNull() 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 QString SymbianDevice::toString() const
@@ -146,7 +233,7 @@ int SymbianDevice::compare(const SymbianDevice &rhs) const
return 0; return 0;
} }
QDebug operator<<(QDebug d, const SymbianDevice &cd) SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd)
{ {
d.nospace() << cd.toString(); d.nospace() << cd.toString();
return d; return d;
@@ -154,10 +241,11 @@ QDebug operator<<(QDebug d, const SymbianDevice &cd)
// ------------- SymbianDeviceManagerPrivate // ------------- SymbianDeviceManagerPrivate
struct SymbianDeviceManagerPrivate { struct SymbianDeviceManagerPrivate {
SymbianDeviceManagerPrivate() : m_initialized(false) {} SymbianDeviceManagerPrivate() : m_initialized(false), m_destroyReleaseMapper(0) {}
bool m_initialized; bool m_initialized;
SymbianDeviceManager::SymbianDeviceList m_devices; SymbianDeviceManager::SymbianDeviceList m_devices;
QSignalMapper *m_destroyReleaseMapper;
}; };
SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : SymbianDeviceManager::SymbianDeviceManager(QObject *parent) :
@@ -173,8 +261,7 @@ SymbianDeviceManager::~SymbianDeviceManager()
SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const
{ {
if (!d->m_initialized) ensureInitialized();
const_cast<SymbianDeviceManager*>(this)->update(false);
return d->m_devices; return d->m_devices;
} }
@@ -182,6 +269,7 @@ QString SymbianDeviceManager::toString() const
{ {
QString rc; QString rc;
QTextStream str(&rc); QTextStream str(&rc);
str << d->m_devices.size() << " devices:\n";
const int count = d->m_devices.size(); const int count = d->m_devices.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
str << '#' << i << ' '; str << '#' << i << ' ';
@@ -191,15 +279,37 @@ QString SymbianDeviceManager::toString() const
return rc; 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 QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const
{ {
if (!d->m_initialized) const int idx = findByPortName(port);
const_cast<SymbianDeviceManager*>(this)->update(false); return idx == -1 ? QString() : d->m_devices.at(idx).friendlyName();
foreach (const SymbianDevice &device, d->m_devices) {
if (device.portName() == port)
return device.friendlyName();
} }
return QString();
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() void SymbianDeviceManager::update()
@@ -207,12 +317,38 @@ void SymbianDeviceManager::update()
update(true); 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) void SymbianDeviceManager::update(bool emitSignals)
{ {
static int n = 0;
typedef SymbianDeviceList::iterator SymbianDeviceListIterator; typedef SymbianDeviceList::iterator SymbianDeviceListIterator;
if (debug) if (debug)
qDebug(">SerialDeviceLister::update(%d)\n%s", int(emitSignals), qDebug(">SerialDeviceLister::update(#%d, signals=%d)\n%s", n++, int(emitSignals),
qPrintable(toString())); qPrintable(toString()));
d->m_initialized = true; d->m_initialized = true;
@@ -220,8 +356,11 @@ void SymbianDeviceManager::update(bool emitSignals)
SymbianDeviceList newDevices = serialPorts() + blueToothDevices(); SymbianDeviceList newDevices = serialPorts() + blueToothDevices();
if (newDevices.size() > 1) if (newDevices.size() > 1)
qStableSort(newDevices.begin(), newDevices.end()); 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; return;
}
// Merge the lists and emit the respective added/removed signals, assuming // 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 // no one can plug a different device on the same port at the speed of lightning
if (!d->m_devices.isEmpty()) { if (!d->m_devices.isEmpty()) {
@@ -230,7 +369,8 @@ void SymbianDeviceManager::update(bool emitSignals)
if (newDevices.contains(*oldIt)) { if (newDevices.contains(*oldIt)) {
++oldIt; ++oldIt;
} else { } else {
const SymbianDevice toBeDeleted = *oldIt; SymbianDevice toBeDeleted = *oldIt;
toBeDeleted.forcedClose();
oldIt = d->m_devices.erase(oldIt); oldIt = d->m_devices.erase(oldIt);
if (emitSignals) if (emitSignals)
emit deviceRemoved(toBeDeleted); emit deviceRemoved(toBeDeleted);
@@ -312,7 +452,7 @@ SymbianDeviceManager *SymbianDeviceManager::instance()
return symbianDeviceManager(); return symbianDeviceManager();
} }
QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm) SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm)
{ {
d.nospace() << sdm.toString(); d.nospace() << sdm.toString();
return d; return d;

View File

@@ -34,12 +34,17 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QExplicitlySharedDataPointer> #include <QtCore/QExplicitlySharedDataPointer>
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QDebug; class QDebug;
class QTextStream; class QTextStream;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace trk {
class TrkDevice;
}
namespace SymbianUtils { namespace SymbianUtils {
struct SymbianDeviceManagerPrivate; struct SymbianDeviceManagerPrivate;
@@ -50,11 +55,16 @@ enum DeviceCommunicationType {
BlueToothCommunication = 1 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 { class SYMBIANUTILS_EXPORT SymbianDevice {
explicit SymbianDevice(SymbianDeviceData *data); explicit SymbianDevice(SymbianDeviceData *data);
friend class SymbianDeviceManager; friend class SymbianDeviceManager;
public: public:
typedef QSharedPointer<trk::TrkDevice> TrkDevicePtr;
SymbianDevice(); SymbianDevice();
SymbianDevice(const SymbianDevice &rhs); SymbianDevice(const SymbianDevice &rhs);
SymbianDevice &operator=(const SymbianDevice &rhs); SymbianDevice &operator=(const SymbianDevice &rhs);
@@ -65,6 +75,17 @@ public:
bool isNull() const; bool isNull() const;
QString portName() const; QString portName() const;
QString friendlyName() 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. // Windows only.
QString deviceDesc() const; QString deviceDesc() const;
@@ -74,10 +95,12 @@ public:
QString toString() const; QString toString() const;
private: private:
void forcedClose();
QExplicitlySharedDataPointer<SymbianDeviceData> m_data; 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) inline bool operator==(const SymbianDevice &d1, const SymbianDevice &d2)
{ return d1.compare(d2) == 0; } { 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. /* SymbianDeviceManager: Singleton that maintains a list of Symbian devices.
* and emits change signals. * and emits change signals.
* On Windows, the update slot must be connected to a signal * On Windows, the update slot must be connected to a [delayed] signal
* emitted from an event handler listening for WM_DEVICECHANGE. */ * emitted from an event handler listening for WM_DEVICECHANGE.
* Device removal will result in the device being closed. */
class SYMBIANUTILS_EXPORT SymbianDeviceManager : public QObject class SYMBIANUTILS_EXPORT SymbianDeviceManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
typedef QList<SymbianDevice> SymbianDeviceList; typedef QList<SymbianDevice> SymbianDeviceList;
typedef QSharedPointer<trk::TrkDevice> TrkDevicePtr;
static const char *linuxBlueToothDeviceRootC; static const char *linuxBlueToothDeviceRootC;
@@ -108,17 +133,25 @@ public:
SymbianDeviceList devices() const; SymbianDeviceList devices() const;
QString toString() 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; QString friendlyNameForPort(const QString &port) const;
public slots: public slots:
void update(); 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: signals:
void deviceRemoved(const SymbianDevice &d); void deviceRemoved(const SymbianUtils::SymbianDevice &d);
void deviceAdded(const SymbianDevice &d); void deviceAdded(const SymbianUtils::SymbianDevice &d);
void updated(); void updated();
private: private:
void ensureInitialized() const;
void update(bool emitSignals); void update(bool emitSignals);
SymbianDeviceList serialPorts() const; SymbianDeviceList serialPorts() const;
SymbianDeviceList blueToothDevices() const; SymbianDeviceList blueToothDevices() const;
@@ -126,7 +159,7 @@ private:
SymbianDeviceManagerPrivate *d; SymbianDeviceManagerPrivate *d;
}; };
QDebug operator<<(QDebug d, const SymbianDeviceManager &); SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &);
} // namespace SymbianUtils } // namespace SymbianUtils

View File

@@ -40,6 +40,7 @@
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <QtCore/QWaitCondition> #include <QtCore/QWaitCondition>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
#include <QtCore/QScopedPointer>
#include <QtCore/QMetaType> #include <QtCore/QMetaType>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@@ -90,6 +91,11 @@ QString winErrorMessage(unsigned long error)
enum { verboseTrk = 0 }; 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 { namespace trk {
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
@@ -147,6 +153,7 @@ class TrkWriteQueue
Q_DISABLE_COPY(TrkWriteQueue) Q_DISABLE_COPY(TrkWriteQueue)
public: public:
explicit TrkWriteQueue(); explicit TrkWriteQueue();
void clear();
// Enqueue messages. // Enqueue messages.
void queueTrkMessage(byte code, TrkCallback callback, 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() byte TrkWriteQueue::nextTrkWriteToken()
{ {
++m_trkWriteToken; ++m_trkWriteToken;
if (m_trkWriteToken == 0) if (m_trkWriteToken == 0)
++m_trkWriteToken; ++m_trkWriteToken;
if (verboseTrk) if (verboseTrk)
qDebug() << "Write token: " << m_trkWriteToken; qDebug() << "nextTrkWriteToken:" << m_trkWriteToken;
return m_trkWriteToken; return m_trkWriteToken;
} }
@@ -450,6 +465,7 @@ void WriterThread::terminate()
m_waitCondition.wakeAll(); m_waitCondition.wakeAll();
wait(); wait();
m_terminate = false; m_terminate = false;
m_queue.clear();
} }
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@@ -580,6 +596,8 @@ class ReaderThreadBase : public QThread
Q_DISABLE_COPY(ReaderThreadBase) Q_DISABLE_COPY(ReaderThreadBase)
public: public:
int bytesPending() const { return m_trkReadBuffer.size(); }
signals: signals:
void messageReceived(const trk::TrkResult &result, const QByteArray &rawData); void messageReceived(const trk::TrkResult &result, const QByteArray &rawData);
@@ -865,8 +883,8 @@ struct TrkDevicePrivate
TrkDevicePrivate(); TrkDevicePrivate();
QSharedPointer<DeviceContext> deviceContext; QSharedPointer<DeviceContext> deviceContext;
QSharedPointer<WriterThread> writerThread; QScopedPointer<WriterThread> writerThread;
QSharedPointer<ReaderThread> readerThread; QScopedPointer<ReaderThread> readerThread;
QByteArray trkReadBuffer; QByteArray trkReadBuffer;
int verbose; int verbose;
@@ -905,14 +923,14 @@ TrkDevice::~TrkDevice()
bool TrkDevice::open(QString *errorMessage) bool TrkDevice::open(QString *errorMessage)
{ {
if (d->verbose) if (d->verbose || verboseTrk)
qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame(); qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame();
if (isOpen())
return true;
if (d->port.isEmpty()) { if (d->port.isEmpty()) {
*errorMessage = QLatin1String("Internal error: No port set on TrkDevice"); *errorMessage = QLatin1String("Internal error: No port set on TrkDevice");
return false; return false;
} }
close();
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
const QString fullPort = QLatin1String("\\\\.\\") + d->port; const QString fullPort = QLatin1String("\\\\.\\") + d->port;
d->deviceContext->device = CreateFile(reinterpret_cast<const WCHAR*>(fullPort.utf16()), d->deviceContext->device = CreateFile(reinterpret_cast<const WCHAR*>(fullPort.utf16()),
@@ -963,7 +981,7 @@ bool TrkDevice::open(QString *errorMessage)
return false; return false;
} }
#endif #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)), connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
Qt::QueuedConnection); Qt::QueuedConnection);
connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)), connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)),
@@ -971,18 +989,22 @@ bool TrkDevice::open(QString *errorMessage)
Qt::QueuedConnection); Qt::QueuedConnection);
d->readerThread->start(); 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)), connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
Qt::QueuedConnection); Qt::QueuedConnection);
d->writerThread->start(); d->writerThread->start();
if (d->verbose) if (d->verbose || verboseTrk)
qDebug() << "Opened" << d->port; qDebug() << "Opened" << d->port << d->readerThread.data() << d->writerThread.data();
return true; return true;
} }
void TrkDevice::close() void TrkDevice::close()
{ {
if (verboseTrk)
qDebug() << "close" << d->port << " is open: " << isOpen()
<< " read pending " << (d->readerThread.isNull() ? 0 : d->readerThread->bytesPending())
<< sender();
if (!isOpen()) if (!isOpen())
return; return;
if (d->readerThread) if (d->readerThread)
@@ -998,6 +1020,7 @@ void TrkDevice::close()
#else #else
d->deviceContext->file.close(); d->deviceContext->file.close();
#endif #endif
if (d->verbose) if (d->verbose)
emitLogMessage("Close"); emitLogMessage("Close");
} }
@@ -1018,6 +1041,8 @@ QString TrkDevice::port() const
void TrkDevice::setPort(const QString &p) void TrkDevice::setPort(const QString &p)
{ {
if (verboseTrk)
qDebug() << "setPort" << p;
d->port = p; d->port = p;
} }
@@ -1033,6 +1058,8 @@ bool TrkDevice::serialFrame() const
void TrkDevice::setSerialFrame(bool f) void TrkDevice::setSerialFrame(bool f)
{ {
if (verboseTrk)
qDebug() << "setSerialFrame" << f;
d->deviceContext->serialFrame = f; d->deviceContext->serialFrame = f;
} }
@@ -1048,6 +1075,7 @@ void TrkDevice::setVerbose(int b)
void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData) void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData)
{ {
if (isOpen()) { // Might receive bytes after closing due to queued connections.
d->writerThread->slotHandleResult(result); d->writerThread->slotHandleResult(result);
if (d->verbose > 1) if (d->verbose > 1)
qDebug() << "Received: " << result.toString(); qDebug() << "Received: " << result.toString();
@@ -1055,6 +1083,7 @@ void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArr
if (!rawData.isEmpty()) if (!rawData.isEmpty())
emit rawDataReceived(rawData); emit rawDataReceived(rawData);
} }
}
void TrkDevice::emitError(const QString &s) void TrkDevice::emitError(const QString &s)
{ {
@@ -1066,12 +1095,18 @@ void TrkDevice::emitError(const QString &s)
void TrkDevice::sendTrkMessage(byte code, TrkCallback callback, void TrkDevice::sendTrkMessage(byte code, TrkCallback callback,
const QByteArray &data, const QVariant &cookie) const QByteArray &data, const QVariant &cookie)
{ {
if (!isOpen()) {
emitError(msgAccessingClosedDevice(d->port));
return;
}
if (!d->writerThread.isNull()) { if (!d->writerThread.isNull()) {
if (d->verbose > 1) { if (d->verbose > 1) {
QByteArray msg = "Sending: "; QByteArray msg = "Sending: 0x";
msg += QByteArray::number(code, 16); msg += QByteArray::number(code, 16);
msg += ": "; msg += ": ";
msg += stringFromArray(data).toLatin1(); msg += stringFromArray(data).toLatin1();
if (cookie.isValid())
msg += " Cookie: " + cookie.toString().toLatin1();
qDebug("%s", msg.data()); qDebug("%s", msg.data());
} }
d->writerThread->queueTrkMessage(code, callback, data, cookie); d->writerThread->queueTrkMessage(code, callback, data, cookie);
@@ -1080,12 +1115,20 @@ void TrkDevice::sendTrkMessage(byte code, TrkCallback callback,
void TrkDevice::sendTrkInitialPing() void TrkDevice::sendTrkInitialPing()
{ {
if (!isOpen()) {
emitError(msgAccessingClosedDevice(d->port));
return;
}
if (!d->writerThread.isNull()) if (!d->writerThread.isNull())
d->writerThread->queueTrkInitialPing(); d->writerThread->queueTrkInitialPing();
} }
bool TrkDevice::sendTrkAck(byte token) bool TrkDevice::sendTrkAck(byte token)
{ {
if (!isOpen()) {
emitError(msgAccessingClosedDevice(d->port));
return false;
}
if (d->writerThread.isNull()) if (d->writerThread.isNull())
return false; return false;
// The acknowledgement must not be queued! // The acknowledgement must not be queued!

View File

@@ -57,7 +57,9 @@ struct TrkDevicePrivate;
* for queueing messages with a notification callback. If the message receives * for queueing messages with a notification callback. If the message receives
* an ACK, the callback is invoked. * an ACK, the callback is invoked.
* The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronization. * 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 }; enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f };