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.
This commit is contained in:
Friedemann Kleint
2009-10-23 18:00:20 +02:00
parent d35dcd8dbe
commit 1af61fefa8
19 changed files with 1132 additions and 83 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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")

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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 ...)
}

View File

@@ -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;

View File

@@ -1,5 +1,5 @@
TEMPLATE = app
QT = core
CONFIG += console
include(../../../src/shared/trk/trk.pri)
win32:CONFIG += console
SOURCES += main.cpp