Commit 5c8e6e9f authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Trk: Make it run on Windows.

Add options page with overrideable device. Correct
wiring of the rfcomm process.
parent 4843f44c
...@@ -6,14 +6,20 @@ HEADERS += \ ...@@ -6,14 +6,20 @@ HEADERS += \
$$PWD/gdbengine.h \ $$PWD/gdbengine.h \
$$PWD/gdboptionspage.h \ $$PWD/gdboptionspage.h \
$$PWD/trkgdbadapter.h \ $$PWD/trkgdbadapter.h \
#$$PWD/gdboptionspage.h \ $$PWD/trkoptions.h \
$$PWD/trkoptionswidget.h \
$$PWD/trkoptionspage.h
SOURCES += \ SOURCES += \
$$PWD/gdbmi.cpp \ $$PWD/gdbmi.cpp \
$$PWD/gdbengine.cpp \ $$PWD/gdbengine.cpp \
$$PWD/gdboptionspage.cpp \ $$PWD/gdboptionspage.cpp \
$$PWD/trkgdbadapter.cpp $$PWD/trkgdbadapter.cpp \
$$PWD/trkoptions.cpp \
$$PWD/trkoptionswidget.cpp \
$$PWD/trkoptionspage.cpp
FORMS += $$PWD/gdboptionspage.ui FORMS += $$PWD/gdboptionspage.ui \
$$PWD/trkoptionswidget.ui
RESOURCES += $$PWD/gdb.qrc RESOURCES += $$PWD/gdb.qrc
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "gdbengine.h" #include "gdbengine.h"
#include "gdboptionspage.h" #include "gdboptionspage.h"
#include "trkoptions.h"
#include "trkoptionspage.h"
#include "trkgdbadapter.h" #include "trkgdbadapter.h"
#include "watchutils.h" #include "watchutils.h"
...@@ -4313,9 +4315,11 @@ IDebuggerEngine *createGdbEngine(DebuggerManager *parent, ...@@ -4313,9 +4315,11 @@ IDebuggerEngine *createGdbEngine(DebuggerManager *parent,
IDebuggerEngine *createSymbianEngine(DebuggerManager *parent, IDebuggerEngine *createSymbianEngine(DebuggerManager *parent,
QList<Core::IOptionsPage*> *opts) QList<Core::IOptionsPage*> *opts)
{ {
Q_UNUSED(opts); QSharedPointer<TrkOptions> options(new TrkOptions);
//opts->push_back(new GdbOptionsPage); options->fromSettings(Core::ICore::instance()->settings());
TrkGdbAdapter *adapter = new TrkGdbAdapter;
opts->push_back(new TrkOptionsPage(options));
TrkGdbAdapter *adapter = new TrkGdbAdapter(options);
GdbEngine *engine = new GdbEngine(parent, adapter); GdbEngine *engine = new GdbEngine(parent, adapter);
QObject::connect(adapter, SIGNAL(output(QString)), QObject::connect(adapter, SIGNAL(output(QString)),
parent, SLOT(showDebuggerOutput(QString))); parent, SLOT(showDebuggerOutput(QString)));
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
**************************************************************************/ **************************************************************************/
#include "trkgdbadapter.h" #include "trkgdbadapter.h"
#include "trkoptions.h"
#ifndef STANDALONE_RUNNER #ifndef STANDALONE_RUNNER
#include "gdbengine.h" #include "gdbengine.h"
#endif #endif
...@@ -36,6 +37,9 @@ ...@@ -36,6 +37,9 @@
# include <unistd.h> # include <unistd.h>
#endif #endif
#include <QtCore/QTimer>
#include <QtCore/QDir>
#define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s) #define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s)
...@@ -71,21 +75,21 @@ static QByteArray dumpRegister(int n, uint value) ...@@ -71,21 +75,21 @@ static QByteArray dumpRegister(int n, uint value)
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
TrkGdbAdapter::TrkGdbAdapter() TrkGdbAdapter::TrkGdbAdapter(const TrkOptionsPtr &options) :
m_options(options),
m_running(false),
m_gdbAckMode(true),
m_verbose(2),
m_bufferedMemoryRead(true),
m_waitCount(0)
{ {
m_running = false;
m_gdbAckMode = true;
m_verbose = 2;
m_serialFrame = false;
m_bufferedMemoryRead = true;
m_rfcommDevice = "/dev/rfcomm0";
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
int userId = 0; const DWORD portOffset = GetCurrentProcessId() % 100;
#else #else
uid_t userId = getuid(); const uid_t portOffset = getuid();
#endif #endif
m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); m_gdbServerName = QString::fromLatin1("127.0.0.1:%1").arg(2222 + portOffset);
connect(&m_gdbProc, SIGNAL(readyReadStandardError()), connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
this, SIGNAL(readyReadStandardError())); this, SIGNAL(readyReadStandardError()));
connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
...@@ -103,18 +107,18 @@ TrkGdbAdapter::TrkGdbAdapter() ...@@ -103,18 +107,18 @@ TrkGdbAdapter::TrkGdbAdapter()
this, SLOT(handleRfcommReadyReadStandardError())); this, SLOT(handleRfcommReadyReadStandardError()));
connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()),
this, SLOT(handleRfcommReadyReadStandardOutput())); this, SLOT(handleRfcommReadyReadStandardOutput()));
connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), connect(&m_rfcommProc, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(handleRfcommError(QProcess::ProcessError))); this, SLOT(handleRfcommError(QProcess::ProcessError)));
connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), connect(&m_rfcommProc, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(handleRfcommFinished(int, QProcess::ExitStatus))); this, SLOT(handleRfcommFinished(int, QProcess::ExitStatus)));
connect(&m_gdbProc, SIGNAL(started()), connect(&m_rfcommProc, SIGNAL(started()),
this, SLOT(handleRfcommStarted())); this, SLOT(handleRfcommStarted()));
connect(&m_gdbProc, SIGNAL(stateChanged(QProcess::ProcessState)), connect(&m_rfcommProc, SIGNAL(stateChanged(QProcess::ProcessState)),
this, SLOT(handleRfcommStateChanged(QProcess::ProcessState))); this, SLOT(handleRfcommStateChanged(QProcess::ProcessState)));
if (m_verbose > 1) if (m_verbose > 1)
m_trkDevice.setVerbose(true); m_trkDevice.setVerbose(true);
m_trkDevice.setSerialFrame(m_serialFrame); m_trkDevice.setSerialFrame(m_options->mode != TrkOptions::BlueTooth);
connect(&m_trkDevice, SIGNAL(logMessage(QString)), connect(&m_trkDevice, SIGNAL(logMessage(QString)),
this, SLOT(trkLogMessage(QString))); this, SLOT(trkLogMessage(QString)));
...@@ -126,6 +130,25 @@ TrkGdbAdapter::~TrkGdbAdapter() ...@@ -126,6 +130,25 @@ TrkGdbAdapter::~TrkGdbAdapter()
logMessage("Shutting down.\n"); logMessage("Shutting down.\n");
} }
QString TrkGdbAdapter::overrideTrkDevice() const
{
return m_overrideTrkDevice;
}
void TrkGdbAdapter::setOverrideTrkDevice(const QString &d)
{
m_overrideTrkDevice = d;
}
QString TrkGdbAdapter::effectiveTrkDevice() const
{
if (!m_overrideTrkDevice.isEmpty())
return m_overrideTrkDevice;
if (m_options->mode == TrkOptions::BlueTooth)
return m_options->blueToothDevice;
return m_options->serialPort;
}
void TrkGdbAdapter::trkLogMessage(const QString &msg) void TrkGdbAdapter::trkLogMessage(const QString &msg)
{ {
logMessage("TRK " + msg); logMessage("TRK " + msg);
...@@ -196,9 +219,16 @@ QByteArray TrkGdbAdapter::trkStepRangeMessage(byte option) ...@@ -196,9 +219,16 @@ QByteArray TrkGdbAdapter::trkStepRangeMessage(byte option)
void TrkGdbAdapter::startInferior() void TrkGdbAdapter::startInferior()
{ {
QString errorMessage; QString errorMessage;
if (!m_trkDevice.open(m_rfcommDevice, &errorMessage)) { const QString device = effectiveTrkDevice();
emit output("LOOPING"); if (!m_trkDevice.open(device, &errorMessage)) {
QTimer::singleShot(1000, this, SLOT(startInferior())); emit output(QString::fromLatin1("Waiting on %1 (%2)").arg(device, errorMessage));
// Do not loop forever
if (m_waitCount++ < (m_options->mode == TrkOptions::BlueTooth ? 60 : 5)) {
QTimer::singleShot(1000, this, SLOT(startInferior()));
} else {
emit output(QString::fromLatin1("Failed to connect to %1 after %2 attempts").arg(device).arg(m_waitCount));
emit finished(-44, QProcess::CrashExit);
}
return; return;
} }
...@@ -1283,14 +1313,21 @@ void TrkGdbAdapter::handleGdbStateChanged(QProcess::ProcessState newState) ...@@ -1283,14 +1313,21 @@ void TrkGdbAdapter::handleGdbStateChanged(QProcess::ProcessState newState)
void TrkGdbAdapter::run() void TrkGdbAdapter::run()
{ {
emit output("### Starting TrkGdbAdapter"); emit output(QLatin1String("### Starting TrkGdbAdapter"));
m_rfcommProc.start("rfcomm -r listen " + m_rfcommDevice + " 1"); if (m_options->mode == TrkOptions::BlueTooth) {
m_rfcommProc.waitForStarted(); const QString device = effectiveTrkDevice();
const QString blueToothListener = QLatin1String("rfcomm");
if (m_rfcommProc.state() != QProcess::Running) { emit output(QString::fromLatin1("### Starting BlueTooth listener %1 on %2").arg(blueToothListener, device));
emit finished(-44, QProcess::CrashExit); m_rfcommProc.start(blueToothListener + QLatin1String(" -r listen ") + m_options->blueToothDevice + QLatin1String(" 1"));
return; m_rfcommProc.waitForStarted();
if (m_rfcommProc.state() != QProcess::Running) {
const QString msg = QString::fromLocal8Bit(m_rfcommProc.readAllStandardError());
emit output(QString::fromLatin1("Failed to start BlueTooth listener %1 on %2: %3\n%4").arg(blueToothListener, device, m_rfcommProc.errorString(), msg));
emit finished(-44, QProcess::CrashExit);
return;
}
} }
m_waitCount = 0;
connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)),
this, SLOT(handleTrkResult(trk::TrkResult))); this, SLOT(handleTrkResult(trk::TrkResult)));
...@@ -1300,6 +1337,29 @@ void TrkGdbAdapter::run() ...@@ -1300,6 +1337,29 @@ void TrkGdbAdapter::run()
startInferior(); startInferior();
} }
#ifdef Q_OS_WIN
// Prepend environment of the Symbian Gdb by Cygwin '/bin'
static void setGdbCygwinEnvironment(const QString &cygwin, QProcess *process)
{
if (cygwin.isEmpty() || !QFileInfo(cygwin).isDir())
return;
const QString cygwinBinPath = QDir::toNativeSeparators(cygwin) + QLatin1String("\\bin");
QStringList env = process->environment();
if (env.isEmpty())
env = QProcess::systemEnvironment();
const QRegExp pathPattern(QLatin1String("^PATH=.*"));
const int index = env.indexOf(pathPattern);
if (index == -1)
return;
QString pathValue = env.at(index).mid(5);
if (pathValue.startsWith(cygwinBinPath))
return;
env[index] = QLatin1String("PATH=") + cygwinBinPath + QLatin1Char(';');
process->setEnvironment(env);
}
#endif
void TrkGdbAdapter::startGdb() void TrkGdbAdapter::startGdb()
{ {
if (!m_gdbServer.listen(QHostAddress(gdbServerIP()), gdbServerPort())) { if (!m_gdbServer.listen(QHostAddress(gdbServerIP()), gdbServerPort())) {
...@@ -1316,11 +1376,15 @@ void TrkGdbAdapter::startGdb() ...@@ -1316,11 +1376,15 @@ void TrkGdbAdapter::startGdb()
this, SLOT(handleGdbConnection())); this, SLOT(handleGdbConnection()));
logMessage("STARTING GDB"); logMessage("STARTING GDB");
emit output(QString::fromLatin1("### Starting gdb %1").arg(m_options->gdb));
QStringList gdbArgs; QStringList gdbArgs;
gdbArgs.append("--nx"); // Do not read .gdbinit file gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
gdbArgs.append("-i"); gdbArgs.append(QLatin1String("-i"));
gdbArgs.append("mi"); gdbArgs.append(QLatin1String("mi"));
m_gdbProc.start(QDir::currentPath() + "/cs-gdb", gdbArgs); #ifdef Q_OS_WIN
setGdbCygwinEnvironment(m_options->cygwin, &m_gdbProc);
#endif
m_gdbProc.start(m_options->gdb, gdbArgs);
} }
void TrkGdbAdapter::sendGdbMessage(const QString &msg, GdbCallback callback, void TrkGdbAdapter::sendGdbMessage(const QString &msg, GdbCallback callback,
...@@ -1379,12 +1443,15 @@ void TrkGdbAdapter::start(const QString &program, const QStringList &args, ...@@ -1379,12 +1443,15 @@ void TrkGdbAdapter::start(const QString &program, const QStringList &args,
QIODevice::OpenMode mode) QIODevice::OpenMode mode)
{ {
Q_UNUSED(mode); Q_UNUSED(mode);
Q_UNUSED(program);
Q_UNUSED(args);
run(); run();
} }
void TrkGdbAdapter::kill() void TrkGdbAdapter::kill()
{ {
m_rfcommProc.kill(); if (m_options->mode == TrkOptions::BlueTooth && m_rfcommProc.state() == QProcess::Running)
m_rfcommProc.kill();
m_gdbProc.kill(); m_gdbProc.kill();
} }
...@@ -1402,7 +1469,7 @@ bool TrkGdbAdapter::waitForFinished(int msecs) ...@@ -1402,7 +1469,7 @@ bool TrkGdbAdapter::waitForFinished(int msecs)
m_rfcommProc.terminate(); m_rfcommProc.terminate();
m_rfcommProc.waitForFinished(); m_rfcommProc.waitForFinished();
QProcess proc; QProcess proc;
proc.start("rfcomm release " + m_rfcommDevice.toLatin1()); proc.start("rfcomm release " + m_options->blueToothDevice);
proc.waitForFinished(); proc.waitForFinished();
return m_gdbProc.waitForFinished(msecs); return m_gdbProc.waitForFinished(msecs);
} }
......
...@@ -34,34 +34,22 @@ ...@@ -34,34 +34,22 @@
#include "trkdevice.h" #include "trkdevice.h"
#include "abstractgdbadapter.h" #include "abstractgdbadapter.h"
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QSharedPointer>
#include <QtCore/QProcess> #include <QtCore/QProcess>
#include <QtCore/QQueue> #include <QtCore/QQueue>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtCore/QTimer>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QMainWindow>
#include <QtGui/QKeyEvent>
#include <QtGui/QTextBlock>
#include <QtGui/QTextEdit>
#include <QtGui/QToolBar>
#include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket> #include <QtNetwork/QTcpSocket>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
struct TrkOptions;
struct GdbResult struct GdbResult
{ {
QByteArray data; QByteArray data;
...@@ -81,18 +69,22 @@ public: ...@@ -81,18 +69,22 @@ public:
typedef trk::TrkResult TrkResult; typedef trk::TrkResult TrkResult;
typedef trk::Callback<const TrkResult &> TrkCallback; typedef trk::Callback<const TrkResult &> TrkCallback;
typedef trk::Callback<const GdbResult &> GdbCallback; typedef trk::Callback<const GdbResult &> GdbCallback;
typedef QSharedPointer<TrkOptions> TrkOptionsPtr;
TrkGdbAdapter(); explicit TrkGdbAdapter(const TrkOptionsPtr &options);
~TrkGdbAdapter(); ~TrkGdbAdapter();
void setGdbServerName(const QString &name); void setGdbServerName(const QString &name);
QString gdbServerName() const { return m_gdbServerName; } QString gdbServerName() const { return m_gdbServerName; }
QString gdbServerIP() const; QString gdbServerIP() const;
uint gdbServerPort() const; uint gdbServerPort() const;
void setVerbose(int verbose) { m_verbose = verbose; } void setVerbose(int verbose) { m_verbose = verbose; }
void setSerialFrame(bool b) { m_serialFrame = b; }
void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; } void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; }
trk::Session &session() { return m_session; } trk::Session &session() { return m_session; }
// Set a device (from the project) to override the settings.
QString overrideTrkDevice() const;
void setOverrideTrkDevice(const QString &);
public slots: public slots:
void startInferior(); void startInferior();
void run(); void run();
...@@ -108,7 +100,9 @@ private slots: ...@@ -108,7 +100,9 @@ private slots:
private: private:
friend class RunnerGui; friend class RunnerGui;
QString m_rfcommDevice; // /dev/rfcomm0 const TrkOptionsPtr m_options;
QString m_overrideTrkDevice;
QString m_gdbServerName; // 127.0.0.1:(2222+uid) QString m_gdbServerName; // 127.0.0.1:(2222+uid)
QProcess m_gdbProc; QProcess m_gdbProc;
...@@ -237,13 +231,15 @@ public: ...@@ -237,13 +231,15 @@ public:
Q_SLOT void handleRfcommStarted(); Q_SLOT void handleRfcommStarted();
Q_SLOT void handleRfcommStateChanged(QProcess::ProcessState newState); Q_SLOT void handleRfcommStateChanged(QProcess::ProcessState newState);
QString effectiveTrkDevice() const;
// Debuggee state // Debuggee state
Q_SLOT void executeCommand(const QString &msg); Q_SLOT void executeCommand(const QString &msg);
trk::Session m_session; // global-ish data (process id, target information) trk::Session m_session; // global-ish data (process id, target information)
trk::Snapshot m_snapshot; // local-ish data (memory and registers) trk::Snapshot m_snapshot; // local-ish data (memory and registers)
int m_verbose; int m_verbose;
bool m_serialFrame;
bool m_bufferedMemoryRead; bool m_bufferedMemoryRead;
int m_waitCount;
}; };
} // namespace Internal } // namespace Internal
......
/**************************************************************************
**
** 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 "trkoptions.h"
#include <QtCore/QSettings>
#include <QtCore/QFileInfo>
#ifdef Q_OS_WIN
# define SERIALPORT_ROOT "COM"
enum { firstSerialPort = 1, lastSerialPort = 12 };
enum { modeDefault = Debugger::Internal::TrkOptions::Serial };
static const char *serialPortDefaultC = SERIALPORT_ROOT"1";
static const char *gdbDefaultC = "symgdb";
#else
# define SERIALPORT_ROOT "/dev/ttyS"
enum { firstSerialPort = 0, lastSerialPort = 3 };
enum { modeDefault = Debugger::Internal::TrkOptions::BlueTooth };
static const char *serialPortDefaultC = SERIALPORT_ROOT"0";
static const char *gdbDefaultC = "symgdb";
#endif
static const char *settingsGroupC = "S60Debugger";
static const char *serialPortKeyC = "Port";
static const char *modeKeyC = "Mode";
static const char *blueToothDeviceKeyC = "BlueToothDevice";
static const char *blueToothDeviceDefaultC = "/dev/rfcomm0";
static const char *gdbKeyC = "gdb";
static const char *cygwinKeyC = "Cygwin";
static inline QString cygwinDefault()
{
#ifdef Q_OS_WIN
// Some smartness to check for Cygwin
static bool firstTime = true;
static QString rc = QLatin1String("C:/cygwin");
if (firstTime) {
if (!QFileInfo(rc).isDir())
rc.clear();
firstTime = false;
}
return rc;
#else
return QString();
#endif
}
namespace Debugger {
namespace Internal {
TrkOptions::TrkOptions() :
mode(modeDefault),
serialPort(QLatin1String(serialPortDefaultC)),
blueToothDevice(QLatin1String(blueToothDeviceDefaultC)),
gdb(QLatin1String(gdbDefaultC)),
cygwin(cygwinDefault())
{
}
void TrkOptions::fromSettings(const QSettings *s)
{
const QString keyRoot = QLatin1String(settingsGroupC) + QLatin1Char('/');
mode = s->value(keyRoot + QLatin1String(modeKeyC), modeDefault).toInt();
serialPort = s->value(keyRoot + QLatin1String(serialPortKeyC), QLatin1String(serialPortDefaultC)).toString();
gdb = s->value(keyRoot + QLatin1String(gdbKeyC),QLatin1String(gdbDefaultC)).toString();
cygwin = s->value(keyRoot + QLatin1String(cygwinKeyC), cygwinDefault()).toString();
blueToothDevice = s->value(keyRoot + QLatin1String(blueToothDeviceKeyC), QLatin1String(blueToothDeviceDefaultC)).toString();
}
void TrkOptions::toSettings(QSettings *s) const
{
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(modeKeyC), mode);
s->setValue(QLatin1String(serialPortKeyC), serialPort);
s->setValue(QLatin1String(blueToothDeviceKeyC), blueToothDevice);
s->setValue(QLatin1String(gdbKeyC), gdb);
s->setValue(QLatin1String(cygwinKeyC), cygwin);
s->endGroup();
}
bool TrkOptions::equals(const TrkOptions &o) const
{
return mode == o.mode
&& serialPort == o.serialPort
&& blueToothDevice == o.blueToothDevice
&& gdb == o.gdb
&& cygwin == o.cygwin;
}
QStringList TrkOptions::serialPorts()
{
QStringList rc;
const QString root = QLatin1String(SERIALPORT_ROOT);
for (int p = firstSerialPort; p != lastSerialPort; p++)