diff options
author | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2009-10-23 18:00:20 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2009-10-23 18:00:20 +0200 |
commit | 1af61fefa8f22932cc0db0559782ec11b0e39fd0 (patch) | |
tree | 0c582cc87579edd7bc9eae2f41aa8889494541fc | |
parent | d35dcd8dbef7e5dc6f2d87870267231f99379082 (diff) | |
download | qt-creator-1af61fefa8f22932cc0db0559782ec11b0e39fd0.tar.gz |
S60: Add startup logic for Bluetooth to the project/run configuration
Prepare trk::Launcher to deal with a shared trkdevice.
Add encapsulation for the rfcomm listener process and helper
classes for prompting the user to connect the Bluetooth
device. Add a command line prompt to the trklauncher test.
19 files changed, 1132 insertions, 83 deletions
diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp index 6252d119d4..7ff9cee01c 100644 --- a/src/plugins/coreplugin/messagemanager.cpp +++ b/src/plugins/coreplugin/messagemanager.cpp @@ -82,3 +82,14 @@ void MessageManager::printToOutputPane(const QString &text, bool bringToForegrou m_messageOutputWindow->popup(false); m_messageOutputWindow->append(text); } + +void MessageManager::printToOutputPanePopup(const QString &text) +{ + printToOutputPane(text, true); +} + +void MessageManager::printToOutputPane(const QString &text) +{ + printToOutputPane(text, false); +} + diff --git a/src/plugins/coreplugin/messagemanager.h b/src/plugins/coreplugin/messagemanager.h index 664269cda6..4191145cd8 100644 --- a/src/plugins/coreplugin/messagemanager.h +++ b/src/plugins/coreplugin/messagemanager.h @@ -55,7 +55,9 @@ public: void showOutputPane(); public slots: - void printToOutputPane(const QString &text, bool bringToForeground = true); + void printToOutputPane(const QString &text, bool bringToForeground); + void printToOutputPanePopup(const QString &text); // pops up + void printToOutputPane(const QString &text); private: Internal::MessageOutputWindow *m_messageOutputWindow; diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri index e7763cecb6..19f453ba7d 100644 --- a/src/plugins/debugger/gdb/gdb.pri +++ b/src/plugins/debugger/gdb/gdb.pri @@ -19,6 +19,7 @@ HEADERS += \ $$PWD/termgdbadapter.h \ $$PWD/remotegdbadapter.h \ $$PWD/trkgdbadapter.h \ + $$PWD/s60debuggerbluetoothstarter.h SOURCES += \ $$PWD/gdbmi.cpp \ @@ -34,6 +35,7 @@ SOURCES += \ $$PWD/termgdbadapter.cpp \ $$PWD/remotegdbadapter.cpp \ $$PWD/trkgdbadapter.cpp \ + $$PWD/s60debuggerbluetoothstarter.cpp FORMS += $$PWD/gdboptionspage.ui \ $$PWD/trkoptionswidget.ui diff --git a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp new file mode 100644 index 0000000000..b1d34f4ff3 --- /dev/null +++ b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp @@ -0,0 +1,51 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "s60debuggerbluetoothstarter.h" +#include "debuggermanager.h" + +namespace Debugger { +namespace Internal { + +S60DebuggerBluetoothStarter::S60DebuggerBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent) : + trk::AbstractBluetoothStarter(trkDevice, parent) +{ +} + +trk::BluetoothListener *S60DebuggerBluetoothStarter::createListener() +{ + DebuggerManager *dm = DebuggerManager::instance(); + trk::BluetoothListener *rc = new trk::BluetoothListener(dm); + rc->setMode(trk::BluetoothListener::Listen); + connect(rc, SIGNAL(message(QString)), dm, SLOT(showDebuggerOutput(QString))); + return rc; +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h new file mode 100644 index 0000000000..216ab80a4b --- /dev/null +++ b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h @@ -0,0 +1,55 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef S60DEBUGGERBLUETOOTHSTARTER_H +#define S60DEBUGGERBLUETOOTHSTARTER_H + +#include "bluetoothlistener.h" + +namespace Debugger { +namespace Internal { + +/* S60DebuggerBluetoothStarter: Creates a listener in 'Listen' mode + * parented on the Debugger manager which outputs to the debugger window. + * Note: This is a "last resort" starter, normally, the run configuration + * should have already started a listener. */ + +class S60DebuggerBluetoothStarter : public trk::AbstractBluetoothStarter +{ +public: + explicit S60DebuggerBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); + +protected: + virtual trk::BluetoothListener *createListener(); +}; + +} // namespace Internal +} // namespace Debugger + +#endif // S60DEBUGGERBLUETOOTHSTARTER_H diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri index 8a445fa8de..c1f2e85765 100644 --- a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri +++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri @@ -10,7 +10,9 @@ $$PWD/s60devicerunconfiguration.cpp \ $$PWD/s60devicerunconfigurationwidget.cpp \ $$PWD/serialdevicelister.cpp \ - $$PWD/rvcttoolchain.cpp + $$PWD/rvcttoolchain.cpp \ + $$PWD/s60runconfigbluetoothstarter.cpp + HEADERS += $$PWD/s60devices.h \ $$PWD/s60devicespreferencepane.h \ $$PWD/s60manager.h \ @@ -20,7 +22,9 @@ $$PWD/s60devicerunconfiguration.h \ $$PWD/s60devicerunconfigurationwidget.h \ $$PWD/serialdevicelister.h \ - $$PWD/rvcttoolchain.h + $$PWD/rvcttoolchain.h \ + $$PWD/s60runconfigbluetoothstarter.h + FORMS += $$PWD/s60devicespreferencepane.ui OTHER_FILES += $$PWD/qt-s60-todo.txt include(../../../shared/trk/trk.pri)||error("could not include trk.pri") diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp index 64b1ee120c..9ab5d93b3b 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp @@ -34,6 +34,8 @@ #include "profilereader.h" #include "s60manager.h" #include "s60devices.h" +#include "s60runconfigbluetoothstarter.h" +#include "bluetoothlistener_gui.h" #include "serialdevicelister.h" #include <coreplugin/icore.h> @@ -572,6 +574,21 @@ void S60DeviceRunControlBase::signsisProcessFinished() 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 + if (m_communicationType == BlueToothCommunication) { + S60RunConfigBluetoothStarter starter(m_launcher->trkDevice()); + switch (trk::startBluetoothGui(starter, 0, &errorMessage)) { + case trk::BluetoothGuiConnected: + break; + case trk::BluetoothGuiCanceled: + case trk::BluetoothGuiError: + delete m_launcher; + m_launcher = 0; + error(this, errorMessage); + emit finished(); + return; + }; + } if (!m_launcher->startServer(&errorMessage)) { delete m_launcher; m_launcher = 0; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp index c0964e6fbb..71369923ab 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp @@ -29,8 +29,12 @@ #include "s60devicerunconfigurationwidget.h" #include "s60devicerunconfiguration.h" +#include "s60runconfigbluetoothstarter.h" +#include "bluetoothlistener_gui.h" #include "s60manager.h" #include "launcher.h" +#include "bluetoothlistener.h" +#include "bluetoothlistener_gui.h" #include "serialdevicelister.h" #include <utils/detailswidget.h> @@ -278,6 +282,7 @@ void S60DeviceRunConfigurationWidget::setDeviceInfoLabel(const QString &message, QString(QLatin1String("background-color: red;")) : QString()); m_deviceInfoLabel->setText(message); + m_deviceInfoLabel->adjustSize(); } void S60DeviceRunConfigurationWidget::updateDeviceInfo() @@ -290,12 +295,29 @@ void S60DeviceRunConfigurationWidget::updateDeviceInfo() bool S60DeviceRunConfigurationWidget::getDeviceInfo(QString *message) { + message->clear(); // Do a launcher run with the ping protocol. Instantiate launcher on heap // as not to introduce delays when destructing a device with timeout - trk::Launcher *launcher = new trk::Launcher(trk::Launcher::ActionPingOnly, this); + trk::Launcher *launcher = new trk::Launcher(trk::Launcher::ActionPingOnly, QSharedPointer<trk::TrkDevice>(), this); const CommunicationDevice commDev = currentDevice(); launcher->setSerialFrame(commDev.type == SerialPortCommunication); launcher->setTrkServerName(commDev.portName); + // Prompt the user to start + if (commDev.type == BlueToothCommunication) { + S60RunConfigBluetoothStarter starter(launcher->trkDevice()); + starter.setDevice(launcher->trkServerName()); + const trk::StartBluetoothGuiResult src = trk::startBluetoothGui(starter, this, message); + switch (src) { + case trk::BluetoothGuiConnected: + break; + case trk::BluetoothGuiCanceled: + launcher->deleteLater(); + return true; + case trk::BluetoothGuiError: + launcher->deleteLater(); + return false; + }; + } if (!launcher->startServer(message)) { launcher->deleteLater(); return false; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp new file mode 100644 index 0000000000..305d917597 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp @@ -0,0 +1,52 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "s60runconfigbluetoothstarter.h" + +#include <coreplugin/icore.h> +#include <coreplugin/messagemanager.h> + +namespace Qt4ProjectManager { +namespace Internal { + +S60RunConfigBluetoothStarter::S60RunConfigBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent) : + trk::AbstractBluetoothStarter(trkDevice, parent) +{ +} + +trk::BluetoothListener *S60RunConfigBluetoothStarter::createListener() +{ + Core::ICore *core = Core::ICore::instance(); + trk::BluetoothListener *rc = new trk::BluetoothListener(core); + rc->setMode(trk::BluetoothListener::Listen); + connect(rc, SIGNAL(message(QString)), core->messageManager(), SLOT(printToOutputPane(QString))); + return rc; +} +} // namespace Internal +} // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h new file mode 100644 index 0000000000..340f74082f --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h @@ -0,0 +1,53 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef S60RUNCONFIGBLUETOOTHSTARTER_H +#define S60RUNCONFIGBLUETOOTHSTARTER_H + +#include "bluetoothlistener.h" + +namespace Qt4ProjectManager { +namespace Internal { + +/* S60RunConfigBluetoothStarter: Creates a listener in 'Listen' mode + * parented on the Qt Creator core which outputs to the message manager. */ + +class S60RunConfigBluetoothStarter : public trk::AbstractBluetoothStarter +{ +public: + explicit S60RunConfigBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); + +protected: + virtual trk::BluetoothListener *createListener(); +}; + +} // namespace Internal +} // namespace Qt4ProjectManager + +#endif // S60RUNCONFIGBLUETOOTHSTARTER_H diff --git a/src/shared/trk/bluetoothlistener.cpp b/src/shared/trk/bluetoothlistener.cpp new file mode 100644 index 0000000000..b395131ad3 --- /dev/null +++ b/src/shared/trk/bluetoothlistener.cpp @@ -0,0 +1,383 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "bluetoothlistener.h" +#include "trkdevice.h" + +#include <QtCore/QDebug> +#include <QtCore/QTimer> +#include <QtCore/QEventLoop> + +#ifdef Q_OS_UNIX +# include <unistd.h> +# include <signal.h> +#endif + +enum { debug = 0 }; + +namespace trk { + +struct BluetoothListenerPrivate { + BluetoothListenerPrivate(); + QString device; + QProcess process; + Q_PID pid; + bool printConsoleMessages; + BluetoothListener::Mode mode; +}; + +BluetoothListenerPrivate::BluetoothListenerPrivate() : + pid(0), + printConsoleMessages(false), + mode(BluetoothListener::Listen) +{ +} + +BluetoothListener::BluetoothListener(QObject *parent) : + QObject(parent), + d(new BluetoothListenerPrivate) +{ + d->process.setProcessChannelMode(QProcess::MergedChannels); + + connect(&d->process, SIGNAL(readyReadStandardError()), + this, SLOT(slotStdError())); + connect(&d->process, SIGNAL(readyReadStandardOutput()), + this, SLOT(slotStdOutput())); + connect(&d->process, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(slotProcessFinished(int,QProcess::ExitStatus))); + connect(&d->process, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(slotProcessError(QProcess::ProcessError))); +} + +BluetoothListener::~BluetoothListener() +{ + const int trc = terminateProcess(); + if (debug) + qDebug() << "~BluetoothListener: terminated" << trc; + delete d; +} + +BluetoothListener::Mode BluetoothListener::mode() const +{ + return d->mode; +} + +void BluetoothListener::setMode(Mode m) +{ + d->mode = m; +} + +bool BluetoothListener::printConsoleMessages() const +{ + return d->printConsoleMessages; +} + +void BluetoothListener::setPrintConsoleMessages(bool p) +{ + d->printConsoleMessages = p; +} + +int BluetoothListener::terminateProcess() +{ + enum { TimeOutMS = 200 }; + if (debug) + qDebug() << "terminateProcess" << d->process.pid() << d->process.state(); + if (d->process.state() == QProcess::NotRunning) + return -1; + emitMessage(tr("%1: Stopping listener %2...").arg(d->device).arg(d->process.pid())); + // When listening, the process should terminate by itself after closing the connection + if (mode() == Listen && d->process.waitForFinished(TimeOutMS)) + return 0; +#ifdef Q_OS_UNIX + kill(d->process.pid(), SIGHUP); // Listens for SIGHUP + if (d->process.waitForFinished(TimeOutMS)) + return 1; +#endif + d->process.terminate(); + if (d->process.waitForFinished(TimeOutMS)) + return 2; + d->process.kill(); + return 3; +} + +bool BluetoothListener::start(const QString &device, QString *errorMessage) +{ + if (d->process.state() != QProcess::NotRunning) { + *errorMessage = QLatin1String("Internal error: Still running."); + return false; + } + d->device = device; + const QString binary = QLatin1String("rfcomm"); + QStringList arguments; + arguments << QLatin1String("-r") + << (d->mode == Listen ? QLatin1String("listen") : QLatin1String("watch")) + << device << QString(QLatin1Char('1')); + if (debug) + qDebug() << binary << arguments; + emitMessage(tr("%1: Starting Bluetooth listener %2...").arg(device, binary)); + d->pid = 0; + d->process.start(binary, arguments); + if (!d->process.waitForStarted()) { + *errorMessage = tr("Unable to run '%1': %2").arg(binary, d->process.errorString()); + return false; + } + d->pid = d->process.pid(); // Forgets it after crash/termination + emitMessage(tr("%1: Bluetooth listener running (%2).").arg(device).arg(d->process.pid())); + return true; +} + +void BluetoothListener::slotStdOutput() +{ + emitMessage(QString::fromLocal8Bit(d->process.readAllStandardOutput())); +} + +void BluetoothListener::emitMessage(const QString &m) +{ + if (d->printConsoleMessages || debug) + qDebug("%s\n", qPrintable(m)); + emit message(m); +} + +void BluetoothListener::slotStdError() +{ + emitMessage(QString::fromLocal8Bit(d->process.readAllStandardError())); +} + +void BluetoothListener::slotProcessFinished(int ex, QProcess::ExitStatus state) +{ + switch (state) { + case QProcess::NormalExit: + emitMessage(tr("%1: Process %2 terminated with exit code %3.") + .arg(d->device).arg(d->pid).arg(ex)); + break; + case QProcess::CrashExit: + emitMessage(tr("%1: Process %2 crashed.").arg(d->device).arg(d->pid)); + break; + } + emit terminated(); +} + +void BluetoothListener::slotProcessError(QProcess::ProcessError error) +{ + emitMessage(tr("%1: Process error %2: %3") + .arg(d->device).arg(error).arg(d->process.errorString())); +} + +// --------------- AbstractBluetoothStarter +struct AbstractBluetoothStarterPrivate { + explicit AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d); + + const AbstractBluetoothStarter::TrkDevicePtr trkDevice; + BluetoothListener *listener; + QTimer *timer; + int intervalMS; + int attempts; + int n; + QString device; + QString errorString; + AbstractBluetoothStarter::State state; +}; + +AbstractBluetoothStarterPrivate::AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d) : + + trkDevice(d), + listener(0), + timer(0), + intervalMS(1000), + attempts(-1), + n(0), + device(QLatin1String("/dev/rfcomm0")), + state(AbstractBluetoothStarter::TimedOut) +{ +} + +AbstractBluetoothStarter::AbstractBluetoothStarter(const TrkDevicePtr &trkDevice, QObject *parent) : + QObject(parent), + d(new AbstractBluetoothStarterPrivate(trkDevice)) +{ +} + +AbstractBluetoothStarter::~AbstractBluetoothStarter() +{ + stopTimer(); + delete d; +} + +void AbstractBluetoothStarter::stopTimer() +{ + if (d->timer && d->timer->isActive()) + d->timer->stop(); +} + +AbstractBluetoothStarter::StartResult AbstractBluetoothStarter::start() +{ + if (state() == Running) { + d->errorString = QLatin1String("Internal error, attempt to re-start AbstractBluetoothStarter.\n"); + return StartError; + } + // Before we instantiate timers, and such, try to open the device, + // which should succeed if another listener is already running in + // 'Watch' mode + if (d->trkDevice->open(d->device , &(d->errorString))) + return ConnectionSucceeded; + // Fire up the listener + d->n = 0; + d->listener = createListener(); + if (!d->listener->start(d->device, &(d->errorString))) + return StartError; + // Start timer + if (!d->timer) { + d->timer = new QTimer; + connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimer())); + } + d->timer->setInterval(d->intervalMS); + d->timer->setSingleShot(false); + d->timer->start(); + d->state = Running; + return Started; +} + +AbstractBluetoothStarter::State AbstractBluetoothStarter::state() const +{ + return d->state; +} + +int AbstractBluetoothStarter::intervalMS() const +{ + return d->intervalMS; +} + +void AbstractBluetoothStarter::setIntervalMS(int i) +{ + d->intervalMS = i; + if (d->timer) + d->timer->setInterval(i); +} + +int AbstractBluetoothStarter::attempts() const +{ + return d->attempts; +} + +void AbstractBluetoothStarter::setAttempts(int a) +{ + d->attempts = a; +} + +QString AbstractBluetoothStarter::device() const +{ + return d->device; +} + +void AbstractBluetoothStarter::setDevice(const QString &dv) +{ + d->device = dv; +} + +QString AbstractBluetoothStarter::errorString() const +{ + return d->errorString; +} + +void AbstractBluetoothStarter::slotTimer() +{ + ++d->n; + // Check for timeout + if (d->attempts >= 0 && d->n >= d->attempts) { + stopTimer(); + d->errorString = tr("%1: timed out after %n attempts using an interval of %2ms.", 0, d->n) + .arg(d->device).arg(d->intervalMS); + d->state = TimedOut; + emit timeout(); + } else { + // Attempt n to connect? + if (d->trkDevice->open(d->device , &(d->errorString))) { + stopTimer(); + const QString msg = tr("%1: Connection attempt %2 succeeded.").arg(d->device).arg(d->n); + d->listener->emitMessage(msg); + d->state = Connected; + emit connected(); + } else { + const QString msg = tr("%1: Connection attempt %2 failed: %3 (retrying)...") + .arg(d->device).arg(d->n).arg(d->errorString); + d->listener->emitMessage(msg); + } + } +} + +// -------- ConsoleBluetoothStarter +ConsoleBluetoothStarter::ConsoleBluetoothStarter(const TrkDevicePtr &trkDevice, + QObject *listenerParent, + QObject *parent) : + AbstractBluetoothStarter(trkDevice, parent), + m_listenerParent(listenerParent) +{ +} + +BluetoothListener *ConsoleBluetoothStarter::createListener() +{ + BluetoothListener *rc = new BluetoothListener(m_listenerParent); + rc->setMode(BluetoothListener::Listen); + rc->setPrintConsoleMessages(true); + return rc; +} + +bool ConsoleBluetoothStarter::startBluetooth(const TrkDevicePtr &trkDevice, + QObject *listenerParent, + const QString &device, + int attempts, + QString *errorMessage) +{ + // Set up a console starter to print to stdout. + ConsoleBluetoothStarter starter(trkDevice, listenerParent); + starter.setDevice(device); + starter.setAttempts(attempts); + switch (starter.start()) { + case Started: + break; + case ConnectionSucceeded: + return true; + case StartError: + *errorMessage = starter.errorString(); + return false; + } + // Run the starter with an event loop. @ToDo: Implement + // some asynchronous keypress read to cancel. + QEventLoop eventLoop; + connect(&starter, SIGNAL(connected()), &eventLoop, SLOT(quit())); + connect(&starter, SIGNAL(timeout()), &eventLoop, SLOT(quit())); + eventLoop.exec(QEventLoop::ExcludeUserInputEvents); + if (starter.state() != AbstractBluetoothStarter::Connected) { + *errorMessage = starter.errorString(); + return false; + } + return true; +} + +} // namespace trk diff --git a/src/shared/trk/bluetoothlistener.h b/src/shared/trk/bluetoothlistener.h new file mode 100644 index 0000000000..581a32cde1 --- /dev/null +++ b/src/shared/trk/bluetoothlistener.h @@ -0,0 +1,174 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef BLUETOOTHLISTENER_H +#define BLUETOOTHLISTENER_H + +#include <QtCore/QObject> +#include <QtCore/QProcess> +#include <QtCore/QSharedPointer> + +namespace trk { +class TrkDevice; +struct BluetoothListenerPrivate; +struct AbstractBluetoothStarterPrivate; + +/* BluetoothListener: Starts a helper process watching connections on a + * Bluetooth device, Linux only: + * The rfcomm command is used. It process can be started in the background + * while connection attempts (TrkDevice::open()) are made in the foreground. */ + +class BluetoothListener : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(BluetoothListener) +public: + // The Mode property must be set before calling start(). + enum Mode { + Listen, /* Terminate after client closed (read: Trk app + * on the phone terminated or disconnected).*/ + Watch // Keep running, watch for next connection from client + }; + + explicit BluetoothListener(QObject *parent = 0); + virtual ~BluetoothListener(); + + Mode mode() const; + void setMode(Mode m); + + bool start(const QString &device, QString *errorMessage); + + // Print messages on the console. + bool printConsoleMessages() const; + void setPrintConsoleMessages(bool p); + +signals: + void terminated(); + void message(const QString &); + +public slots: + void emitMessage(const QString &m); // accessed by starter + +private slots: + void slotStdOutput(); + void slotStdError(); + void slotProcessFinished(int, QProcess::ExitStatus); + void slotProcessError(QProcess::ProcessError error); + +private: + int terminateProcess(); + + BluetoothListenerPrivate *d; +}; + +/* AbstractBluetoothStarter: Repeatedly tries to open a trk device + * until a connection succeeds, allowing to do something else in the + * foreground (local event loop or asynchronous operation). + * Note that in case a Listener is already running in watch mode, it might + * also happen that connection succeeds immediately. + * Implementations must provide a factory function that creates and sets up the + * listener (mode, message connection, etc). */ + +class AbstractBluetoothStarter : public QObject { + Q_OBJECT + Q_DISABLE_COPY(AbstractBluetoothStarter) +public: + typedef QSharedPointer<TrkDevice> TrkDevicePtr; + + enum State { Running, Connected, TimedOut }; + + virtual ~AbstractBluetoothStarter(); + + int intervalMS() const; + void setIntervalMS(int i); + + int attempts() const; + void setAttempts(int a); + + QString device() const; + void setDevice(const QString &); + + State state() const; + QString errorString() const; + + enum StartResult { + Started, // Starter is now running. + ConnectionSucceeded, /* Initial connection attempt succeeded, + * no need to keep running. */ + StartError // Error occurred during start. + }; + + StartResult start(); + +signals: + void connected(); + void timeout(); + +private slots: + void slotTimer(); + +protected: + explicit AbstractBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); + // Overwrite to create and parametrize the listener. + virtual BluetoothListener *createListener() = 0; + +private: + inline void stopTimer(); + + AbstractBluetoothStarterPrivate *d; +}; + +/* ConsoleBluetoothStarter: Convenience class for console processes. Creates a + * listener in "Listen" mode with the messages redirected to standard output. */ + +class ConsoleBluetoothStarter : public AbstractBluetoothStarter { + Q_OBJECT + Q_DISABLE_COPY(ConsoleBluetoothStarter) +public: + + static bool startBluetooth(const TrkDevicePtr& trkDevice, + QObject *listenerParent, + const QString &device, + int attempts, + QString *errorMessage); + +protected: + virtual BluetoothListener *createListener(); + +private: + explicit ConsoleBluetoothStarter(const TrkDevicePtr& trkDevice, + QObject *listenerParent, + QObject *parent = 0); + + QObject *m_listenerParent; +}; + +} // namespace trk + +#endif // BLUETOOTHLISTENER_H diff --git a/src/shared/trk/bluetoothlistener_gui.cpp b/src/shared/trk/bluetoothlistener_gui.cpp new file mode 100644 index 0000000000..9723a36d9d --- /dev/null +++ b/src/shared/trk/bluetoothlistener_gui.cpp @@ -0,0 +1,74 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "bluetoothlistener_gui.h" +#include "bluetoothlistener.h" + +#include <QtGui/QMessageBox> +#include <QtGui/QPushButton> +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> + +namespace trk { + +StartBluetoothGuiResult + startBluetoothGui(AbstractBluetoothStarter &starter, + QWidget *msgBoxParent, + QString *errorMessage) +{ + errorMessage->clear(); + switch (starter.start()) { + case AbstractBluetoothStarter::Started: + break; + case AbstractBluetoothStarter::ConnectionSucceeded: + return BluetoothGuiConnected; + case AbstractBluetoothStarter::StartError: + *errorMessage = starter.errorString(); + return BluetoothGuiError; + } + // Run the starter with the event loop of a message box, close it + // with the finished signals. + const QString title = QCoreApplication::translate("trk::startBluetoothGui", "Waiting for Bluetooth Connection"); + const QString message = QCoreApplication::translate("trk::startBluetoothGui", "Connecting to %1...").arg(starter.device()); + QMessageBox messageBox(QMessageBox::Information, title, message, QMessageBox::Cancel, msgBoxParent); + QObject::connect(&starter, SIGNAL(connected()), &messageBox, SLOT(close())); + QObject::connect(&starter, SIGNAL(timeout()), &messageBox, SLOT(close())); + messageBox.exec(); + // Only starter.state() is reliable here. + if (starter.state() == AbstractBluetoothStarter::Running) { + *errorMessage = QCoreApplication::translate("trk::startBluetoothGui", "Connection on %1 canceled.").arg(starter.device()); + return BluetoothGuiCanceled; + } + if (starter.state() != AbstractBluetoothStarter::Connected) { + *errorMessage = starter.errorString(); + return BluetoothGuiError; + } + return BluetoothGuiConnected; +} +} // namespace trk diff --git a/src/shared/trk/bluetoothlistener_gui.h b/src/shared/trk/bluetoothlistener_gui.h new file mode 100644 index 0000000000..2a7c57e291 --- /dev/null +++ b/src/shared/trk/bluetoothlistener_gui.h @@ -0,0 +1,58 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef BLUETOOTHLISTENER_GUI_H +#define BLUETOOTHLISTENER_GUI_H + +#include <QtCore/QtGlobal> + +QT_BEGIN_NAMESPACE +class QWidget; +QT_END_NAMESPACE + +namespace trk { + class AbstractBluetoothStarter; + + /* startBluetoothGui(): Prompt the user to start a Bluetooth + * connection with a message box he can cancel. Pass in + * the starter with device and parameters set up. */ + + enum StartBluetoothGuiResult { + BluetoothGuiConnected, + BluetoothGuiCanceled, + BluetoothGuiError + }; + + StartBluetoothGuiResult + startBluetoothGui(AbstractBluetoothStarter &starter, + QWidget *msgBoxParent, + QString *errorMessage); +} // namespace trk + +#endif // BLUETOOTHLISTENER_GUI_H diff --git a/src/shared/trk/launcher.cpp b/src/shared/trk/launcher.cpp index cff53c02a1..f066ab4864 100644 --- a/src/shared/trk/launcher.cpp +++ b/src/shared/trk/launcher.cpp @@ -30,6 +30,7 @@ #include "launcher.h" #include "trkutils.h" #include "trkdevice.h" +#include "bluetoothlistener.h" #include <QtCore/QTimer> #include <QtCore/QDateTime> @@ -50,8 +51,9 @@ struct LauncherPrivate { int position; }; - LauncherPrivate(); - TrkDevice m_device; + explicit LauncherPrivate(const TrkDevicePtr &d); + + TrkDevicePtr m_device; QString m_trkServerName; QByteArray m_trkReadBuffer; @@ -65,21 +67,28 @@ struct LauncherPrivate { int m_verbose; Launcher::Actions m_startupActions; bool m_connected; + bool m_closeDevice; }; -LauncherPrivate::LauncherPrivate() : +LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) : + m_device(d), m_verbose(0), - m_connected(false) + m_connected(false), + m_closeDevice(true) { + if (m_device.isNull()) + m_device = TrkDevicePtr(new TrkDevice); } -Launcher::Launcher(Actions startupActions, QObject *parent) : +Launcher::Launcher(Actions startupActions, + const TrkDevicePtr &dev, + QObject *parent) : QObject(parent), - d(new LauncherPrivate) + d(new LauncherPrivate(dev)) { d->m_startupActions = startupActions; - connect(&d->m_device, SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult))); - connect(this, SIGNAL(finished()), &d->m_device, SLOT(close())); + 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() @@ -98,6 +107,16 @@ void Launcher::setTrkServerName(const QString &name) d->m_trkServerName = name; } +QString Launcher::trkServerName() const +{ + return d->m_trkServerName; +} + +TrkDevicePtr Launcher::trkDevice() const +{ + return d->m_device; +} + void Launcher::setFileName(const QString &name) { d->m_fileName = name; @@ -116,16 +135,28 @@ void Launcher::setInstallFileName(const QString &name) void Launcher::setSerialFrame(bool b) { - d->m_device.setSerialFrame(b); + d->m_device->setSerialFrame(b); } bool Launcher::serialFrame() const { - return d->m_device.serialFrame(); + return d->m_device->serialFrame(); +} + + +bool Launcher::closeDevice() const +{ + return d->m_closeDevice; +} + +void Launcher::setCloseDevice(bool c) +{ + d->m_closeDevice = c; } bool Launcher::startServer(QString *errorMessage) { + errorMessage->clear(); if (d->m_verbose) { const QString msg = QString::fromLatin1("Port=%1 Executable=%2 Package=%3 Remote Package=%4 Install file=%5") .arg(d->m_trkServerName, d->m_fileName, d->m_copyState.sourceFileName, d->m_copyState.destinationFileName, d->m_installFileName); @@ -148,15 +179,21 @@ bool Launcher::startServer(QString *errorMessage) qWarning("No remote executable given for running."); return false; } - if (!d->m_device.open(d->m_trkServerName, errorMessage)) + if (!d->m_device->isOpen() && !d->m_device->open(d->m_trkServerName, errorMessage)) return false; - d->m_device.sendTrkInitialPing(); - d->m_device.sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected - d->m_device.sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask)); - d->m_device.sendTrkMessage(TrkCpuType, TrkCallback(this, &Launcher::handleCpuType)); - d->m_device.sendTrkMessage(TrkVersions, TrkCallback(this, &Launcher::handleTrkVersion)); + if (d->m_closeDevice) { + connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); + } else { + disconnect(this, SIGNAL(finished()), d->m_device.data(), 0); + } + + d->m_device->sendTrkInitialPing(); + d->m_device->sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected + d->m_device->sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask)); + d->m_device->sendTrkMessage(TrkCpuType, TrkCallback(this, &Launcher::handleCpuType)); + d->m_device->sendTrkMessage(TrkVersions, TrkCallback(this, &Launcher::handleTrkVersion)); if (d->m_startupActions != ActionPingOnly) - d->m_device.sendTrkMessage(TrkConnect, TrkCallback(this, &Launcher::handleConnect)); + d->m_device->sendTrkMessage(TrkConnect, TrkCallback(this, &Launcher::handleConnect)); return true; } @@ -178,7 +215,7 @@ void Launcher::handleConnect(const TrkResult &result) void Launcher::setVerbose(int v) { d->m_verbose = v; - d->m_device.setVerbose(v); + d->m_device->setVerbose(v); } void Launcher::logMessage(const QString &msg) @@ -193,7 +230,7 @@ void Launcher::terminate() QByteArray ba; appendShort(&ba, 0x0000, TargetByteOrder); appendInt(&ba, d->m_session.pid, TargetByteOrder); - d->m_device.sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); + d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); } else if (d->m_connected) { if (d->m_copyState.copyFileHandle) closeRemoteFile(true); @@ -235,17 +272,17 @@ void Launcher::handleResult(const TrkResult &result) // uint pid = extractInt(data + 4); // ProcessID: 4 bytes; // uint tid = extractInt(data + 8); // ThreadID: 4 bytes //logMessage(prefix << " ADDR: " << addr << " PID: " << pid << " TID: " << tid); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); break; } case TrkNotifyException: { // Notify Exception (obsolete) logMessage(prefix + "NOTE: EXCEPTION " + str); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); break; } case TrkNotifyInternalError: { // logMessage(prefix + "NOTE: INTERNAL ERROR: " + str); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); break; } @@ -278,8 +315,8 @@ void Launcher::handleResult(const TrkResult &result) break; QByteArray ba; ba.append(result.data.mid(2, 8)); - d->m_device.sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); - //d->m_device.sendTrkAck(result.token) + d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); + //d->m_device->sendTrkAck(result.token) break; } case TrkNotifyDeleted: { // NotifyDeleted @@ -289,7 +326,7 @@ void Launcher::handleResult(const TrkResult &result) logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3"). arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")). arg(name)); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); if (itemType == 0 // process && result.data.size() >= 10 && d->m_session.pid == extractInt(result.data.data() + 6)) { @@ -299,17 +336,17 @@ void Launcher::handleResult(const TrkResult &result) } case TrkNotifyProcessorStarted: { // NotifyProcessorStarted logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); break; } case TrkNotifyProcessorStandBy: { // NotifyProcessorStandby logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); break; } case TrkNotifyProcessorReset: { // NotifyProcessorReset logMessage(prefix + "NOTE: PROCESSOR RESET: " + str); - d->m_device.sendTrkAck(result.token); + d->m_device->sendTrkAck(result.token); break; } default: { @@ -384,7 +421,7 @@ void Launcher::continueCopying(uint lastCopiedBlockSize) QByteArray ba; appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder); appendString(&ba, d->m_copyState.data->mid(d->m_copyState.position, 2048), TargetByteOrder, false); - d->m_device.sendTrkMessage(TrkWriteFile, TrkCallback(this, &Launcher::handleCopy), ba); + d->m_device->sendTrkMessage(TrkWriteFile, TrkCallback(this, &Launcher::handleCopy), ba); } else { closeRemoteFile(); } @@ -395,7 +432,7 @@ void Launcher::closeRemoteFile(bool failed) QByteArray ba; appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder); appendInt(&ba, QDateTime::currentDateTime().toTime_t(), TargetByteOrder); - d->m_device.sendTrkMessage(TrkCloseFile, + d->m_device->sendTrkMessage(TrkCloseFile, failed ? TrkCallback() : TrkCallback(this, &Launcher::handleFileCopied), ba); d->m_copyState.data.reset(); @@ -458,7 +495,7 @@ void Launcher::handleCreateProcess(const TrkResult &result) QByteArray ba; appendInt(&ba, d->m_session.pid); appendInt(&ba, d->m_session.tid); - d->m_device.sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); + d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); } void Launcher::handleWaitForFinished(const TrkResult &result) @@ -496,7 +533,7 @@ void Launcher::cleanUp() appendByte(&ba, 0x00); appendByte(&ba, 0x00); appendInt(&ba, d->m_session.pid); - d->m_device.sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process"); + d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process"); //---TRK------------------------------------------------------ // Command: 0x80 Acknowledge @@ -540,7 +577,7 @@ void Launcher::cleanUp() void Launcher::disconnectTrk() { - d->m_device.sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished)); + d->m_device->sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished)); } void Launcher::copyFileToRemote() @@ -549,7 +586,7 @@ void Launcher::copyFileToRemote() QByteArray ba; appendByte(&ba, 0x10); appendString(&ba, d->m_copyState.destinationFileName.toLocal8Bit(), TargetByteOrder, false); - d->m_device.sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba); + d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba); } void Launcher::installRemotePackageSilently() @@ -558,7 +595,7 @@ void Launcher::installRemotePackageSilently() QByteArray ba; appendByte(&ba, 'C'); appendString(&ba, d->m_installFileName.toLocal8Bit(), TargetByteOrder, false); - d->m_device.sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba); + d->m_device->sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba); } void Launcher::handleInstallPackageFinished(const TrkResult &result) @@ -586,7 +623,6 @@ void Launcher::startInferiorIfNeeded() appendByte(&ba, 0); // create new process appendByte(&ba, 0); // ? appendString(&ba, d->m_fileName.toLocal8Bit(), TargetByteOrder); - d->m_device.sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), ba); // Create Item -} - + d->m_device->sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), ba); // Create Item } +} // namespace trk diff --git a/src/shared/trk/launcher.h b/src/shared/trk/launcher.h index 93f5d52923..2c4881de6d 100644 --- a/src/shared/trk/launcher.h +++ b/src/shared/trk/launcher.h @@ -29,8 +29,11 @@ #ifndef LAUNCHER_H #define LAUNCHER_H +#include "trkdevice.h" + #include <QtCore/QObject> #include <QtCore/QVariant> +#include <QtCore/QSharedPointer> namespace trk { @@ -38,9 +41,12 @@ struct TrkResult; struct TrkMessage; struct LauncherPrivate; +typedef QSharedPointer<TrkDevice> TrkDevicePtr; + class Launcher : public QObject { Q_OBJECT + Q_DISABLE_COPY(Launcher) public: typedef void (Launcher::*TrkCallBack)(const TrkResult &); @@ -56,10 +62,12 @@ public: }; explicit Launcher(trk::Launcher::Actions startupActions = trk::Launcher::ActionPingOnly, + const TrkDevicePtr &trkDevice = TrkDevicePtr(), QObject *parent = 0); ~Launcher(); void addStartupActions(trk::Launcher::Actions startupActions); void setTrkServerName(const QString &name); + QString trkServerName() const; void setFileName(const QString &name); void setCopyFileName(const QString &srcName, const QString &dstName); void setInstallFileName(const QString &name); @@ -67,6 +75,11 @@ public: void setVerbose(int v); void setSerialFrame(bool b); bool serialFrame() const; + // Close device or leave it open + bool closeDevice() const; + void setCloseDevice(bool c); + + TrkDevicePtr trkDevice() const; // becomes valid after successful execution of ActionPingOnly QString deviceDescription(unsigned verbose = 0u) const; diff --git a/src/shared/trk/trk.pri b/src/shared/trk/trk.pri index 1564e4684d..8965948f19 100644 --- a/src/shared/trk/trk.pri +++ b/src/shared/trk/trk.pri @@ -1,13 +1,20 @@ INCLUDEPATH *= $$PWD # Input -HEADERS += \ - $$PWD/callback.h \ +HEADERS += $$PWD/callback.h \ $$PWD/trkutils.h \ $$PWD/trkdevice.h \ - $$PWD/launcher.h + $$PWD/launcher.h \ + $$PWD/bluetoothlistener.h -SOURCES += \ - $$PWD/trkutils.cpp \ +SOURCES += $$PWD/trkutils.cpp \ $$PWD/trkdevice.cpp \ - $$PWD/launcher.cpp + $$PWD/launcher.cpp \ + $$PWD/bluetoothlistener.cpp + +contains(QT, gui) { + HEADERS += $$PWD/bluetoothlistener_gui.h + SOURCES += $$PWD/bluetoothlistener_gui.cpp +} else { + message(Trk: Console ...) +} diff --git a/tests/manual/trklauncher/main.cpp b/tests/manual/trklauncher/main.cpp index 65031e7cc5..e9847d33b8 100644 --- a/tests/manual/trklauncher/main.cpp +++ b/tests/manual/trklauncher/main.cpp @@ -1,13 +1,19 @@ #include "launcher.h" +#include "bluetoothlistener.h" #include <QtCore/QCoreApplication> +#include <QtCore/QSharedPointer> #include <QtCore/QDebug> #include <QtCore/QStringList> static const char *usageC = -"\nUsage: %1 <trk_port_name> [-v] [-i remote_sis_file | -I local_sis_file remote_sis_file] [<remote_executable_name>]\n" +"\n" +"Usage: %1 [options] <trk_port_name>\n" +" %1 [options] -i <trk_port_name> remote_sis_file\n" +" %1 [options] -I local_sis_file remote_sis_file] [<remote_executable_name>]\n" "\nOptions:\n -v verbose\n" - " -f turn serial message frame off\n\n" + " -b Prompt for Bluetooth connect (Linux only)\n" + " -f turn serial message frame off (Bluetooth)\n" "\nPing:\n" "%1 COM5\n" "\nRemote launch:\n" @@ -27,74 +33,94 @@ static void usage() qWarning("%s", qPrintable(msg)); } -static bool parseArguments(const QStringList &arguments, trk::Launcher &launcher) +typedef QSharedPointer<trk::Launcher> TrkLauncherPtr; + +// Parse arguments, return pointer or a null none. + +static inline TrkLauncherPtr createLauncher(trk::Launcher::Actions actions, + const QString &serverName, + bool serialFrame, + int verbosity) +{ + TrkLauncherPtr launcher(new trk::Launcher(actions)); + launcher->setTrkServerName(serverName); + launcher->setSerialFrame(serialFrame); + launcher->setVerbose(verbosity); + return launcher; +} + +static TrkLauncherPtr parseArguments(const QStringList &arguments, bool *bluetooth) { // Parse away options bool install = false; bool customInstall = false; + bool serialFrame = true; const int argCount = arguments.size(); int verbosity = 0; + *bluetooth = false; + trk::Launcher::Actions actions = trk::Launcher::ActionPingOnly; int a = 1; for ( ; a < argCount; a++) { const QString option = arguments.at(a); if (!option.startsWith(QLatin1Char('-'))) break; if (option.size() != 2) - return false; + return TrkLauncherPtr(); switch (option.at(1).toAscii()) { case 'v': verbosity++; break; case 'f': - launcher.setSerialFrame(false); - break;verbosity++; + serialFrame = false; + break; + case 'b': + *bluetooth = true; + break; case 'i': install = true; - launcher.addStartupActions(trk::Launcher::ActionInstall); + actions = trk::Launcher::ActionInstall; break; case 'I': customInstall = true; - launcher.addStartupActions(trk::Launcher::ActionCopyInstall); + actions = trk::Launcher::ActionCopyInstall; break; default: - return false; + return TrkLauncherPtr(); } } - - launcher.setVerbose(verbosity); // Evaluate arguments const int remainingArgsCount = argCount - a; - if (remainingArgsCount == 1 && !install && !customInstall) { - launcher.setTrkServerName(arguments.at(a)); // ping - return true; + if (remainingArgsCount == 1 && !install && !customInstall) { // Ping + return createLauncher(actions, arguments.at(a), serialFrame, verbosity); } if (remainingArgsCount == 2 && !install && !customInstall) { // remote exec - launcher.addStartupActions(trk::Launcher::ActionRun); - launcher.setTrkServerName(arguments.at(a)); - launcher.setFileName(arguments.at(a + 1)); - return true; + TrkLauncherPtr launcher = createLauncher(actions, arguments.at(a), serialFrame, verbosity); + launcher->addStartupActions(trk::Launcher::ActionRun); + launcher->setFileName(arguments.at(a + 1)); + return launcher; } if ((remainingArgsCount == 3 || remainingArgsCount == 2) && install && !customInstall) { - launcher.setTrkServerName(arguments.at(a)); // ping - launcher.setInstallFileName(arguments.at(a + 1)); + TrkLauncherPtr launcher = createLauncher(actions, arguments.at(a), serialFrame, verbosity); + launcher->setInstallFileName(arguments.at(a + 1)); if (remainingArgsCount == 3) { - launcher.addStartupActions(trk::Launcher::ActionRun); - launcher.setFileName(arguments.at(a + 2)); + launcher->addStartupActions(trk::Launcher::ActionRun); + launcher->setFileName(arguments.at(a + 2)); } - return true; + return launcher; } if ((remainingArgsCount == 4 || remainingArgsCount == 3) && !install && customInstall) { - launcher.setTrkServerName(arguments.at(a)); // ping - launcher.setCopyFileName(arguments.at(a + 1), arguments.at(a + 2)); - launcher.setInstallFileName(arguments.at(a + 2)); + TrkLauncherPtr launcher = createLauncher(actions, arguments.at(a), serialFrame, verbosity); + launcher->setTrkServerName(arguments.at(a)); // ping + launcher->setCopyFileName(arguments.at(a + 1), arguments.at(a + 2)); + launcher->setInstallFileName(arguments.at(a + 2)); if (remainingArgsCount == 4) { - launcher.addStartupActions(trk::Launcher::ActionRun); - launcher.setFileName(arguments.at(a + 3)); + launcher->addStartupActions(trk::Launcher::ActionRun); + launcher->setFileName(arguments.at(a + 3)); } - return true; + return launcher; } - return false; + return TrkLauncherPtr(); } int main(int argc, char *argv[]) @@ -103,14 +129,23 @@ int main(int argc, char *argv[]) QCoreApplication::setApplicationName(QLatin1String("trklauncher")); QCoreApplication::setOrganizationName(QLatin1String("Nokia")); - trk::Launcher launcher; - if (!parseArguments(app.arguments(), launcher)) { + bool bluetooth; + const TrkLauncherPtr launcher = parseArguments(app.arguments(), &bluetooth); + if (launcher.isNull()) { usage(); return 1; } - QObject::connect(&launcher, SIGNAL(finished()), &app, SLOT(quit())); + QObject::connect(launcher.data(), SIGNAL(finished()), &app, SLOT(quit())); + // BLuetooth: Open with prompt QString errorMessage; - if (launcher.startServer(&errorMessage)) + if (bluetooth && !trk::ConsoleBluetoothStarter::startBluetooth(launcher->trkDevice(), + launcher.data(), + launcher->trkServerName(), + 30, &errorMessage)) { + qWarning("%s\n", qPrintable(errorMessage)); + return -1; + } + if (launcher->startServer(&errorMessage)) return app.exec(); qWarning("%s\n", qPrintable(errorMessage)); return 4; diff --git a/tests/manual/trklauncher/trklauncher.pro b/tests/manual/trklauncher/trklauncher.pro index 73e7f7d781..943afde4ad 100644 --- a/tests/manual/trklauncher/trklauncher.pro +++ b/tests/manual/trklauncher/trklauncher.pro @@ -1,5 +1,5 @@ TEMPLATE = app QT = core +CONFIG += console include(../../../src/shared/trk/trk.pri) -win32:CONFIG += console SOURCES += main.cpp |