From 0a9c7a44c6a9ca134c7a23a33a9285787a7a6d19 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 9 Feb 2010 16:05:50 +0100 Subject: Fix tst_QAbstractItemView::task250754_fontChange and tst_QAbstractItemView::QTBUG6407_extendedSelection for Symbian & 5800 We should consider the difference between Point and Pixel for font size. And also the margin and some other settings in style for views. Reviewed-by: TrustMe --- tests/auto/qabstractitemview/tst_qabstractitemview.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/auto/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/qabstractitemview/tst_qabstractitemview.cpp index 504ceac..ea86c16 100644 --- a/tests/auto/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/qabstractitemview/tst_qabstractitemview.cpp @@ -1213,14 +1213,14 @@ void tst_QAbstractItemView::task250754_fontChange() tree.setModel(m); w.show(); - w.resize(150,150); + w.resize(150,240); QTest::qWait(30); QFont font = tree.font(); - font.setPointSize(5); + font.setPixelSize(10); tree.setFont(font); QTRY_VERIFY(!tree.verticalScrollBar()->isVisible()); - font.setPointSize(45); + font.setPixelSize(60); tree.setFont(font); //now with the huge items, the scrollbar must be visible QTRY_VERIFY(tree.verticalScrollBar()->isVisible()); @@ -1444,7 +1444,10 @@ void tst_QAbstractItemView::QTBUG6407_extendedSelection() for(int i = 0; i < 50; ++i) view.addItem(QString::number(i)); - view.resize(200,200); + QFont font = view.font(); + font.setPixelSize(10); + view.setFont(font); + view.resize(200,240); view.show(); QApplication::setActiveWindow(&view); -- cgit v0.12 From 33aa8f4a035c1ce9231b40844e6e0793205d12aa Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 9 Feb 2010 11:37:18 +0000 Subject: Added qwidget test case which displays a native child widget As of commit bc82db, show()ing a native child widget causes a panic on Symbian. The panic code (WSERV-10) indicates that Activate() is being called on an already-active graphics context. This test case reproduces the defect. Task-number: QTBUG-7960 --- tests/auto/qwidget/tst_qwidget.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index 03eddee..b59017b 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -250,6 +250,7 @@ private slots: #else void persistentWinId(); #endif + void showNativeChild(); void qobject_castInDestroyedSlot(); void showHideEvent_data(); @@ -4586,6 +4587,16 @@ void tst_QWidget::persistentWinId() } #endif // Q_OS_SYMBIAN +void tst_QWidget::showNativeChild() +{ + QWidget topLevel; + topLevel.setGeometry(0, 0, 100, 100); + QWidget child(&topLevel); + child.winId(); + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); +} + class ShowHideEventWidget : public QWidget { public: -- cgit v0.12 From 46df42af1a25fd06247bb96d9e0bf24bf19defe8 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 9 Feb 2010 09:41:29 +0000 Subject: Fixed defect in handling of expose events for Symbian Commit bc82db did not correctly handle native child widgets. Consider the case when we have a top-level widget A with a native child widget B. When QSymbianControl::Draw() is called on the control corresponding to B, the following occurs: 1. The inExpose flag is set in B's QWExtra structure. 2. The call to syncBackingStore() results in a call to QWidgetBackingStore::flush(), passing default parameters. 3. Because no target widget was passed to flush(), this function selects the top-level widget (A) as the target for the flush operation, passing A as the first argument of QS60WindowSurface::flush(). 4. QS60WindowSurface::flush() checks the inExpose flag from A's QWExtra structure, finds it to be false, and proceeds to call DrawNow() on A's control. Because QSymbianControl::Draw() uses the default graphics context, this context is shared between controls. This means that the DrawNow() call in step 4 causes a WSERV-10 panic (Activate() called on an already-active) graphics context. This patch moves the inExpose flag from B's QWExtra into A's QTLWExtra, with the result that the call to DrawNow() in step 4 is suppressed. Task-number: QTBUG-7960 Reviewed-by: axis --- src/gui/kernel/qapplication_s60.cpp | 11 +++++++---- src/gui/kernel/qwidget_p.h | 3 ++- src/gui/kernel/qwidget_s60.cpp | 2 +- src/gui/painting/qwindowsurface_s60.cpp | 11 +++++++---- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 4a137ee..bf3ad71 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -809,12 +809,15 @@ TCoeInputCapabilities QSymbianControl::InputCapabilities() const void QSymbianControl::Draw(const TRect& controlRect) const { // Set flag to avoid calling DrawNow in window surface - QWExtra *extra = qwidget->d_func()->extraData(); - if (extra && !extra->inExpose) { - extra->inExpose = true; + QWidget *window = qwidget->window(); + Q_ASSERT(window); + QTLWExtra *topExtra = window->d_func()->maybeTopData(); + Q_ASSERT(topExtra); + if (!topExtra->inExpose) { + topExtra->inExpose = true; QRect exposeRect = qt_TRect2QRect(controlRect); qwidget->d_func()->syncBackingStore(exposeRect); - extra->inExpose = false; + topExtra->inExpose = false; } QWindowSurface *surface = qwidget->windowSurface(); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index b1eb3c3..4b62074 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -173,6 +173,8 @@ struct QTLWExtra { #ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif +#elif defined(Q_OS_SYMBIAN) + uint inExpose : 1; // Prevents drawing recursion #endif }; @@ -229,7 +231,6 @@ struct QWExtra { #endif #elif defined(Q_OS_SYMBIAN) // <----------------------------------------------------- Symbian uint activated : 1; // RWindowBase::Activated has been called - uint inExpose : 1; // Prevents drawing recursion /** * Defines the behaviour of QSymbianControl::Draw. diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index a844430..ebd289c 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -878,6 +878,7 @@ void QWidgetPrivate::registerDropSite(bool /* on */) void QWidgetPrivate::createTLSysExtra() { extra->topextra->backingStore = 0; + extra->topextra->inExpose = 0; } void QWidgetPrivate::deleteTLSysExtra() @@ -891,7 +892,6 @@ void QWidgetPrivate::createSysExtra() extra->activated = 0; extra->nativePaintMode = QWExtra::Default; extra->receiveNativePaintEvents = 0; - extra->inExpose = 0; } void QWidgetPrivate::deleteSysExtra() diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index b41dc2c..6cbf3d9 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -145,12 +145,15 @@ QImage* QS60WindowSurface::buffer(const QWidget *widget) void QS60WindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &) { - QWExtra *extra = widget->d_func()->extraData(); - if (extra && !extra->inExpose) { - extra->inExpose = true; // Prevent DrawNow() from calling syncBackingStore() again + QWidget *window = widget->window(); + Q_ASSERT(window); + QTLWExtra *topExtra = window->d_func()->maybeTopData(); + Q_ASSERT(topExtra); + if (!topExtra->inExpose) { + topExtra->inExpose = true; // Prevent DrawNow() from calling syncBackingStore() again TRect tr = qt_QRect2TRect(region.boundingRect()); widget->winId()->DrawNow(tr); - extra->inExpose = false; + topExtra->inExpose = false; } } -- cgit v0.12 From 3208a33a18d7eb666f0f47eff02ce4b21e248c10 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 9 Feb 2010 11:45:01 +0100 Subject: Catch up TRK library to creator f2b3e9f2dfbc580389b9b683a3e46e5a8422f55b This is the last SHA before trk directory is renamed. Note the \\.\ is prepended to windows com ports inside the library now, so main.cpp no longer has this windows specific code. commit f2b3e9f2dfbc580389b9b683a3e46e5a8422f55b Author: Friedemann Kleint Date: Fri Feb 5 12:24:46 2010 +0100 S60/Trk: Change trkutils to be a library of its own. To be able to share TrkDevices between Debugger and Qt4ProjectManager. commit 61c3a260b59433abf8c3ef481ec536af88f8026c Author: Sarika Kamisetty Date: Thu Feb 4 09:57:54 2010 +0100 Fix to App TRK connection with 'high COM port' does not work Merge-request: 111 Reviewed-by: hjk commit 2fd8b2d7ffa2ac032bfe3a17efe7d152c4cef14d Author: Friedemann Kleint Date: Mon Feb 1 12:43:56 2010 +0100 Fix some code scanning issues. QString: Use QChar where appropriate. commit 805b0a9cc165ef6cd596bd8f5e59f650cd0eebb2 Author: hjk Date: Mon Feb 1 11:45:44 2010 +0100 debugger: trk log output cosmetic commit 75b42f18d886b59dbf3380dd12f39f40005ef08b Merge: 4320314 a6ca348 Author: Oswald Buddenhagen Date: Fri Jan 29 22:49:55 2010 +0100 Merge remote branch 'origin/1.3' Trailing whitespace removal re-applied manually. commit a6ca348636dd92ab1445cff2286b3293163f5cea Author: Oswald Buddenhagen Date: Fri Jan 29 21:33:57 2010 +0100 remove trailing whitespace doing it in 1.3 as well to avoid possible later conflicts commit 4ec51219ed5c2150e164473b9c5326b6c68d096a Author: Friedemann Kleint Date: Thu Jan 28 17:04:05 2010 +0100 Trk: Fix source code scanning tool issues. showing up in Qt. --- tools/runonphone/main.cpp | 4 - tools/runonphone/trk/bluetoothlistener.cpp | 2 +- tools/runonphone/trk/bluetoothlistener.h | 4 +- tools/runonphone/trk/bluetoothlistener_gui.cpp | 6 +- tools/runonphone/trk/bluetoothlistener_gui.h | 8 +- tools/runonphone/trk/callback.h | 2 +- tools/runonphone/trk/communicationstarter.h | 8 +- tools/runonphone/trk/launcher.cpp | 25 +++--- tools/runonphone/trk/launcher.h | 2 +- tools/runonphone/trk/symbianutils_global.h | 55 +++++++++++++ tools/runonphone/trk/trk.pri | 4 +- tools/runonphone/trk/trkdevice.cpp | 18 +++-- tools/runonphone/trk/trkdevice.h | 3 +- tools/runonphone/trk/trkutils.cpp | 105 ++++++++++++------------- tools/runonphone/trk/trkutils.h | 45 +++++------ tools/runonphone/trk/trkutils_p.h | 62 +++++++++++++++ 16 files changed, 233 insertions(+), 120 deletions(-) create mode 100644 tools/runonphone/trk/symbianutils_global.h create mode 100644 tools/runonphone/trk/trkutils_p.h diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp index a77e713..1a5cdee 100644 --- a/tools/runonphone/main.cpp +++ b/tools/runonphone/main.cpp @@ -174,11 +174,7 @@ int main(int argc, char *argv[]) } if(loglevel > 0) outstream << "Connecting to target via " << serialPortName << endl; -#ifdef Q_OS_WIN - launcher->setTrkServerName(QString("\\\\.\\") + serialPortName); -#else launcher->setTrkServerName(serialPortName); -#endif launcher->setFileName(QString("c:\\sys\\bin\\") + exeFile); launcher->setCommandLineArgs(cmdLine); diff --git a/tools/runonphone/trk/bluetoothlistener.cpp b/tools/runonphone/trk/bluetoothlistener.cpp index 8d45fb5..df04288 100644 --- a/tools/runonphone/trk/bluetoothlistener.cpp +++ b/tools/runonphone/trk/bluetoothlistener.cpp @@ -184,7 +184,7 @@ bool BluetoothListener::start(const QString &device, QString *errorMessage) return true; } -void BluetoothListener::slotStdOutput() +void BluetoothListener::slotStdOutput() { emitMessage(QString::fromLocal8Bit(d->process.readAllStandardOutput())); } diff --git a/tools/runonphone/trk/bluetoothlistener.h b/tools/runonphone/trk/bluetoothlistener.h index 027f286..36894e7 100644 --- a/tools/runonphone/trk/bluetoothlistener.h +++ b/tools/runonphone/trk/bluetoothlistener.h @@ -42,6 +42,8 @@ #ifndef BLUETOOTHLISTENER_H #define BLUETOOTHLISTENER_H +#include "symbianutils_global.h" + #include #include @@ -53,7 +55,7 @@ struct BluetoothListenerPrivate; * 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 +class SYMBIANUTILS_EXPORT BluetoothListener : public QObject { Q_OBJECT Q_DISABLE_COPY(BluetoothListener) diff --git a/tools/runonphone/trk/bluetoothlistener_gui.cpp b/tools/runonphone/trk/bluetoothlistener_gui.cpp index 6ffdaef..5994eb5 100644 --- a/tools/runonphone/trk/bluetoothlistener_gui.cpp +++ b/tools/runonphone/trk/bluetoothlistener_gui.cpp @@ -50,7 +50,7 @@ namespace trk { -PromptStartCommunicationResult +SYMBIANUTILS_EXPORT PromptStartCommunicationResult promptStartCommunication(BaseCommunicationStarter &starter, const QString &msgBoxTitle, const QString &msgBoxText, @@ -88,7 +88,7 @@ PromptStartCommunicationResult return PromptStartCommunicationConnected; } -PromptStartCommunicationResult +SYMBIANUTILS_EXPORT PromptStartCommunicationResult promptStartSerial(BaseCommunicationStarter &starter, QWidget *msgBoxParent, QString *errorMessage) @@ -98,7 +98,7 @@ PromptStartCommunicationResult return promptStartCommunication(starter, title, message, msgBoxParent, errorMessage); } -PromptStartCommunicationResult +SYMBIANUTILS_EXPORT PromptStartCommunicationResult promptStartBluetooth(BaseCommunicationStarter &starter, QWidget *msgBoxParent, QString *errorMessage) diff --git a/tools/runonphone/trk/bluetoothlistener_gui.h b/tools/runonphone/trk/bluetoothlistener_gui.h index d673ffe..10e7145 100644 --- a/tools/runonphone/trk/bluetoothlistener_gui.h +++ b/tools/runonphone/trk/bluetoothlistener_gui.h @@ -42,6 +42,8 @@ #ifndef BLUETOOTHLISTENER_GUI_H #define BLUETOOTHLISTENER_GUI_H +#include "symbianutils_global.h" + #include QT_BEGIN_NAMESPACE @@ -62,7 +64,7 @@ enum PromptStartCommunicationResult { PromptStartCommunicationError }; -PromptStartCommunicationResult +SYMBIANUTILS_EXPORT PromptStartCommunicationResult promptStartCommunication(BaseCommunicationStarter &starter, const QString &msgBoxTitle, const QString &msgBoxText, @@ -71,14 +73,14 @@ PromptStartCommunicationResult // Convenience to start a serial connection (messages prompting // to launch Trk). -PromptStartCommunicationResult +SYMBIANUTILS_EXPORT PromptStartCommunicationResult promptStartSerial(BaseCommunicationStarter &starter, QWidget *msgBoxParent, QString *errorMessage); // Convenience to start blue tooth connection (messages // prompting to connect). -PromptStartCommunicationResult +SYMBIANUTILS_EXPORT PromptStartCommunicationResult promptStartBluetooth(BaseCommunicationStarter &starter, QWidget *msgBoxParent, QString *errorMessage); diff --git a/tools/runonphone/trk/callback.h b/tools/runonphone/trk/callback.h index edc2c74..3996d73 100644 --- a/tools/runonphone/trk/callback.h +++ b/tools/runonphone/trk/callback.h @@ -42,7 +42,7 @@ #ifndef DEBUGGER_CALLBACK_H #define DEBUGGER_CALLBACK_H -#include +#include "symbianutils_global.h" namespace trk { namespace Internal { diff --git a/tools/runonphone/trk/communicationstarter.h b/tools/runonphone/trk/communicationstarter.h index 34cf398..2d7dc50 100644 --- a/tools/runonphone/trk/communicationstarter.h +++ b/tools/runonphone/trk/communicationstarter.h @@ -42,6 +42,8 @@ #ifndef COMMUNICATIONSTARTER_H #define COMMUNICATIONSTARTER_H +#include "symbianutils_global.h" + #include #include @@ -60,7 +62,7 @@ struct BaseCommunicationStarterPrivate; * The base class can be used as is to prompt the user to launch App TRK for a * serial communication as this requires no further resource setup. */ -class BaseCommunicationStarter : public QObject { +class SYMBIANUTILS_EXPORT BaseCommunicationStarter : public QObject { Q_OBJECT Q_DISABLE_COPY(BaseCommunicationStarter) public: @@ -117,7 +119,7 @@ private: * implement as a factory function that creates and sets up the * listener (mode, message connection, etc). */ -class AbstractBluetoothStarter : public BaseCommunicationStarter { +class SYMBIANUTILS_EXPORT AbstractBluetoothStarter : public BaseCommunicationStarter { Q_OBJECT Q_DISABLE_COPY(AbstractBluetoothStarter) public: @@ -134,7 +136,7 @@ protected: /* ConsoleBluetoothStarter: Convenience class for console processes. Creates a * listener in "Listen" mode with the messages redirected to standard output. */ -class ConsoleBluetoothStarter : public AbstractBluetoothStarter { +class SYMBIANUTILS_EXPORT ConsoleBluetoothStarter : public AbstractBluetoothStarter { Q_OBJECT Q_DISABLE_COPY(ConsoleBluetoothStarter) public: diff --git a/tools/runonphone/trk/launcher.cpp b/tools/runonphone/trk/launcher.cpp index 1796fc5..4f91545 100644 --- a/tools/runonphone/trk/launcher.cpp +++ b/tools/runonphone/trk/launcher.cpp @@ -41,6 +41,7 @@ #include "launcher.h" #include "trkutils.h" +#include "trkutils_p.h" #include "trkdevice.h" #include "bluetoothlistener.h" @@ -595,17 +596,19 @@ void Launcher::handleSupportMask(const TrkResult &result) return; const char *data = result.data.data() + 1; - QByteArray str; + QString str = QLatin1String("SUPPORTED: "); for (int i = 0; i < 32; ++i) { //str.append(" [" + formatByte(data[i]) + "]: "); - for (int j = 0; j < 8; ++j) - if (data[i] & (1 << j)) - str.append(QByteArray::number(i * 8 + j, 16) + " "); + for (int j = 0; j < 8; ++j) { + if (data[i] & (1 << j)) { + str.append(QString::number(i * 8 + j, 16)); + str.append(QLatin1Char(' ')); + } + } } - logMessage("SUPPORTED: " + str); + logMessage(str); } - void Launcher::cleanUp() { // @@ -614,9 +617,7 @@ void Launcher::cleanUp() // Sub Cmd: Delete Process //ProcessID: 0x0000071F (1823) // [41 24 00 00 00 00 07 1F] - QByteArray ba; - appendByte(&ba, 0x00); - appendByte(&ba, 0x00); + QByteArray ba(2, char(0)); appendInt(&ba, d->m_session.pid); d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process"); @@ -669,7 +670,7 @@ void Launcher::copyFileToRemote() { emit copyingStarted(); QByteArray ba; - appendByte(&ba, 0x10); + ba.append(char(10)); appendString(&ba, d->m_copyState.destinationFileName.toLocal8Bit(), TargetByteOrder, false); d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba); } @@ -678,7 +679,7 @@ void Launcher::installRemotePackageSilently() { emit installingStarted(); QByteArray ba; - appendByte(&ba, 'C'); + ba.append('C'); appendString(&ba, d->m_installFileName.toLocal8Bit(), TargetByteOrder, false); d->m_device->sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba); } @@ -705,7 +706,7 @@ QByteArray Launcher::startProcessMessage(const QString &executable, // It's not started yet QByteArray ba; appendShort(&ba, 0, TargetByteOrder); // create new process - appendByte(&ba, 0); // options - currently unused + ba.append(char(0)); // options - currently unused if(arguments.isEmpty()) { appendString(&ba, executable.toLocal8Bit(), TargetByteOrder); return ba; diff --git a/tools/runonphone/trk/launcher.h b/tools/runonphone/trk/launcher.h index 8dc6ebe..2b23fd8 100644 --- a/tools/runonphone/trk/launcher.h +++ b/tools/runonphone/trk/launcher.h @@ -56,7 +56,7 @@ struct LauncherPrivate; typedef QSharedPointer TrkDevicePtr; -class Launcher : public QObject +class SYMBIANUTILS_EXPORT Launcher : public QObject { Q_OBJECT Q_DISABLE_COPY(Launcher) diff --git a/tools/runonphone/trk/symbianutils_global.h b/tools/runonphone/trk/symbianutils_global.h new file mode 100644 index 0000000..a6ffbe7 --- /dev/null +++ b/tools/runonphone/trk/symbianutils_global.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SYMBIANUTILS_GLOBAL_H +#define SYMBIANUTILS_GLOBAL_H + +#include + +#if defined(SYMBIANUTILS_BUILD_LIB) +# define SYMBIANUTILS_EXPORT Q_DECL_EXPORT +#elif defined(SYMBIANUTILS_BUILD_STATIC_LIB) || defined(SYMBIANUTILS_INCLUDE_PRI) +# define SYMBIANUTILS_EXPORT +#else +# define SYMBIANUTILS_EXPORT Q_DECL_IMPORT +#endif + +#endif // SYMBIANUTILS_GLOBAL_H diff --git a/tools/runonphone/trk/trk.pri b/tools/runonphone/trk/trk.pri index 2ce17c0..a54df76 100644 --- a/tools/runonphone/trk/trk.pri +++ b/tools/runonphone/trk/trk.pri @@ -1,8 +1,10 @@ INCLUDEPATH *= $$PWD # Input -HEADERS += $$PWD/callback.h \ +HEADERS += $$PWD/symbianutils_global.h \ + $$PWD/callback.h \ $$PWD/trkutils.h \ + $$PWD/trkutils_p.h \ $$PWD/trkdevice.h \ $$PWD/launcher.h \ $$PWD/bluetoothlistener.h \ diff --git a/tools/runonphone/trk/trkdevice.cpp b/tools/runonphone/trk/trkdevice.cpp index fe3261b..d587135 100644 --- a/tools/runonphone/trk/trkdevice.cpp +++ b/tools/runonphone/trk/trkdevice.cpp @@ -41,6 +41,7 @@ #include "trkdevice.h" #include "trkutils.h" +#include "trkutils_p.h" #include #include @@ -516,7 +517,7 @@ static inline bool overlappedSyncWrite(HANDLE file, bool WriterThread::write(const QByteArray &data, QString *errorMessage) { if (verboseTrk) - qDebug() << "Write raw data: " << data.toHex(); + qDebug() << "Write raw data: " << stringFromArray(data).toLatin1(); QMutexLocker locker(&m_context->mutex); #ifdef Q_OS_WIN DWORD charsWritten; @@ -856,8 +857,8 @@ void UnixReaderThread::terminate() { // Trigger select() by writing to the pipe char c = 0; - int written = write(m_terminatePipeFileDescriptors[1], &c, 1); - // FIXME: Use result. + const int written = write(m_terminatePipeFileDescriptors[1], &c, 1); + Q_UNUSED(written) wait(); } @@ -919,7 +920,7 @@ bool TrkDevice::open(const QString &port, QString *errorMessage) qDebug() << "Opening" << port << "is open: " << isOpen() << " serialFrame=" << serialFrame(); close(); #ifdef Q_OS_WIN - d->deviceContext->device = CreateFile(port.toStdWString().c_str(), + d->deviceContext->device = CreateFile(QString("\\\\.\\").append(port).toStdWString().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -1061,8 +1062,13 @@ void TrkDevice::sendTrkMessage(byte code, TrkCallback callback, const QByteArray &data, const QVariant &cookie) { if (!d->writerThread.isNull()) { - if (d->verbose > 1) - qDebug() << "Sending " << code << data.toHex(); + if (d->verbose > 1) { + QByteArray msg = "Sending: "; + msg += QByteArray::number(code, 16); + msg += ": "; + msg += stringFromArray(data).toLatin1(); + qDebug("%s", msg.data()); + } d->writerThread->queueTrkMessage(code, callback, data, cookie); } } diff --git a/tools/runonphone/trk/trkdevice.h b/tools/runonphone/trk/trkdevice.h index e04f791..21a3cc1 100644 --- a/tools/runonphone/trk/trkdevice.h +++ b/tools/runonphone/trk/trkdevice.h @@ -42,6 +42,7 @@ #ifndef TRKDEVICE_H #define TRKDEVICE_H +#include "symbianutils_global.h" #include "callback.h" #include @@ -74,7 +75,7 @@ enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f }; typedef trk::Callback TrkCallback; -class TrkDevice : public QObject +class SYMBIANUTILS_EXPORT TrkDevice : public QObject { Q_OBJECT Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame) diff --git a/tools/runonphone/trk/trkutils.cpp b/tools/runonphone/trk/trkutils.cpp index 3a96053..5cce950 100644 --- a/tools/runonphone/trk/trkutils.cpp +++ b/tools/runonphone/trk/trkutils.cpp @@ -86,7 +86,7 @@ void Session::reset() trkAppVersion.reset(); } -QString formatCpu(int major, int minor) +static QString formatCpu(int major, int minor) { //: CPU description of an S60 device //: %1 major verison, %2 minor version @@ -144,13 +144,44 @@ QString Session::deviceDescription(unsigned verbose) const } +QByteArray decode7d(const QByteArray &ba) +{ + QByteArray res; + res.reserve(ba.size()); + for (int i = 0; i < ba.size(); ++i) { + byte c = byte(ba.at(i)); + if (c == 0x7d) { + ++i; + c = 0x20 ^ byte(ba.at(i)); + } + res.append(c); + } + return res; +} + +QByteArray encode7d(const QByteArray &ba) +{ + QByteArray res; + res.reserve(ba.size() + 2); + for (int i = 0; i < ba.size(); ++i) { + byte c = byte(ba.at(i)); + if (c == 0x7e || c == 0x7d) { + res.append(0x7d); + res.append(0x20 ^ c); + } else { + res.append(c); + } + } + return res; +} + // FIXME: Use the QByteArray based version below? -QString stringFromByte(byte c) +static inline QString stringFromByte(byte c) { - return QString("%1 ").arg(c, 2, 16, QChar('0')); + return QString::fromLatin1("%1").arg(c, 2, 16, QChar('0')); } -QString stringFromArray(const QByteArray &ba, int maxLen) +SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen) { QString str; QString ascii; @@ -170,7 +201,7 @@ QString stringFromArray(const QByteArray &ba, int maxLen) return str + " " + ascii; } -QByteArray hexNumber(uint n, int digits) +SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) { QByteArray ba = QByteArray::number(n, 16); if (digits == 0 || ba.size() == digits) @@ -178,7 +209,7 @@ QByteArray hexNumber(uint n, int digits) return QByteArray(digits - ba.size(), '0') + ba; } -QByteArray hexxNumber(uint n, int digits) +SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits) { return "0x" + hexNumber(n, digits); } @@ -200,9 +231,13 @@ void TrkResult::clear() QString TrkResult::toString() const { - QString res = stringFromByte(code) + "[" + stringFromByte(token); - res.chop(1); - return res + "] " + stringFromArray(data); + QString res = stringFromByte(code); + res += QLatin1String(" ["); + res += stringFromByte(token); + res += QLatin1Char(']'); + res += QLatin1Char(' '); + res += stringFromArray(data); + return res; } QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame) @@ -303,12 +338,12 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByt return true; } -ushort extractShort(const char *data) +SYMBIANUTILS_EXPORT ushort extractShort(const char *data) { return byte(data[0]) * 256 + byte(data[1]); } -uint extractInt(const char *data) +SYMBIANUTILS_EXPORT uint extractInt(const char *data) { uint res = byte(data[0]); res *= 256; res += byte(data[1]); @@ -317,7 +352,7 @@ uint extractInt(const char *data) return res; } -QString quoteUnprintableLatin1(const QByteArray &ba) +SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba) { QString res; char buf[10]; @@ -333,49 +368,7 @@ QString quoteUnprintableLatin1(const QByteArray &ba) return res; } -QByteArray decode7d(const QByteArray &ba) -{ - QByteArray res; - res.reserve(ba.size()); - for (int i = 0; i < ba.size(); ++i) { - byte c = byte(ba.at(i)); - if (c == 0x7d) { - ++i; - c = 0x20 ^ byte(ba.at(i)); - } - res.append(c); - } - //if (res != ba) - // logMessage("DECODED: " << stringFromArray(ba) - // << " -> " << stringFromArray(res)); - return res; -} - -QByteArray encode7d(const QByteArray &ba) -{ - QByteArray res; - res.reserve(ba.size() + 2); - for (int i = 0; i < ba.size(); ++i) { - byte c = byte(ba.at(i)); - if (c == 0x7e || c == 0x7d) { - res.append(0x7d); - res.append(0x20 ^ c); - } else { - res.append(c); - } - } - //if (res != ba) - // logMessage("ENCODED: " << stringFromArray(ba) - // << " -> " << stringFromArray(res)); - return res; -} - -void appendByte(QByteArray *ba, byte b) -{ - ba->append(b); -} - -void appendShort(QByteArray *ba, ushort s, Endianness endian) +SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness endian) { if (endian == BigEndian) { ba->append(s / 256); @@ -386,7 +379,7 @@ void appendShort(QByteArray *ba, ushort s, Endianness endian) } } -void appendInt(QByteArray *ba, uint i, Endianness endian) +SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness endian) { const uchar b3 = i % 256; i /= 256; const uchar b2 = i % 256; i /= 256; diff --git a/tools/runonphone/trk/trkutils.h b/tools/runonphone/trk/trkutils.h index 328dd2b..3a485c7 100644 --- a/tools/runonphone/trk/trkutils.h +++ b/tools/runonphone/trk/trkutils.h @@ -42,19 +42,20 @@ #ifndef DEBUGGER_TRK_UTILS #define DEBUGGER_TRK_UTILS +#include "symbianutils_global.h" #include #include #include #include -typedef unsigned char byte; - QT_BEGIN_NAMESPACE class QDateTime; QT_END_NAMESPACE namespace trk { +typedef unsigned char byte; + enum Command { TrkPing = 0x00, TrkConnect = 0x01, @@ -85,17 +86,14 @@ enum Command { TrkNotifyProcessorReset = 0xa7 }; -QByteArray decode7d(const QByteArray &ba); -QByteArray encode7d(const QByteArray &ba); - inline byte extractByte(const char *data) { return *data; } -ushort extractShort(const char *data); -uint extractInt(const char *data); +SYMBIANUTILS_EXPORT ushort extractShort(const char *data); +SYMBIANUTILS_EXPORT uint extractInt(const char *data); -QString quoteUnprintableLatin1(const QByteArray &ba); +SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba); // produces "xx xx xx " -QString stringFromArray(const QByteArray &ba, int maxLen = - 1); +SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen = - 1); enum Endianness { @@ -104,13 +102,11 @@ enum Endianness TargetByteOrder = BigEndian, }; -void appendByte(QByteArray *ba, byte b); -void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder); -void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder); -void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true); -void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness = TargetByteOrder); +SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder); +SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder); +SYMBIANUTILS_EXPORT void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true); -struct Library +struct SYMBIANUTILS_EXPORT Library { Library() {} @@ -119,7 +115,7 @@ struct Library uint dataseg; }; -struct TrkAppVersion +struct SYMBIANUTILS_EXPORT TrkAppVersion { TrkAppVersion(); void reset(); @@ -130,7 +126,7 @@ struct TrkAppVersion int protocolMinor; }; -struct Session +struct SYMBIANUTILS_EXPORT Session { Session(); void reset(); @@ -163,7 +159,7 @@ struct Session QStringList modules; }; -struct TrkResult +struct SYMBIANUTILS_EXPORT TrkResult { TrkResult(); void clear(); @@ -179,15 +175,10 @@ struct TrkResult bool isDebugOutput; }; -// returns a QByteArray containing optionally -// the serial frame [0x01 0x90 ] and 0x7e encoded7d(ba) 0x7e -QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame); -ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame); -bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0); -QByteArray errorMessage(byte code); -QByteArray hexNumber(uint n, int digits = 0); -QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too -uint swapEndian(uint in); +SYMBIANUTILS_EXPORT QByteArray errorMessage(byte code); +SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits = 0); +SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too +SYMBIANUTILS_EXPORT uint swapEndian(uint in); } // namespace trk diff --git a/tools/runonphone/trk/trkutils_p.h b/tools/runonphone/trk/trkutils_p.h new file mode 100644 index 0000000..12b0109 --- /dev/null +++ b/tools/runonphone/trk/trkutils_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEBUGGER_TRK_PRIVATE_UTILS +#define DEBUGGER_TRK_PRIVATE_UTILS + +#include "trkutils.h" +#include "symbianutils_global.h" + +QT_BEGIN_NAMESPACE +class QDateTime; +QT_END_NAMESPACE + +namespace trk { + +void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness = TargetByteOrder); +// returns a QByteArray containing optionally +// the serial frame [0x01 0x90 ] and 0x7e encoded7d(ba) 0x7e +QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame); +bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0); + +} // namespace trk + +#endif // DEBUGGER_TRK_PRIVATE_UTILS -- cgit v0.12 From 9965d0e0484882d905c1f8a3bdf19f6eecd30226 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 9 Feb 2010 11:50:08 +0100 Subject: rename trk -> symbianutils commit 9c2676167a3aaeb99024a22343c3d998f191a75f Author: Friedemann Kleint Date: Fri Feb 5 12:32:32 2010 +0100 src/shared: Rename trk to symbianutils --- tools/runonphone/runonphone.pro | 4 +- .../runonphone/symbianutils/bluetoothlistener.cpp | 224 ++++ tools/runonphone/symbianutils/bluetoothlistener.h | 103 ++ .../symbianutils/bluetoothlistener_gui.cpp | 111 ++ .../symbianutils/bluetoothlistener_gui.h | 89 ++ tools/runonphone/symbianutils/callback.h | 160 +++ .../symbianutils/communicationstarter.cpp | 260 +++++ .../runonphone/symbianutils/communicationstarter.h | 162 +++ tools/runonphone/symbianutils/launcher.cpp | 741 +++++++++++++ tools/runonphone/symbianutils/launcher.h | 179 ++++ tools/runonphone/symbianutils/symbianutils.pri | 25 + .../runonphone/symbianutils/symbianutils_global.h | 55 + tools/runonphone/symbianutils/trkdevice.cpp | 1105 ++++++++++++++++++++ tools/runonphone/symbianutils/trkdevice.h | 134 +++ tools/runonphone/symbianutils/trkutils.cpp | 479 +++++++++ tools/runonphone/symbianutils/trkutils.h | 185 ++++ tools/runonphone/symbianutils/trkutils_p.h | 62 ++ tools/runonphone/trk/bluetoothlistener.cpp | 224 ---- tools/runonphone/trk/bluetoothlistener.h | 103 -- tools/runonphone/trk/bluetoothlistener_gui.cpp | 111 -- tools/runonphone/trk/bluetoothlistener_gui.h | 89 -- tools/runonphone/trk/callback.h | 160 --- tools/runonphone/trk/communicationstarter.cpp | 260 ----- tools/runonphone/trk/communicationstarter.h | 162 --- tools/runonphone/trk/launcher.cpp | 741 ------------- tools/runonphone/trk/launcher.h | 179 ---- tools/runonphone/trk/symbianutils_global.h | 55 - tools/runonphone/trk/trk.pri | 25 - tools/runonphone/trk/trkdevice.cpp | 1105 -------------------- tools/runonphone/trk/trkdevice.h | 134 --- tools/runonphone/trk/trkutils.cpp | 479 --------- tools/runonphone/trk/trkutils.h | 185 ---- tools/runonphone/trk/trkutils_p.h | 62 -- 33 files changed, 4077 insertions(+), 4075 deletions(-) create mode 100644 tools/runonphone/symbianutils/bluetoothlistener.cpp create mode 100644 tools/runonphone/symbianutils/bluetoothlistener.h create mode 100644 tools/runonphone/symbianutils/bluetoothlistener_gui.cpp create mode 100644 tools/runonphone/symbianutils/bluetoothlistener_gui.h create mode 100644 tools/runonphone/symbianutils/callback.h create mode 100644 tools/runonphone/symbianutils/communicationstarter.cpp create mode 100644 tools/runonphone/symbianutils/communicationstarter.h create mode 100644 tools/runonphone/symbianutils/launcher.cpp create mode 100644 tools/runonphone/symbianutils/launcher.h create mode 100644 tools/runonphone/symbianutils/symbianutils.pri create mode 100644 tools/runonphone/symbianutils/symbianutils_global.h create mode 100644 tools/runonphone/symbianutils/trkdevice.cpp create mode 100644 tools/runonphone/symbianutils/trkdevice.h create mode 100644 tools/runonphone/symbianutils/trkutils.cpp create mode 100644 tools/runonphone/symbianutils/trkutils.h create mode 100644 tools/runonphone/symbianutils/trkutils_p.h delete mode 100644 tools/runonphone/trk/bluetoothlistener.cpp delete mode 100644 tools/runonphone/trk/bluetoothlistener.h delete mode 100644 tools/runonphone/trk/bluetoothlistener_gui.cpp delete mode 100644 tools/runonphone/trk/bluetoothlistener_gui.h delete mode 100644 tools/runonphone/trk/callback.h delete mode 100644 tools/runonphone/trk/communicationstarter.cpp delete mode 100644 tools/runonphone/trk/communicationstarter.h delete mode 100644 tools/runonphone/trk/launcher.cpp delete mode 100644 tools/runonphone/trk/launcher.h delete mode 100644 tools/runonphone/trk/symbianutils_global.h delete mode 100644 tools/runonphone/trk/trk.pri delete mode 100644 tools/runonphone/trk/trkdevice.cpp delete mode 100644 tools/runonphone/trk/trkdevice.h delete mode 100644 tools/runonphone/trk/trkutils.cpp delete mode 100644 tools/runonphone/trk/trkutils.h delete mode 100644 tools/runonphone/trk/trkutils_p.h diff --git a/tools/runonphone/runonphone.pro b/tools/runonphone/runonphone.pro index 2c1be98..7bed3e5 100644 --- a/tools/runonphone/runonphone.pro +++ b/tools/runonphone/runonphone.pro @@ -4,7 +4,7 @@ QT -= gui CONFIG += console CONFIG -= app_bundle -include(trk/trk.pri) +include(symbianutils/symbianutils.pri) SOURCES += main.cpp \ trksignalhandler.cpp @@ -12,6 +12,8 @@ SOURCES += main.cpp \ HEADERS += trksignalhandler.h \ serenum.h +DEFINES += SYMBIANUTILS_INCLUDE_PRI + windows { SOURCES += serenum_win.cpp LIBS += -lsetupapi \ diff --git a/tools/runonphone/symbianutils/bluetoothlistener.cpp b/tools/runonphone/symbianutils/bluetoothlistener.cpp new file mode 100644 index 0000000..df04288 --- /dev/null +++ b/tools/runonphone/symbianutils/bluetoothlistener.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bluetoothlistener.h" +#include "trkdevice.h" + +#include + +#ifdef Q_OS_UNIX +# include +# include +#else +# include +#endif + +// Process id helpers. +#ifdef Q_OS_WIN +inline DWORD processId(const QProcess &p) +{ + if (const Q_PID processInfoStruct = p.pid()) + return processInfoStruct->dwProcessId; + return 0; +} +#else +inline Q_PID processId(const QProcess &p) +{ + return p.pid(); +} +#endif + + +enum { debug = 0 }; + +namespace trk { + +struct BluetoothListenerPrivate { + BluetoothListenerPrivate(); + QString device; + QProcess process; +#ifdef Q_OS_WIN + DWORD pid; +#else + Q_PID pid; +#endif + 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(processId(d->process))); + // 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 = processId(d->process); // Forgets it after crash/termination + emitMessage(tr("%1: Bluetooth listener running (%2).").arg(device).arg(processId(d->process))); + 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())); +} + +} // namespace trk diff --git a/tools/runonphone/symbianutils/bluetoothlistener.h b/tools/runonphone/symbianutils/bluetoothlistener.h new file mode 100644 index 0000000..36894e7 --- /dev/null +++ b/tools/runonphone/symbianutils/bluetoothlistener.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BLUETOOTHLISTENER_H +#define BLUETOOTHLISTENER_H + +#include "symbianutils_global.h" + +#include +#include + +namespace trk { +struct BluetoothListenerPrivate; + +/* 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 SYMBIANUTILS_EXPORT 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; +}; + +} // namespace trk + +#endif // BLUETOOTHLISTENER_H diff --git a/tools/runonphone/symbianutils/bluetoothlistener_gui.cpp b/tools/runonphone/symbianutils/bluetoothlistener_gui.cpp new file mode 100644 index 0000000..5994eb5 --- /dev/null +++ b/tools/runonphone/symbianutils/bluetoothlistener_gui.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bluetoothlistener_gui.h" +#include "bluetoothlistener.h" +#include "communicationstarter.h" + +#include +#include +#include +#include + +namespace trk { + +SYMBIANUTILS_EXPORT PromptStartCommunicationResult + promptStartCommunication(BaseCommunicationStarter &starter, + const QString &msgBoxTitle, + const QString &msgBoxText, + QWidget *msgBoxParent, + QString *errorMessage) +{ + errorMessage->clear(); + // Initial connection attempt. + switch (starter.start()) { + case BaseCommunicationStarter::Started: + break; + case BaseCommunicationStarter::ConnectionSucceeded: + return PromptStartCommunicationConnected; + case BaseCommunicationStarter::StartError: + *errorMessage = starter.errorString(); + return PromptStartCommunicationError; + } + // Run the starter with the event loop of a message box, have the box + // closed by the signals of the starter. + QMessageBox messageBox(QMessageBox::Information, msgBoxTitle, msgBoxText, 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 to obtain the state. + switch (starter.state()) { + case AbstractBluetoothStarter::Running: + *errorMessage = QCoreApplication::translate("trk::promptStartCommunication", "Connection on %1 canceled.").arg(starter.device()); + return PromptStartCommunicationCanceled; + case AbstractBluetoothStarter::TimedOut: + *errorMessage = starter.errorString(); + return PromptStartCommunicationError; + case AbstractBluetoothStarter::Connected: + break; + } + return PromptStartCommunicationConnected; +} + +SYMBIANUTILS_EXPORT PromptStartCommunicationResult + promptStartSerial(BaseCommunicationStarter &starter, + QWidget *msgBoxParent, + QString *errorMessage) +{ + const QString title = QCoreApplication::translate("trk::promptStartCommunication", "Waiting for App TRK"); + const QString message = QCoreApplication::translate("trk::promptStartCommunication", "Waiting for App TRK to start on %1...").arg(starter.device()); + return promptStartCommunication(starter, title, message, msgBoxParent, errorMessage); +} + +SYMBIANUTILS_EXPORT PromptStartCommunicationResult + promptStartBluetooth(BaseCommunicationStarter &starter, + QWidget *msgBoxParent, + QString *errorMessage) +{ + const QString title = QCoreApplication::translate("trk::promptStartCommunication", "Waiting for Bluetooth Connection"); + const QString message = QCoreApplication::translate("trk::promptStartCommunication", "Connecting to %1...").arg(starter.device()); + return promptStartCommunication(starter, title, message, msgBoxParent, errorMessage); +} + +} // namespace trk diff --git a/tools/runonphone/symbianutils/bluetoothlistener_gui.h b/tools/runonphone/symbianutils/bluetoothlistener_gui.h new file mode 100644 index 0000000..10e7145 --- /dev/null +++ b/tools/runonphone/symbianutils/bluetoothlistener_gui.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BLUETOOTHLISTENER_GUI_H +#define BLUETOOTHLISTENER_GUI_H + +#include "symbianutils_global.h" + +#include + +QT_BEGIN_NAMESPACE +class QWidget; +QT_END_NAMESPACE + +namespace trk { +class BaseCommunicationStarter; + +/* promptStartCommunication(): Convenience functions that + * prompt the user to start a communication (launching or + * connecting TRK) using a modal message box in which they can cancel. + * Pass in the starter with device and parameters set up. */ + +enum PromptStartCommunicationResult { + PromptStartCommunicationConnected, + PromptStartCommunicationCanceled, + PromptStartCommunicationError +}; + +SYMBIANUTILS_EXPORT PromptStartCommunicationResult + promptStartCommunication(BaseCommunicationStarter &starter, + const QString &msgBoxTitle, + const QString &msgBoxText, + QWidget *msgBoxParent, + QString *errorMessage); + +// Convenience to start a serial connection (messages prompting +// to launch Trk). +SYMBIANUTILS_EXPORT PromptStartCommunicationResult + promptStartSerial(BaseCommunicationStarter &starter, + QWidget *msgBoxParent, + QString *errorMessage); + +// Convenience to start blue tooth connection (messages +// prompting to connect). +SYMBIANUTILS_EXPORT PromptStartCommunicationResult + promptStartBluetooth(BaseCommunicationStarter &starter, + QWidget *msgBoxParent, + QString *errorMessage); +} // namespace trk + +#endif // BLUETOOTHLISTENER_GUI_H diff --git a/tools/runonphone/symbianutils/callback.h b/tools/runonphone/symbianutils/callback.h new file mode 100644 index 0000000..3996d73 --- /dev/null +++ b/tools/runonphone/symbianutils/callback.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEBUGGER_CALLBACK_H +#define DEBUGGER_CALLBACK_H + +#include "symbianutils_global.h" + +namespace trk { +namespace Internal { + +/* Helper class for the 1-argument functor: + * Cloneable base class for the implementation which is + * invokeable with the argument. */ +template +class CallbackImplBase +{ + Q_DISABLE_COPY(CallbackImplBase) +public: + CallbackImplBase() {} + virtual CallbackImplBase *clone() const = 0; + virtual void invoke(Argument a) = 0; + virtual ~CallbackImplBase() {} +}; + +/* Helper class for the 1-argument functor: Implementation for + * a class instance with a member function pointer. */ +template +class CallbackMemberPtrImpl : public CallbackImplBase +{ +public: + typedef void (Class::*MemberFuncPtr)(Argument); + + CallbackMemberPtrImpl(Class *instance, + MemberFuncPtr memberFunc) : + m_instance(instance), + m_memberFunc(memberFunc) {} + + virtual CallbackImplBase *clone() const + { + return new CallbackMemberPtrImpl(m_instance, m_memberFunc); + } + + virtual void invoke(Argument a) + { (m_instance->*m_memberFunc)(a); } +private: + Class *m_instance; + MemberFuncPtr m_memberFunc; +}; + +} // namespace Internal + +/* Default-constructible, copyable 1-argument functor providing an + * operator()(Argument) that invokes a member function of a class: + * \code +class Foo { +public: + void print(const std::string &); +}; +... +Foo foo; +Callback f1(&foo, &Foo::print); +f1("test"); +\endcode */ + +template +class Callback +{ +public: + Callback() : m_impl(0) {} + + template + Callback(Class *instance, void (Class::*memberFunc)(Argument)) : + m_impl(new Internal::CallbackMemberPtrImpl(instance, memberFunc)) + {} + + ~Callback() + { + clean(); + } + + Callback(const Callback &rhs) : + m_impl(0) + { + if (rhs.m_impl) + m_impl = rhs.m_impl->clone(); + } + + Callback &operator=(const Callback &rhs) + { + if (this != &rhs) { + clean(); + if (rhs.m_impl) + m_impl = rhs.m_impl->clone(); + } + return *this; + } + + bool isNull() const { return m_impl == 0; } + operator bool() const { return !isNull(); } + + void operator()(Argument a) + { + if (m_impl) + m_impl->invoke(a); + } + +private: + void clean() + { + if (m_impl) { + delete m_impl; + m_impl = 0; + } + } + + Internal::CallbackImplBase *m_impl; +}; + +} // namespace trk + +#endif // DEBUGGER_CALLBACK_H diff --git a/tools/runonphone/symbianutils/communicationstarter.cpp b/tools/runonphone/symbianutils/communicationstarter.cpp new file mode 100644 index 0000000..e5e556e --- /dev/null +++ b/tools/runonphone/symbianutils/communicationstarter.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "communicationstarter.h" +#include "bluetoothlistener.h" +#include "trkdevice.h" + +#include +#include + +namespace trk { + +// --------------- AbstractBluetoothStarter +struct BaseCommunicationStarterPrivate { + explicit BaseCommunicationStarterPrivate(const BaseCommunicationStarter::TrkDevicePtr &d); + + const BaseCommunicationStarter::TrkDevicePtr trkDevice; + BluetoothListener *listener; + QTimer *timer; + int intervalMS; + int attempts; + int n; + QString device; + QString errorString; + BaseCommunicationStarter::State state; +}; + +BaseCommunicationStarterPrivate::BaseCommunicationStarterPrivate(const BaseCommunicationStarter::TrkDevicePtr &d) : + trkDevice(d), + listener(0), + timer(0), + intervalMS(1000), + attempts(-1), + n(0), + device(QLatin1String("/dev/rfcomm0")), + state(BaseCommunicationStarter::TimedOut) +{ +} + +BaseCommunicationStarter::BaseCommunicationStarter(const TrkDevicePtr &trkDevice, QObject *parent) : + QObject(parent), + d(new BaseCommunicationStarterPrivate(trkDevice)) +{ +} + +BaseCommunicationStarter::~BaseCommunicationStarter() +{ + stopTimer(); + delete d; +} + +void BaseCommunicationStarter::stopTimer() +{ + if (d->timer && d->timer->isActive()) + d->timer->stop(); +} + +bool BaseCommunicationStarter::initializeStartupResources(QString *errorMessage) +{ + errorMessage->clear(); + return true; +} + +BaseCommunicationStarter::StartResult BaseCommunicationStarter::start() +{ + if (state() == Running) { + d->errorString = QLatin1String("Internal error, attempt to re-start BaseCommunicationStarter.\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; + // Pull up resources for next attempt + d->n = 0; + if (!initializeStartupResources(&(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; +} + +BaseCommunicationStarter::State BaseCommunicationStarter::state() const +{ + return d->state; +} + +int BaseCommunicationStarter::intervalMS() const +{ + return d->intervalMS; +} + +void BaseCommunicationStarter::setIntervalMS(int i) +{ + d->intervalMS = i; + if (d->timer) + d->timer->setInterval(i); +} + +int BaseCommunicationStarter::attempts() const +{ + return d->attempts; +} + +void BaseCommunicationStarter::setAttempts(int a) +{ + d->attempts = a; +} + +QString BaseCommunicationStarter::device() const +{ + return d->device; +} + +void BaseCommunicationStarter::setDevice(const QString &dv) +{ + d->device = dv; +} + +QString BaseCommunicationStarter::errorString() const +{ + return d->errorString; +} + +void BaseCommunicationStarter::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); + emit message(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); + emit message(msg); + } + } +} + +// --------------- AbstractBluetoothStarter + +AbstractBluetoothStarter::AbstractBluetoothStarter(const TrkDevicePtr &trkDevice, QObject *parent) : + BaseCommunicationStarter(trkDevice, parent) +{ +} + +bool AbstractBluetoothStarter::initializeStartupResources(QString *errorMessage) +{ + // Create the listener and forward messages to it. + BluetoothListener *listener = createListener(); + connect(this, SIGNAL(message(QString)), listener, SLOT(emitMessage(QString))); + return listener->start(device(), errorMessage); +} + +// -------- 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/tools/runonphone/symbianutils/communicationstarter.h b/tools/runonphone/symbianutils/communicationstarter.h new file mode 100644 index 0000000..2d7dc50 --- /dev/null +++ b/tools/runonphone/symbianutils/communicationstarter.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMMUNICATIONSTARTER_H +#define COMMUNICATIONSTARTER_H + +#include "symbianutils_global.h" + +#include +#include + +namespace trk { +class TrkDevice; +class BluetoothListener; +struct BaseCommunicationStarterPrivate; + +/* BaseCommunicationStarter: A QObject that repeatedly tries to open a + * trk device until a connection succeeds or a timeout occurs (emitting + * signals), allowing to do something else in the foreground (local event loop + * [say QMessageBox] or some asynchronous operation). If the initial + * connection attempt in start() fails, the + * virtual initializeStartupResources() is called to initialize resources + * required to pull up the communication (namely Bluetooth listeners). + * The base class can be used as is to prompt the user to launch App TRK for a + * serial communication as this requires no further resource setup. */ + +class SYMBIANUTILS_EXPORT BaseCommunicationStarter : public QObject { + Q_OBJECT + Q_DISABLE_COPY(BaseCommunicationStarter) +public: + typedef QSharedPointer TrkDevicePtr; + + enum State { Running, Connected, TimedOut }; + + explicit BaseCommunicationStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); + virtual ~BaseCommunicationStarter(); + + 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(); + void message(const QString &); + +private slots: + void slotTimer(); + +protected: + virtual bool initializeStartupResources(QString *errorMessage); + +private: + inline void stopTimer(); + + BaseCommunicationStarterPrivate *d; +}; + +/* AbstractBluetoothStarter: Repeatedly tries to open a trk Bluetooth + * device. Note that in case a Listener is already running mode, the + * connection will succeed immediately. + * initializeStartupResources() is implemented to fire up the listener. + * Introduces a new virtual createListener() that derived classes must + * implement as a factory function that creates and sets up the + * listener (mode, message connection, etc). */ + +class SYMBIANUTILS_EXPORT AbstractBluetoothStarter : public BaseCommunicationStarter { + Q_OBJECT + Q_DISABLE_COPY(AbstractBluetoothStarter) +public: + +protected: + explicit AbstractBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); + + // Implemented to fire up the listener. + virtual bool initializeStartupResources(QString *errorMessage); + // New virtual: Overwrite to create and parametrize the listener. + virtual BluetoothListener *createListener() = 0; +}; + +/* ConsoleBluetoothStarter: Convenience class for console processes. Creates a + * listener in "Listen" mode with the messages redirected to standard output. */ + +class SYMBIANUTILS_EXPORT 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 // COMMUNICATIONSTARTER_H diff --git a/tools/runonphone/symbianutils/launcher.cpp b/tools/runonphone/symbianutils/launcher.cpp new file mode 100644 index 0000000..4f91545 --- /dev/null +++ b/tools/runonphone/symbianutils/launcher.cpp @@ -0,0 +1,741 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "launcher.h" +#include "trkutils.h" +#include "trkutils_p.h" +#include "trkdevice.h" +#include "bluetoothlistener.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace trk { + +struct LauncherPrivate { + struct CopyState { + QString sourceFileName; + QString destinationFileName; + uint copyFileHandle; + QScopedPointer data; + int position; + }; + + explicit LauncherPrivate(const TrkDevicePtr &d); + + TrkDevicePtr m_device; + QString m_trkServerName; + QByteArray m_trkReadBuffer; + Launcher::State m_state; + + void logMessage(const QString &msg); + // Debuggee state + Session m_session; // global-ish data (process id, target information) + + CopyState m_copyState; + QString m_fileName; + QStringList m_commandLineArgs; + QString m_installFileName; + int m_verbose; + Launcher::Actions m_startupActions; + bool m_closeDevice; +}; + +LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) : + m_device(d), + m_state(Launcher::Disconnected), + m_verbose(0), + m_closeDevice(true) +{ + if (m_device.isNull()) + m_device = TrkDevicePtr(new TrkDevice); +} + +Launcher::Launcher(Actions startupActions, + const TrkDevicePtr &dev, + QObject *parent) : + QObject(parent), + d(new LauncherPrivate(dev)) +{ + d->m_startupActions = startupActions; + connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult))); + connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); +} + +Launcher::~Launcher() +{ + logMessage("Shutting down.\n"); + delete d; +} + +Launcher::State Launcher::state() const +{ + return d->m_state; +} + +void Launcher::setState(State s) +{ + if (s != d->m_state) { + d->m_state = s; + emit stateChanged(s); + } +} + +void Launcher::addStartupActions(trk::Launcher::Actions startupActions) +{ + d->m_startupActions = Actions(d->m_startupActions | startupActions); +} + +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; +} + +void Launcher::setCopyFileName(const QString &srcName, const QString &dstName) +{ + d->m_copyState.sourceFileName = srcName; + d->m_copyState.destinationFileName = dstName; +} + +void Launcher::setInstallFileName(const QString &name) +{ + d->m_installFileName = name; +} + +void Launcher::setCommandLineArgs(const QStringList &args) +{ + d->m_commandLineArgs = args; +} + +void Launcher::setSerialFrame(bool b) +{ + d->m_device->setSerialFrame(b); +} + +bool Launcher::serialFrame() const +{ + 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 Arguments=%3 Package=%4 Remote Package=%5 Install file=%6") + .arg(d->m_trkServerName, d->m_fileName, + d->m_commandLineArgs.join(QString(QLatin1Char(' '))), + d->m_copyState.sourceFileName, d->m_copyState.destinationFileName, d->m_installFileName); + logMessage(msg); + } + if (d->m_startupActions & ActionCopy) { + if (d->m_copyState.sourceFileName.isEmpty()) { + qWarning("No local filename given for copying package."); + return false; + } else if (d->m_copyState.destinationFileName.isEmpty()) { + qWarning("No remote filename given for copying package."); + return false; + } + } + if (d->m_startupActions & ActionInstall && d->m_installFileName.isEmpty()) { + qWarning("No package name given for installing."); + return false; + } + if (d->m_startupActions & ActionRun && d->m_fileName.isEmpty()) { + qWarning("No remote executable given for running."); + return false; + } + if (!d->m_device->isOpen() && !d->m_device->open(d->m_trkServerName, errorMessage)) + return false; + if (d->m_closeDevice) { + connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); + } else { + disconnect(this, SIGNAL(finished()), d->m_device.data(), 0); + } + setState(Connecting); + // Set up the temporary 'waiting' state if we do not get immediate connection + QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk())); + 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)); + return true; +} + +void Launcher::slotWaitingForTrk() +{ + // Set temporary state if we are still in connected state + if (state() == Connecting) + setState(WaitingForTrk); +} + +void Launcher::handleConnect(const TrkResult &result) +{ + if (result.errorCode()) { + emit canNotConnect(result.errorString()); + return; + } + setState(Connected); + if (d->m_startupActions & ActionCopy) + copyFileToRemote(); + else if (d->m_startupActions & ActionInstall) + installRemotePackageSilently(); + else if (d->m_startupActions & ActionRun) + startInferiorIfNeeded(); +} + +void Launcher::setVerbose(int v) +{ + d->m_verbose = v; + d->m_device->setVerbose(v); +} + +void Launcher::logMessage(const QString &msg) +{ + if (d->m_verbose) + qDebug() << "LAUNCHER: " << qPrintable(msg); +} + +void Launcher::terminate() +{ + switch (state()) { + case DeviceDescriptionReceived: + case Connected: + if (d->m_session.pid) { + QByteArray ba; + appendShort(&ba, 0x0000, TargetByteOrder); + appendInt(&ba, d->m_session.pid, TargetByteOrder); + d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); + return; + } + if (d->m_copyState.copyFileHandle) + closeRemoteFile(true); + disconnectTrk(); + break; + case Disconnected: + break; + case Connecting: + case WaitingForTrk: + setState(Disconnected); + emit finished(); + break; + } +} + +void Launcher::handleRemoteProcessKilled(const TrkResult &result) +{ + Q_UNUSED(result) + disconnectTrk(); +} + +QString Launcher::msgStopped(uint pid, uint tid, uint address, const QString &why) +{ + return QString::fromLatin1("Process %1, thread %2 stopped at 0x%3: %4"). + arg(pid).arg(tid).arg(address, 0, 16). + arg(why.isEmpty() ? QString::fromLatin1("") : why); +} + +bool Launcher::parseNotifyStopped(const QByteArray &dataBA, + uint *pid, uint *tid, uint *address, + QString *why /* = 0 */) +{ + if (why) + why->clear(); + *address = *pid = *tid = 0; + if (dataBA.size() < 12) + return false; + const char *data = dataBA.data(); + *address = extractInt(data); + *pid = extractInt(data + 4); + *tid = extractInt(data + 8); + if (why && dataBA.size() >= 14) { + const unsigned short len = extractShort(data + 12); + if (len > 0) + *why = QString::fromLatin1(data + 14, len); + } + return true; +} + +void Launcher::handleResult(const TrkResult &result) +{ + QByteArray prefix = "READ BUF: "; + QByteArray str = result.toString().toUtf8(); + if (result.isDebugOutput) { // handle application output + logMessage("APPLICATION OUTPUT: " + result.data); + emit applicationOutputReceived(result.data); + return; + } + switch (result.code) { + case TrkNotifyAck: + break; + case TrkNotifyNak: { // NAK + logMessage(prefix + "NAK: " + str); + //logMessage(prefix << "TOKEN: " << result.token); + logMessage(prefix + "ERROR: " + errorMessage(result.data.at(0))); + break; + } + case TrkNotifyStopped: { // Notified Stopped + QString reason; + uint pc; + uint pid; + uint tid; + parseNotifyStopped(result.data, &pid, &tid, &pc, &reason); + logMessage(prefix + msgStopped(pid, tid, pc, reason)); + emit(processStopped(pc, pid, tid, reason)); + d->m_device->sendTrkAck(result.token); + break; + } + case TrkNotifyException: { // Notify Exception (obsolete) + logMessage(prefix + "NOTE: EXCEPTION " + str); + d->m_device->sendTrkAck(result.token); + break; + } + case TrkNotifyInternalError: { // + logMessage(prefix + "NOTE: INTERNAL ERROR: " + str); + d->m_device->sendTrkAck(result.token); + break; + } + + // target->host OS notification + case TrkNotifyCreated: { // Notify Created + /* + const char *data = result.data.data(); + byte error = result.data.at(0); + byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2. + uint pid = extractInt(data + 2); // ProcessID: 4 bytes; + uint tid = extractInt(data + 6); //threadID: 4 bytes + uint codeseg = extractInt(data + 10); //code address: 4 bytes; code base address for the library + uint dataseg = extractInt(data + 14); //data address: 4 bytes; data base address for the library + uint len = extractShort(data + 18); //length: 2 bytes; length of the library name string to follow + QByteArray name = result.data.mid(20, len); // name: library name + + logMessage(prefix + "NOTE: LIBRARY LOAD: " + str); + logMessage(prefix + "TOKEN: " + result.token); + logMessage(prefix + "ERROR: " + int(error)); + logMessage(prefix + "TYPE: " + int(type)); + logMessage(prefix + "PID: " + pid); + logMessage(prefix + "TID: " + tid); + logMessage(prefix + "CODE: " + codeseg); + logMessage(prefix + "DATA: " + dataseg); + logMessage(prefix + "LEN: " + len); + logMessage(prefix + "NAME: " + name); + */ + + if (result.data.size() < 10) + break; + QByteArray ba; + ba.append(result.data.mid(2, 8)); + d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); + //d->m_device->sendTrkAck(result.token) + break; + } + case TrkNotifyDeleted: { // NotifyDeleted + const ushort itemType = (unsigned char)result.data.at(1); + const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0); + const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString(); + 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); + if (itemType == 0 // process + && result.data.size() >= 10 + && d->m_session.pid == extractInt(result.data.data() + 6)) { + disconnectTrk(); + } + break; + } + case TrkNotifyProcessorStarted: { // NotifyProcessorStarted + logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str); + d->m_device->sendTrkAck(result.token); + break; + } + case TrkNotifyProcessorStandBy: { // NotifyProcessorStandby + logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str); + d->m_device->sendTrkAck(result.token); + break; + } + case TrkNotifyProcessorReset: { // NotifyProcessorReset + logMessage(prefix + "NOTE: PROCESSOR RESET: " + str); + d->m_device->sendTrkAck(result.token); + break; + } + default: { + logMessage(prefix + "INVALID: " + str); + break; + } + } +} + +QString Launcher::deviceDescription(unsigned verbose) const +{ + return d->m_session.deviceDescription(verbose); +} + +void Launcher::handleTrkVersion(const TrkResult &result) +{ + if (result.errorCode() || result.data.size() < 5) { + if (d->m_startupActions == ActionPingOnly) { + setState(Disconnected); + emit finished(); + } + return; + } + d->m_session.trkAppVersion.trkMajor = result.data.at(1); + d->m_session.trkAppVersion.trkMinor = result.data.at(2); + d->m_session.trkAppVersion.protocolMajor = result.data.at(3); + d->m_session.trkAppVersion.protocolMinor = result.data.at(4); + setState(DeviceDescriptionReceived); + // Ping mode: Log & Terminate + if (d->m_startupActions == ActionPingOnly) { + qWarning("%s", qPrintable(deviceDescription())); + setState(Disconnected); + emit finished(); + } +} + +void Launcher::handleFileCreation(const TrkResult &result) +{ + if (result.errorCode() || result.data.size() < 6) { + emit canNotCreateFile(d->m_copyState.destinationFileName, result.errorString()); + disconnectTrk(); + return; + } + const char *data = result.data.data(); + d->m_copyState.copyFileHandle = extractInt(data + 2); + QFile file(d->m_copyState.sourceFileName); + file.open(QIODevice::ReadOnly); + d->m_copyState.data.reset(new QByteArray(file.readAll())); + d->m_copyState.position = 0; + file.close(); + continueCopying(); +} + +void Launcher::handleCopy(const TrkResult &result) +{ + if (result.errorCode() || result.data.size() < 4) { + closeRemoteFile(true); + emit canNotWriteFile(d->m_copyState.destinationFileName, result.errorString()); + disconnectTrk(); + } else { + continueCopying(extractShort(result.data.data() + 2)); + } +} + +void Launcher::continueCopying(uint lastCopiedBlockSize) +{ + int size = d->m_copyState.data->length(); + d->m_copyState.position += lastCopiedBlockSize; + if (size == 0) + emit copyProgress(100); + else { + int percent = qMin((d->m_copyState.position*100)/size, 100); + emit copyProgress(percent); + } + if (d->m_copyState.position < size) { + 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); + } else { + closeRemoteFile(); + } +} + +void Launcher::closeRemoteFile(bool failed) +{ + QByteArray ba; + appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder); + appendDateTime(&ba, QDateTime::currentDateTime(), TargetByteOrder); + d->m_device->sendTrkMessage(TrkCloseFile, + failed ? TrkCallback() : TrkCallback(this, &Launcher::handleFileCopied), + ba); + d->m_copyState.data.reset(); + d->m_copyState.copyFileHandle = 0; + d->m_copyState.position = 0; +} + +void Launcher::handleFileCopied(const TrkResult &result) +{ + if (result.errorCode()) + emit canNotCloseFile(d->m_copyState.destinationFileName, result.errorString()); + if (d->m_startupActions & ActionInstall) + installRemotePackageSilently(); + else if (d->m_startupActions & ActionRun) + startInferiorIfNeeded(); + else + disconnectTrk(); +} + +void Launcher::handleCpuType(const TrkResult &result) +{ + logMessage("HANDLE CPU TYPE: " + result.toString()); + if(result.errorCode() || result.data.size() < 7) + return; + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 03 00 04 00 00 04 00 00 00] + d->m_session.cpuMajor = result.data.at(1); + d->m_session.cpuMinor = result.data.at(2); + d->m_session.bigEndian = result.data.at(3); + d->m_session.defaultTypeSize = result.data.at(4); + d->m_session.fpTypeSize = result.data.at(5); + d->m_session.extended1TypeSize = result.data.at(6); + //d->m_session.extended2TypeSize = result.data[6]; +} + +void Launcher::handleCreateProcess(const TrkResult &result) +{ + if (result.errorCode()) { + emit canNotRun(result.errorString()); + disconnectTrk(); + return; + } + // 40 00 00] + //logMessage(" RESULT: " + result.toString()); + // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] + const char *data = result.data.data(); + d->m_session.pid = extractInt(data + 1); + d->m_session.tid = extractInt(data + 5); + d->m_session.codeseg = extractInt(data + 9); + d->m_session.dataseg = extractInt(data + 13); + if (d->m_verbose) { + const QString msg = QString::fromLatin1("Process id: %1 Thread id: %2 code: 0x%3 data: 0x%4"). + arg(d->m_session.pid).arg(d->m_session.tid).arg(d->m_session.codeseg, 0, 16). + arg(d->m_session.dataseg, 0 ,16); + logMessage(msg); + } + emit applicationRunning(d->m_session.pid); + QByteArray ba; + appendInt(&ba, d->m_session.pid); + appendInt(&ba, d->m_session.tid); + d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); +} + +void Launcher::handleWaitForFinished(const TrkResult &result) +{ + logMessage(" FINISHED: " + stringFromArray(result.data)); + setState(Disconnected); + emit finished(); +} + +void Launcher::handleSupportMask(const TrkResult &result) +{ + if (result.errorCode() || result.data.size() < 32) + return; + const char *data = result.data.data() + 1; + + QString str = QLatin1String("SUPPORTED: "); + for (int i = 0; i < 32; ++i) { + //str.append(" [" + formatByte(data[i]) + "]: "); + for (int j = 0; j < 8; ++j) { + if (data[i] & (1 << j)) { + str.append(QString::number(i * 8 + j, 16)); + str.append(QLatin1Char(' ')); + } + } + } + logMessage(str); +} + +void Launcher::cleanUp() +{ + // + //---IDE------------------------------------------------------ + // Command: 0x41 Delete Item + // Sub Cmd: Delete Process + //ProcessID: 0x0000071F (1823) + // [41 24 00 00 00 00 07 1F] + QByteArray ba(2, char(0)); + appendInt(&ba, d->m_session.pid); + d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process"); + + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 24 00] + + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 25 00 00 00 0A 78 6A 43 40] + + //---TRK------------------------------------------------------ + // Command: 0xA1 Notify Deleted + // [A1 09 00 00 00 00 00 00 00 00 07 1F] + //---IDE------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00] + + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 25 00] + + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 26 00 00 00 0B 78 6A 43 70] + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 26 00] + + + //---IDE------------------------------------------------------ + // Command: 0x02 Disconnect + // [02 27] +// sendTrkMessage(0x02, TrkCallback(this, &Launcher::handleDisconnect)); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 +} + +void Launcher::disconnectTrk() +{ + d->m_device->sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished)); +} + +void Launcher::copyFileToRemote() +{ + emit copyingStarted(); + QByteArray ba; + ba.append(char(10)); + appendString(&ba, d->m_copyState.destinationFileName.toLocal8Bit(), TargetByteOrder, false); + d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba); +} + +void Launcher::installRemotePackageSilently() +{ + emit installingStarted(); + QByteArray ba; + ba.append('C'); + appendString(&ba, d->m_installFileName.toLocal8Bit(), TargetByteOrder, false); + d->m_device->sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba); +} + +void Launcher::handleInstallPackageFinished(const TrkResult &result) +{ + if (result.errorCode()) { + emit canNotInstall(d->m_installFileName, result.errorString()); + disconnectTrk(); + return; + } else { + emit installingFinished(); + } + if (d->m_startupActions & ActionRun) { + startInferiorIfNeeded(); + } else { + disconnectTrk(); + } +} + +QByteArray Launcher::startProcessMessage(const QString &executable, + const QStringList &arguments) +{ + // It's not started yet + QByteArray ba; + appendShort(&ba, 0, TargetByteOrder); // create new process + ba.append(char(0)); // options - currently unused + if(arguments.isEmpty()) { + appendString(&ba, executable.toLocal8Bit(), TargetByteOrder); + return ba; + } + // Append full command line as one string (leading length information). + QByteArray commandLineBa; + commandLineBa.append(executable.toLocal8Bit()); + commandLineBa.append('\0'); + commandLineBa.append(arguments.join(QString(QLatin1Char(' '))).toLocal8Bit()); + appendString(&ba, commandLineBa, TargetByteOrder); + return ba; +} + +void Launcher::startInferiorIfNeeded() +{ + emit startingApplication(); + if (d->m_session.pid != 0) { + logMessage("Process already 'started'"); + return; + } + d->m_device->sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), + startProcessMessage(d->m_fileName, d->m_commandLineArgs)); // Create Item +} + +void Launcher::resumeProcess(uint pid, uint tid) +{ + QByteArray ba; + appendInt(&ba, pid, BigEndian); + appendInt(&ba, tid, BigEndian); + d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); +} +} // namespace trk diff --git a/tools/runonphone/symbianutils/launcher.h b/tools/runonphone/symbianutils/launcher.h new file mode 100644 index 0000000..2b23fd8 --- /dev/null +++ b/tools/runonphone/symbianutils/launcher.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LAUNCHER_H +#define LAUNCHER_H + +#include "trkdevice.h" + +#include +#include +#include + +namespace trk { + +struct TrkResult; +struct TrkMessage; +struct LauncherPrivate; + +typedef QSharedPointer TrkDevicePtr; + +class SYMBIANUTILS_EXPORT Launcher : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(Launcher) +public: + typedef void (Launcher::*TrkCallBack)(const TrkResult &); + + enum Actions { + ActionPingOnly = 0x0, + ActionCopy = 0x1, + ActionInstall = 0x2, + ActionCopyInstall = ActionCopy | ActionInstall, + ActionRun = 0x4, + ActionCopyRun = ActionCopy | ActionRun, + ActionInstallRun = ActionInstall | ActionRun, + ActionCopyInstallRun = ActionCopy | ActionInstall | ActionRun + }; + + enum State { Disconnected, Connecting, Connected, + WaitingForTrk, // This occurs only if the initial ping times out after + // a reasonable timeout, indicating that Trk is not + // running. Note that this will never happen with + // Bluetooth as communication immediately starts + // after connecting. + DeviceDescriptionReceived }; + + explicit Launcher(trk::Launcher::Actions startupActions = trk::Launcher::ActionPingOnly, + const TrkDevicePtr &trkDevice = TrkDevicePtr(), + QObject *parent = 0); + ~Launcher(); + + State state() const; + + 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); + void setCommandLineArgs(const QStringList &args); + bool startServer(QString *errorMessage); + 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; + + static QByteArray startProcessMessage(const QString &executable, + const QStringList &arguments); + // Parse a TrkNotifyStopped message + static bool parseNotifyStopped(const QByteArray &a, + uint *pid, uint *tid, uint *address, + QString *why = 0); + // Helper message + static QString msgStopped(uint pid, uint tid, uint address, const QString &why); + +signals: + void copyingStarted(); + void canNotConnect(const QString &errorMessage); + void canNotCreateFile(const QString &filename, const QString &errorMessage); + void canNotWriteFile(const QString &filename, const QString &errorMessage); + void canNotCloseFile(const QString &filename, const QString &errorMessage); + void installingStarted(); + void canNotInstall(const QString &packageFilename, const QString &errorMessage); + void installingFinished(); + void startingApplication(); + void applicationRunning(uint pid); + void canNotRun(const QString &errorMessage); + void finished(); + void applicationOutputReceived(const QString &output); + void copyProgress(int percent); + void stateChanged(int); + void processStopped(uint pc, uint pid, uint tid, const QString& reason); + +public slots: + void terminate(); + void resumeProcess(uint pid, uint tid); + +private slots: + void handleResult(const trk::TrkResult &data); + void slotWaitingForTrk(); + +private: + // kill process and breakpoints + void cleanUp(); + void disconnectTrk(); + + void handleRemoteProcessKilled(const TrkResult &result); + void handleConnect(const TrkResult &result); + void handleFileCreation(const TrkResult &result); + void handleCopy(const TrkResult &result); + void continueCopying(uint lastCopiedBlockSize = 0); + void closeRemoteFile(bool failed = false); + void handleFileCopied(const TrkResult &result); + void handleInstallPackageFinished(const TrkResult &result); + void handleCpuType(const TrkResult &result); + void handleCreateProcess(const TrkResult &result); + void handleWaitForFinished(const TrkResult &result); + void handleStop(const TrkResult &result); + void handleSupportMask(const TrkResult &result); + void handleTrkVersion(const TrkResult &result); + + void copyFileToRemote(); + void installRemotePackageSilently(); + void startInferiorIfNeeded(); + + void logMessage(const QString &msg); + void setState(State s); + + LauncherPrivate *d; +}; + +} // namespace Trk + +#endif // LAUNCHER_H diff --git a/tools/runonphone/symbianutils/symbianutils.pri b/tools/runonphone/symbianutils/symbianutils.pri new file mode 100644 index 0000000..a54df76 --- /dev/null +++ b/tools/runonphone/symbianutils/symbianutils.pri @@ -0,0 +1,25 @@ +INCLUDEPATH *= $$PWD + +# Input +HEADERS += $$PWD/symbianutils_global.h \ + $$PWD/callback.h \ + $$PWD/trkutils.h \ + $$PWD/trkutils_p.h \ + $$PWD/trkdevice.h \ + $$PWD/launcher.h \ + $$PWD/bluetoothlistener.h \ + $$PWD/communicationstarter.h + +SOURCES += $$PWD/trkutils.cpp \ + $$PWD/trkdevice.cpp \ + $$PWD/launcher.cpp \ + $$PWD/bluetoothlistener.cpp \ + $$PWD/communicationstarter.cpp + +# Tests/trklauncher is a console application +contains(QT, gui) { + HEADERS += $$PWD/bluetoothlistener_gui.h + SOURCES += $$PWD/bluetoothlistener_gui.cpp +} else { + message(Trk: Console ...) +} diff --git a/tools/runonphone/symbianutils/symbianutils_global.h b/tools/runonphone/symbianutils/symbianutils_global.h new file mode 100644 index 0000000..a6ffbe7 --- /dev/null +++ b/tools/runonphone/symbianutils/symbianutils_global.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SYMBIANUTILS_GLOBAL_H +#define SYMBIANUTILS_GLOBAL_H + +#include + +#if defined(SYMBIANUTILS_BUILD_LIB) +# define SYMBIANUTILS_EXPORT Q_DECL_EXPORT +#elif defined(SYMBIANUTILS_BUILD_STATIC_LIB) || defined(SYMBIANUTILS_INCLUDE_PRI) +# define SYMBIANUTILS_EXPORT +#else +# define SYMBIANUTILS_EXPORT Q_DECL_IMPORT +#endif + +#endif // SYMBIANUTILS_GLOBAL_H diff --git a/tools/runonphone/symbianutils/trkdevice.cpp b/tools/runonphone/symbianutils/trkdevice.cpp new file mode 100644 index 0000000..d587135 --- /dev/null +++ b/tools/runonphone/symbianutils/trkdevice.cpp @@ -0,0 +1,1105 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "trkdevice.h" +#include "trkutils.h" +#include "trkutils_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +# include +#else +# include + +# include +# include +# include +# include +# include +# include +# include +/* Required headers for select() according to POSIX.1-2001 */ +# include +/* Required headers for select() according to earlier standards: + #include + #include + #include +*/ +#endif + +#ifdef Q_OS_WIN + +// Format windows error from GetLastError() value: +// TODO: Use the one provided by the utils lib. +QString winErrorMessage(unsigned long error) +{ + QString rc = QString::fromLatin1("#%1: ").arg(error); + ushort *lpMsgBuf; + + const int len = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL); + if (len) { + rc = QString::fromUtf16(lpMsgBuf, len); + LocalFree(lpMsgBuf); + } else { + rc += QString::fromLatin1(""); + } + return rc; +} + +#endif + +enum { verboseTrk = 0 }; + +namespace trk { + +/////////////////////////////////////////////////////////////////////// +// +// TrkMessage +// +/////////////////////////////////////////////////////////////////////// + +/* A message to be send to TRK, triggering a callback on receipt + * of the answer. */ +struct TrkMessage +{ + explicit TrkMessage(byte code = 0u, byte token = 0u, + TrkCallback callback = TrkCallback()); + + byte code; + byte token; + QByteArray data; + QVariant cookie; + TrkCallback callback; +}; + +TrkMessage::TrkMessage(byte c, byte t, TrkCallback cb) : + code(c), + token(t), + callback(cb) +{ +} + +QDebug operator<<(QDebug d, const TrkMessage &msg) +{ + return d << "Message: Code: " << msg.code + << " Token: " << msg.token << " " << msg.data.toHex(); +} + +} // namespace trk + +Q_DECLARE_METATYPE(trk::TrkMessage) +Q_DECLARE_METATYPE(trk::TrkResult) + +namespace trk { + +/////////////////////////////////////////////////////////////////////// +// +// TrkWriteQueue: Mixin class that manages a write queue of Trk messages. +// pendingMessage()/notifyWriteResult() should be called from a worked/timer +// that writes the messages. The class does not take precautions for multithreading. +// A no-op message is simply taken off the queue. The calling class +// can use the helper invokeNoopMessage() to trigger its callback. +// +/////////////////////////////////////////////////////////////////////// + +class TrkWriteQueue +{ + Q_DISABLE_COPY(TrkWriteQueue) +public: + explicit TrkWriteQueue(); + + // Enqueue messages. + void queueTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie); + void queueTrkInitialPing(); + + // Call this from the device read notification with the results. + void slotHandleResult(const TrkResult &result, QMutex *mutex = 0); + + // pendingMessage() can be called periodically in a timer to retrieve + // the pending messages to be sent. + enum PendingMessageResult { + NoMessage, // No message in queue. + PendingMessage, /* There is a queued message. The calling class + * can write it out and use notifyWriteResult() + * to notify about the result. */ + NoopMessageDequeued // A no-op message has been dequeued. see invokeNoopMessage(). + }; + + PendingMessageResult pendingMessage(TrkMessage *message); + // Notify the queue about the success of the write operation + // after taking the pendingMessage off. + enum WriteResult { + WriteOk, + WriteFailedDiscard, // Discard failed message + WriteFailedKeep, // Keep failed message + }; + void notifyWriteResult(WriteResult ok); + + // Helper function that invokes the callback of a no-op message + static void invokeNoopMessage(trk::TrkMessage); + +private: + typedef QMap TokenMessageMap; + + byte nextTrkWriteToken(); + + byte m_trkWriteToken; + QQueue m_trkWriteQueue; + TokenMessageMap m_writtenTrkMessages; + bool m_trkWriteBusy; +}; + +TrkWriteQueue::TrkWriteQueue() : + m_trkWriteToken(0), + m_trkWriteBusy(false) +{ +} + +byte TrkWriteQueue::nextTrkWriteToken() +{ + ++m_trkWriteToken; + if (m_trkWriteToken == 0) + ++m_trkWriteToken; + if (verboseTrk) + qDebug() << "Write token: " << m_trkWriteToken; + return m_trkWriteToken; +} + +void TrkWriteQueue::queueTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie) +{ + const byte token = code == TRK_WRITE_QUEUE_NOOP_CODE ? + byte(0) : nextTrkWriteToken(); + TrkMessage msg(code, token, callback); + msg.data = data; + msg.cookie = cookie; + m_trkWriteQueue.append(msg); +} + +TrkWriteQueue::PendingMessageResult TrkWriteQueue::pendingMessage(TrkMessage *message) +{ + // Invoked from timer, try to flush out message queue + if (m_trkWriteBusy || m_trkWriteQueue.isEmpty()) + return NoMessage; + // Handle the noop message, just invoke CB in slot (ower thread) + if (m_trkWriteQueue.front().code == TRK_WRITE_QUEUE_NOOP_CODE) { + *message = m_trkWriteQueue.dequeue(); + return NoopMessageDequeued; + } + // Insert into map fir answers (as reading threads might get an + // answer before notifyWriteResult(true)) is called. + *message = m_trkWriteQueue.front(); + m_writtenTrkMessages.insert(message->token, *message); + m_trkWriteBusy = true; + return PendingMessage; +} + +void TrkWriteQueue::invokeNoopMessage(trk::TrkMessage noopMessage) +{ + TrkResult result; + result.code = noopMessage.code; + result.token = noopMessage.token; + result.data = noopMessage.data; + result.cookie = noopMessage.cookie; + noopMessage.callback(result); +} + +void TrkWriteQueue::notifyWriteResult(WriteResult wr) +{ + // On success, dequeue message and await result + const byte token = m_trkWriteQueue.front().token; + switch (wr) { + case WriteOk: + m_trkWriteQueue.dequeue(); + break; + case WriteFailedKeep: + case WriteFailedDiscard: + m_writtenTrkMessages.remove(token); + m_trkWriteBusy = false; + if (wr == WriteFailedDiscard) + m_trkWriteQueue.dequeue(); + break; + } +} + +void TrkWriteQueue::slotHandleResult(const TrkResult &result, QMutex *mutex) +{ + // Find which request the message belongs to and invoke callback + // if ACK or on NAK if desired. + if (mutex) + mutex->lock(); + m_trkWriteBusy = false; + const TokenMessageMap::iterator it = m_writtenTrkMessages.find(result.token); + if (it == m_writtenTrkMessages.end()) { + if (mutex) + mutex->unlock(); + return; + } + TrkCallback callback = it.value().callback; + const QVariant cookie = it.value().cookie; + m_writtenTrkMessages.erase(it); + if (mutex) + mutex->unlock(); + // Invoke callback + if (callback) { + TrkResult result1 = result; + result1.cookie = cookie; + callback(result1); + } +} + +void TrkWriteQueue::queueTrkInitialPing() +{ + // Ping, reset sequence count + m_trkWriteToken = 0; + m_trkWriteQueue.append(TrkMessage(TrkPing, 0)); +} + +/////////////////////////////////////////////////////////////////////// +// +// DeviceContext to be shared between threads +// +/////////////////////////////////////////////////////////////////////// + +struct DeviceContext { + DeviceContext(); +#ifdef Q_OS_WIN + HANDLE device; + OVERLAPPED readOverlapped; + OVERLAPPED writeOverlapped; +#else + QFile file; +#endif + bool serialFrame; + QMutex mutex; +}; + +DeviceContext::DeviceContext() : +#ifdef Q_OS_WIN + device(INVALID_HANDLE_VALUE), +#endif + serialFrame(true) +{ +} + +/////////////////////////////////////////////////////////////////////// +// +// TrkWriterThread: A thread operating a TrkWriteQueue. +// with exception of the handling of the TRK_WRITE_QUEUE_NOOP_CODE +// synchronization message. The invocation of the callback is then +// done by the thread owning the TrkWriteQueue, while pendingMessage() is called +// from another thread. This happens via a Qt::BlockingQueuedConnection. + +/////////////////////////////////////////////////////////////////////// + +class WriterThread : public QThread +{ + Q_OBJECT + Q_DISABLE_COPY(WriterThread) +public: + explicit WriterThread(const QSharedPointer &context); + + // Enqueue messages. + void queueTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie); + void queueTrkInitialPing(); + + // Call this from the device read notification with the results. + void slotHandleResult(const TrkResult &result); + + virtual void run(); + +signals: + void error(const QString &); + void internalNoopMessageDequeued(const trk::TrkMessage&); + +public slots: + bool trkWriteRawMessage(const TrkMessage &msg); + void terminate(); + void tryWrite(); + +private slots: + void invokeNoopMessage(const trk::TrkMessage &); + +private: + bool write(const QByteArray &data, QString *errorMessage); + inline int writePendingMessage(); + + const QSharedPointer m_context; + QMutex m_dataMutex; + QMutex m_waitMutex; + QWaitCondition m_waitCondition; + TrkWriteQueue m_queue; + bool m_terminate; +}; + +WriterThread::WriterThread(const QSharedPointer &context) : + m_context(context), + m_terminate(false) +{ + static const int trkMessageMetaId = qRegisterMetaType(); + Q_UNUSED(trkMessageMetaId) + connect(this, SIGNAL(internalNoopMessageDequeued(trk::TrkMessage)), + this, SLOT(invokeNoopMessage(trk::TrkMessage)), Qt::BlockingQueuedConnection); +} + +void WriterThread::run() +{ + while (writePendingMessage() == 0) ; +} + +int WriterThread::writePendingMessage() +{ + enum { MaxAttempts = 100, RetryIntervalMS = 200 }; + + // Wait. Use a timeout in case something is already queued before we + // start up or some weird hanging exit condition + m_waitMutex.lock(); + m_waitCondition.wait(&m_waitMutex, 100); + m_waitMutex.unlock(); + if (m_terminate) + return 1; + + // Send off message + m_dataMutex.lock(); + TrkMessage message; + const TrkWriteQueue::PendingMessageResult pr = m_queue.pendingMessage(&message); + m_dataMutex.unlock(); + + switch (pr) { + case TrkWriteQueue::NoMessage: + break; + case TrkWriteQueue::PendingMessage: { + //qDebug() << "Write pending message " << message; + // Untested: try to re-send a few times + bool success = false; + for (int r = 0; !success && (r < MaxAttempts); r++) { + success = trkWriteRawMessage(message); + if (!success) { + emit error(QString::fromLatin1("Write failure, attempt %1 of %2.").arg(r).arg(int(MaxAttempts))); + if (m_terminate) + return 1; + QThread::msleep(RetryIntervalMS); + } + } + // Notify queue. If still failed, give up. + m_dataMutex.lock(); + m_queue.notifyWriteResult(success ? TrkWriteQueue::WriteOk : TrkWriteQueue::WriteFailedDiscard); + m_dataMutex.unlock(); + } + break; + case TrkWriteQueue::NoopMessageDequeued: + // Sync with thread that owns us via a blocking signal + if (verboseTrk) + qDebug() << "Noop message dequeued" << message; + emit internalNoopMessageDequeued(message); + break; + } // switch + return 0; +} + +void WriterThread::invokeNoopMessage(const trk::TrkMessage &msg) +{ + TrkWriteQueue::invokeNoopMessage(msg); +} + +void WriterThread::terminate() +{ + m_terminate = true; + m_waitCondition.wakeAll(); + wait(); + m_terminate = false; +} + +#ifdef Q_OS_WIN + +static inline QString msgTerminated(int size) +{ + return QString::fromLatin1("Terminated with %1 bytes pending.").arg(size); +} + +// Interruptible synchronous write function. +static inline bool overlappedSyncWrite(HANDLE file, + const bool &terminateFlag, + const char *data, + DWORD size, DWORD *charsWritten, + OVERLAPPED *overlapped, + QString *errorMessage) +{ + if (WriteFile(file, data, size, charsWritten, overlapped)) + return true; + const DWORD writeError = GetLastError(); + if (writeError != ERROR_IO_PENDING) { + *errorMessage = QString::fromLatin1("WriteFile failed: %1").arg(winErrorMessage(writeError)); + return false; + } + // Wait for written or thread terminated + const DWORD timeoutMS = 200; + const unsigned maxAttempts = 20; + DWORD wr = WaitForSingleObject(overlapped->hEvent, timeoutMS); + for (unsigned n = 0; wr == WAIT_TIMEOUT && n < maxAttempts && !terminateFlag; + wr = WaitForSingleObject(overlapped->hEvent, timeoutMS), n++); + if (terminateFlag) { + *errorMessage = msgTerminated(size); + return false; + } + switch (wr) { + case WAIT_OBJECT_0: + break; + case WAIT_TIMEOUT: + *errorMessage = QString::fromLatin1("Write timed out."); + return false; + default: + *errorMessage = QString::fromLatin1("Error while waiting for WriteFile results: %1").arg(winErrorMessage(GetLastError())); + return false; + } + if (!GetOverlappedResult(file, overlapped, charsWritten, TRUE)) { + *errorMessage = QString::fromLatin1("Error writing %1 bytes: %2").arg(size).arg(winErrorMessage(GetLastError())); + return false; + } + return true; +} +#endif + +bool WriterThread::write(const QByteArray &data, QString *errorMessage) +{ + if (verboseTrk) + qDebug() << "Write raw data: " << stringFromArray(data).toLatin1(); + QMutexLocker locker(&m_context->mutex); +#ifdef Q_OS_WIN + DWORD charsWritten; + if (!overlappedSyncWrite(m_context->device, m_terminate, data.data(), data.size(), &charsWritten, &m_context->writeOverlapped, errorMessage)) { + return false; + } + FlushFileBuffers(m_context->device); + return true; +#else + if (m_context->file.write(data) == -1 || !m_context->file.flush()) { + *errorMessage = QString::fromLatin1("Cannot write: %1").arg(m_context->file.errorString()); + return false; + } + return true; +#endif +} + +bool WriterThread::trkWriteRawMessage(const TrkMessage &msg) +{ + const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, m_context->serialFrame); + QString errorMessage; + const bool rc = write(ba, &errorMessage); + if (!rc) { + qWarning("%s\n", qPrintable(errorMessage)); + emit error(errorMessage); + } + return rc; +} + +void WriterThread::tryWrite() +{ + m_waitCondition.wakeAll(); +} + +void WriterThread::queueTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie) +{ + m_dataMutex.lock(); + m_queue.queueTrkMessage(code, callback, data, cookie); + m_dataMutex.unlock(); + tryWrite(); +} + +void WriterThread::queueTrkInitialPing() +{ + m_dataMutex.lock(); + m_queue.queueTrkInitialPing(); + m_dataMutex.unlock(); + tryWrite(); +} + +// Call this from the device read notification with the results. +void WriterThread::slotHandleResult(const TrkResult &result) +{ + m_queue.slotHandleResult(result, &m_dataMutex); + tryWrite(); // Have messages been enqueued in-between? +} + + +/////////////////////////////////////////////////////////////////////// +// +// ReaderThreadBase: Base class for a thread that reads data from +// the device, decodes the messages and emit signals for the messages. +// A Qt::BlockingQueuedConnection should be used for the message signal +// to ensure messages are processed in the correct sequence. +// +/////////////////////////////////////////////////////////////////////// + +class ReaderThreadBase : public QThread +{ + Q_OBJECT + Q_DISABLE_COPY(ReaderThreadBase) +public: + +signals: + void messageReceived(const trk::TrkResult &result, const QByteArray &rawData); + +protected: + explicit ReaderThreadBase(const QSharedPointer &context); + void processData(const QByteArray &a); + void processData(char c); + + const QSharedPointer m_context; + +private: + void readMessages(); + + QByteArray m_trkReadBuffer; +}; + +ReaderThreadBase::ReaderThreadBase(const QSharedPointer &context) : + m_context(context) +{ + static const int trkResultMetaId = qRegisterMetaType(); + Q_UNUSED(trkResultMetaId) +} + +void ReaderThreadBase::processData(const QByteArray &a) +{ + m_trkReadBuffer += a; + readMessages(); +} + +void ReaderThreadBase::processData(char c) +{ + m_trkReadBuffer += c; + if (m_trkReadBuffer.size() > 1) + readMessages(); +} + +void ReaderThreadBase::readMessages() +{ + TrkResult r; + QByteArray rawData; + while (extractResult(&m_trkReadBuffer, m_context->serialFrame, &r, &rawData)) { + emit messageReceived(r, rawData); + } +} + +#ifdef Q_OS_WIN +/////////////////////////////////////////////////////////////////////// +// +// WinReaderThread: A thread reading from the device using Windows API. +// Waits on an overlapped I/O handle and an event that tells the thread to +// terminate. +// +/////////////////////////////////////////////////////////////////////// + +class WinReaderThread : public ReaderThreadBase +{ + Q_OBJECT + Q_DISABLE_COPY(WinReaderThread) +public: + explicit WinReaderThread(const QSharedPointer &context); + ~WinReaderThread(); + + virtual void run(); + +signals: + void error(const QString &); + +public slots: + void terminate(); + +private: + enum Handles { FileHandle, TerminateEventHandle, HandleCount }; + + inline int tryRead(); + + HANDLE m_handles[HandleCount]; +}; + +WinReaderThread::WinReaderThread(const QSharedPointer &context) : + ReaderThreadBase(context) +{ + m_handles[FileHandle] = NULL; + m_handles[TerminateEventHandle] = CreateEvent(NULL, FALSE, FALSE, NULL); +} + +WinReaderThread::~WinReaderThread() +{ + CloseHandle(m_handles[TerminateEventHandle]); +} + +// Return 0 to continue or error code +int WinReaderThread::tryRead() +{ + enum { BufSize = 1024 }; + char buffer[BufSize]; + // Check if there are already bytes waiting. If not, wait for first byte + COMSTAT comStat; + if (!ClearCommError(m_context->device, NULL, &comStat)){ + emit error(QString::fromLatin1("ClearCommError failed: %1").arg(winErrorMessage(GetLastError()))); + return -7; + } + const DWORD bytesToRead = qMax(DWORD(1), qMin(comStat.cbInQue, DWORD(BufSize))); + // Trigger read + DWORD bytesRead = 0; + if (ReadFile(m_context->device, &buffer, bytesToRead, &bytesRead, &m_context->readOverlapped)) { + if (bytesRead == 1) { + processData(buffer[0]); + } else { + processData(QByteArray(buffer, bytesRead)); + } + return 0; + } + const DWORD readError = GetLastError(); + if (readError != ERROR_IO_PENDING) { + emit error(QString::fromLatin1("Read error: %1").arg(winErrorMessage(readError))); + return -1; + } + // Wait for either termination or data + const DWORD wr = WaitForMultipleObjects(HandleCount, m_handles, false, INFINITE); + if (wr == WAIT_FAILED) { + emit error(QString::fromLatin1("Wait failed: %1").arg(winErrorMessage(GetLastError()))); + return -2; + } + if (wr - WAIT_OBJECT_0 == TerminateEventHandle) { + return 1; // Terminate + } + // Check data + if (!GetOverlappedResult(m_context->device, &m_context->readOverlapped, &bytesRead, true)) { + emit error(QString::fromLatin1("GetOverlappedResult failed: %1").arg(winErrorMessage(GetLastError()))); + return -3; + } + if (bytesRead == 1) { + processData(buffer[0]); + } else { + processData(QByteArray(buffer, bytesRead)); + } + return 0; +} + +void WinReaderThread::run() +{ + m_handles[FileHandle] = m_context->readOverlapped.hEvent; + while ( tryRead() == 0) ; +} + +void WinReaderThread::terminate() +{ + SetEvent(m_handles[TerminateEventHandle]); + wait(); +} + +typedef WinReaderThread ReaderThread; + +#else + +/////////////////////////////////////////////////////////////////////// +// +// UnixReaderThread: A thread reading from the device. +// Uses select() to wait and a special ioctl() to find out the number +// of bytes queued. For clean termination, the self-pipe trick is used. +// The class maintains a pipe, on whose read end the select waits besides +// the device file handle. To terminate, a byte is written to the pipe. +// +/////////////////////////////////////////////////////////////////////// + +static inline QString msgUnixCallFailedErrno(const char *func, int errorNumber) +{ + return QString::fromLatin1("Call to %1() failed: %2").arg(QLatin1String(func), QString::fromLocal8Bit(strerror(errorNumber))); +} + +class UnixReaderThread : public ReaderThreadBase { + Q_OBJECT + Q_DISABLE_COPY(UnixReaderThread) +public: + explicit UnixReaderThread(const QSharedPointer &context); + ~UnixReaderThread(); + + virtual void run(); + +signals: + void error(const QString &); + +public slots: + void terminate(); + +private: + inline int tryRead(); + + int m_terminatePipeFileDescriptors[2]; +}; + +UnixReaderThread::UnixReaderThread(const QSharedPointer &context) : + ReaderThreadBase(context) +{ + m_terminatePipeFileDescriptors[0] = m_terminatePipeFileDescriptors[1] = -1; + // Set up pipes for termination. Should not fail + if (pipe(m_terminatePipeFileDescriptors) < 0) + qWarning("%s\n", qPrintable(msgUnixCallFailedErrno("pipe", errno))); +} + +UnixReaderThread::~UnixReaderThread() +{ + close(m_terminatePipeFileDescriptors[0]); + close(m_terminatePipeFileDescriptors[1]); +} + +int UnixReaderThread::tryRead() +{ + fd_set readSet, tempReadSet, tempExceptionSet; + struct timeval timeOut; + const int fileDescriptor = m_context->file.handle(); + FD_ZERO(&readSet); + FD_SET(fileDescriptor, &readSet); + FD_SET(m_terminatePipeFileDescriptors[0], &readSet); + const int maxFileDescriptor = qMax(m_terminatePipeFileDescriptors[0], fileDescriptor); + int result = 0; + do { + memcpy(&tempReadSet, &readSet, sizeof(fd_set)); + memcpy(&tempExceptionSet, &readSet, sizeof(fd_set)); + timeOut.tv_sec = 1; + timeOut.tv_usec = 0; + result = select(maxFileDescriptor + 1, &tempReadSet, NULL, &tempExceptionSet, &timeOut); + } while ( result < 0 && errno == EINTR ); + // Timeout? + if (result == 0) + return 0; + // Something wrong? + if (result < 0) { + emit error(msgUnixCallFailedErrno("select", errno)); + return -1; + } + // Did the exception set trigger on the device? + if (FD_ISSET(fileDescriptor,&tempExceptionSet)) { + emit error(QLatin1String("An Exception occurred on the device.")); + return -2; + } + // Check termination pipe. + if (FD_ISSET(m_terminatePipeFileDescriptors[0], &tempReadSet) + || FD_ISSET(m_terminatePipeFileDescriptors[0], &tempExceptionSet)) + return 1; + + // determine number of pending bytes and read + int numBytes; + if (ioctl(fileDescriptor, FIONREAD, &numBytes) < 0) { + emit error(msgUnixCallFailedErrno("ioctl", errno)); + return -1; + } + m_context->mutex.lock(); + const QByteArray data = m_context->file.read(numBytes); + m_context->mutex.unlock(); + processData(data); + return 0; +} + +void UnixReaderThread::run() +{ + // Read loop + while (tryRead() == 0) + ; +} + +void UnixReaderThread::terminate() +{ + // Trigger select() by writing to the pipe + char c = 0; + const int written = write(m_terminatePipeFileDescriptors[1], &c, 1); + Q_UNUSED(written) + wait(); +} + +typedef UnixReaderThread ReaderThread; + +#endif + +/////////////////////////////////////////////////////////////////////// +// +// TrkDevicePrivate +// +/////////////////////////////////////////////////////////////////////// + +struct TrkDevicePrivate +{ + TrkDevicePrivate(); + + QSharedPointer deviceContext; + QSharedPointer writerThread; + QSharedPointer readerThread; + + QByteArray trkReadBuffer; + int verbose; + QString errorString; +}; + +/////////////////////////////////////////////////////////////////////// +// +// TrkDevice +// +/////////////////////////////////////////////////////////////////////// + +TrkDevicePrivate::TrkDevicePrivate() : + deviceContext(new DeviceContext), + verbose(0) +{ +} + +/////////////////////////////////////////////////////////////////////// +// +// TrkDevice +// +/////////////////////////////////////////////////////////////////////// + +TrkDevice::TrkDevice(QObject *parent) : + QObject(parent), + d(new TrkDevicePrivate) +{} + +TrkDevice::~TrkDevice() +{ + close(); + delete d; +} + +bool TrkDevice::open(const QString &port, QString *errorMessage) +{ + if (d->verbose) + qDebug() << "Opening" << port << "is open: " << isOpen() << " serialFrame=" << serialFrame(); + close(); +#ifdef Q_OS_WIN + d->deviceContext->device = CreateFile(QString("\\\\.\\").append(port).toStdWString().c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING|FILE_FLAG_OVERLAPPED, + NULL); + + if (INVALID_HANDLE_VALUE == d->deviceContext->device) { + *errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port, winErrorMessage(GetLastError())); + return false; + } + memset(&d->deviceContext->readOverlapped, 0, sizeof(OVERLAPPED)); + d->deviceContext->readOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + memset(&d->deviceContext->writeOverlapped, 0, sizeof(OVERLAPPED)); + d->deviceContext->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (d->deviceContext->readOverlapped.hEvent == NULL || d->deviceContext->writeOverlapped.hEvent == NULL) { + *errorMessage = QString::fromLatin1("Failed to create events: %1").arg(winErrorMessage(GetLastError())); + return false; + } +#else + d->deviceContext->file.setFileName(port); + if (!d->deviceContext->file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) { + *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(port, d->deviceContext->file.errorString()); + return false; + } + + struct termios termInfo; + if (tcgetattr(d->deviceContext->file.handle(), &termInfo) < 0) { + *errorMessage = QString::fromLatin1("Unable to retrieve terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno))); + return false; + } + // Turn off terminal echo as not get messages back, among other things + termInfo.c_cflag |= CREAD|CLOCAL; + termInfo.c_lflag &= (~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG)); + termInfo.c_iflag &= (~(INPCK|IGNPAR|PARMRK|ISTRIP|ICRNL|IXANY)); + termInfo.c_oflag &= (~OPOST); + termInfo.c_cc[VMIN] = 0; + termInfo.c_cc[VINTR] = _POSIX_VDISABLE; + termInfo.c_cc[VQUIT] = _POSIX_VDISABLE; + termInfo.c_cc[VSTART] = _POSIX_VDISABLE; + termInfo.c_cc[VSTOP] = _POSIX_VDISABLE; + termInfo.c_cc[VSUSP] = _POSIX_VDISABLE; + if (tcsetattr(d->deviceContext->file.handle(), TCSAFLUSH, &termInfo) < 0) { + *errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno))); + return false; + } +#endif + d->readerThread = QSharedPointer(new ReaderThread(d->deviceContext)); + connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)), + Qt::QueuedConnection); + connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)), + this, SLOT(slotMessageReceived(trk::TrkResult,QByteArray)), + Qt::QueuedConnection); + d->readerThread->start(); + + d->writerThread = QSharedPointer(new WriterThread(d->deviceContext)); + connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)), + Qt::QueuedConnection); + d->writerThread->start(); + + if (d->verbose) + qDebug() << "Opened" << port; + return true; +} + +void TrkDevice::close() +{ + if (!isOpen()) + return; + if (d->readerThread) + d->readerThread->terminate(); + if (d->writerThread) + d->writerThread->terminate(); +#ifdef Q_OS_WIN + CloseHandle(d->deviceContext->device); + d->deviceContext->device = INVALID_HANDLE_VALUE; + CloseHandle(d->deviceContext->readOverlapped.hEvent); + CloseHandle(d->deviceContext->writeOverlapped.hEvent); + d->deviceContext->readOverlapped.hEvent = d->deviceContext->writeOverlapped.hEvent = NULL; +#else + d->deviceContext->file.close(); +#endif + if (d->verbose) + emitLogMessage("Close"); +} + +bool TrkDevice::isOpen() const +{ +#ifdef Q_OS_WIN + return d->deviceContext->device != INVALID_HANDLE_VALUE; +#else + return d->deviceContext->file.isOpen(); +#endif +} + +QString TrkDevice::errorString() const +{ + return d->errorString; +} + +bool TrkDevice::serialFrame() const +{ + return d->deviceContext->serialFrame; +} + +void TrkDevice::setSerialFrame(bool f) +{ + d->deviceContext->serialFrame = f; +} + +int TrkDevice::verbose() const +{ + return d->verbose; +} + +void TrkDevice::setVerbose(int b) +{ + d->verbose = b; +} + +void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData) +{ + d->writerThread->slotHandleResult(result); + if (d->verbose > 1) + qDebug() << "Received: " << result.toString(); + emit messageReceived(result); + if (!rawData.isEmpty()) + emit rawDataReceived(rawData); +} + +void TrkDevice::emitError(const QString &s) +{ + d->errorString = s; + qWarning("%s\n", qPrintable(s)); + emit error(s); +} + +void TrkDevice::sendTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie) +{ + if (!d->writerThread.isNull()) { + if (d->verbose > 1) { + QByteArray msg = "Sending: "; + msg += QByteArray::number(code, 16); + msg += ": "; + msg += stringFromArray(data).toLatin1(); + qDebug("%s", msg.data()); + } + d->writerThread->queueTrkMessage(code, callback, data, cookie); + } +} + +void TrkDevice::sendTrkInitialPing() +{ + if (!d->writerThread.isNull()) + d->writerThread->queueTrkInitialPing(); +} + +bool TrkDevice::sendTrkAck(byte token) +{ + if (d->writerThread.isNull()) + return false; + // The acknowledgement must not be queued! + TrkMessage msg(0x80, token); + msg.token = token; + msg.data.append('\0'); + if (verboseTrk) + qDebug() << "Write synchroneous message: " << msg; + return d->writerThread->trkWriteRawMessage(msg); + // 01 90 00 07 7e 80 01 00 7d 5e 7e +} + +void TrkDevice::emitLogMessage(const QString &msg) +{ + if (d->verbose) + qDebug("%s\n", qPrintable(msg)); + emit logMessage(msg); +} + +} // namespace trk + +#include "trkdevice.moc" diff --git a/tools/runonphone/symbianutils/trkdevice.h b/tools/runonphone/symbianutils/trkdevice.h new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/tools/runonphone/symbianutils/trkdevice.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TRKDEVICE_H +#define TRKDEVICE_H + +#include "symbianutils_global.h" +#include "callback.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QIODevice; +QT_END_NAMESPACE + +namespace trk { + +struct TrkResult; +struct TrkMessage; +struct TrkDevicePrivate; + +/* TrkDevice: Implements a Windows COM or Linux device for + * Trk communications. Provides synchronous write and asynchronous + * read operation. + * The serialFrames property specifies whether packets are encapsulated in + * "0x90 " frames, which is currently the case for serial ports. + * Contains a write message queue allowing + * for queueing messages with a notification callback. If the message receives + * an ACK, the callback is invoked. + * The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronisation. + * The respective message will not be sent, the callback is just invoked. */ + +enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f }; + +typedef trk::Callback TrkCallback; + +class SYMBIANUTILS_EXPORT TrkDevice : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame) + Q_PROPERTY(bool verbose READ verbose WRITE setVerbose) +public: + explicit TrkDevice(QObject *parent = 0); + virtual ~TrkDevice(); + + bool open(const QString &port, QString *errorMessage); + bool isOpen() const; + + QString errorString() const; + + bool serialFrame() const; + void setSerialFrame(bool f); + + int verbose() const; + void setVerbose(int b); + + // Enqueue a message with a notification callback. + void sendTrkMessage(unsigned char code, + TrkCallback callBack = TrkCallback(), + const QByteArray &data = QByteArray(), + const QVariant &cookie = QVariant()); + + // Enqeue an initial ping + void sendTrkInitialPing(); + + // Send an Ack synchronously, bypassing the queue + bool sendTrkAck(unsigned char token); + +signals: + void messageReceived(const trk::TrkResult &result); + // Emitted with the contents of messages enclosed in 07e, not for log output + void rawDataReceived(const QByteArray &data); + void error(const QString &msg); + void logMessage(const QString &msg); + +private slots: + void slotMessageReceived(const trk::TrkResult &result, const QByteArray &a); + +protected slots: + void emitError(const QString &msg); + void emitLogMessage(const QString &msg); + +public slots: + void close(); + +private: + void readMessages(); + TrkDevicePrivate *d; +}; + +} // namespace trk + +#endif // TRKDEVICE_H diff --git a/tools/runonphone/symbianutils/trkutils.cpp b/tools/runonphone/symbianutils/trkutils.cpp new file mode 100644 index 0000000..5cce950 --- /dev/null +++ b/tools/runonphone/symbianutils/trkutils.cpp @@ -0,0 +1,479 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "trkutils.h" +#include + +#include +#include +#include +#include +#include + +#define logMessage(s) do { qDebug() << "TRKCLIENT: " << s; } while (0) + +namespace trk { + +TrkAppVersion::TrkAppVersion() +{ + reset(); +} + +void TrkAppVersion::reset() +{ + trkMajor = trkMinor= protocolMajor = protocolMinor = 0; +} + +Session::Session() +{ + reset(); +} + +void Session::reset() +{ + cpuMajor = 0; + cpuMinor = 0; + bigEndian = 0; + defaultTypeSize = 0; + fpTypeSize = 0; + extended1TypeSize = 0; + extended2TypeSize = 0; + pid = 0; + tid = 0; + codeseg = 0; + dataseg = 0; + + currentThread = 0; + libraries.clear(); + trkAppVersion.reset(); +} + +static QString formatCpu(int major, int minor) +{ + //: CPU description of an S60 device + //: %1 major verison, %2 minor version + //: %3 real name of major verison, %4 real name of minor version + const QString str = QCoreApplication::translate("trk::Session", "CPU: v%1.%2%3%4"); + QString majorStr; + QString minorStr; + switch (major) { + case 0x04: + majorStr = " ARM"; + break; + } + switch (minor) { + case 0x00: + minorStr = " 920T"; + break; + } + return str.arg(major).arg(minor).arg(majorStr).arg(minorStr); + } + +QString formatTrkVersion(const TrkAppVersion &version) +{ + QString str = QCoreApplication::translate("trk::Session", + "App TRK: v%1.%2 TRK protocol: v%3.%4"); + str = str.arg(version.trkMajor).arg(version.trkMinor); + return str.arg(version.protocolMajor).arg(version.protocolMinor); +} + +QString Session::deviceDescription(unsigned verbose) const +{ + if (!cpuMajor) + return QString(); + + //: s60description + //: description of an S60 device + //: %1 CPU description, %2 endianness + //: %3 default type size (if any), %4 float size (if any) + //: %5 TRK version + QString msg = QCoreApplication::translate("trk::Session", "%1, %2%3%4, %5"); + QString endianness = bigEndian + ? QCoreApplication::translate("trk::Session", "big endian") + : QCoreApplication::translate("trk::Session", "little endian"); + msg = msg.arg(formatCpu(cpuMajor, cpuMinor)).arg(endianness); + //: The separator in a list of strings + QString defaultTypeSizeStr; + QString fpTypeSizeStr; + if (verbose && defaultTypeSize) + //: will be inserted into s60description + defaultTypeSizeStr = QCoreApplication::translate("trk::Session", ", type size: %1").arg(defaultTypeSize); + if (verbose && fpTypeSize) + //: will be inserted into s60description + fpTypeSizeStr = QCoreApplication::translate("trk::Session", ", float size: %1").arg(fpTypeSize); + msg = msg.arg(defaultTypeSizeStr).arg(fpTypeSizeStr); + return msg.arg(formatTrkVersion(trkAppVersion)); +} + + +QByteArray decode7d(const QByteArray &ba) +{ + QByteArray res; + res.reserve(ba.size()); + for (int i = 0; i < ba.size(); ++i) { + byte c = byte(ba.at(i)); + if (c == 0x7d) { + ++i; + c = 0x20 ^ byte(ba.at(i)); + } + res.append(c); + } + return res; +} + +QByteArray encode7d(const QByteArray &ba) +{ + QByteArray res; + res.reserve(ba.size() + 2); + for (int i = 0; i < ba.size(); ++i) { + byte c = byte(ba.at(i)); + if (c == 0x7e || c == 0x7d) { + res.append(0x7d); + res.append(0x20 ^ c); + } else { + res.append(c); + } + } + return res; +} + +// FIXME: Use the QByteArray based version below? +static inline QString stringFromByte(byte c) +{ + return QString::fromLatin1("%1").arg(c, 2, 16, QChar('0')); +} + +SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen) +{ + QString str; + QString ascii; + const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen); + for (int i = 0; i < size; ++i) { + //if (i == 5 || i == ba.size() - 2) + // str += " "; + int c = byte(ba.at(i)); + str += QString("%1 ").arg(c, 2, 16, QChar('0')); + if (i >= 8 && i < ba.size() - 2) + ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); + } + if (size != ba.size()) { + str += "..."; + ascii += "..."; + } + return str + " " + ascii; +} + +SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) +{ + QByteArray ba = QByteArray::number(n, 16); + if (digits == 0 || ba.size() == digits) + return ba; + return QByteArray(digits - ba.size(), '0') + ba; +} + +SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits) +{ + return "0x" + hexNumber(n, digits); +} + +TrkResult::TrkResult() : + code(0), + token(0), + isDebugOutput(false) +{ +} + +void TrkResult::clear() +{ + code = token= 0; + isDebugOutput = false; + data.clear(); + cookie = QVariant(); +} + +QString TrkResult::toString() const +{ + QString res = stringFromByte(code); + res += QLatin1String(" ["); + res += stringFromByte(token); + res += QLatin1Char(']'); + res += QLatin1Char(' '); + res += stringFromArray(data); + return res; +} + +QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame) +{ + byte s = command + token; + for (int i = 0; i != data.size(); ++i) + s += data.at(i); + byte checksum = 255 - (s & 0xff); + //int x = s + ~s; + //logMessage("check: " << s << checksum << x; + + QByteArray response; + response.reserve(data.size() + 3); + response.append(char(command)); + response.append(char(token)); + response.append(data); + response.append(char(checksum)); + + QByteArray encodedData = encode7d(response); + + QByteArray ba; + ba.reserve(encodedData.size() + 6); + if (serialFrame) { + ba.append(char(0x01)); + ba.append(char(0x90)); + const ushort encodedSize = encodedData.size() + 2; // 2 x 0x7e + appendShort(&ba, encodedSize, BigEndian); + } + ba.append(char(0x7e)); + ba.append(encodedData); + ba.append(char(0x7e)); + + return ba; +} + +/* returns 0 if array doesn't represent a result, +otherwise returns the length of the result data */ +ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame) +{ + if (serialFrame) { + // Serial protocol with length info + if (buffer.length() < 4) + return 0; + if (buffer.at(0) != 0x01 || byte(buffer.at(1)) != 0x90) + return 0; + const ushort len = extractShort(buffer.data() + 2); + return (buffer.size() >= len + 4) ? len : ushort(0); + } + // Frameless protocol without length info + const char delimiter = char(0x7e); + const int firstDelimiterPos = buffer.indexOf(delimiter); + // Regular message delimited by 0x7e..0x7e + if (firstDelimiterPos == 0) { + const int endPos = buffer.indexOf(delimiter, firstDelimiterPos + 1); + return endPos != -1 ? endPos + 1 - firstDelimiterPos : 0; + } + // Some ASCII log message up to first delimiter or all + return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size(); +} + +bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData) +{ + result->clear(); + if(rawData) + rawData->clear(); + const ushort len = isValidTrkResult(*buffer, serialFrame); + if (!len) + return false; + // handle receiving application output, which is not a regular command + const int delimiterPos = serialFrame ? 4 : 0; + if (buffer->at(delimiterPos) != 0x7e) { + result->isDebugOutput = true; + result->data = buffer->mid(delimiterPos, len); + result->data.replace("\r\n", "\n"); + *buffer->remove(0, delimiterPos + len); + return true; + } + // FIXME: what happens if the length contains 0xfe? + // Assume for now that it passes unencoded! + const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2)); + if(rawData) + *rawData = data; + *buffer->remove(0, delimiterPos + len); + + byte sum = 0; + for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum + sum += byte(data.at(i)); + if (sum != 0xff) + logMessage("*** CHECKSUM ERROR: " << byte(sum)); + + result->code = data.at(0); + result->token = data.at(1); + result->data = data.mid(2, data.size() - 3); + //logMessage(" REST BUF: " << stringFromArray(*buffer)); + //logMessage(" CURR DATA: " << stringFromArray(data)); + //QByteArray prefix = "READ BUF: "; + //logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data()); + return true; +} + +SYMBIANUTILS_EXPORT ushort extractShort(const char *data) +{ + return byte(data[0]) * 256 + byte(data[1]); +} + +SYMBIANUTILS_EXPORT uint extractInt(const char *data) +{ + uint res = byte(data[0]); + res *= 256; res += byte(data[1]); + res *= 256; res += byte(data[2]); + res *= 256; res += byte(data[3]); + return res; +} + +SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba) +{ + QString res; + char buf[10]; + for (int i = 0, n = ba.size(); i != n; ++i) { + const byte c = ba.at(i); + if (isprint(c)) { + res += c; + } else { + qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c)); + res += buf; + } + } + return res; +} + +SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness endian) +{ + if (endian == BigEndian) { + ba->append(s / 256); + ba->append(s % 256); + } else { + ba->append(s % 256); + ba->append(s / 256); + } +} + +SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness endian) +{ + const uchar b3 = i % 256; i /= 256; + const uchar b2 = i % 256; i /= 256; + const uchar b1 = i % 256; i /= 256; + const uchar b0 = i; + ba->reserve(ba->size() + 4); + if (endian == BigEndian) { + ba->append(b0); + ba->append(b1); + ba->append(b2); + ba->append(b3); + } else { + ba->append(b3); + ba->append(b2); + ba->append(b1); + ba->append(b0); + } +} + +void appendString(QByteArray *ba, const QByteArray &str, Endianness endian, bool appendNullTerminator) +{ + const int fullSize = str.size() + (appendNullTerminator ? 1 : 0); + appendShort(ba, fullSize, endian); // count the terminating \0 + ba->append(str); + if (appendNullTerminator) + ba->append('\0'); +} + +void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness endian) +{ + // convert the QDateTime to UTC and append its representation to QByteArray + // format is the same as in FAT file system + dateTime = dateTime.toUTC(); + const QTime utcTime = dateTime.time(); + const QDate utcDate = dateTime.date(); + uint fatDateTime = (utcTime.hour() << 11 | utcTime.minute() << 5 | utcTime.second()/2) << 16; + fatDateTime |= (utcDate.year()-1980) << 9 | utcDate.month() << 5 | utcDate.day(); + appendInt(ba, fatDateTime, endian); +} + +QByteArray errorMessage(byte code) +{ + switch (code) { + case 0x00: return "No error"; + case 0x01: return "Generic error in CWDS message"; + case 0x02: return "Unexpected packet size in send msg"; + case 0x03: return "Internal error occurred in CWDS"; + case 0x04: return "Escape followed by frame flag"; + case 0x05: return "Bad FCS in packet"; + case 0x06: return "Packet too long"; + case 0x07: return "Sequence ID not expected (gap in sequence)"; + + case 0x10: return "Command not supported"; + case 0x11: return "Command param out of range"; + case 0x12: return "An option was not supported"; + case 0x13: return "Read/write to invalid memory"; + case 0x14: return "Read/write invalid registers"; + case 0x15: return "Exception occurred in CWDS"; + case 0x16: return "Targeted system or thread is running"; + case 0x17: return "Breakpoint resources (HW or SW) exhausted"; + case 0x18: return "Requested breakpoint conflicts with existing one"; + + case 0x20: return "General OS-related error"; + case 0x21: return "Request specified invalid process"; + case 0x22: return "Request specified invalid thread"; + } + return "Unknown error"; +} + +uint swapEndian(uint in) +{ + return (in>>24) | ((in<<8) & 0x00FF0000) | ((in>>8) & 0x0000FF00) | (in<<24); +} + +int TrkResult::errorCode() const +{ + // NAK means always error, else data sized 1 with a non-null element + const bool isNAK = code == 0xff; + if (data.size() != 1 && !isNAK) + return 0; + if (const int errorCode = data.at(0)) + return errorCode; + return isNAK ? 0xff : 0; +} + +QString TrkResult::errorString() const +{ + // NAK means always error, else data sized 1 with a non-null element + if (code == 0xff) + return "NAK"; + if (data.size() < 1) + return "Unknown error packet"; + return errorMessage(data.at(0)); +} + +} // namespace trk + diff --git a/tools/runonphone/symbianutils/trkutils.h b/tools/runonphone/symbianutils/trkutils.h new file mode 100644 index 0000000..3a485c7 --- /dev/null +++ b/tools/runonphone/symbianutils/trkutils.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEBUGGER_TRK_UTILS +#define DEBUGGER_TRK_UTILS + +#include "symbianutils_global.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QDateTime; +QT_END_NAMESPACE + +namespace trk { + +typedef unsigned char byte; + +enum Command { + TrkPing = 0x00, + TrkConnect = 0x01, + TrkDisconnect = 0x02, + TrkVersions = 0x04, + TrkSupported = 0x05, + TrkCpuType = 0x06, + TrkHostVersions = 0x09, + TrkContinue = 0x18, + TrkCreateItem = 0x40, + TrkDeleteItem = 0x41, + + TrkWriteFile = 0x48, + TrkOpenFile = 0x4a, + TrkCloseFile = 0x4b, + TrkInstallFile = 0x4d, + TrkInstallFile2 = 0x4e, + + TrkNotifyAck = 0x80, + TrkNotifyNak = 0xff, + TrkNotifyStopped = 0x90, + TrkNotifyException = 0x91, + TrkNotifyInternalError = 0x92, + TrkNotifyCreated = 0xa0, + TrkNotifyDeleted = 0xa1, + TrkNotifyProcessorStarted = 0xa2, + TrkNotifyProcessorStandBy = 0xa6, + TrkNotifyProcessorReset = 0xa7 +}; + +inline byte extractByte(const char *data) { return *data; } +SYMBIANUTILS_EXPORT ushort extractShort(const char *data); +SYMBIANUTILS_EXPORT uint extractInt(const char *data); + +SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba); + +// produces "xx xx xx " +SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen = - 1); + +enum Endianness +{ + LittleEndian, + BigEndian, + TargetByteOrder = BigEndian, +}; + +SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder); +SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder); +SYMBIANUTILS_EXPORT void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true); + +struct SYMBIANUTILS_EXPORT Library +{ + Library() {} + + QByteArray name; + uint codeseg; + uint dataseg; +}; + +struct SYMBIANUTILS_EXPORT TrkAppVersion +{ + TrkAppVersion(); + void reset(); + + int trkMajor; + int trkMinor; + int protocolMajor; + int protocolMinor; +}; + +struct SYMBIANUTILS_EXPORT Session +{ + Session(); + void reset(); + QString deviceDescription(unsigned verbose) const; + + // Trk feedback + byte cpuMajor; + byte cpuMinor; + byte bigEndian; + byte defaultTypeSize; + byte fpTypeSize; + byte extended1TypeSize; + byte extended2TypeSize; + TrkAppVersion trkAppVersion; + uint pid; + uint tid; + uint codeseg; + uint dataseg; + QHash addressToBP; + + typedef QList Libraries; + Libraries libraries; + + typedef uint Thread; + typedef QList Threads; + Threads threads; + + // Gdb request + uint currentThread; + QStringList modules; +}; + +struct SYMBIANUTILS_EXPORT TrkResult +{ + TrkResult(); + void clear(); + QString toString() const; + // 0 for no error. + int errorCode() const; + QString errorString() const; + + byte code; + byte token; + QByteArray data; + QVariant cookie; + bool isDebugOutput; +}; + +SYMBIANUTILS_EXPORT QByteArray errorMessage(byte code); +SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits = 0); +SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too +SYMBIANUTILS_EXPORT uint swapEndian(uint in); + +} // namespace trk + +#endif // DEBUGGER_TRK_UTILS diff --git a/tools/runonphone/symbianutils/trkutils_p.h b/tools/runonphone/symbianutils/trkutils_p.h new file mode 100644 index 0000000..12b0109 --- /dev/null +++ b/tools/runonphone/symbianutils/trkutils_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEBUGGER_TRK_PRIVATE_UTILS +#define DEBUGGER_TRK_PRIVATE_UTILS + +#include "trkutils.h" +#include "symbianutils_global.h" + +QT_BEGIN_NAMESPACE +class QDateTime; +QT_END_NAMESPACE + +namespace trk { + +void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness = TargetByteOrder); +// returns a QByteArray containing optionally +// the serial frame [0x01 0x90 ] and 0x7e encoded7d(ba) 0x7e +QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame); +bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0); + +} // namespace trk + +#endif // DEBUGGER_TRK_PRIVATE_UTILS diff --git a/tools/runonphone/trk/bluetoothlistener.cpp b/tools/runonphone/trk/bluetoothlistener.cpp deleted file mode 100644 index df04288..0000000 --- a/tools/runonphone/trk/bluetoothlistener.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "bluetoothlistener.h" -#include "trkdevice.h" - -#include - -#ifdef Q_OS_UNIX -# include -# include -#else -# include -#endif - -// Process id helpers. -#ifdef Q_OS_WIN -inline DWORD processId(const QProcess &p) -{ - if (const Q_PID processInfoStruct = p.pid()) - return processInfoStruct->dwProcessId; - return 0; -} -#else -inline Q_PID processId(const QProcess &p) -{ - return p.pid(); -} -#endif - - -enum { debug = 0 }; - -namespace trk { - -struct BluetoothListenerPrivate { - BluetoothListenerPrivate(); - QString device; - QProcess process; -#ifdef Q_OS_WIN - DWORD pid; -#else - Q_PID pid; -#endif - 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(processId(d->process))); - // 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 = processId(d->process); // Forgets it after crash/termination - emitMessage(tr("%1: Bluetooth listener running (%2).").arg(device).arg(processId(d->process))); - 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())); -} - -} // namespace trk diff --git a/tools/runonphone/trk/bluetoothlistener.h b/tools/runonphone/trk/bluetoothlistener.h deleted file mode 100644 index 36894e7..0000000 --- a/tools/runonphone/trk/bluetoothlistener.h +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef BLUETOOTHLISTENER_H -#define BLUETOOTHLISTENER_H - -#include "symbianutils_global.h" - -#include -#include - -namespace trk { -struct BluetoothListenerPrivate; - -/* 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 SYMBIANUTILS_EXPORT 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; -}; - -} // namespace trk - -#endif // BLUETOOTHLISTENER_H diff --git a/tools/runonphone/trk/bluetoothlistener_gui.cpp b/tools/runonphone/trk/bluetoothlistener_gui.cpp deleted file mode 100644 index 5994eb5..0000000 --- a/tools/runonphone/trk/bluetoothlistener_gui.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "bluetoothlistener_gui.h" -#include "bluetoothlistener.h" -#include "communicationstarter.h" - -#include -#include -#include -#include - -namespace trk { - -SYMBIANUTILS_EXPORT PromptStartCommunicationResult - promptStartCommunication(BaseCommunicationStarter &starter, - const QString &msgBoxTitle, - const QString &msgBoxText, - QWidget *msgBoxParent, - QString *errorMessage) -{ - errorMessage->clear(); - // Initial connection attempt. - switch (starter.start()) { - case BaseCommunicationStarter::Started: - break; - case BaseCommunicationStarter::ConnectionSucceeded: - return PromptStartCommunicationConnected; - case BaseCommunicationStarter::StartError: - *errorMessage = starter.errorString(); - return PromptStartCommunicationError; - } - // Run the starter with the event loop of a message box, have the box - // closed by the signals of the starter. - QMessageBox messageBox(QMessageBox::Information, msgBoxTitle, msgBoxText, 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 to obtain the state. - switch (starter.state()) { - case AbstractBluetoothStarter::Running: - *errorMessage = QCoreApplication::translate("trk::promptStartCommunication", "Connection on %1 canceled.").arg(starter.device()); - return PromptStartCommunicationCanceled; - case AbstractBluetoothStarter::TimedOut: - *errorMessage = starter.errorString(); - return PromptStartCommunicationError; - case AbstractBluetoothStarter::Connected: - break; - } - return PromptStartCommunicationConnected; -} - -SYMBIANUTILS_EXPORT PromptStartCommunicationResult - promptStartSerial(BaseCommunicationStarter &starter, - QWidget *msgBoxParent, - QString *errorMessage) -{ - const QString title = QCoreApplication::translate("trk::promptStartCommunication", "Waiting for App TRK"); - const QString message = QCoreApplication::translate("trk::promptStartCommunication", "Waiting for App TRK to start on %1...").arg(starter.device()); - return promptStartCommunication(starter, title, message, msgBoxParent, errorMessage); -} - -SYMBIANUTILS_EXPORT PromptStartCommunicationResult - promptStartBluetooth(BaseCommunicationStarter &starter, - QWidget *msgBoxParent, - QString *errorMessage) -{ - const QString title = QCoreApplication::translate("trk::promptStartCommunication", "Waiting for Bluetooth Connection"); - const QString message = QCoreApplication::translate("trk::promptStartCommunication", "Connecting to %1...").arg(starter.device()); - return promptStartCommunication(starter, title, message, msgBoxParent, errorMessage); -} - -} // namespace trk diff --git a/tools/runonphone/trk/bluetoothlistener_gui.h b/tools/runonphone/trk/bluetoothlistener_gui.h deleted file mode 100644 index 10e7145..0000000 --- a/tools/runonphone/trk/bluetoothlistener_gui.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef BLUETOOTHLISTENER_GUI_H -#define BLUETOOTHLISTENER_GUI_H - -#include "symbianutils_global.h" - -#include - -QT_BEGIN_NAMESPACE -class QWidget; -QT_END_NAMESPACE - -namespace trk { -class BaseCommunicationStarter; - -/* promptStartCommunication(): Convenience functions that - * prompt the user to start a communication (launching or - * connecting TRK) using a modal message box in which they can cancel. - * Pass in the starter with device and parameters set up. */ - -enum PromptStartCommunicationResult { - PromptStartCommunicationConnected, - PromptStartCommunicationCanceled, - PromptStartCommunicationError -}; - -SYMBIANUTILS_EXPORT PromptStartCommunicationResult - promptStartCommunication(BaseCommunicationStarter &starter, - const QString &msgBoxTitle, - const QString &msgBoxText, - QWidget *msgBoxParent, - QString *errorMessage); - -// Convenience to start a serial connection (messages prompting -// to launch Trk). -SYMBIANUTILS_EXPORT PromptStartCommunicationResult - promptStartSerial(BaseCommunicationStarter &starter, - QWidget *msgBoxParent, - QString *errorMessage); - -// Convenience to start blue tooth connection (messages -// prompting to connect). -SYMBIANUTILS_EXPORT PromptStartCommunicationResult - promptStartBluetooth(BaseCommunicationStarter &starter, - QWidget *msgBoxParent, - QString *errorMessage); -} // namespace trk - -#endif // BLUETOOTHLISTENER_GUI_H diff --git a/tools/runonphone/trk/callback.h b/tools/runonphone/trk/callback.h deleted file mode 100644 index 3996d73..0000000 --- a/tools/runonphone/trk/callback.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef DEBUGGER_CALLBACK_H -#define DEBUGGER_CALLBACK_H - -#include "symbianutils_global.h" - -namespace trk { -namespace Internal { - -/* Helper class for the 1-argument functor: - * Cloneable base class for the implementation which is - * invokeable with the argument. */ -template -class CallbackImplBase -{ - Q_DISABLE_COPY(CallbackImplBase) -public: - CallbackImplBase() {} - virtual CallbackImplBase *clone() const = 0; - virtual void invoke(Argument a) = 0; - virtual ~CallbackImplBase() {} -}; - -/* Helper class for the 1-argument functor: Implementation for - * a class instance with a member function pointer. */ -template -class CallbackMemberPtrImpl : public CallbackImplBase -{ -public: - typedef void (Class::*MemberFuncPtr)(Argument); - - CallbackMemberPtrImpl(Class *instance, - MemberFuncPtr memberFunc) : - m_instance(instance), - m_memberFunc(memberFunc) {} - - virtual CallbackImplBase *clone() const - { - return new CallbackMemberPtrImpl(m_instance, m_memberFunc); - } - - virtual void invoke(Argument a) - { (m_instance->*m_memberFunc)(a); } -private: - Class *m_instance; - MemberFuncPtr m_memberFunc; -}; - -} // namespace Internal - -/* Default-constructible, copyable 1-argument functor providing an - * operator()(Argument) that invokes a member function of a class: - * \code -class Foo { -public: - void print(const std::string &); -}; -... -Foo foo; -Callback f1(&foo, &Foo::print); -f1("test"); -\endcode */ - -template -class Callback -{ -public: - Callback() : m_impl(0) {} - - template - Callback(Class *instance, void (Class::*memberFunc)(Argument)) : - m_impl(new Internal::CallbackMemberPtrImpl(instance, memberFunc)) - {} - - ~Callback() - { - clean(); - } - - Callback(const Callback &rhs) : - m_impl(0) - { - if (rhs.m_impl) - m_impl = rhs.m_impl->clone(); - } - - Callback &operator=(const Callback &rhs) - { - if (this != &rhs) { - clean(); - if (rhs.m_impl) - m_impl = rhs.m_impl->clone(); - } - return *this; - } - - bool isNull() const { return m_impl == 0; } - operator bool() const { return !isNull(); } - - void operator()(Argument a) - { - if (m_impl) - m_impl->invoke(a); - } - -private: - void clean() - { - if (m_impl) { - delete m_impl; - m_impl = 0; - } - } - - Internal::CallbackImplBase *m_impl; -}; - -} // namespace trk - -#endif // DEBUGGER_CALLBACK_H diff --git a/tools/runonphone/trk/communicationstarter.cpp b/tools/runonphone/trk/communicationstarter.cpp deleted file mode 100644 index e5e556e..0000000 --- a/tools/runonphone/trk/communicationstarter.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "communicationstarter.h" -#include "bluetoothlistener.h" -#include "trkdevice.h" - -#include -#include - -namespace trk { - -// --------------- AbstractBluetoothStarter -struct BaseCommunicationStarterPrivate { - explicit BaseCommunicationStarterPrivate(const BaseCommunicationStarter::TrkDevicePtr &d); - - const BaseCommunicationStarter::TrkDevicePtr trkDevice; - BluetoothListener *listener; - QTimer *timer; - int intervalMS; - int attempts; - int n; - QString device; - QString errorString; - BaseCommunicationStarter::State state; -}; - -BaseCommunicationStarterPrivate::BaseCommunicationStarterPrivate(const BaseCommunicationStarter::TrkDevicePtr &d) : - trkDevice(d), - listener(0), - timer(0), - intervalMS(1000), - attempts(-1), - n(0), - device(QLatin1String("/dev/rfcomm0")), - state(BaseCommunicationStarter::TimedOut) -{ -} - -BaseCommunicationStarter::BaseCommunicationStarter(const TrkDevicePtr &trkDevice, QObject *parent) : - QObject(parent), - d(new BaseCommunicationStarterPrivate(trkDevice)) -{ -} - -BaseCommunicationStarter::~BaseCommunicationStarter() -{ - stopTimer(); - delete d; -} - -void BaseCommunicationStarter::stopTimer() -{ - if (d->timer && d->timer->isActive()) - d->timer->stop(); -} - -bool BaseCommunicationStarter::initializeStartupResources(QString *errorMessage) -{ - errorMessage->clear(); - return true; -} - -BaseCommunicationStarter::StartResult BaseCommunicationStarter::start() -{ - if (state() == Running) { - d->errorString = QLatin1String("Internal error, attempt to re-start BaseCommunicationStarter.\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; - // Pull up resources for next attempt - d->n = 0; - if (!initializeStartupResources(&(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; -} - -BaseCommunicationStarter::State BaseCommunicationStarter::state() const -{ - return d->state; -} - -int BaseCommunicationStarter::intervalMS() const -{ - return d->intervalMS; -} - -void BaseCommunicationStarter::setIntervalMS(int i) -{ - d->intervalMS = i; - if (d->timer) - d->timer->setInterval(i); -} - -int BaseCommunicationStarter::attempts() const -{ - return d->attempts; -} - -void BaseCommunicationStarter::setAttempts(int a) -{ - d->attempts = a; -} - -QString BaseCommunicationStarter::device() const -{ - return d->device; -} - -void BaseCommunicationStarter::setDevice(const QString &dv) -{ - d->device = dv; -} - -QString BaseCommunicationStarter::errorString() const -{ - return d->errorString; -} - -void BaseCommunicationStarter::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); - emit message(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); - emit message(msg); - } - } -} - -// --------------- AbstractBluetoothStarter - -AbstractBluetoothStarter::AbstractBluetoothStarter(const TrkDevicePtr &trkDevice, QObject *parent) : - BaseCommunicationStarter(trkDevice, parent) -{ -} - -bool AbstractBluetoothStarter::initializeStartupResources(QString *errorMessage) -{ - // Create the listener and forward messages to it. - BluetoothListener *listener = createListener(); - connect(this, SIGNAL(message(QString)), listener, SLOT(emitMessage(QString))); - return listener->start(device(), errorMessage); -} - -// -------- 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/tools/runonphone/trk/communicationstarter.h b/tools/runonphone/trk/communicationstarter.h deleted file mode 100644 index 2d7dc50..0000000 --- a/tools/runonphone/trk/communicationstarter.h +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef COMMUNICATIONSTARTER_H -#define COMMUNICATIONSTARTER_H - -#include "symbianutils_global.h" - -#include -#include - -namespace trk { -class TrkDevice; -class BluetoothListener; -struct BaseCommunicationStarterPrivate; - -/* BaseCommunicationStarter: A QObject that repeatedly tries to open a - * trk device until a connection succeeds or a timeout occurs (emitting - * signals), allowing to do something else in the foreground (local event loop - * [say QMessageBox] or some asynchronous operation). If the initial - * connection attempt in start() fails, the - * virtual initializeStartupResources() is called to initialize resources - * required to pull up the communication (namely Bluetooth listeners). - * The base class can be used as is to prompt the user to launch App TRK for a - * serial communication as this requires no further resource setup. */ - -class SYMBIANUTILS_EXPORT BaseCommunicationStarter : public QObject { - Q_OBJECT - Q_DISABLE_COPY(BaseCommunicationStarter) -public: - typedef QSharedPointer TrkDevicePtr; - - enum State { Running, Connected, TimedOut }; - - explicit BaseCommunicationStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); - virtual ~BaseCommunicationStarter(); - - 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(); - void message(const QString &); - -private slots: - void slotTimer(); - -protected: - virtual bool initializeStartupResources(QString *errorMessage); - -private: - inline void stopTimer(); - - BaseCommunicationStarterPrivate *d; -}; - -/* AbstractBluetoothStarter: Repeatedly tries to open a trk Bluetooth - * device. Note that in case a Listener is already running mode, the - * connection will succeed immediately. - * initializeStartupResources() is implemented to fire up the listener. - * Introduces a new virtual createListener() that derived classes must - * implement as a factory function that creates and sets up the - * listener (mode, message connection, etc). */ - -class SYMBIANUTILS_EXPORT AbstractBluetoothStarter : public BaseCommunicationStarter { - Q_OBJECT - Q_DISABLE_COPY(AbstractBluetoothStarter) -public: - -protected: - explicit AbstractBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0); - - // Implemented to fire up the listener. - virtual bool initializeStartupResources(QString *errorMessage); - // New virtual: Overwrite to create and parametrize the listener. - virtual BluetoothListener *createListener() = 0; -}; - -/* ConsoleBluetoothStarter: Convenience class for console processes. Creates a - * listener in "Listen" mode with the messages redirected to standard output. */ - -class SYMBIANUTILS_EXPORT 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 // COMMUNICATIONSTARTER_H diff --git a/tools/runonphone/trk/launcher.cpp b/tools/runonphone/trk/launcher.cpp deleted file mode 100644 index 4f91545..0000000 --- a/tools/runonphone/trk/launcher.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "launcher.h" -#include "trkutils.h" -#include "trkutils_p.h" -#include "trkdevice.h" -#include "bluetoothlistener.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace trk { - -struct LauncherPrivate { - struct CopyState { - QString sourceFileName; - QString destinationFileName; - uint copyFileHandle; - QScopedPointer data; - int position; - }; - - explicit LauncherPrivate(const TrkDevicePtr &d); - - TrkDevicePtr m_device; - QString m_trkServerName; - QByteArray m_trkReadBuffer; - Launcher::State m_state; - - void logMessage(const QString &msg); - // Debuggee state - Session m_session; // global-ish data (process id, target information) - - CopyState m_copyState; - QString m_fileName; - QStringList m_commandLineArgs; - QString m_installFileName; - int m_verbose; - Launcher::Actions m_startupActions; - bool m_closeDevice; -}; - -LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) : - m_device(d), - m_state(Launcher::Disconnected), - m_verbose(0), - m_closeDevice(true) -{ - if (m_device.isNull()) - m_device = TrkDevicePtr(new TrkDevice); -} - -Launcher::Launcher(Actions startupActions, - const TrkDevicePtr &dev, - QObject *parent) : - QObject(parent), - d(new LauncherPrivate(dev)) -{ - d->m_startupActions = startupActions; - connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult))); - connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); -} - -Launcher::~Launcher() -{ - logMessage("Shutting down.\n"); - delete d; -} - -Launcher::State Launcher::state() const -{ - return d->m_state; -} - -void Launcher::setState(State s) -{ - if (s != d->m_state) { - d->m_state = s; - emit stateChanged(s); - } -} - -void Launcher::addStartupActions(trk::Launcher::Actions startupActions) -{ - d->m_startupActions = Actions(d->m_startupActions | startupActions); -} - -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; -} - -void Launcher::setCopyFileName(const QString &srcName, const QString &dstName) -{ - d->m_copyState.sourceFileName = srcName; - d->m_copyState.destinationFileName = dstName; -} - -void Launcher::setInstallFileName(const QString &name) -{ - d->m_installFileName = name; -} - -void Launcher::setCommandLineArgs(const QStringList &args) -{ - d->m_commandLineArgs = args; -} - -void Launcher::setSerialFrame(bool b) -{ - d->m_device->setSerialFrame(b); -} - -bool Launcher::serialFrame() const -{ - 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 Arguments=%3 Package=%4 Remote Package=%5 Install file=%6") - .arg(d->m_trkServerName, d->m_fileName, - d->m_commandLineArgs.join(QString(QLatin1Char(' '))), - d->m_copyState.sourceFileName, d->m_copyState.destinationFileName, d->m_installFileName); - logMessage(msg); - } - if (d->m_startupActions & ActionCopy) { - if (d->m_copyState.sourceFileName.isEmpty()) { - qWarning("No local filename given for copying package."); - return false; - } else if (d->m_copyState.destinationFileName.isEmpty()) { - qWarning("No remote filename given for copying package."); - return false; - } - } - if (d->m_startupActions & ActionInstall && d->m_installFileName.isEmpty()) { - qWarning("No package name given for installing."); - return false; - } - if (d->m_startupActions & ActionRun && d->m_fileName.isEmpty()) { - qWarning("No remote executable given for running."); - return false; - } - if (!d->m_device->isOpen() && !d->m_device->open(d->m_trkServerName, errorMessage)) - return false; - if (d->m_closeDevice) { - connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); - } else { - disconnect(this, SIGNAL(finished()), d->m_device.data(), 0); - } - setState(Connecting); - // Set up the temporary 'waiting' state if we do not get immediate connection - QTimer::singleShot(1000, this, SLOT(slotWaitingForTrk())); - 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)); - return true; -} - -void Launcher::slotWaitingForTrk() -{ - // Set temporary state if we are still in connected state - if (state() == Connecting) - setState(WaitingForTrk); -} - -void Launcher::handleConnect(const TrkResult &result) -{ - if (result.errorCode()) { - emit canNotConnect(result.errorString()); - return; - } - setState(Connected); - if (d->m_startupActions & ActionCopy) - copyFileToRemote(); - else if (d->m_startupActions & ActionInstall) - installRemotePackageSilently(); - else if (d->m_startupActions & ActionRun) - startInferiorIfNeeded(); -} - -void Launcher::setVerbose(int v) -{ - d->m_verbose = v; - d->m_device->setVerbose(v); -} - -void Launcher::logMessage(const QString &msg) -{ - if (d->m_verbose) - qDebug() << "LAUNCHER: " << qPrintable(msg); -} - -void Launcher::terminate() -{ - switch (state()) { - case DeviceDescriptionReceived: - case Connected: - if (d->m_session.pid) { - QByteArray ba; - appendShort(&ba, 0x0000, TargetByteOrder); - appendInt(&ba, d->m_session.pid, TargetByteOrder); - d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); - return; - } - if (d->m_copyState.copyFileHandle) - closeRemoteFile(true); - disconnectTrk(); - break; - case Disconnected: - break; - case Connecting: - case WaitingForTrk: - setState(Disconnected); - emit finished(); - break; - } -} - -void Launcher::handleRemoteProcessKilled(const TrkResult &result) -{ - Q_UNUSED(result) - disconnectTrk(); -} - -QString Launcher::msgStopped(uint pid, uint tid, uint address, const QString &why) -{ - return QString::fromLatin1("Process %1, thread %2 stopped at 0x%3: %4"). - arg(pid).arg(tid).arg(address, 0, 16). - arg(why.isEmpty() ? QString::fromLatin1("") : why); -} - -bool Launcher::parseNotifyStopped(const QByteArray &dataBA, - uint *pid, uint *tid, uint *address, - QString *why /* = 0 */) -{ - if (why) - why->clear(); - *address = *pid = *tid = 0; - if (dataBA.size() < 12) - return false; - const char *data = dataBA.data(); - *address = extractInt(data); - *pid = extractInt(data + 4); - *tid = extractInt(data + 8); - if (why && dataBA.size() >= 14) { - const unsigned short len = extractShort(data + 12); - if (len > 0) - *why = QString::fromLatin1(data + 14, len); - } - return true; -} - -void Launcher::handleResult(const TrkResult &result) -{ - QByteArray prefix = "READ BUF: "; - QByteArray str = result.toString().toUtf8(); - if (result.isDebugOutput) { // handle application output - logMessage("APPLICATION OUTPUT: " + result.data); - emit applicationOutputReceived(result.data); - return; - } - switch (result.code) { - case TrkNotifyAck: - break; - case TrkNotifyNak: { // NAK - logMessage(prefix + "NAK: " + str); - //logMessage(prefix << "TOKEN: " << result.token); - logMessage(prefix + "ERROR: " + errorMessage(result.data.at(0))); - break; - } - case TrkNotifyStopped: { // Notified Stopped - QString reason; - uint pc; - uint pid; - uint tid; - parseNotifyStopped(result.data, &pid, &tid, &pc, &reason); - logMessage(prefix + msgStopped(pid, tid, pc, reason)); - emit(processStopped(pc, pid, tid, reason)); - d->m_device->sendTrkAck(result.token); - break; - } - case TrkNotifyException: { // Notify Exception (obsolete) - logMessage(prefix + "NOTE: EXCEPTION " + str); - d->m_device->sendTrkAck(result.token); - break; - } - case TrkNotifyInternalError: { // - logMessage(prefix + "NOTE: INTERNAL ERROR: " + str); - d->m_device->sendTrkAck(result.token); - break; - } - - // target->host OS notification - case TrkNotifyCreated: { // Notify Created - /* - const char *data = result.data.data(); - byte error = result.data.at(0); - byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2. - uint pid = extractInt(data + 2); // ProcessID: 4 bytes; - uint tid = extractInt(data + 6); //threadID: 4 bytes - uint codeseg = extractInt(data + 10); //code address: 4 bytes; code base address for the library - uint dataseg = extractInt(data + 14); //data address: 4 bytes; data base address for the library - uint len = extractShort(data + 18); //length: 2 bytes; length of the library name string to follow - QByteArray name = result.data.mid(20, len); // name: library name - - logMessage(prefix + "NOTE: LIBRARY LOAD: " + str); - logMessage(prefix + "TOKEN: " + result.token); - logMessage(prefix + "ERROR: " + int(error)); - logMessage(prefix + "TYPE: " + int(type)); - logMessage(prefix + "PID: " + pid); - logMessage(prefix + "TID: " + tid); - logMessage(prefix + "CODE: " + codeseg); - logMessage(prefix + "DATA: " + dataseg); - logMessage(prefix + "LEN: " + len); - logMessage(prefix + "NAME: " + name); - */ - - if (result.data.size() < 10) - break; - QByteArray ba; - ba.append(result.data.mid(2, 8)); - d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); - //d->m_device->sendTrkAck(result.token) - break; - } - case TrkNotifyDeleted: { // NotifyDeleted - const ushort itemType = (unsigned char)result.data.at(1); - const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0); - const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString(); - 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); - if (itemType == 0 // process - && result.data.size() >= 10 - && d->m_session.pid == extractInt(result.data.data() + 6)) { - disconnectTrk(); - } - break; - } - case TrkNotifyProcessorStarted: { // NotifyProcessorStarted - logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str); - d->m_device->sendTrkAck(result.token); - break; - } - case TrkNotifyProcessorStandBy: { // NotifyProcessorStandby - logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str); - d->m_device->sendTrkAck(result.token); - break; - } - case TrkNotifyProcessorReset: { // NotifyProcessorReset - logMessage(prefix + "NOTE: PROCESSOR RESET: " + str); - d->m_device->sendTrkAck(result.token); - break; - } - default: { - logMessage(prefix + "INVALID: " + str); - break; - } - } -} - -QString Launcher::deviceDescription(unsigned verbose) const -{ - return d->m_session.deviceDescription(verbose); -} - -void Launcher::handleTrkVersion(const TrkResult &result) -{ - if (result.errorCode() || result.data.size() < 5) { - if (d->m_startupActions == ActionPingOnly) { - setState(Disconnected); - emit finished(); - } - return; - } - d->m_session.trkAppVersion.trkMajor = result.data.at(1); - d->m_session.trkAppVersion.trkMinor = result.data.at(2); - d->m_session.trkAppVersion.protocolMajor = result.data.at(3); - d->m_session.trkAppVersion.protocolMinor = result.data.at(4); - setState(DeviceDescriptionReceived); - // Ping mode: Log & Terminate - if (d->m_startupActions == ActionPingOnly) { - qWarning("%s", qPrintable(deviceDescription())); - setState(Disconnected); - emit finished(); - } -} - -void Launcher::handleFileCreation(const TrkResult &result) -{ - if (result.errorCode() || result.data.size() < 6) { - emit canNotCreateFile(d->m_copyState.destinationFileName, result.errorString()); - disconnectTrk(); - return; - } - const char *data = result.data.data(); - d->m_copyState.copyFileHandle = extractInt(data + 2); - QFile file(d->m_copyState.sourceFileName); - file.open(QIODevice::ReadOnly); - d->m_copyState.data.reset(new QByteArray(file.readAll())); - d->m_copyState.position = 0; - file.close(); - continueCopying(); -} - -void Launcher::handleCopy(const TrkResult &result) -{ - if (result.errorCode() || result.data.size() < 4) { - closeRemoteFile(true); - emit canNotWriteFile(d->m_copyState.destinationFileName, result.errorString()); - disconnectTrk(); - } else { - continueCopying(extractShort(result.data.data() + 2)); - } -} - -void Launcher::continueCopying(uint lastCopiedBlockSize) -{ - int size = d->m_copyState.data->length(); - d->m_copyState.position += lastCopiedBlockSize; - if (size == 0) - emit copyProgress(100); - else { - int percent = qMin((d->m_copyState.position*100)/size, 100); - emit copyProgress(percent); - } - if (d->m_copyState.position < size) { - 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); - } else { - closeRemoteFile(); - } -} - -void Launcher::closeRemoteFile(bool failed) -{ - QByteArray ba; - appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder); - appendDateTime(&ba, QDateTime::currentDateTime(), TargetByteOrder); - d->m_device->sendTrkMessage(TrkCloseFile, - failed ? TrkCallback() : TrkCallback(this, &Launcher::handleFileCopied), - ba); - d->m_copyState.data.reset(); - d->m_copyState.copyFileHandle = 0; - d->m_copyState.position = 0; -} - -void Launcher::handleFileCopied(const TrkResult &result) -{ - if (result.errorCode()) - emit canNotCloseFile(d->m_copyState.destinationFileName, result.errorString()); - if (d->m_startupActions & ActionInstall) - installRemotePackageSilently(); - else if (d->m_startupActions & ActionRun) - startInferiorIfNeeded(); - else - disconnectTrk(); -} - -void Launcher::handleCpuType(const TrkResult &result) -{ - logMessage("HANDLE CPU TYPE: " + result.toString()); - if(result.errorCode() || result.data.size() < 7) - return; - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 03 00 04 00 00 04 00 00 00] - d->m_session.cpuMajor = result.data.at(1); - d->m_session.cpuMinor = result.data.at(2); - d->m_session.bigEndian = result.data.at(3); - d->m_session.defaultTypeSize = result.data.at(4); - d->m_session.fpTypeSize = result.data.at(5); - d->m_session.extended1TypeSize = result.data.at(6); - //d->m_session.extended2TypeSize = result.data[6]; -} - -void Launcher::handleCreateProcess(const TrkResult &result) -{ - if (result.errorCode()) { - emit canNotRun(result.errorString()); - disconnectTrk(); - return; - } - // 40 00 00] - //logMessage(" RESULT: " + result.toString()); - // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] - const char *data = result.data.data(); - d->m_session.pid = extractInt(data + 1); - d->m_session.tid = extractInt(data + 5); - d->m_session.codeseg = extractInt(data + 9); - d->m_session.dataseg = extractInt(data + 13); - if (d->m_verbose) { - const QString msg = QString::fromLatin1("Process id: %1 Thread id: %2 code: 0x%3 data: 0x%4"). - arg(d->m_session.pid).arg(d->m_session.tid).arg(d->m_session.codeseg, 0, 16). - arg(d->m_session.dataseg, 0 ,16); - logMessage(msg); - } - emit applicationRunning(d->m_session.pid); - QByteArray ba; - appendInt(&ba, d->m_session.pid); - appendInt(&ba, d->m_session.tid); - d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); -} - -void Launcher::handleWaitForFinished(const TrkResult &result) -{ - logMessage(" FINISHED: " + stringFromArray(result.data)); - setState(Disconnected); - emit finished(); -} - -void Launcher::handleSupportMask(const TrkResult &result) -{ - if (result.errorCode() || result.data.size() < 32) - return; - const char *data = result.data.data() + 1; - - QString str = QLatin1String("SUPPORTED: "); - for (int i = 0; i < 32; ++i) { - //str.append(" [" + formatByte(data[i]) + "]: "); - for (int j = 0; j < 8; ++j) { - if (data[i] & (1 << j)) { - str.append(QString::number(i * 8 + j, 16)); - str.append(QLatin1Char(' ')); - } - } - } - logMessage(str); -} - -void Launcher::cleanUp() -{ - // - //---IDE------------------------------------------------------ - // Command: 0x41 Delete Item - // Sub Cmd: Delete Process - //ProcessID: 0x0000071F (1823) - // [41 24 00 00 00 00 07 1F] - QByteArray ba(2, char(0)); - appendInt(&ba, d->m_session.pid); - d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process"); - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 24 00] - - //---IDE------------------------------------------------------ - // Command: 0x1C Clear Break - // [1C 25 00 00 00 0A 78 6A 43 40] - - //---TRK------------------------------------------------------ - // Command: 0xA1 Notify Deleted - // [A1 09 00 00 00 00 00 00 00 00 07 1F] - //---IDE------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00] - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 25 00] - - //---IDE------------------------------------------------------ - // Command: 0x1C Clear Break - // [1C 26 00 00 00 0B 78 6A 43 70] - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 26 00] - - - //---IDE------------------------------------------------------ - // Command: 0x02 Disconnect - // [02 27] -// sendTrkMessage(0x02, TrkCallback(this, &Launcher::handleDisconnect)); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 -} - -void Launcher::disconnectTrk() -{ - d->m_device->sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished)); -} - -void Launcher::copyFileToRemote() -{ - emit copyingStarted(); - QByteArray ba; - ba.append(char(10)); - appendString(&ba, d->m_copyState.destinationFileName.toLocal8Bit(), TargetByteOrder, false); - d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba); -} - -void Launcher::installRemotePackageSilently() -{ - emit installingStarted(); - QByteArray ba; - ba.append('C'); - appendString(&ba, d->m_installFileName.toLocal8Bit(), TargetByteOrder, false); - d->m_device->sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba); -} - -void Launcher::handleInstallPackageFinished(const TrkResult &result) -{ - if (result.errorCode()) { - emit canNotInstall(d->m_installFileName, result.errorString()); - disconnectTrk(); - return; - } else { - emit installingFinished(); - } - if (d->m_startupActions & ActionRun) { - startInferiorIfNeeded(); - } else { - disconnectTrk(); - } -} - -QByteArray Launcher::startProcessMessage(const QString &executable, - const QStringList &arguments) -{ - // It's not started yet - QByteArray ba; - appendShort(&ba, 0, TargetByteOrder); // create new process - ba.append(char(0)); // options - currently unused - if(arguments.isEmpty()) { - appendString(&ba, executable.toLocal8Bit(), TargetByteOrder); - return ba; - } - // Append full command line as one string (leading length information). - QByteArray commandLineBa; - commandLineBa.append(executable.toLocal8Bit()); - commandLineBa.append('\0'); - commandLineBa.append(arguments.join(QString(QLatin1Char(' '))).toLocal8Bit()); - appendString(&ba, commandLineBa, TargetByteOrder); - return ba; -} - -void Launcher::startInferiorIfNeeded() -{ - emit startingApplication(); - if (d->m_session.pid != 0) { - logMessage("Process already 'started'"); - return; - } - d->m_device->sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), - startProcessMessage(d->m_fileName, d->m_commandLineArgs)); // Create Item -} - -void Launcher::resumeProcess(uint pid, uint tid) -{ - QByteArray ba; - appendInt(&ba, pid, BigEndian); - appendInt(&ba, tid, BigEndian); - d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); -} -} // namespace trk diff --git a/tools/runonphone/trk/launcher.h b/tools/runonphone/trk/launcher.h deleted file mode 100644 index 2b23fd8..0000000 --- a/tools/runonphone/trk/launcher.h +++ /dev/null @@ -1,179 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef LAUNCHER_H -#define LAUNCHER_H - -#include "trkdevice.h" - -#include -#include -#include - -namespace trk { - -struct TrkResult; -struct TrkMessage; -struct LauncherPrivate; - -typedef QSharedPointer TrkDevicePtr; - -class SYMBIANUTILS_EXPORT Launcher : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(Launcher) -public: - typedef void (Launcher::*TrkCallBack)(const TrkResult &); - - enum Actions { - ActionPingOnly = 0x0, - ActionCopy = 0x1, - ActionInstall = 0x2, - ActionCopyInstall = ActionCopy | ActionInstall, - ActionRun = 0x4, - ActionCopyRun = ActionCopy | ActionRun, - ActionInstallRun = ActionInstall | ActionRun, - ActionCopyInstallRun = ActionCopy | ActionInstall | ActionRun - }; - - enum State { Disconnected, Connecting, Connected, - WaitingForTrk, // This occurs only if the initial ping times out after - // a reasonable timeout, indicating that Trk is not - // running. Note that this will never happen with - // Bluetooth as communication immediately starts - // after connecting. - DeviceDescriptionReceived }; - - explicit Launcher(trk::Launcher::Actions startupActions = trk::Launcher::ActionPingOnly, - const TrkDevicePtr &trkDevice = TrkDevicePtr(), - QObject *parent = 0); - ~Launcher(); - - State state() const; - - 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); - void setCommandLineArgs(const QStringList &args); - bool startServer(QString *errorMessage); - 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; - - static QByteArray startProcessMessage(const QString &executable, - const QStringList &arguments); - // Parse a TrkNotifyStopped message - static bool parseNotifyStopped(const QByteArray &a, - uint *pid, uint *tid, uint *address, - QString *why = 0); - // Helper message - static QString msgStopped(uint pid, uint tid, uint address, const QString &why); - -signals: - void copyingStarted(); - void canNotConnect(const QString &errorMessage); - void canNotCreateFile(const QString &filename, const QString &errorMessage); - void canNotWriteFile(const QString &filename, const QString &errorMessage); - void canNotCloseFile(const QString &filename, const QString &errorMessage); - void installingStarted(); - void canNotInstall(const QString &packageFilename, const QString &errorMessage); - void installingFinished(); - void startingApplication(); - void applicationRunning(uint pid); - void canNotRun(const QString &errorMessage); - void finished(); - void applicationOutputReceived(const QString &output); - void copyProgress(int percent); - void stateChanged(int); - void processStopped(uint pc, uint pid, uint tid, const QString& reason); - -public slots: - void terminate(); - void resumeProcess(uint pid, uint tid); - -private slots: - void handleResult(const trk::TrkResult &data); - void slotWaitingForTrk(); - -private: - // kill process and breakpoints - void cleanUp(); - void disconnectTrk(); - - void handleRemoteProcessKilled(const TrkResult &result); - void handleConnect(const TrkResult &result); - void handleFileCreation(const TrkResult &result); - void handleCopy(const TrkResult &result); - void continueCopying(uint lastCopiedBlockSize = 0); - void closeRemoteFile(bool failed = false); - void handleFileCopied(const TrkResult &result); - void handleInstallPackageFinished(const TrkResult &result); - void handleCpuType(const TrkResult &result); - void handleCreateProcess(const TrkResult &result); - void handleWaitForFinished(const TrkResult &result); - void handleStop(const TrkResult &result); - void handleSupportMask(const TrkResult &result); - void handleTrkVersion(const TrkResult &result); - - void copyFileToRemote(); - void installRemotePackageSilently(); - void startInferiorIfNeeded(); - - void logMessage(const QString &msg); - void setState(State s); - - LauncherPrivate *d; -}; - -} // namespace Trk - -#endif // LAUNCHER_H diff --git a/tools/runonphone/trk/symbianutils_global.h b/tools/runonphone/trk/symbianutils_global.h deleted file mode 100644 index a6ffbe7..0000000 --- a/tools/runonphone/trk/symbianutils_global.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SYMBIANUTILS_GLOBAL_H -#define SYMBIANUTILS_GLOBAL_H - -#include - -#if defined(SYMBIANUTILS_BUILD_LIB) -# define SYMBIANUTILS_EXPORT Q_DECL_EXPORT -#elif defined(SYMBIANUTILS_BUILD_STATIC_LIB) || defined(SYMBIANUTILS_INCLUDE_PRI) -# define SYMBIANUTILS_EXPORT -#else -# define SYMBIANUTILS_EXPORT Q_DECL_IMPORT -#endif - -#endif // SYMBIANUTILS_GLOBAL_H diff --git a/tools/runonphone/trk/trk.pri b/tools/runonphone/trk/trk.pri deleted file mode 100644 index a54df76..0000000 --- a/tools/runonphone/trk/trk.pri +++ /dev/null @@ -1,25 +0,0 @@ -INCLUDEPATH *= $$PWD - -# Input -HEADERS += $$PWD/symbianutils_global.h \ - $$PWD/callback.h \ - $$PWD/trkutils.h \ - $$PWD/trkutils_p.h \ - $$PWD/trkdevice.h \ - $$PWD/launcher.h \ - $$PWD/bluetoothlistener.h \ - $$PWD/communicationstarter.h - -SOURCES += $$PWD/trkutils.cpp \ - $$PWD/trkdevice.cpp \ - $$PWD/launcher.cpp \ - $$PWD/bluetoothlistener.cpp \ - $$PWD/communicationstarter.cpp - -# Tests/trklauncher is a console application -contains(QT, gui) { - HEADERS += $$PWD/bluetoothlistener_gui.h - SOURCES += $$PWD/bluetoothlistener_gui.cpp -} else { - message(Trk: Console ...) -} diff --git a/tools/runonphone/trk/trkdevice.cpp b/tools/runonphone/trk/trkdevice.cpp deleted file mode 100644 index d587135..0000000 --- a/tools/runonphone/trk/trkdevice.cpp +++ /dev/null @@ -1,1105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "trkdevice.h" -#include "trkutils.h" -#include "trkutils_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_WIN -# include -#else -# include - -# include -# include -# include -# include -# include -# include -# include -/* Required headers for select() according to POSIX.1-2001 */ -# include -/* Required headers for select() according to earlier standards: - #include - #include - #include -*/ -#endif - -#ifdef Q_OS_WIN - -// Format windows error from GetLastError() value: -// TODO: Use the one provided by the utils lib. -QString winErrorMessage(unsigned long error) -{ - QString rc = QString::fromLatin1("#%1: ").arg(error); - ushort *lpMsgBuf; - - const int len = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL); - if (len) { - rc = QString::fromUtf16(lpMsgBuf, len); - LocalFree(lpMsgBuf); - } else { - rc += QString::fromLatin1(""); - } - return rc; -} - -#endif - -enum { verboseTrk = 0 }; - -namespace trk { - -/////////////////////////////////////////////////////////////////////// -// -// TrkMessage -// -/////////////////////////////////////////////////////////////////////// - -/* A message to be send to TRK, triggering a callback on receipt - * of the answer. */ -struct TrkMessage -{ - explicit TrkMessage(byte code = 0u, byte token = 0u, - TrkCallback callback = TrkCallback()); - - byte code; - byte token; - QByteArray data; - QVariant cookie; - TrkCallback callback; -}; - -TrkMessage::TrkMessage(byte c, byte t, TrkCallback cb) : - code(c), - token(t), - callback(cb) -{ -} - -QDebug operator<<(QDebug d, const TrkMessage &msg) -{ - return d << "Message: Code: " << msg.code - << " Token: " << msg.token << " " << msg.data.toHex(); -} - -} // namespace trk - -Q_DECLARE_METATYPE(trk::TrkMessage) -Q_DECLARE_METATYPE(trk::TrkResult) - -namespace trk { - -/////////////////////////////////////////////////////////////////////// -// -// TrkWriteQueue: Mixin class that manages a write queue of Trk messages. -// pendingMessage()/notifyWriteResult() should be called from a worked/timer -// that writes the messages. The class does not take precautions for multithreading. -// A no-op message is simply taken off the queue. The calling class -// can use the helper invokeNoopMessage() to trigger its callback. -// -/////////////////////////////////////////////////////////////////////// - -class TrkWriteQueue -{ - Q_DISABLE_COPY(TrkWriteQueue) -public: - explicit TrkWriteQueue(); - - // Enqueue messages. - void queueTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie); - void queueTrkInitialPing(); - - // Call this from the device read notification with the results. - void slotHandleResult(const TrkResult &result, QMutex *mutex = 0); - - // pendingMessage() can be called periodically in a timer to retrieve - // the pending messages to be sent. - enum PendingMessageResult { - NoMessage, // No message in queue. - PendingMessage, /* There is a queued message. The calling class - * can write it out and use notifyWriteResult() - * to notify about the result. */ - NoopMessageDequeued // A no-op message has been dequeued. see invokeNoopMessage(). - }; - - PendingMessageResult pendingMessage(TrkMessage *message); - // Notify the queue about the success of the write operation - // after taking the pendingMessage off. - enum WriteResult { - WriteOk, - WriteFailedDiscard, // Discard failed message - WriteFailedKeep, // Keep failed message - }; - void notifyWriteResult(WriteResult ok); - - // Helper function that invokes the callback of a no-op message - static void invokeNoopMessage(trk::TrkMessage); - -private: - typedef QMap TokenMessageMap; - - byte nextTrkWriteToken(); - - byte m_trkWriteToken; - QQueue m_trkWriteQueue; - TokenMessageMap m_writtenTrkMessages; - bool m_trkWriteBusy; -}; - -TrkWriteQueue::TrkWriteQueue() : - m_trkWriteToken(0), - m_trkWriteBusy(false) -{ -} - -byte TrkWriteQueue::nextTrkWriteToken() -{ - ++m_trkWriteToken; - if (m_trkWriteToken == 0) - ++m_trkWriteToken; - if (verboseTrk) - qDebug() << "Write token: " << m_trkWriteToken; - return m_trkWriteToken; -} - -void TrkWriteQueue::queueTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie) -{ - const byte token = code == TRK_WRITE_QUEUE_NOOP_CODE ? - byte(0) : nextTrkWriteToken(); - TrkMessage msg(code, token, callback); - msg.data = data; - msg.cookie = cookie; - m_trkWriteQueue.append(msg); -} - -TrkWriteQueue::PendingMessageResult TrkWriteQueue::pendingMessage(TrkMessage *message) -{ - // Invoked from timer, try to flush out message queue - if (m_trkWriteBusy || m_trkWriteQueue.isEmpty()) - return NoMessage; - // Handle the noop message, just invoke CB in slot (ower thread) - if (m_trkWriteQueue.front().code == TRK_WRITE_QUEUE_NOOP_CODE) { - *message = m_trkWriteQueue.dequeue(); - return NoopMessageDequeued; - } - // Insert into map fir answers (as reading threads might get an - // answer before notifyWriteResult(true)) is called. - *message = m_trkWriteQueue.front(); - m_writtenTrkMessages.insert(message->token, *message); - m_trkWriteBusy = true; - return PendingMessage; -} - -void TrkWriteQueue::invokeNoopMessage(trk::TrkMessage noopMessage) -{ - TrkResult result; - result.code = noopMessage.code; - result.token = noopMessage.token; - result.data = noopMessage.data; - result.cookie = noopMessage.cookie; - noopMessage.callback(result); -} - -void TrkWriteQueue::notifyWriteResult(WriteResult wr) -{ - // On success, dequeue message and await result - const byte token = m_trkWriteQueue.front().token; - switch (wr) { - case WriteOk: - m_trkWriteQueue.dequeue(); - break; - case WriteFailedKeep: - case WriteFailedDiscard: - m_writtenTrkMessages.remove(token); - m_trkWriteBusy = false; - if (wr == WriteFailedDiscard) - m_trkWriteQueue.dequeue(); - break; - } -} - -void TrkWriteQueue::slotHandleResult(const TrkResult &result, QMutex *mutex) -{ - // Find which request the message belongs to and invoke callback - // if ACK or on NAK if desired. - if (mutex) - mutex->lock(); - m_trkWriteBusy = false; - const TokenMessageMap::iterator it = m_writtenTrkMessages.find(result.token); - if (it == m_writtenTrkMessages.end()) { - if (mutex) - mutex->unlock(); - return; - } - TrkCallback callback = it.value().callback; - const QVariant cookie = it.value().cookie; - m_writtenTrkMessages.erase(it); - if (mutex) - mutex->unlock(); - // Invoke callback - if (callback) { - TrkResult result1 = result; - result1.cookie = cookie; - callback(result1); - } -} - -void TrkWriteQueue::queueTrkInitialPing() -{ - // Ping, reset sequence count - m_trkWriteToken = 0; - m_trkWriteQueue.append(TrkMessage(TrkPing, 0)); -} - -/////////////////////////////////////////////////////////////////////// -// -// DeviceContext to be shared between threads -// -/////////////////////////////////////////////////////////////////////// - -struct DeviceContext { - DeviceContext(); -#ifdef Q_OS_WIN - HANDLE device; - OVERLAPPED readOverlapped; - OVERLAPPED writeOverlapped; -#else - QFile file; -#endif - bool serialFrame; - QMutex mutex; -}; - -DeviceContext::DeviceContext() : -#ifdef Q_OS_WIN - device(INVALID_HANDLE_VALUE), -#endif - serialFrame(true) -{ -} - -/////////////////////////////////////////////////////////////////////// -// -// TrkWriterThread: A thread operating a TrkWriteQueue. -// with exception of the handling of the TRK_WRITE_QUEUE_NOOP_CODE -// synchronization message. The invocation of the callback is then -// done by the thread owning the TrkWriteQueue, while pendingMessage() is called -// from another thread. This happens via a Qt::BlockingQueuedConnection. - -/////////////////////////////////////////////////////////////////////// - -class WriterThread : public QThread -{ - Q_OBJECT - Q_DISABLE_COPY(WriterThread) -public: - explicit WriterThread(const QSharedPointer &context); - - // Enqueue messages. - void queueTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie); - void queueTrkInitialPing(); - - // Call this from the device read notification with the results. - void slotHandleResult(const TrkResult &result); - - virtual void run(); - -signals: - void error(const QString &); - void internalNoopMessageDequeued(const trk::TrkMessage&); - -public slots: - bool trkWriteRawMessage(const TrkMessage &msg); - void terminate(); - void tryWrite(); - -private slots: - void invokeNoopMessage(const trk::TrkMessage &); - -private: - bool write(const QByteArray &data, QString *errorMessage); - inline int writePendingMessage(); - - const QSharedPointer m_context; - QMutex m_dataMutex; - QMutex m_waitMutex; - QWaitCondition m_waitCondition; - TrkWriteQueue m_queue; - bool m_terminate; -}; - -WriterThread::WriterThread(const QSharedPointer &context) : - m_context(context), - m_terminate(false) -{ - static const int trkMessageMetaId = qRegisterMetaType(); - Q_UNUSED(trkMessageMetaId) - connect(this, SIGNAL(internalNoopMessageDequeued(trk::TrkMessage)), - this, SLOT(invokeNoopMessage(trk::TrkMessage)), Qt::BlockingQueuedConnection); -} - -void WriterThread::run() -{ - while (writePendingMessage() == 0) ; -} - -int WriterThread::writePendingMessage() -{ - enum { MaxAttempts = 100, RetryIntervalMS = 200 }; - - // Wait. Use a timeout in case something is already queued before we - // start up or some weird hanging exit condition - m_waitMutex.lock(); - m_waitCondition.wait(&m_waitMutex, 100); - m_waitMutex.unlock(); - if (m_terminate) - return 1; - - // Send off message - m_dataMutex.lock(); - TrkMessage message; - const TrkWriteQueue::PendingMessageResult pr = m_queue.pendingMessage(&message); - m_dataMutex.unlock(); - - switch (pr) { - case TrkWriteQueue::NoMessage: - break; - case TrkWriteQueue::PendingMessage: { - //qDebug() << "Write pending message " << message; - // Untested: try to re-send a few times - bool success = false; - for (int r = 0; !success && (r < MaxAttempts); r++) { - success = trkWriteRawMessage(message); - if (!success) { - emit error(QString::fromLatin1("Write failure, attempt %1 of %2.").arg(r).arg(int(MaxAttempts))); - if (m_terminate) - return 1; - QThread::msleep(RetryIntervalMS); - } - } - // Notify queue. If still failed, give up. - m_dataMutex.lock(); - m_queue.notifyWriteResult(success ? TrkWriteQueue::WriteOk : TrkWriteQueue::WriteFailedDiscard); - m_dataMutex.unlock(); - } - break; - case TrkWriteQueue::NoopMessageDequeued: - // Sync with thread that owns us via a blocking signal - if (verboseTrk) - qDebug() << "Noop message dequeued" << message; - emit internalNoopMessageDequeued(message); - break; - } // switch - return 0; -} - -void WriterThread::invokeNoopMessage(const trk::TrkMessage &msg) -{ - TrkWriteQueue::invokeNoopMessage(msg); -} - -void WriterThread::terminate() -{ - m_terminate = true; - m_waitCondition.wakeAll(); - wait(); - m_terminate = false; -} - -#ifdef Q_OS_WIN - -static inline QString msgTerminated(int size) -{ - return QString::fromLatin1("Terminated with %1 bytes pending.").arg(size); -} - -// Interruptible synchronous write function. -static inline bool overlappedSyncWrite(HANDLE file, - const bool &terminateFlag, - const char *data, - DWORD size, DWORD *charsWritten, - OVERLAPPED *overlapped, - QString *errorMessage) -{ - if (WriteFile(file, data, size, charsWritten, overlapped)) - return true; - const DWORD writeError = GetLastError(); - if (writeError != ERROR_IO_PENDING) { - *errorMessage = QString::fromLatin1("WriteFile failed: %1").arg(winErrorMessage(writeError)); - return false; - } - // Wait for written or thread terminated - const DWORD timeoutMS = 200; - const unsigned maxAttempts = 20; - DWORD wr = WaitForSingleObject(overlapped->hEvent, timeoutMS); - for (unsigned n = 0; wr == WAIT_TIMEOUT && n < maxAttempts && !terminateFlag; - wr = WaitForSingleObject(overlapped->hEvent, timeoutMS), n++); - if (terminateFlag) { - *errorMessage = msgTerminated(size); - return false; - } - switch (wr) { - case WAIT_OBJECT_0: - break; - case WAIT_TIMEOUT: - *errorMessage = QString::fromLatin1("Write timed out."); - return false; - default: - *errorMessage = QString::fromLatin1("Error while waiting for WriteFile results: %1").arg(winErrorMessage(GetLastError())); - return false; - } - if (!GetOverlappedResult(file, overlapped, charsWritten, TRUE)) { - *errorMessage = QString::fromLatin1("Error writing %1 bytes: %2").arg(size).arg(winErrorMessage(GetLastError())); - return false; - } - return true; -} -#endif - -bool WriterThread::write(const QByteArray &data, QString *errorMessage) -{ - if (verboseTrk) - qDebug() << "Write raw data: " << stringFromArray(data).toLatin1(); - QMutexLocker locker(&m_context->mutex); -#ifdef Q_OS_WIN - DWORD charsWritten; - if (!overlappedSyncWrite(m_context->device, m_terminate, data.data(), data.size(), &charsWritten, &m_context->writeOverlapped, errorMessage)) { - return false; - } - FlushFileBuffers(m_context->device); - return true; -#else - if (m_context->file.write(data) == -1 || !m_context->file.flush()) { - *errorMessage = QString::fromLatin1("Cannot write: %1").arg(m_context->file.errorString()); - return false; - } - return true; -#endif -} - -bool WriterThread::trkWriteRawMessage(const TrkMessage &msg) -{ - const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, m_context->serialFrame); - QString errorMessage; - const bool rc = write(ba, &errorMessage); - if (!rc) { - qWarning("%s\n", qPrintable(errorMessage)); - emit error(errorMessage); - } - return rc; -} - -void WriterThread::tryWrite() -{ - m_waitCondition.wakeAll(); -} - -void WriterThread::queueTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie) -{ - m_dataMutex.lock(); - m_queue.queueTrkMessage(code, callback, data, cookie); - m_dataMutex.unlock(); - tryWrite(); -} - -void WriterThread::queueTrkInitialPing() -{ - m_dataMutex.lock(); - m_queue.queueTrkInitialPing(); - m_dataMutex.unlock(); - tryWrite(); -} - -// Call this from the device read notification with the results. -void WriterThread::slotHandleResult(const TrkResult &result) -{ - m_queue.slotHandleResult(result, &m_dataMutex); - tryWrite(); // Have messages been enqueued in-between? -} - - -/////////////////////////////////////////////////////////////////////// -// -// ReaderThreadBase: Base class for a thread that reads data from -// the device, decodes the messages and emit signals for the messages. -// A Qt::BlockingQueuedConnection should be used for the message signal -// to ensure messages are processed in the correct sequence. -// -/////////////////////////////////////////////////////////////////////// - -class ReaderThreadBase : public QThread -{ - Q_OBJECT - Q_DISABLE_COPY(ReaderThreadBase) -public: - -signals: - void messageReceived(const trk::TrkResult &result, const QByteArray &rawData); - -protected: - explicit ReaderThreadBase(const QSharedPointer &context); - void processData(const QByteArray &a); - void processData(char c); - - const QSharedPointer m_context; - -private: - void readMessages(); - - QByteArray m_trkReadBuffer; -}; - -ReaderThreadBase::ReaderThreadBase(const QSharedPointer &context) : - m_context(context) -{ - static const int trkResultMetaId = qRegisterMetaType(); - Q_UNUSED(trkResultMetaId) -} - -void ReaderThreadBase::processData(const QByteArray &a) -{ - m_trkReadBuffer += a; - readMessages(); -} - -void ReaderThreadBase::processData(char c) -{ - m_trkReadBuffer += c; - if (m_trkReadBuffer.size() > 1) - readMessages(); -} - -void ReaderThreadBase::readMessages() -{ - TrkResult r; - QByteArray rawData; - while (extractResult(&m_trkReadBuffer, m_context->serialFrame, &r, &rawData)) { - emit messageReceived(r, rawData); - } -} - -#ifdef Q_OS_WIN -/////////////////////////////////////////////////////////////////////// -// -// WinReaderThread: A thread reading from the device using Windows API. -// Waits on an overlapped I/O handle and an event that tells the thread to -// terminate. -// -/////////////////////////////////////////////////////////////////////// - -class WinReaderThread : public ReaderThreadBase -{ - Q_OBJECT - Q_DISABLE_COPY(WinReaderThread) -public: - explicit WinReaderThread(const QSharedPointer &context); - ~WinReaderThread(); - - virtual void run(); - -signals: - void error(const QString &); - -public slots: - void terminate(); - -private: - enum Handles { FileHandle, TerminateEventHandle, HandleCount }; - - inline int tryRead(); - - HANDLE m_handles[HandleCount]; -}; - -WinReaderThread::WinReaderThread(const QSharedPointer &context) : - ReaderThreadBase(context) -{ - m_handles[FileHandle] = NULL; - m_handles[TerminateEventHandle] = CreateEvent(NULL, FALSE, FALSE, NULL); -} - -WinReaderThread::~WinReaderThread() -{ - CloseHandle(m_handles[TerminateEventHandle]); -} - -// Return 0 to continue or error code -int WinReaderThread::tryRead() -{ - enum { BufSize = 1024 }; - char buffer[BufSize]; - // Check if there are already bytes waiting. If not, wait for first byte - COMSTAT comStat; - if (!ClearCommError(m_context->device, NULL, &comStat)){ - emit error(QString::fromLatin1("ClearCommError failed: %1").arg(winErrorMessage(GetLastError()))); - return -7; - } - const DWORD bytesToRead = qMax(DWORD(1), qMin(comStat.cbInQue, DWORD(BufSize))); - // Trigger read - DWORD bytesRead = 0; - if (ReadFile(m_context->device, &buffer, bytesToRead, &bytesRead, &m_context->readOverlapped)) { - if (bytesRead == 1) { - processData(buffer[0]); - } else { - processData(QByteArray(buffer, bytesRead)); - } - return 0; - } - const DWORD readError = GetLastError(); - if (readError != ERROR_IO_PENDING) { - emit error(QString::fromLatin1("Read error: %1").arg(winErrorMessage(readError))); - return -1; - } - // Wait for either termination or data - const DWORD wr = WaitForMultipleObjects(HandleCount, m_handles, false, INFINITE); - if (wr == WAIT_FAILED) { - emit error(QString::fromLatin1("Wait failed: %1").arg(winErrorMessage(GetLastError()))); - return -2; - } - if (wr - WAIT_OBJECT_0 == TerminateEventHandle) { - return 1; // Terminate - } - // Check data - if (!GetOverlappedResult(m_context->device, &m_context->readOverlapped, &bytesRead, true)) { - emit error(QString::fromLatin1("GetOverlappedResult failed: %1").arg(winErrorMessage(GetLastError()))); - return -3; - } - if (bytesRead == 1) { - processData(buffer[0]); - } else { - processData(QByteArray(buffer, bytesRead)); - } - return 0; -} - -void WinReaderThread::run() -{ - m_handles[FileHandle] = m_context->readOverlapped.hEvent; - while ( tryRead() == 0) ; -} - -void WinReaderThread::terminate() -{ - SetEvent(m_handles[TerminateEventHandle]); - wait(); -} - -typedef WinReaderThread ReaderThread; - -#else - -/////////////////////////////////////////////////////////////////////// -// -// UnixReaderThread: A thread reading from the device. -// Uses select() to wait and a special ioctl() to find out the number -// of bytes queued. For clean termination, the self-pipe trick is used. -// The class maintains a pipe, on whose read end the select waits besides -// the device file handle. To terminate, a byte is written to the pipe. -// -/////////////////////////////////////////////////////////////////////// - -static inline QString msgUnixCallFailedErrno(const char *func, int errorNumber) -{ - return QString::fromLatin1("Call to %1() failed: %2").arg(QLatin1String(func), QString::fromLocal8Bit(strerror(errorNumber))); -} - -class UnixReaderThread : public ReaderThreadBase { - Q_OBJECT - Q_DISABLE_COPY(UnixReaderThread) -public: - explicit UnixReaderThread(const QSharedPointer &context); - ~UnixReaderThread(); - - virtual void run(); - -signals: - void error(const QString &); - -public slots: - void terminate(); - -private: - inline int tryRead(); - - int m_terminatePipeFileDescriptors[2]; -}; - -UnixReaderThread::UnixReaderThread(const QSharedPointer &context) : - ReaderThreadBase(context) -{ - m_terminatePipeFileDescriptors[0] = m_terminatePipeFileDescriptors[1] = -1; - // Set up pipes for termination. Should not fail - if (pipe(m_terminatePipeFileDescriptors) < 0) - qWarning("%s\n", qPrintable(msgUnixCallFailedErrno("pipe", errno))); -} - -UnixReaderThread::~UnixReaderThread() -{ - close(m_terminatePipeFileDescriptors[0]); - close(m_terminatePipeFileDescriptors[1]); -} - -int UnixReaderThread::tryRead() -{ - fd_set readSet, tempReadSet, tempExceptionSet; - struct timeval timeOut; - const int fileDescriptor = m_context->file.handle(); - FD_ZERO(&readSet); - FD_SET(fileDescriptor, &readSet); - FD_SET(m_terminatePipeFileDescriptors[0], &readSet); - const int maxFileDescriptor = qMax(m_terminatePipeFileDescriptors[0], fileDescriptor); - int result = 0; - do { - memcpy(&tempReadSet, &readSet, sizeof(fd_set)); - memcpy(&tempExceptionSet, &readSet, sizeof(fd_set)); - timeOut.tv_sec = 1; - timeOut.tv_usec = 0; - result = select(maxFileDescriptor + 1, &tempReadSet, NULL, &tempExceptionSet, &timeOut); - } while ( result < 0 && errno == EINTR ); - // Timeout? - if (result == 0) - return 0; - // Something wrong? - if (result < 0) { - emit error(msgUnixCallFailedErrno("select", errno)); - return -1; - } - // Did the exception set trigger on the device? - if (FD_ISSET(fileDescriptor,&tempExceptionSet)) { - emit error(QLatin1String("An Exception occurred on the device.")); - return -2; - } - // Check termination pipe. - if (FD_ISSET(m_terminatePipeFileDescriptors[0], &tempReadSet) - || FD_ISSET(m_terminatePipeFileDescriptors[0], &tempExceptionSet)) - return 1; - - // determine number of pending bytes and read - int numBytes; - if (ioctl(fileDescriptor, FIONREAD, &numBytes) < 0) { - emit error(msgUnixCallFailedErrno("ioctl", errno)); - return -1; - } - m_context->mutex.lock(); - const QByteArray data = m_context->file.read(numBytes); - m_context->mutex.unlock(); - processData(data); - return 0; -} - -void UnixReaderThread::run() -{ - // Read loop - while (tryRead() == 0) - ; -} - -void UnixReaderThread::terminate() -{ - // Trigger select() by writing to the pipe - char c = 0; - const int written = write(m_terminatePipeFileDescriptors[1], &c, 1); - Q_UNUSED(written) - wait(); -} - -typedef UnixReaderThread ReaderThread; - -#endif - -/////////////////////////////////////////////////////////////////////// -// -// TrkDevicePrivate -// -/////////////////////////////////////////////////////////////////////// - -struct TrkDevicePrivate -{ - TrkDevicePrivate(); - - QSharedPointer deviceContext; - QSharedPointer writerThread; - QSharedPointer readerThread; - - QByteArray trkReadBuffer; - int verbose; - QString errorString; -}; - -/////////////////////////////////////////////////////////////////////// -// -// TrkDevice -// -/////////////////////////////////////////////////////////////////////// - -TrkDevicePrivate::TrkDevicePrivate() : - deviceContext(new DeviceContext), - verbose(0) -{ -} - -/////////////////////////////////////////////////////////////////////// -// -// TrkDevice -// -/////////////////////////////////////////////////////////////////////// - -TrkDevice::TrkDevice(QObject *parent) : - QObject(parent), - d(new TrkDevicePrivate) -{} - -TrkDevice::~TrkDevice() -{ - close(); - delete d; -} - -bool TrkDevice::open(const QString &port, QString *errorMessage) -{ - if (d->verbose) - qDebug() << "Opening" << port << "is open: " << isOpen() << " serialFrame=" << serialFrame(); - close(); -#ifdef Q_OS_WIN - d->deviceContext->device = CreateFile(QString("\\\\.\\").append(port).toStdWString().c_str(), - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING|FILE_FLAG_OVERLAPPED, - NULL); - - if (INVALID_HANDLE_VALUE == d->deviceContext->device) { - *errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port, winErrorMessage(GetLastError())); - return false; - } - memset(&d->deviceContext->readOverlapped, 0, sizeof(OVERLAPPED)); - d->deviceContext->readOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - memset(&d->deviceContext->writeOverlapped, 0, sizeof(OVERLAPPED)); - d->deviceContext->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (d->deviceContext->readOverlapped.hEvent == NULL || d->deviceContext->writeOverlapped.hEvent == NULL) { - *errorMessage = QString::fromLatin1("Failed to create events: %1").arg(winErrorMessage(GetLastError())); - return false; - } -#else - d->deviceContext->file.setFileName(port); - if (!d->deviceContext->file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) { - *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(port, d->deviceContext->file.errorString()); - return false; - } - - struct termios termInfo; - if (tcgetattr(d->deviceContext->file.handle(), &termInfo) < 0) { - *errorMessage = QString::fromLatin1("Unable to retrieve terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno))); - return false; - } - // Turn off terminal echo as not get messages back, among other things - termInfo.c_cflag |= CREAD|CLOCAL; - termInfo.c_lflag &= (~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG)); - termInfo.c_iflag &= (~(INPCK|IGNPAR|PARMRK|ISTRIP|ICRNL|IXANY)); - termInfo.c_oflag &= (~OPOST); - termInfo.c_cc[VMIN] = 0; - termInfo.c_cc[VINTR] = _POSIX_VDISABLE; - termInfo.c_cc[VQUIT] = _POSIX_VDISABLE; - termInfo.c_cc[VSTART] = _POSIX_VDISABLE; - termInfo.c_cc[VSTOP] = _POSIX_VDISABLE; - termInfo.c_cc[VSUSP] = _POSIX_VDISABLE; - if (tcsetattr(d->deviceContext->file.handle(), TCSAFLUSH, &termInfo) < 0) { - *errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno))); - return false; - } -#endif - d->readerThread = QSharedPointer(new ReaderThread(d->deviceContext)); - connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)), - Qt::QueuedConnection); - connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)), - this, SLOT(slotMessageReceived(trk::TrkResult,QByteArray)), - Qt::QueuedConnection); - d->readerThread->start(); - - d->writerThread = QSharedPointer(new WriterThread(d->deviceContext)); - connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)), - Qt::QueuedConnection); - d->writerThread->start(); - - if (d->verbose) - qDebug() << "Opened" << port; - return true; -} - -void TrkDevice::close() -{ - if (!isOpen()) - return; - if (d->readerThread) - d->readerThread->terminate(); - if (d->writerThread) - d->writerThread->terminate(); -#ifdef Q_OS_WIN - CloseHandle(d->deviceContext->device); - d->deviceContext->device = INVALID_HANDLE_VALUE; - CloseHandle(d->deviceContext->readOverlapped.hEvent); - CloseHandle(d->deviceContext->writeOverlapped.hEvent); - d->deviceContext->readOverlapped.hEvent = d->deviceContext->writeOverlapped.hEvent = NULL; -#else - d->deviceContext->file.close(); -#endif - if (d->verbose) - emitLogMessage("Close"); -} - -bool TrkDevice::isOpen() const -{ -#ifdef Q_OS_WIN - return d->deviceContext->device != INVALID_HANDLE_VALUE; -#else - return d->deviceContext->file.isOpen(); -#endif -} - -QString TrkDevice::errorString() const -{ - return d->errorString; -} - -bool TrkDevice::serialFrame() const -{ - return d->deviceContext->serialFrame; -} - -void TrkDevice::setSerialFrame(bool f) -{ - d->deviceContext->serialFrame = f; -} - -int TrkDevice::verbose() const -{ - return d->verbose; -} - -void TrkDevice::setVerbose(int b) -{ - d->verbose = b; -} - -void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData) -{ - d->writerThread->slotHandleResult(result); - if (d->verbose > 1) - qDebug() << "Received: " << result.toString(); - emit messageReceived(result); - if (!rawData.isEmpty()) - emit rawDataReceived(rawData); -} - -void TrkDevice::emitError(const QString &s) -{ - d->errorString = s; - qWarning("%s\n", qPrintable(s)); - emit error(s); -} - -void TrkDevice::sendTrkMessage(byte code, TrkCallback callback, - const QByteArray &data, const QVariant &cookie) -{ - if (!d->writerThread.isNull()) { - if (d->verbose > 1) { - QByteArray msg = "Sending: "; - msg += QByteArray::number(code, 16); - msg += ": "; - msg += stringFromArray(data).toLatin1(); - qDebug("%s", msg.data()); - } - d->writerThread->queueTrkMessage(code, callback, data, cookie); - } -} - -void TrkDevice::sendTrkInitialPing() -{ - if (!d->writerThread.isNull()) - d->writerThread->queueTrkInitialPing(); -} - -bool TrkDevice::sendTrkAck(byte token) -{ - if (d->writerThread.isNull()) - return false; - // The acknowledgement must not be queued! - TrkMessage msg(0x80, token); - msg.token = token; - msg.data.append('\0'); - if (verboseTrk) - qDebug() << "Write synchroneous message: " << msg; - return d->writerThread->trkWriteRawMessage(msg); - // 01 90 00 07 7e 80 01 00 7d 5e 7e -} - -void TrkDevice::emitLogMessage(const QString &msg) -{ - if (d->verbose) - qDebug("%s\n", qPrintable(msg)); - emit logMessage(msg); -} - -} // namespace trk - -#include "trkdevice.moc" diff --git a/tools/runonphone/trk/trkdevice.h b/tools/runonphone/trk/trkdevice.h deleted file mode 100644 index 21a3cc1..0000000 --- a/tools/runonphone/trk/trkdevice.h +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef TRKDEVICE_H -#define TRKDEVICE_H - -#include "symbianutils_global.h" -#include "callback.h" - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QIODevice; -QT_END_NAMESPACE - -namespace trk { - -struct TrkResult; -struct TrkMessage; -struct TrkDevicePrivate; - -/* TrkDevice: Implements a Windows COM or Linux device for - * Trk communications. Provides synchronous write and asynchronous - * read operation. - * The serialFrames property specifies whether packets are encapsulated in - * "0x90 " frames, which is currently the case for serial ports. - * Contains a write message queue allowing - * for queueing messages with a notification callback. If the message receives - * an ACK, the callback is invoked. - * The special message TRK_WRITE_QUEUE_NOOP_CODE code can be used for synchronisation. - * The respective message will not be sent, the callback is just invoked. */ - -enum { TRK_WRITE_QUEUE_NOOP_CODE = 0x7f }; - -typedef trk::Callback TrkCallback; - -class SYMBIANUTILS_EXPORT TrkDevice : public QObject -{ - Q_OBJECT - Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame) - Q_PROPERTY(bool verbose READ verbose WRITE setVerbose) -public: - explicit TrkDevice(QObject *parent = 0); - virtual ~TrkDevice(); - - bool open(const QString &port, QString *errorMessage); - bool isOpen() const; - - QString errorString() const; - - bool serialFrame() const; - void setSerialFrame(bool f); - - int verbose() const; - void setVerbose(int b); - - // Enqueue a message with a notification callback. - void sendTrkMessage(unsigned char code, - TrkCallback callBack = TrkCallback(), - const QByteArray &data = QByteArray(), - const QVariant &cookie = QVariant()); - - // Enqeue an initial ping - void sendTrkInitialPing(); - - // Send an Ack synchronously, bypassing the queue - bool sendTrkAck(unsigned char token); - -signals: - void messageReceived(const trk::TrkResult &result); - // Emitted with the contents of messages enclosed in 07e, not for log output - void rawDataReceived(const QByteArray &data); - void error(const QString &msg); - void logMessage(const QString &msg); - -private slots: - void slotMessageReceived(const trk::TrkResult &result, const QByteArray &a); - -protected slots: - void emitError(const QString &msg); - void emitLogMessage(const QString &msg); - -public slots: - void close(); - -private: - void readMessages(); - TrkDevicePrivate *d; -}; - -} // namespace trk - -#endif // TRKDEVICE_H diff --git a/tools/runonphone/trk/trkutils.cpp b/tools/runonphone/trk/trkutils.cpp deleted file mode 100644 index 5cce950..0000000 --- a/tools/runonphone/trk/trkutils.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "trkutils.h" -#include - -#include -#include -#include -#include -#include - -#define logMessage(s) do { qDebug() << "TRKCLIENT: " << s; } while (0) - -namespace trk { - -TrkAppVersion::TrkAppVersion() -{ - reset(); -} - -void TrkAppVersion::reset() -{ - trkMajor = trkMinor= protocolMajor = protocolMinor = 0; -} - -Session::Session() -{ - reset(); -} - -void Session::reset() -{ - cpuMajor = 0; - cpuMinor = 0; - bigEndian = 0; - defaultTypeSize = 0; - fpTypeSize = 0; - extended1TypeSize = 0; - extended2TypeSize = 0; - pid = 0; - tid = 0; - codeseg = 0; - dataseg = 0; - - currentThread = 0; - libraries.clear(); - trkAppVersion.reset(); -} - -static QString formatCpu(int major, int minor) -{ - //: CPU description of an S60 device - //: %1 major verison, %2 minor version - //: %3 real name of major verison, %4 real name of minor version - const QString str = QCoreApplication::translate("trk::Session", "CPU: v%1.%2%3%4"); - QString majorStr; - QString minorStr; - switch (major) { - case 0x04: - majorStr = " ARM"; - break; - } - switch (minor) { - case 0x00: - minorStr = " 920T"; - break; - } - return str.arg(major).arg(minor).arg(majorStr).arg(minorStr); - } - -QString formatTrkVersion(const TrkAppVersion &version) -{ - QString str = QCoreApplication::translate("trk::Session", - "App TRK: v%1.%2 TRK protocol: v%3.%4"); - str = str.arg(version.trkMajor).arg(version.trkMinor); - return str.arg(version.protocolMajor).arg(version.protocolMinor); -} - -QString Session::deviceDescription(unsigned verbose) const -{ - if (!cpuMajor) - return QString(); - - //: s60description - //: description of an S60 device - //: %1 CPU description, %2 endianness - //: %3 default type size (if any), %4 float size (if any) - //: %5 TRK version - QString msg = QCoreApplication::translate("trk::Session", "%1, %2%3%4, %5"); - QString endianness = bigEndian - ? QCoreApplication::translate("trk::Session", "big endian") - : QCoreApplication::translate("trk::Session", "little endian"); - msg = msg.arg(formatCpu(cpuMajor, cpuMinor)).arg(endianness); - //: The separator in a list of strings - QString defaultTypeSizeStr; - QString fpTypeSizeStr; - if (verbose && defaultTypeSize) - //: will be inserted into s60description - defaultTypeSizeStr = QCoreApplication::translate("trk::Session", ", type size: %1").arg(defaultTypeSize); - if (verbose && fpTypeSize) - //: will be inserted into s60description - fpTypeSizeStr = QCoreApplication::translate("trk::Session", ", float size: %1").arg(fpTypeSize); - msg = msg.arg(defaultTypeSizeStr).arg(fpTypeSizeStr); - return msg.arg(formatTrkVersion(trkAppVersion)); -} - - -QByteArray decode7d(const QByteArray &ba) -{ - QByteArray res; - res.reserve(ba.size()); - for (int i = 0; i < ba.size(); ++i) { - byte c = byte(ba.at(i)); - if (c == 0x7d) { - ++i; - c = 0x20 ^ byte(ba.at(i)); - } - res.append(c); - } - return res; -} - -QByteArray encode7d(const QByteArray &ba) -{ - QByteArray res; - res.reserve(ba.size() + 2); - for (int i = 0; i < ba.size(); ++i) { - byte c = byte(ba.at(i)); - if (c == 0x7e || c == 0x7d) { - res.append(0x7d); - res.append(0x20 ^ c); - } else { - res.append(c); - } - } - return res; -} - -// FIXME: Use the QByteArray based version below? -static inline QString stringFromByte(byte c) -{ - return QString::fromLatin1("%1").arg(c, 2, 16, QChar('0')); -} - -SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen) -{ - QString str; - QString ascii; - const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen); - for (int i = 0; i < size; ++i) { - //if (i == 5 || i == ba.size() - 2) - // str += " "; - int c = byte(ba.at(i)); - str += QString("%1 ").arg(c, 2, 16, QChar('0')); - if (i >= 8 && i < ba.size() - 2) - ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); - } - if (size != ba.size()) { - str += "..."; - ascii += "..."; - } - return str + " " + ascii; -} - -SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) -{ - QByteArray ba = QByteArray::number(n, 16); - if (digits == 0 || ba.size() == digits) - return ba; - return QByteArray(digits - ba.size(), '0') + ba; -} - -SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits) -{ - return "0x" + hexNumber(n, digits); -} - -TrkResult::TrkResult() : - code(0), - token(0), - isDebugOutput(false) -{ -} - -void TrkResult::clear() -{ - code = token= 0; - isDebugOutput = false; - data.clear(); - cookie = QVariant(); -} - -QString TrkResult::toString() const -{ - QString res = stringFromByte(code); - res += QLatin1String(" ["); - res += stringFromByte(token); - res += QLatin1Char(']'); - res += QLatin1Char(' '); - res += stringFromArray(data); - return res; -} - -QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame) -{ - byte s = command + token; - for (int i = 0; i != data.size(); ++i) - s += data.at(i); - byte checksum = 255 - (s & 0xff); - //int x = s + ~s; - //logMessage("check: " << s << checksum << x; - - QByteArray response; - response.reserve(data.size() + 3); - response.append(char(command)); - response.append(char(token)); - response.append(data); - response.append(char(checksum)); - - QByteArray encodedData = encode7d(response); - - QByteArray ba; - ba.reserve(encodedData.size() + 6); - if (serialFrame) { - ba.append(char(0x01)); - ba.append(char(0x90)); - const ushort encodedSize = encodedData.size() + 2; // 2 x 0x7e - appendShort(&ba, encodedSize, BigEndian); - } - ba.append(char(0x7e)); - ba.append(encodedData); - ba.append(char(0x7e)); - - return ba; -} - -/* returns 0 if array doesn't represent a result, -otherwise returns the length of the result data */ -ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame) -{ - if (serialFrame) { - // Serial protocol with length info - if (buffer.length() < 4) - return 0; - if (buffer.at(0) != 0x01 || byte(buffer.at(1)) != 0x90) - return 0; - const ushort len = extractShort(buffer.data() + 2); - return (buffer.size() >= len + 4) ? len : ushort(0); - } - // Frameless protocol without length info - const char delimiter = char(0x7e); - const int firstDelimiterPos = buffer.indexOf(delimiter); - // Regular message delimited by 0x7e..0x7e - if (firstDelimiterPos == 0) { - const int endPos = buffer.indexOf(delimiter, firstDelimiterPos + 1); - return endPos != -1 ? endPos + 1 - firstDelimiterPos : 0; - } - // Some ASCII log message up to first delimiter or all - return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size(); -} - -bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData) -{ - result->clear(); - if(rawData) - rawData->clear(); - const ushort len = isValidTrkResult(*buffer, serialFrame); - if (!len) - return false; - // handle receiving application output, which is not a regular command - const int delimiterPos = serialFrame ? 4 : 0; - if (buffer->at(delimiterPos) != 0x7e) { - result->isDebugOutput = true; - result->data = buffer->mid(delimiterPos, len); - result->data.replace("\r\n", "\n"); - *buffer->remove(0, delimiterPos + len); - return true; - } - // FIXME: what happens if the length contains 0xfe? - // Assume for now that it passes unencoded! - const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2)); - if(rawData) - *rawData = data; - *buffer->remove(0, delimiterPos + len); - - byte sum = 0; - for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum - sum += byte(data.at(i)); - if (sum != 0xff) - logMessage("*** CHECKSUM ERROR: " << byte(sum)); - - result->code = data.at(0); - result->token = data.at(1); - result->data = data.mid(2, data.size() - 3); - //logMessage(" REST BUF: " << stringFromArray(*buffer)); - //logMessage(" CURR DATA: " << stringFromArray(data)); - //QByteArray prefix = "READ BUF: "; - //logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data()); - return true; -} - -SYMBIANUTILS_EXPORT ushort extractShort(const char *data) -{ - return byte(data[0]) * 256 + byte(data[1]); -} - -SYMBIANUTILS_EXPORT uint extractInt(const char *data) -{ - uint res = byte(data[0]); - res *= 256; res += byte(data[1]); - res *= 256; res += byte(data[2]); - res *= 256; res += byte(data[3]); - return res; -} - -SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba) -{ - QString res; - char buf[10]; - for (int i = 0, n = ba.size(); i != n; ++i) { - const byte c = ba.at(i); - if (isprint(c)) { - res += c; - } else { - qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c)); - res += buf; - } - } - return res; -} - -SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness endian) -{ - if (endian == BigEndian) { - ba->append(s / 256); - ba->append(s % 256); - } else { - ba->append(s % 256); - ba->append(s / 256); - } -} - -SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness endian) -{ - const uchar b3 = i % 256; i /= 256; - const uchar b2 = i % 256; i /= 256; - const uchar b1 = i % 256; i /= 256; - const uchar b0 = i; - ba->reserve(ba->size() + 4); - if (endian == BigEndian) { - ba->append(b0); - ba->append(b1); - ba->append(b2); - ba->append(b3); - } else { - ba->append(b3); - ba->append(b2); - ba->append(b1); - ba->append(b0); - } -} - -void appendString(QByteArray *ba, const QByteArray &str, Endianness endian, bool appendNullTerminator) -{ - const int fullSize = str.size() + (appendNullTerminator ? 1 : 0); - appendShort(ba, fullSize, endian); // count the terminating \0 - ba->append(str); - if (appendNullTerminator) - ba->append('\0'); -} - -void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness endian) -{ - // convert the QDateTime to UTC and append its representation to QByteArray - // format is the same as in FAT file system - dateTime = dateTime.toUTC(); - const QTime utcTime = dateTime.time(); - const QDate utcDate = dateTime.date(); - uint fatDateTime = (utcTime.hour() << 11 | utcTime.minute() << 5 | utcTime.second()/2) << 16; - fatDateTime |= (utcDate.year()-1980) << 9 | utcDate.month() << 5 | utcDate.day(); - appendInt(ba, fatDateTime, endian); -} - -QByteArray errorMessage(byte code) -{ - switch (code) { - case 0x00: return "No error"; - case 0x01: return "Generic error in CWDS message"; - case 0x02: return "Unexpected packet size in send msg"; - case 0x03: return "Internal error occurred in CWDS"; - case 0x04: return "Escape followed by frame flag"; - case 0x05: return "Bad FCS in packet"; - case 0x06: return "Packet too long"; - case 0x07: return "Sequence ID not expected (gap in sequence)"; - - case 0x10: return "Command not supported"; - case 0x11: return "Command param out of range"; - case 0x12: return "An option was not supported"; - case 0x13: return "Read/write to invalid memory"; - case 0x14: return "Read/write invalid registers"; - case 0x15: return "Exception occurred in CWDS"; - case 0x16: return "Targeted system or thread is running"; - case 0x17: return "Breakpoint resources (HW or SW) exhausted"; - case 0x18: return "Requested breakpoint conflicts with existing one"; - - case 0x20: return "General OS-related error"; - case 0x21: return "Request specified invalid process"; - case 0x22: return "Request specified invalid thread"; - } - return "Unknown error"; -} - -uint swapEndian(uint in) -{ - return (in>>24) | ((in<<8) & 0x00FF0000) | ((in>>8) & 0x0000FF00) | (in<<24); -} - -int TrkResult::errorCode() const -{ - // NAK means always error, else data sized 1 with a non-null element - const bool isNAK = code == 0xff; - if (data.size() != 1 && !isNAK) - return 0; - if (const int errorCode = data.at(0)) - return errorCode; - return isNAK ? 0xff : 0; -} - -QString TrkResult::errorString() const -{ - // NAK means always error, else data sized 1 with a non-null element - if (code == 0xff) - return "NAK"; - if (data.size() < 1) - return "Unknown error packet"; - return errorMessage(data.at(0)); -} - -} // namespace trk - diff --git a/tools/runonphone/trk/trkutils.h b/tools/runonphone/trk/trkutils.h deleted file mode 100644 index 3a485c7..0000000 --- a/tools/runonphone/trk/trkutils.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef DEBUGGER_TRK_UTILS -#define DEBUGGER_TRK_UTILS - -#include "symbianutils_global.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QDateTime; -QT_END_NAMESPACE - -namespace trk { - -typedef unsigned char byte; - -enum Command { - TrkPing = 0x00, - TrkConnect = 0x01, - TrkDisconnect = 0x02, - TrkVersions = 0x04, - TrkSupported = 0x05, - TrkCpuType = 0x06, - TrkHostVersions = 0x09, - TrkContinue = 0x18, - TrkCreateItem = 0x40, - TrkDeleteItem = 0x41, - - TrkWriteFile = 0x48, - TrkOpenFile = 0x4a, - TrkCloseFile = 0x4b, - TrkInstallFile = 0x4d, - TrkInstallFile2 = 0x4e, - - TrkNotifyAck = 0x80, - TrkNotifyNak = 0xff, - TrkNotifyStopped = 0x90, - TrkNotifyException = 0x91, - TrkNotifyInternalError = 0x92, - TrkNotifyCreated = 0xa0, - TrkNotifyDeleted = 0xa1, - TrkNotifyProcessorStarted = 0xa2, - TrkNotifyProcessorStandBy = 0xa6, - TrkNotifyProcessorReset = 0xa7 -}; - -inline byte extractByte(const char *data) { return *data; } -SYMBIANUTILS_EXPORT ushort extractShort(const char *data); -SYMBIANUTILS_EXPORT uint extractInt(const char *data); - -SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba); - -// produces "xx xx xx " -SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen = - 1); - -enum Endianness -{ - LittleEndian, - BigEndian, - TargetByteOrder = BigEndian, -}; - -SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder); -SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder); -SYMBIANUTILS_EXPORT void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true); - -struct SYMBIANUTILS_EXPORT Library -{ - Library() {} - - QByteArray name; - uint codeseg; - uint dataseg; -}; - -struct SYMBIANUTILS_EXPORT TrkAppVersion -{ - TrkAppVersion(); - void reset(); - - int trkMajor; - int trkMinor; - int protocolMajor; - int protocolMinor; -}; - -struct SYMBIANUTILS_EXPORT Session -{ - Session(); - void reset(); - QString deviceDescription(unsigned verbose) const; - - // Trk feedback - byte cpuMajor; - byte cpuMinor; - byte bigEndian; - byte defaultTypeSize; - byte fpTypeSize; - byte extended1TypeSize; - byte extended2TypeSize; - TrkAppVersion trkAppVersion; - uint pid; - uint tid; - uint codeseg; - uint dataseg; - QHash addressToBP; - - typedef QList Libraries; - Libraries libraries; - - typedef uint Thread; - typedef QList Threads; - Threads threads; - - // Gdb request - uint currentThread; - QStringList modules; -}; - -struct SYMBIANUTILS_EXPORT TrkResult -{ - TrkResult(); - void clear(); - QString toString() const; - // 0 for no error. - int errorCode() const; - QString errorString() const; - - byte code; - byte token; - QByteArray data; - QVariant cookie; - bool isDebugOutput; -}; - -SYMBIANUTILS_EXPORT QByteArray errorMessage(byte code); -SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits = 0); -SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too -SYMBIANUTILS_EXPORT uint swapEndian(uint in); - -} // namespace trk - -#endif // DEBUGGER_TRK_UTILS diff --git a/tools/runonphone/trk/trkutils_p.h b/tools/runonphone/trk/trkutils_p.h deleted file mode 100644 index 12b0109..0000000 --- a/tools/runonphone/trk/trkutils_p.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef DEBUGGER_TRK_PRIVATE_UTILS -#define DEBUGGER_TRK_PRIVATE_UTILS - -#include "trkutils.h" -#include "symbianutils_global.h" - -QT_BEGIN_NAMESPACE -class QDateTime; -QT_END_NAMESPACE - -namespace trk { - -void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness = TargetByteOrder); -// returns a QByteArray containing optionally -// the serial frame [0x01 0x90 ] and 0x7e encoded7d(ba) 0x7e -QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame); -bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0); - -} // namespace trk - -#endif // DEBUGGER_TRK_PRIVATE_UTILS -- cgit v0.12 From 39709d61fbd4a17edf5f141877d312d3872ccce0 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 9 Feb 2010 11:56:37 +0100 Subject: Catch up symbianutils to creator 3efdb87682a5785bac7b90f9f9a8bb819a1cb053 commit 3efdb87682a5785bac7b90f9f9a8bb819a1cb053 Author: Friedemann Kleint Date: Mon Feb 8 14:10:51 2010 +0100 S60/Trk: Make the port a property of TrkDevice. Associate the port with the device instead of passing it to open for better handling. commit 76872c6ed8a1477f1914266d6917ee4aad6ff7e9 Author: Friedemann Kleint Date: Fri Feb 5 17:34:02 2010 +0100 S60: Move serialdevicelister.cpp to symbianutils/symbiandevicemanager.cpp --- .../symbianutils/communicationstarter.cpp | 21 +- .../runonphone/symbianutils/communicationstarter.h | 2 - tools/runonphone/symbianutils/launcher.cpp | 9 +- .../symbianutils/symbiandevicemanager.cpp | 331 +++++++++++++++++++++ .../runonphone/symbianutils/symbiandevicemanager.h | 145 +++++++++ tools/runonphone/symbianutils/symbianutils.pri | 6 +- tools/runonphone/symbianutils/trkdevice.cpp | 31 +- tools/runonphone/symbianutils/trkdevice.h | 6 +- tools/runonphone/symbianutils/trkutils.cpp | 1 + 9 files changed, 520 insertions(+), 32 deletions(-) create mode 100644 tools/runonphone/symbianutils/symbiandevicemanager.cpp create mode 100644 tools/runonphone/symbianutils/symbiandevicemanager.h diff --git a/tools/runonphone/symbianutils/communicationstarter.cpp b/tools/runonphone/symbianutils/communicationstarter.cpp index e5e556e..cdee49f 100644 --- a/tools/runonphone/symbianutils/communicationstarter.cpp +++ b/tools/runonphone/symbianutils/communicationstarter.cpp @@ -58,7 +58,6 @@ struct BaseCommunicationStarterPrivate { int intervalMS; int attempts; int n; - QString device; QString errorString; BaseCommunicationStarter::State state; }; @@ -70,7 +69,6 @@ BaseCommunicationStarterPrivate::BaseCommunicationStarterPrivate(const BaseCommu intervalMS(1000), attempts(-1), n(0), - device(QLatin1String("/dev/rfcomm0")), state(BaseCommunicationStarter::TimedOut) { } @@ -108,7 +106,7 @@ BaseCommunicationStarter::StartResult BaseCommunicationStarter::start() // 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))) + if (d->trkDevice->open(&(d->errorString))) return ConnectionSucceeded; // Pull up resources for next attempt d->n = 0; @@ -155,12 +153,7 @@ void BaseCommunicationStarter::setAttempts(int a) QString BaseCommunicationStarter::device() const { - return d->device; -} - -void BaseCommunicationStarter::setDevice(const QString &dv) -{ - d->device = dv; + return d->trkDevice->port(); } QString BaseCommunicationStarter::errorString() const @@ -175,20 +168,20 @@ void BaseCommunicationStarter::slotTimer() 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); + .arg(d->trkDevice->port()).arg(d->intervalMS); d->state = TimedOut; emit timeout(); } else { // Attempt n to connect? - if (d->trkDevice->open(d->device , &(d->errorString))) { + if (d->trkDevice->open(&(d->errorString))) { stopTimer(); - const QString msg = tr("%1: Connection attempt %2 succeeded.").arg(d->device).arg(d->n); + const QString msg = tr("%1: Connection attempt %2 succeeded.").arg(d->trkDevice->port()).arg(d->n); emit message(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); + .arg(d->trkDevice->port()).arg(d->n).arg(d->errorString); emit message(msg); } } @@ -228,13 +221,11 @@ BluetoothListener *ConsoleBluetoothStarter::createListener() 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: diff --git a/tools/runonphone/symbianutils/communicationstarter.h b/tools/runonphone/symbianutils/communicationstarter.h index 2d7dc50..0a060ee 100644 --- a/tools/runonphone/symbianutils/communicationstarter.h +++ b/tools/runonphone/symbianutils/communicationstarter.h @@ -80,7 +80,6 @@ public: void setAttempts(int a); QString device() const; - void setDevice(const QString &); State state() const; QString errorString() const; @@ -142,7 +141,6 @@ class SYMBIANUTILS_EXPORT ConsoleBluetoothStarter : public AbstractBluetoothStar public: static bool startBluetooth(const TrkDevicePtr& trkDevice, QObject *listenerParent, - const QString &device, int attempts, QString *errorMessage); diff --git a/tools/runonphone/symbianutils/launcher.cpp b/tools/runonphone/symbianutils/launcher.cpp index 4f91545..408829b 100644 --- a/tools/runonphone/symbianutils/launcher.cpp +++ b/tools/runonphone/symbianutils/launcher.cpp @@ -67,7 +67,6 @@ struct LauncherPrivate { explicit LauncherPrivate(const TrkDevicePtr &d); TrkDevicePtr m_device; - QString m_trkServerName; QByteArray m_trkReadBuffer; Launcher::State m_state; @@ -131,12 +130,12 @@ void Launcher::addStartupActions(trk::Launcher::Actions startupActions) void Launcher::setTrkServerName(const QString &name) { - d->m_trkServerName = name; + d->m_device->setPort(name); } QString Launcher::trkServerName() const { - return d->m_trkServerName; + return d->m_device->port(); } TrkDevicePtr Launcher::trkDevice() const @@ -191,7 +190,7 @@ bool Launcher::startServer(QString *errorMessage) errorMessage->clear(); if (d->m_verbose) { const QString msg = QString::fromLatin1("Port=%1 Executable=%2 Arguments=%3 Package=%4 Remote Package=%5 Install file=%6") - .arg(d->m_trkServerName, d->m_fileName, + .arg(trkServerName(), d->m_fileName, d->m_commandLineArgs.join(QString(QLatin1Char(' '))), d->m_copyState.sourceFileName, d->m_copyState.destinationFileName, d->m_installFileName); logMessage(msg); @@ -213,7 +212,7 @@ bool Launcher::startServer(QString *errorMessage) qWarning("No remote executable given for running."); return false; } - if (!d->m_device->isOpen() && !d->m_device->open(d->m_trkServerName, errorMessage)) + if (!d->m_device->isOpen() && !d->m_device->open(errorMessage)) return false; if (d->m_closeDevice) { connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close())); diff --git a/tools/runonphone/symbianutils/symbiandevicemanager.cpp b/tools/runonphone/symbianutils/symbiandevicemanager.cpp new file mode 100644 index 0000000..f663816 --- /dev/null +++ b/tools/runonphone/symbianutils/symbiandevicemanager.cpp @@ -0,0 +1,331 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "symbiandevicemanager.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace SymbianUtils { + +enum { debug = 0 }; + +static const char REGKEY_CURRENT_CONTROL_SET[] = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet"; +static const char USBSER[] = "Services/usbser/Enum"; + +const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm"; + +// ------------- SymbianDevice +class SymbianDeviceData : public QSharedData { +public: + SymbianDeviceData() : type(SerialPortCommunication) {} + + QString portName; + QString friendlyName; + QString deviceDesc; + QString manufacturer; + DeviceCommunicationType type; +}; + +SymbianDevice::SymbianDevice(SymbianDeviceData *data) : + m_data(data) +{ + +} + +SymbianDevice::SymbianDevice() : + m_data(new SymbianDeviceData) +{ +} +SymbianDevice::SymbianDevice(const SymbianDevice &rhs) : + m_data(rhs.m_data) +{ +} + +SymbianDevice &SymbianDevice::operator=(const SymbianDevice &rhs) +{ + if (this != &rhs) + m_data = rhs.m_data; + return *this; +} + +SymbianDevice::~SymbianDevice() +{ +} + +QString SymbianDevice::portName() const +{ + return m_data->portName; +} + +QString SymbianDevice::friendlyName() const +{ + return m_data->friendlyName; +} + +QString SymbianDevice::deviceDesc() const +{ + return m_data->deviceDesc; +} + +QString SymbianDevice::manufacturer() const +{ + return m_data->manufacturer; +} + +DeviceCommunicationType SymbianDevice::type() const +{ + return m_data->type; +} + +bool SymbianDevice::isNull() const +{ + return !m_data->portName.isEmpty(); +} + +QString SymbianDevice::toString() const +{ + QString rc; + QTextStream str(&rc); + format(str); + return rc; +} + +void SymbianDevice::format(QTextStream &str) const +{ + str << (m_data->type == BlueToothCommunication ? "Bluetooth: " : "Serial: ") + << m_data->portName; + if (!m_data->friendlyName.isEmpty()) { + str << " (" << m_data->friendlyName; + if (!m_data->deviceDesc.isEmpty()) + str << " / " << m_data->deviceDesc; + str << ')'; + } + if (!m_data->manufacturer.isEmpty()) + str << " [" << m_data->manufacturer << ']'; +} + +// Compare by port and friendly name +int SymbianDevice::compare(const SymbianDevice &rhs) const +{ + if (const int prc = m_data->portName.compare(rhs.m_data->portName)) + return prc; + if (const int frc = m_data->friendlyName.compare(rhs.m_data->friendlyName)) + return frc; + return 0; +} + +QDebug operator<<(QDebug d, const SymbianDevice &cd) +{ + d.nospace() << cd.toString(); + return d; +} + +// ------------- SymbianDeviceManagerPrivate +struct SymbianDeviceManagerPrivate { + SymbianDeviceManagerPrivate() : m_initialized(false) {} + + bool m_initialized; + SymbianDeviceManager::SymbianDeviceList m_devices; +}; + +SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : + QObject(parent), + d(new SymbianDeviceManagerPrivate) +{ +} + +SymbianDeviceManager::~SymbianDeviceManager() +{ + delete d; +} + +SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const +{ + if (!d->m_initialized) + const_cast(this)->update(false); + return d->m_devices; +} + +QString SymbianDeviceManager::toString() const +{ + QString rc; + QTextStream str(&rc); + const int count = d->m_devices.size(); + for (int i = 0; i < count; i++) { + str << '#' << i << ' '; + d->m_devices.at(i).format(str); + str << '\n'; + } + return rc; +} + +QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const +{ + foreach (const SymbianDevice &device, d->m_devices) { + if (device.portName() == port) + return device.friendlyName(); + } + return QString(); +} + +void SymbianDeviceManager::update() +{ + update(true); +} + +void SymbianDeviceManager::update(bool emitSignals) +{ + typedef SymbianDeviceList::iterator SymbianDeviceListIterator; + + if (debug) + qDebug(">SerialDeviceLister::update(%d)\n%s", int(emitSignals), + qPrintable(toString())); + + d->m_initialized = true; + // Get ordered new list + SymbianDeviceList newDevices = serialPorts() + blueToothDevices(); + if (newDevices.size() > 1) + qStableSort(newDevices.begin(), newDevices.end()); + if (d->m_devices == newDevices) // Happy, nothing changed. + return; + // Merge the lists and emit the respective added/removed signals, assuming + // no one can plug a different device on the same port at the speed of lightning + if (!d->m_devices.isEmpty()) { + // Find deleted devices + for (SymbianDeviceListIterator oldIt = d->m_devices.begin(); oldIt != d->m_devices.end(); ) { + if (newDevices.contains(*oldIt)) { + ++oldIt; + } else { + const SymbianDevice toBeDeleted = *oldIt; + oldIt = d->m_devices.erase(oldIt); + if (emitSignals) + emit deviceRemoved(toBeDeleted); + } + } + } + if (!newDevices.isEmpty()) { + // Find new devices and insert in order + foreach(const SymbianDevice &newDevice, newDevices) { + if (!d->m_devices.contains(newDevice)) { + d->m_devices.append(newDevice); + if (emitSignals) + emit deviceAdded(newDevice); + } + } + if (d->m_devices.size() > 1) + qStableSort(d->m_devices.begin(), d->m_devices.end()); + } + if (emitSignals) + emit updated(); + + if (debug) + qDebug(" 1) + qDebug() << "SerialDeviceLister::serialPorts(): Checking " << i << count + << REGKEY_CURRENT_CONTROL_SET << usbSerialRootKey << driverRootKey; + QScopedPointer device(new SymbianDeviceData); + device->type = SerialPortCommunication; + device->friendlyName = registry.value(driverRootKey + QLatin1String("FriendlyName")).toString(); + device->portName = registry.value(driverRootKey + QLatin1String("Device Parameters/PortName")).toString(); + device->deviceDesc = registry.value(driverRootKey + QLatin1String("DeviceDesc")).toString(); + device->manufacturer = registry.value(driverRootKey + QLatin1String("Mfg")).toString(); + rc.append(SymbianDevice(device.take())); + } + } +#endif + return rc; +} + +SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::blueToothDevices() const +{ + SymbianDeviceList rc; +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) + // Bluetooth devices are created on connection. List the existing ones + // or at least the first one. + const QString prefix = QLatin1String(linuxBlueToothDeviceRootC); + const QString friendlyFormat = QLatin1String("Bluetooth device (%1)"); + for (int d = 0; d < 4; d++) { + QScopedPointer device(new SymbianDeviceData); + device->type = BlueToothCommunication; + device->portName = prefix + QString::number(d); + if (d == 0 || QFileInfo(device->portName).exists()) { + device->friendlyName = friendlyFormat.arg(device->portName); + rc.push_back(SymbianDevice(device.take())); + } + } +#endif + return rc; +} + +Q_GLOBAL_STATIC(SymbianDeviceManager, symbianDeviceManager) + +SymbianDeviceManager *SymbianDeviceManager::instance() +{ + return symbianDeviceManager(); +} + +QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm) +{ + d.nospace() << sdm.toString(); + return d; +} + +} // namespace SymbianUtilsInternal diff --git a/tools/runonphone/symbianutils/symbiandevicemanager.h b/tools/runonphone/symbianutils/symbiandevicemanager.h new file mode 100644 index 0000000..dcf131a --- /dev/null +++ b/tools/runonphone/symbianutils/symbiandevicemanager.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SYMBIANDEVICEMANAGER_H +#define SYMBIANDEVICEMANAGER_H + +#include "symbianutils_global.h" + +#include +#include + +QT_BEGIN_NAMESPACE +class QDebug; +class QTextStream; +QT_END_NAMESPACE + +namespace SymbianUtils { + +struct SymbianDeviceManagerPrivate; +class SymbianDeviceData; + +enum DeviceCommunicationType { + SerialPortCommunication = 0, + BlueToothCommunication = 1 +}; + +// SymbianDevice, explicitly shared. +class SYMBIANUTILS_EXPORT SymbianDevice { + explicit SymbianDevice(SymbianDeviceData *data); + friend class SymbianDeviceManager; +public: + SymbianDevice(); + SymbianDevice(const SymbianDevice &rhs); + SymbianDevice &operator=(const SymbianDevice &rhs); + ~SymbianDevice(); + int compare(const SymbianDevice &rhs) const; + + DeviceCommunicationType type() const; + bool isNull() const; + QString portName() const; + QString friendlyName() const; + + // Windows only. + QString deviceDesc() const; + QString manufacturer() const; + + void format(QTextStream &str) const; + QString toString() const; + +private: + QExplicitlySharedDataPointer m_data; +}; + +QDebug operator<<(QDebug d, const SymbianDevice &); + +inline bool operator==(const SymbianDevice &d1, const SymbianDevice &d2) + { return d1.compare(d2) == 0; } +inline bool operator!=(const SymbianDevice &d1, const SymbianDevice &d2) + { return d1.compare(d2) != 0; } +inline bool operator<(const SymbianDevice &d1, const SymbianDevice &d2) + { return d1.compare(d2) < 0; } + +/* SymbianDeviceManager: Singleton that maintains a list of Symbian devices. + * and emits change signals. + * On Windows, the update slot must be connected to a signal + * emitted from an event handler listening for WM_DEVICECHANGE. */ +class SYMBIANUTILS_EXPORT SymbianDeviceManager : public QObject +{ + Q_OBJECT +public: + typedef QList SymbianDeviceList; + + static const char *linuxBlueToothDeviceRootC; + + // Do not use this constructor, it is just public for Q_GLOBAL_STATIC + explicit SymbianDeviceManager(QObject *parent = 0); + virtual ~SymbianDeviceManager(); + + // Singleton access. + static SymbianDeviceManager *instance(); + + SymbianDeviceList devices() const; + QString toString() const; + + QString friendlyNameForPort(const QString &port) const; + +public slots: + void update(); + +signals: + void deviceRemoved(const SymbianDevice &d); + void deviceAdded(const SymbianDevice &d); + void updated(); + +private: + void update(bool emitSignals); + SymbianDeviceList serialPorts() const; + SymbianDeviceList blueToothDevices() const; + + SymbianDeviceManagerPrivate *d; +}; + +QDebug operator<<(QDebug d, const SymbianDeviceManager &); + +} // namespace SymbianUtils + +#endif // SYMBIANDEVICEMANAGER_H diff --git a/tools/runonphone/symbianutils/symbianutils.pri b/tools/runonphone/symbianutils/symbianutils.pri index a54df76..6309517 100644 --- a/tools/runonphone/symbianutils/symbianutils.pri +++ b/tools/runonphone/symbianutils/symbianutils.pri @@ -8,13 +8,15 @@ HEADERS += $$PWD/symbianutils_global.h \ $$PWD/trkdevice.h \ $$PWD/launcher.h \ $$PWD/bluetoothlistener.h \ - $$PWD/communicationstarter.h + $$PWD/communicationstarter.h \ + $$PWD/symbiandevicemanager.h SOURCES += $$PWD/trkutils.cpp \ $$PWD/trkdevice.cpp \ $$PWD/launcher.cpp \ $$PWD/bluetoothlistener.cpp \ - $$PWD/communicationstarter.cpp + $$PWD/communicationstarter.cpp \ + $$PWD/symbiandevicemanager.cpp # Tests/trklauncher is a console application contains(QT, gui) { diff --git a/tools/runonphone/symbianutils/trkdevice.cpp b/tools/runonphone/symbianutils/trkdevice.cpp index d587135..b327ab3 100644 --- a/tools/runonphone/symbianutils/trkdevice.cpp +++ b/tools/runonphone/symbianutils/trkdevice.cpp @@ -883,6 +883,7 @@ struct TrkDevicePrivate QByteArray trkReadBuffer; int verbose; QString errorString; + QString port; }; /////////////////////////////////////////////////////////////////////// @@ -914,13 +915,19 @@ TrkDevice::~TrkDevice() delete d; } -bool TrkDevice::open(const QString &port, QString *errorMessage) +bool TrkDevice::open(QString *errorMessage) { if (d->verbose) - qDebug() << "Opening" << port << "is open: " << isOpen() << " serialFrame=" << serialFrame(); + qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame(); + if (d->port.isEmpty()) { + *errorMessage = QLatin1String("Internal error: No port set on TrkDevice"); + return false; + } + close(); #ifdef Q_OS_WIN - d->deviceContext->device = CreateFile(QString("\\\\.\\").append(port).toStdWString().c_str(), + const QString fullPort = QLatin1String("\\\\.\\") + d->port; + d->deviceContext->device = CreateFile(reinterpret_cast(fullPort.utf16()), GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -929,7 +936,7 @@ bool TrkDevice::open(const QString &port, QString *errorMessage) NULL); if (INVALID_HANDLE_VALUE == d->deviceContext->device) { - *errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port, winErrorMessage(GetLastError())); + *errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port(), winErrorMessage(GetLastError())); return false; } memset(&d->deviceContext->readOverlapped, 0, sizeof(OVERLAPPED)); @@ -941,9 +948,9 @@ bool TrkDevice::open(const QString &port, QString *errorMessage) return false; } #else - d->deviceContext->file.setFileName(port); + d->deviceContext->file.setFileName(d->port); if (!d->deviceContext->file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) { - *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(port, d->deviceContext->file.errorString()); + *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(d->port, d->deviceContext->file.errorString()); return false; } @@ -982,7 +989,7 @@ bool TrkDevice::open(const QString &port, QString *errorMessage) d->writerThread->start(); if (d->verbose) - qDebug() << "Opened" << port; + qDebug() << "Opened" << d->port; return true; } @@ -1016,6 +1023,16 @@ bool TrkDevice::isOpen() const #endif } +QString TrkDevice::port() const +{ + return d->port; +} + +void TrkDevice::setPort(const QString &p) +{ + d->port = p; +} + QString TrkDevice::errorString() const { return d->errorString; diff --git a/tools/runonphone/symbianutils/trkdevice.h b/tools/runonphone/symbianutils/trkdevice.h index 21a3cc1..78012fd 100644 --- a/tools/runonphone/symbianutils/trkdevice.h +++ b/tools/runonphone/symbianutils/trkdevice.h @@ -80,13 +80,17 @@ class SYMBIANUTILS_EXPORT TrkDevice : public QObject Q_OBJECT Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame) Q_PROPERTY(bool verbose READ verbose WRITE setVerbose) + Q_PROPERTY(QString port READ port WRITE setPort) public: explicit TrkDevice(QObject *parent = 0); virtual ~TrkDevice(); - bool open(const QString &port, QString *errorMessage); + bool open(QString *errorMessage); bool isOpen() const; + QString port() const; + void setPort(const QString &p); + QString errorString() const; bool serialFrame() const; diff --git a/tools/runonphone/symbianutils/trkutils.cpp b/tools/runonphone/symbianutils/trkutils.cpp index 5cce950..9b43c96 100644 --- a/tools/runonphone/symbianutils/trkutils.cpp +++ b/tools/runonphone/symbianutils/trkutils.cpp @@ -143,6 +143,7 @@ QString Session::deviceDescription(unsigned verbose) const return msg.arg(formatTrkVersion(trkAppVersion)); } +// -------------- QByteArray decode7d(const QByteArray &ba) { -- cgit v0.12 From b0c972dfd208411086b53ee2c2b0594ade3e2d10 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 9 Feb 2010 20:04:09 +0100 Subject: Add the download URI for smart installer package to documentation Task-number: QTBUG-8068 Reviewed-by: David Boddie --- doc/src/deployment/deployment.qdoc | 7 ++++++- doc/src/platforms/symbian-introduction.qdoc | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/src/deployment/deployment.qdoc b/doc/src/deployment/deployment.qdoc index 41babd9..43f5d33 100644 --- a/doc/src/deployment/deployment.qdoc +++ b/doc/src/deployment/deployment.qdoc @@ -1581,7 +1581,12 @@ \snippet doc/src/snippets/code/doc_src_deployment.qdoc 58 If everything compiled and linked without any errors, we are now ready to create - an application installation package (\c wiggly_installer.sis): + an application installation package (\c wiggly_installer.sis). + + If you haven't done so already, download the latest release of the Smart Installer + from \l{http://get.qt.nokia.com/nokiasmartinstaller/}, and install it on top of the Qt package + + Then use this command to create the installer sis package: \snippet doc/src/snippets/code/doc_src_deployment.qdoc 59 diff --git a/doc/src/platforms/symbian-introduction.qdoc b/doc/src/platforms/symbian-introduction.qdoc index 94075f5..5cebee3 100644 --- a/doc/src/platforms/symbian-introduction.qdoc +++ b/doc/src/platforms/symbian-introduction.qdoc @@ -127,7 +127,8 @@ \row \o \c run \o Run the application on the emulator. \row \o \c runonphone \o Run the application on a device. \row \o \c sis \o Create signed \c .sis file for project. - \row \o \c installer_sis \o Create signed smart installer \c .sis file for project. + \row \o \c installer_sis \o Create signed \l{Smart Installer}{smart installer} + \c .sis file for project. Smart installer will attempt to download missing dependencies in addition to just installing the application. @@ -141,6 +142,14 @@ To work on your project in Carbide, simply import the \c .pro file by right clicking on the project explorer and executing "Import...". + \section2 Smart Installer + + The Smart Installer makes sure that deployed applications have all the Qt dependencies + they need to run on a device. + + Download the latest release of the Smart Installer from \l{http://get.qt.nokia.com/nokiasmartinstaller/}, + and install it on top of the Qt package. + \section1 Installing your own applications To install your own applications on hardware, you need a signed \c .sis file. -- cgit v0.12