diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp
index 45cc4ba9bac09517bd889e1a44b7854b04d28058..eeb080ca0d8ec2128e0c2ab79a0f3099b0cb7359 100755
--- a/tests/manual/trk/runner.cpp
+++ b/tests/manual/trk/runner.cpp
@@ -28,7 +28,7 @@
 **************************************************************************/
 
 #include "trkutils.h"
-#include "trkdevice.h"
+#include "trkdevicex.h"
 
 #include <QtCore/QCoreApplication>
 #include <QtCore/QDebug>
@@ -58,6 +58,8 @@ using namespace trk;
 
 enum { KnownRegisters = RegisterPSGdb + 1};
 
+#define CB(s) Callback(this, &Adapter::s)
+
 static const char *registerNames[KnownRegisters] =
 {
     "A1", "A2", "A3", "A4",
@@ -69,17 +71,18 @@ static const char *registerNames[KnownRegisters] =
     0, "PSGdb"
 };
 
-static inline void dumpRegister(int n, uint value, QByteArray &a)
+static QByteArray dumpRegister(int n, uint value)
 {
-    a += ' ';
+    QByteArray ba;
+    ba += ' ';
     if (n < KnownRegisters && registerNames[n]) {
-        a += registerNames[n];
+        ba += registerNames[n];
     } else {
-        a += '#';
-        a += QByteArray::number(n);
+        ba += '#';
+        ba += QByteArray::number(n);
     }
-    a += "=0x";
-    a += QByteArray::number(value, 16);
+    ba += "=0x" + hexNumber(value);
+    return ba;
 }
 
 ///////////////////////////////////////////////////////////////////////
@@ -104,7 +107,7 @@ public:
     void setVerbose(int verbose) { m_verbose = verbose; }
     void setSerialFrame(bool b) { m_serialFrame = b; }
     void setRegisterEndianness(Endianness r) { m_registerEndianness = r; }
-    void setBufferedMemoryRead(bool b) { qDebug() << "Buffered=" << b; m_bufferedMemoryRead = b; }
+    void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; }
 
 public slots:
     void startServer();
@@ -124,6 +127,7 @@ private slots:
     void handleProcStateChanged(QProcess::ProcessState newState);
     void run();
     void startGdb();
+    void writeToGdb(const QString &msg);
 
 private:
     friend class RunnerGui;
@@ -131,11 +135,8 @@ private:
     void sendOutput(QObject *sender, const QString &data);
     void sendOutput(const QString &data) { sendOutput(0, data); }
 
-    QStringList m_trkServerOptions;
     QString m_endianness;
-    QString m_trkServerName;
-    bool m_isUnix;
-    bool m_waitForAdapter;
+    QString m_trkServerName; // 
     QString m_gdbServerName; // 127.0.0.1:(2222+uid)
 
     QProcess m_gdbProc;
@@ -178,6 +179,7 @@ public:
     void handleAndReportSetBreakpoint(const TrkResult &result);
     void handleReadMemoryBuffered(const TrkResult &result);
     void handleReadMemoryUnbuffered(const TrkResult &result);
+    void handleStepRange(const TrkResult &result);
     void reportReadMemoryBuffered(const TrkResult &result);
     void reportToGdb(const TrkResult &result);
 
@@ -190,7 +192,7 @@ public:
     void startInferiorIfNeeded();
     void interruptInferior();
 
-    TrkWriteQueueDevice m_trkDevice;
+    TrkDevice m_trkDevice;
 
     QList<Breakpoint> m_breakpoints;
 
@@ -200,13 +202,16 @@ public:
     Q_SLOT void handleGdbConnection();
     Q_SLOT void readFromGdb();
     void handleGdbResponse(const QByteArray &ba);
-    void sendGdbMessage(const QByteArray &msg, const QByteArray &logNote = QByteArray());
-    void sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote = QByteArray());
+    void sendGdbMessage(const QByteArray &msg,
+        const QByteArray &logNote = QByteArray());
+    void sendGdbMessageAfterSync(const QByteArray &msg,
+        const QByteArray &logNote = QByteArray());
     void sendGdbAckMessage();
     bool sendGdbPacket(const QByteArray &packet, bool doFlush);
     void executeGdbCommand(const QString &msg);
 
     void logMessage(const QString &msg, bool force = false);
+    Q_SLOT void trkLogMessage(const QString &msg);
 
     QTcpServer m_gdbServer;
     QPointer<QTcpSocket> m_gdbConnection;
@@ -226,22 +231,18 @@ public:
 Adapter::Adapter()
 {
     m_gdbAckMode = true;
-    m_verbose = 1;
+    m_verbose = 2;
     m_registerEndianness = LittleEndian;
     //m_serialFrame = true;
     m_serialFrame = false;
     m_startInferiorTriggered = false;
-    m_bufferedMemoryRead = true;
+    //m_bufferedMemoryRead = true;
+    m_bufferedMemoryRead = false;
     // m_breakpoints.append(Breakpoint(0x0040)); // E32Main
+    m_breakpoints.append(Breakpoint(0x0cc8)); // E32Main
     m_trkServerName = "/dev/rfcomm0";
 
-#ifdef Q_OS_UNIX
-    m_isUnix = true;
-#else
-    m_isUnix = false;
-#endif
     m_endianness = "little";
-    m_waitForAdapter = false;
 
     uid_t userId = getuid();
     m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId);
@@ -251,17 +252,22 @@ Adapter::Adapter()
 
     m_rfcommProc.setObjectName("RFCOMM PROCESS");
     connectProcess(&m_rfcommProc);
+
+    connect(&m_trkDevice, SIGNAL(logMessage(QString)),
+        this, SLOT(trkLogMessage(QString)));
 }
 
 Adapter::~Adapter()
 {
-    // Trk
-
-    // Gdb
     m_gdbServer.close();
     logMessage("Shutting down.\n", true);
 }
 
+void Adapter::trkLogMessage(const QString &msg)
+{
+    logMessage("TRK " + msg);
+}
+
 void Adapter::setGdbServerName(const QString &name)
 {
     m_gdbServerName = name;
@@ -295,9 +301,9 @@ void Adapter::startServer()
 
     sendTrkInitialPing();
     sendTrkMessage(0x01); // Connect
-    sendTrkMessage(0x05, Callback(this, &Adapter::handleSupportMask));
-    sendTrkMessage(0x06, Callback(this, &Adapter::handleCpuType));
-    sendTrkMessage(0x04, Callback(this, &Adapter::handleTrkVersions)); // Versions
+    sendTrkMessage(0x05, CB(handleSupportMask));
+    sendTrkMessage(0x06, CB(handleCpuType));
+    sendTrkMessage(0x04, CB(handleTrkVersions)); // Versions
     //sendTrkMessage(0x09); // Unrecognized command
     //sendTrkMessage(0x4a, 0,
     //    "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
@@ -324,7 +330,7 @@ void Adapter::startServer()
 void Adapter::logMessage(const QString &msg, bool force)
 {
     if (m_verbose || force)
-        emit output("ADAPTER: ", msg);
+        emit output(QString(), msg);
 }
 
 //
@@ -344,7 +350,7 @@ void Adapter::handleGdbConnection()
 
 static inline QString msgGdbPacket(const QString &p)
 {
-    return QLatin1String("gdb: -> ") + p;
+    return QLatin1String("gdb:                              ") + p;
 }
 
 void Adapter::readFromGdb()
@@ -352,7 +358,7 @@ void Adapter::readFromGdb()
     QByteArray packet = m_gdbConnection->readAll();
     m_gdbReadBuffer.append(packet);
 
-    logMessage(msgGdbPacket(QString::fromAscii(packet)));
+    logMessage("gdb: -> " + QString::fromAscii(packet));
     if (packet != m_gdbReadBuffer)
         logMessage("buffer: " + m_gdbReadBuffer);
 
@@ -462,7 +468,7 @@ void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote)
 void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote)
 {
     QByteArray ba = msg + char(1) + logNote;
-    sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportToGdb), "", ba); // Answer gdb
+    sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, CB(reportToGdb), "", ba); // Answer gdb
 }
 
 void Adapter::reportToGdb(const TrkResult &result)
@@ -481,7 +487,7 @@ void Adapter::reportToGdb(const TrkResult &result)
     sendGdbMessage(message, note);
 }
 
-static QByteArray breakpointTrkMessage(uint addr, int len, int pid, bool armMode = true)
+static QByteArray trkBreakpointMessage(uint addr, int len, int pid, bool armMode = true)
 {
     QByteArray ba;
     appendByte(&ba, 0x82);  // unused option
@@ -543,7 +549,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         QByteArray ba;
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x18, Callback(this, &Adapter::handleSignalContinue), ba, signalNumber); // Continue
+        sendTrkMessage(0x18, CB(handleSignalContinue), ba, signalNumber); // Continue
     }
 
     else if (response.startsWith("D")) {
@@ -564,7 +570,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         appendShort(&ba, RegisterCount - 1); // last register
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x12, Callback(this, &Adapter::handleAndReportReadRegisters), ba, QVariant(), true);
+        sendTrkMessage(0x12, CB(handleAndReportReadRegisters), ba, QVariant(), true);
     }
 
     else if (response.startsWith("Hc")) {
@@ -574,7 +580,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         // for step and continue operations
         //$Hc-1#09
         sendGdbAckMessage();
-        sendGdbMessage("OK", "set current thread for step & continue");
+        sendGdbMessage("OK", "Set current thread for step & continue");
     }
 
     else if (response.startsWith("Hg")) {
@@ -585,7 +591,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         //$Hg0#df
         sendGdbAckMessage();
         m_session.currentThread = response.mid(2).toInt(0, 16);
-        sendGdbMessage("OK", "set current thread "
+        sendGdbMessage("OK", "Set current thread "
             + QByteArray::number(m_session.currentThread));
     }
 
@@ -665,16 +671,16 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         #endif
         bool ok = false;
         const uint registerNumber = response.mid(1).toInt(&ok, 16);
-        QByteArray logMsg = "read register";
+        QByteArray logMsg = "Read Register";
         if (registerNumber == RegisterPSGdb) {
             QByteArray ba;
             appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness);
-            dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk], logMsg);
+            logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]);
             sendGdbMessage(ba.toHex(), logMsg);
         } else if (registerNumber < RegisterCount) {
             QByteArray ba;
             appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness);
-            dumpRegister(registerNumber, m_snapshot.registers[registerNumber], logMsg);
+            logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]);
             sendGdbMessage(ba.toHex(), logMsg);
         } else {
             sendGdbMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber));
@@ -775,7 +781,7 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address
         appendInt(&ba, m_session.pid);
         appendInt(&ba, m_session.tid);
-        sendTrkMessage(0x19, Callback(), ba, "Step range");
+        sendTrkMessage(0x19, CB(handleStepRange), ba, "Step range");
         // FIXME: should be triggered by "real" stop"
         //sendGdbMessageAfterSync("S05", "target halted");
     }
@@ -823,8 +829,8 @@ void Adapter::handleGdbResponse(const QByteArray &response)
         // ThreadID: 0xffffffff (-1)
         // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00
         //  00 00 01 B5 FF FF FF FF]
-        const QByteArray ba = breakpointTrkMessage(addr, len, m_session.pid);
-        sendTrkMessage(0x1B, Callback(this, &Adapter::handleAndReportSetBreakpoint), ba);
+        const QByteArray ba = trkBreakpointMessage(addr, len, m_session.pid);
+        sendTrkMessage(0x1B, CB(handleAndReportSetBreakpoint), ba);
         //m_session.toekn
 
         //---TRK------------------------------------------------------
@@ -865,9 +871,11 @@ void Adapter::executeGdbCommand(const QString &msg)
 {
     logMessage("EXECUTING GDB COMMAND " + msg);
     if (msg == "S")
-        m_gdbProc.write("-exec-interrupt");
+        writeToGdb("-exec-interrupt");
+    if (msg == "I")
+        interruptInferior();
     else
-        m_gdbProc.write(msg.toLatin1());
+        writeToGdb(msg);
 }
 
 bool Adapter::openTrkPort(const QString &port, QString *errorMessage)
@@ -902,7 +910,7 @@ void Adapter::sendTrkContinue()
 void Adapter::waitForTrkFinished()
 {
     // initiate one last roundtrip to ensure all is flushed
-    sendTrkMessage(0x0, Callback(this, &Adapter::handleWaitForFinished));
+    sendTrkMessage(0x0, CB(handleWaitForFinished));
 }
 
 void Adapter::sendTrkAck(byte token)
@@ -934,11 +942,13 @@ void Adapter::handleResult(const TrkResult &result)
             const uint addr = extractInt(data); //code address: 4 bytes; code base address for the library
             const uint pid = extractInt(data + 4); // ProcessID: 4 bytes;
             const uint tid = extractInt(data + 8); // ThreadID: 4 bytes
-            logMessage(prefix + QString::fromLatin1("NOTE: PID %1/TID %2 STOPPED at 0x%3").arg(pid).arg(tid).arg(addr, 0, 16));
+            logMessage(prefix + QString::fromLatin1("NOTE: PID %1/TID %2 "
+                "STOPPED at 0x%3").arg(pid).arg(tid).arg(addr, 0, 16));
             sendTrkAck(result.token);
             if (addr) {
-                // Todo: Do not send off GdbMessages if a synced gdb query is pending, queue instead
-                sendGdbMessage("S05", "Target stopped");
+                // Todo: Do not send off GdbMessages if a synced gdb
+                // query is pending, queue instead
+                //sendGdbMessage("S05", "Target stopped");
             } else {
                 if (m_verbose)
                     logMessage(QLatin1String("Ignoring stop at 0"));
@@ -988,9 +998,10 @@ void Adapter::handleResult(const TrkResult &result)
             const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString();
             if (!name.isEmpty())
                 m_session.modules.removeAll(name);
-            logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
-                       arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
-                       arg(name));
+            logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3")
+                .arg(QString::fromAscii(prefix))
+                .arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS"))
+                .arg(name));
             sendTrkAck(result.token);
             break;
         }
@@ -1040,24 +1051,24 @@ void Adapter::handleCpuType(const TrkResult &result)
 
 void Adapter::setTrkBreakpoint(const Breakpoint &bp)
 {
-        //---IDE------------------------------------------------------
-        //  Command: 0x1B Set Break
-        //BreakType: 0x82
-        //  Options: 0x00
-        //  Address: 0x78674340 (2020033344)    i.e + 0x00000340
-        //   Length: 0x00000001 (1)
-        //    Count: 0x00000000 (0)
-        //ProcessID: 0x000001b5 (437)
-        // ThreadID: 0xffffffff (-1)
-        // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00
-        //  00 00 01 B5 FF FF FF FF]
-    const QByteArray ba = breakpointTrkMessage(m_session.codeseg + bp.offset, 1, m_session.pid);
-    sendTrkMessage(0x1B, Callback(this, &Adapter::handleSetTrkBreakpoint), ba);
+    //---IDE------------------------------------------------------
+    //  Command: 0x1B Set Break
+    //BreakType: 0x82
+    //  Options: 0x00
+    //  Address: 0x78674340 (2020033344)    i.e + 0x00000340
+    //   Length: 0x00000001 (1)
+    //    Count: 0x00000000 (0)
+    //ProcessID: 0x000001b5 (437)
+    // ThreadID: 0xffffffff (-1)
+    // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00
+    //  00 00 01 B5 FF FF FF FF]
+    const QByteArray ba = trkBreakpointMessage(m_session.codeseg + bp.offset, 1, m_session.pid);
+    sendTrkMessage(0x1B, CB(handleSetTrkBreakpoint), ba);
 
-        //---TRK------------------------------------------------------
-        //  Command: 0x80 Acknowledge
-        //    Error: 0x00
-        // [80 09 00 00 00 00 0A]
+    //---TRK------------------------------------------------------
+    //  Command: 0x80 Acknowledge
+    //    Error: 0x00
+    // [80 09 00 00 00 00 0A]
 }
 
 void Adapter::handleSetTrkBreakpoint(const TrkResult &result)
@@ -1081,37 +1092,34 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     m_session.tid = extractInt(data + 5);
     m_session.codeseg = extractInt(data + 9);
     m_session.dataseg = extractInt(data + 13);
-    QString logMsg = QString::fromLatin1("handleCreateProcess PID=%1 TID=%2 CODE=0x%3 (%4) DATA=0x%5 (%6)")
-                     .arg(m_session.pid).arg(m_session.tid).arg(m_session.codeseg, 0 ,16).arg(m_session.codeseg).arg(m_session.dataseg, 0, 16).arg(m_session.dataseg);
-    logMessage(logMsg);
+
+    logMessage("PID: 0x" + hexNumber(m_session.pid));
+    logMessage("TID: 0x" + hexNumber(m_session.tid));
+    logMessage("COD: 0x" + hexNumber(m_session.codeseg));
+    logMessage("DAT: 0x" + hexNumber(m_session.dataseg));
+
+    writeToGdb("add-symbol-file filebrowseapp.sym 0x"
+        + hexNumber(m_session.codeseg));
+    writeToGdb("symbol-file filebrowseapp.sym");
+
     foreach (const Breakpoint &bp, m_breakpoints)
         setTrkBreakpoint(bp);
 
     sendTrkContinue();
-#if 0
-    /*
-    logMessage("PID: " + formatInt(m_session.pid) + m_session.pid);
-    logMessage("TID: " + formatInt(m_session.tid) + m_session.tid);
-    logMessage("COD: " + formatInt(m_session.codeseg) + m_session.codeseg);
-    logMessage("DAT: " + formatInt(m_session.dataseg) + m_session.dataseg);
-    */
-
 
+#if 0
     //setTrkBreakpoint(0x0000, ArmMode);
     //clearTrkBreakpoint(0x0000);
 
-
-
-
 #if 1
     //---IDE------------------------------------------------------
     //  Command: 0x42 Read Info
     //          [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F
     //  72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00]
-    sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
+    sendTrkMessage(0x42, CB(handleReadInfo),
         "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F "
         "72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00");
-    //sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
+    //sendTrkMessage(0x42, CB(handleReadInfo),
     //        "00 01 00 00 00 00");
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
@@ -1123,7 +1131,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     //  Command: 0x42 Read Info
     // [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F
     //  72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00]
-    sendTrkMessage(0x42, Callback(this, &Adapter::handleReadInfo),
+    sendTrkMessage(0x42, CB(handleReadInfo),
         "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F "
         "72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00");
     //---TRK------------------------------------------------------
@@ -1132,7 +1140,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     // [80 0D 20]
 #endif
 
-    //sendTrkMessage(0x18, Callback(this, &Adapter::handleStop),
+    //sendTrkMessage(0x18, CB(handleStop),
     //    "01 " + formatInt(m_session.pid) + formatInt(m_session.tid));
 
     //---IDE------------------------------------------------------
@@ -1143,8 +1151,8 @@ void Adapter::handleCreateProcess(const TrkResult &result)
     QByteArray ba;
     appendInt(&ba, m_session.pid);
     appendInt(&ba, m_session.tid);
-    sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue), ba);
-    //sendTrkMessage(0x18, Callback(this, &Adapter::handleContinue),
+    sendTrkMessage(0x18, CB(handleContinue), ba);
+    //sendTrkMessage(0x18, CB(handleContinue),
     //    formatInt(m_session.pid) + "ff ff ff ff");
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
@@ -1155,7 +1163,7 @@ void Adapter::handleCreateProcess(const TrkResult &result)
 
 void Adapter::handleAndReportReadRegisters(const TrkResult &result)
 {
-    //logMessage("       RESULT: " + result.toString());
+    logMessage("       RESULT: " + result.toString());
     // [80 0B 00   00 00 00 00   C9 24 FF BC   00 00 00 00   00
     //  60 00 00   00 00 00 00   78 67 79 70   00 00 00 00   00...]
 
@@ -1165,13 +1173,16 @@ void Adapter::handleAndReportReadRegisters(const TrkResult &result)
     }
     QByteArray ba;
     for (int i = 0; i < 16; ++i) {
-        const uint reg = m_registerEndianness == LittleEndian ? swapEndian(m_snapshot.registers[i]) : m_snapshot.registers[i];
+        const uint reg = m_registerEndianness == LittleEndian
+            ? swapEndian(m_snapshot.registers[i]) : m_snapshot.registers[i];
         ba += hexNumber(reg, 8);
     }
-    QByteArray logMsg = "register contents";
+    QByteArray logMsg = "REGISTER CONTENTS: ";
     if (m_verbose > 1) {
-        for (int i = 0; i < RegisterCount; ++i)
-            dumpRegister(i, m_snapshot.registers[i], logMsg);
+        for (int i = 0; i < RegisterCount; ++i) {
+            logMsg += dumpRegister(i, m_snapshot.registers[i]);
+            logMsg += ' ';
+        }
     }
     sendGdbMessage(ba, logMsg);
 }
@@ -1210,7 +1221,8 @@ QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &
                 logMsg += "[SP]";
             } else if (addr == m_snapshot.registers[RegisterLR]) {
                 logMsg += "[LR]";
-            } else if (addr > m_snapshot.registers[RegisterSP] && (addr - m_snapshot.registers[RegisterSP]) < 10240) {
+            } else if (addr > m_snapshot.registers[RegisterSP] &&
+                    (addr - m_snapshot.registers[RegisterSP]) < 10240) {
                 logMsg += "[SP+"; // Stack area ...stack seems to be top-down
                 logMsg += QByteArray::number(addr - m_snapshot.registers[RegisterSP]);
                 logMsg += ']';
@@ -1256,16 +1268,28 @@ void Adapter::reportReadMemoryBuffered(const TrkResult &result)
 
 void Adapter::handleReadMemoryUnbuffered(const TrkResult &result)
 {
+    //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data));
     const uint blockaddr = result.cookie.toUInt();
+    if (extractShort(result.data.data() + 1) + 3 != result.data.size()) {
+        logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n");
+    }
     if (const int errorCode = result.errorCode()) {
         const QByteArray ba = "E20";
         sendGdbMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1());
     } else {
-        const QByteArray ba = result.data.mid(1);
+        const QByteArray ba = result.data.mid(3);
         sendGdbMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba));
     }
 }
 
+void Adapter::handleStepRange(const TrkResult &result)
+{
+    // [80 0f 12]
+    //uint bpnr = extractInt(result.data.data());
+    logMessage("STEPPING FINISHED " + stringFromArray(result.data.data()));
+    sendGdbMessage("S05", "Stepping finished");
+}
+
 void Adapter::handleAndReportSetBreakpoint(const TrkResult &result)
 {
     //---TRK------------------------------------------------------
@@ -1286,7 +1310,7 @@ void Adapter::clearTrkBreakpoint(const Breakpoint &bp)
     appendByte(&ba, 0x00);
     appendShort(&ba, bp.number);
     appendInt(&ba, m_session.codeseg + bp.offset);
-    sendTrkMessage(0x1C, Callback(this, &Adapter::handleClearBreakpoint), ba);
+    sendTrkMessage(0x1C, CB(handleClearBreakpoint), ba);
 }
 
 void Adapter::handleClearBreakpoint(const TrkResult &result)
@@ -1333,8 +1357,10 @@ void Adapter::handleTrkVersions(const TrkResult &result)
     QTextStream str(&logMsg);
     str << "Versions: ";
     if (result.data.size() >= 5) {
-        str << "Trk version " << int(result.data.at(1)) << '.' << int(result.data.at(2))
-                << ", Protocol version " << int(result.data.at(3)) << '.' << int(result.data.at(4));
+        str << "Trk version " << int(result.data.at(1)) << '.'
+            << int(result.data.at(2))
+            << ", Protocol version " << int(result.data.at(3))
+             << '.' << int(result.data.at(4));
     }
     logMessage(logMsg);
 }
@@ -1370,7 +1396,7 @@ void Adapter::cleanUp()
     foreach (const Breakpoint &bp, m_breakpoints)
         clearTrkBreakpoint(bp);
 
-    sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect));
+    sendTrkMessage(0x02, CB(handleDisconnect));
     m_startInferiorTriggered = false;
     //---IDE------------------------------------------------------
     //  Command: 0x1C Clear Break
@@ -1401,7 +1427,7 @@ void Adapter::cleanUp()
     //---IDE------------------------------------------------------
     //  Command: 0x02 Disconnect
     // [02 27]
-//    sendTrkMessage(0x02, Callback(this, &Adapter::handleDisconnect));
+//    sendTrkMessage(0x02, CB(handleDisconnect));
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
     // Error: 0x00
@@ -1432,17 +1458,17 @@ void Adapter::readMemory(uint addr, uint len)
             if (!m_snapshot.memory.contains(blockaddr)) {
                 if (m_verbose)
                     logMessage(QString::fromLatin1("Requesting buffered memory %1 bytes from 0x%2").arg(MemoryChunkSize).arg(blockaddr, 0, 16));
-                sendTrkMessage(0x10, Callback(this, &Adapter::handleReadMemoryBuffered),
+                sendTrkMessage(0x10, CB(handleReadMemoryBuffered),
                                memoryRequestTrkMessage(blockaddr, MemoryChunkSize, m_session.pid, m_session.tid),
                                QVariant(blockaddr), true);
             }
         }
         const qulonglong cookie = (qulonglong(addr) << 32) + len;
-        sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, Callback(this, &Adapter::reportReadMemoryBuffered), QByteArray(), cookie);
+        sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, CB(reportReadMemoryBuffered), QByteArray(), cookie);
     } else {
         if (m_verbose)
             logMessage(QString::fromLatin1("Requesting unbuffered memory %1 bytes from 0x%2").arg(len).arg(addr, 0, 16));
-        sendTrkMessage(0x10, Callback(this, &Adapter::handleReadMemoryUnbuffered),
+        sendTrkMessage(0x10, CB(handleReadMemoryUnbuffered),
                        memoryRequestTrkMessage(addr, len, m_session.pid, m_session.tid),
                        QVariant(addr), true);
     }
@@ -1465,7 +1491,7 @@ void Adapter::startInferiorIfNeeded()
 
     QByteArray file("C:\\sys\\bin\\filebrowseapp.exe");
     appendString(&ba, file, TargetByteOrder);
-    sendTrkMessage(0x40, Callback(this, &Adapter::handleCreateProcess), ba); // Create Item
+    sendTrkMessage(0x40, CB(handleCreateProcess), ba); // Create Item
 }
 
 void Adapter::interruptInferior()
@@ -1478,7 +1504,6 @@ void Adapter::interruptInferior()
     sendTrkMessage(0x1A, Callback(), ba, "Interrupting...");
 }
 
-
 void Adapter::connectProcess(QProcess *proc)
 {
     connect(proc, SIGNAL(error(QProcess::ProcessError)),
@@ -1495,11 +1520,10 @@ void Adapter::connectProcess(QProcess *proc)
         this, SLOT(handleProcStateChanged(QProcess::ProcessState)));
 }
 
-
 void Adapter::sendOutput(QObject *sender, const QString &data)
 {
     if (sender)
-        emit output(sender->objectName(), data);
+        emit output(sender->objectName() + " : ", data);
     else
         emit output(QString(), data);
 }
@@ -1539,11 +1563,6 @@ void Adapter::handleProcStateChanged(QProcess::ProcessState newState)
 
 void Adapter::run()
 {
-    if (m_isUnix) {
-        QProcess::execute("killall -s USR adapter trkserver");
-        QProcess::execute("killall adapter trkserver");
-    }
-
     startServer();
     sendOutput("### Starting Adapter");
 
@@ -1564,22 +1583,26 @@ void Adapter::startGdb()
     m_gdbProc.start(QDir::currentPath() + "/cs-gdb", gdbArgs);
     m_gdbProc.waitForStarted();
 
-    QTextStream ts(&m_gdbProc);
-    ts << "# This is generated. Changes will be lost.\n";
-    ts << "#set remote noack-packet on\n";
-    ts << "set confirm off\n";
-    ts << "set endian " + m_endianness + "\n";
-    ts << "#set debug remote 1\n";
-    ts << "#target remote " + m_gdbServerName + "\n";
-    ts << "target extended-remote " + m_gdbServerName + "\n";
-    ts << "#file filebrowseapp.sym\n";
-//    ts << "add-symbol-file filebrowseapp.sym " + m_baseAddress + "\n";
-//    ts << "symbol-file filebrowseapp.sym\n";
-//    ts << "print E32Main\n";
-//    ts << "break E32Main\n";
-    ts << "#continue\n";
-    ts << "#info files\n";
-    ts << "#file filebrowseapp.sym -readnow\n";
+    //writeToGdb("set remote noack-packet on");
+    writeToGdb("set confirm off");
+    writeToGdb("set endian " + m_endianness);
+    //writeToGdb("set debug remote 1");
+    //writeToGdb("target remote " + m_gdbServerName);
+    writeToGdb("target extended-remote " + m_gdbServerName);
+    //writeToGdb("file filebrowseapp.sym");
+//    writeToGdb("add-symbol-file filebrowseapp.sym " + m_baseAddress);
+//    writeToGdb("symbol-file filebrowseapp.sym");
+//    writeToGdb("print E32Main");
+//    writeToGdb("break E32Main");
+    //writeToGdb("continue");
+    //writeToGdb("info files");
+    //writeToGdb("file filebrowseapp.sym -readnow");
+}
+
+void Adapter::writeToGdb(const QString &msg)
+{
+    logMessage("<- GDB: " + msg);
+    m_gdbProc.write(msg.toLatin1() + "\n");
 }
 
 ///////////////////////////////////////////////////////////////////////
@@ -1606,15 +1629,29 @@ private:
 RunnerGui::RunnerGui(Adapter *adapter)
     : m_adapter(adapter) 
 {
-    resize(1000, 1000);
+    resize(1200, 1000);
     connect(adapter, SIGNAL(output(QString,QString)),
         this, SLOT(handleOutput(QString,QString)));
 }
 
 void RunnerGui::handleOutput(const QString &senderName, const QString &data)
 {
-    append(senderName + " : " + data);
+    append(senderName + data);
+    QTextCursor tc = textCursor();
+    tc.movePosition(QTextCursor::End);
+    setTextCursor(tc);
+    if (senderName.startsWith("GDB PROCESS")) {
+        QString str = data;
+        int pos = str.indexOf("~\"");
+        if (pos != -1)
+            str = str.mid(pos + 2);
+        str.replace("\\t", QString(QChar(0x09)));
+        str.replace("\\n", QString("\n"));
+        insertHtml("<b>" + str + "</b>");
+        setCurrentCharFormat(QTextCharFormat());
+    }
     ensureCursorVisible();
+
 }
 
 void RunnerGui::keyPressEvent(QKeyEvent *ev)
diff --git a/tests/manual/trk/runner.pro b/tests/manual/trk/runner.pro
index 0bf878e42027672082e8b89352eae99c6cfd3fb3..4ced7ccd71abbd0302dc062e6acca3867e284054 100644
--- a/tests/manual/trk/runner.pro
+++ b/tests/manual/trk/runner.pro
@@ -7,9 +7,9 @@ win32:CONFIG+=console
 
 HEADERS += \
     trkutils.h \
-    trkdevice.h \
+    trkdevicex.h \
 
 SOURCES += \
     runner.cpp \
     trkutils.cpp \
-    trkdevice.cpp \
+    trkdevicex.cpp \
diff --git a/tests/manual/trk/trkdevice.cpp b/tests/manual/trk/trkdevice.cpp
index 6746e5b1f64e5d286af6a14a284381aa15c02890..b0e5c2f8140232f02d92e5b354a92c36618903b5 100644
--- a/tests/manual/trk/trkdevice.cpp
+++ b/tests/manual/trk/trkdevice.cpp
@@ -80,7 +80,7 @@ BOOL WINAPI TryReadFile(HANDLE          hFile,
 {
     COMSTAT comStat;
     if (!ClearCommError(hFile, NULL, &comStat)){
-        qDebug() << "ClearCommError() failed";
+        logMessage("ClearCommError() failed");
         return FALSE;
     }
     if (comStat.cbInQue == 0) {
@@ -202,8 +202,8 @@ void TrkDevice::close()
 #else
     d->file.close();
 #endif
-    if (d->verbose)
-        qDebug() << "Close";
+    if (verbose())
+        logMessage("Close");
 }
 
 bool TrkDevice::isOpen() const
@@ -232,7 +232,7 @@ void TrkDevice::setSerialFrame(bool f)
 
 bool TrkDevice::verbose() const
 {
-    return d->verbose;
+    return true || d->verbose;
 }
 
 void TrkDevice::setVerbose(bool b)
@@ -242,8 +242,8 @@ void TrkDevice::setVerbose(bool b)
 
 bool TrkDevice::write(const QByteArray &data, QString *errorMessage)
 {
-    if (d->verbose)
-        qDebug() << ">WRITE" << data.toHex();
+    if (verbose())
+        logMessage("XWRITE " + data.toHex());
 #ifdef Q_OS_WIN
     DWORD charsWritten;
     if (!WriteFile(d->hdevice, data.data(), data.size(), &charsWritten, NULL)) {
@@ -286,8 +286,8 @@ void TrkDevice::tryTrkRead()
         if (isValidTrkResult(d->trkReadBuffer, d->serialFrame))
             break;
     }
-    if (d->verbose && totalCharsRead)
-        qDebug() << "Read" << d->trkReadBuffer.toHex();
+    if (verbose() && totalCharsRead)
+        logMessage("Read" + d->trkReadBuffer.toHex());
     if (!totalCharsRead)
         return;
     const ushort len = isValidTrkResult(d->trkReadBuffer, d->serialFrame);
@@ -301,6 +301,8 @@ void TrkDevice::tryTrkRead()
     if (!size)
         return;
     const QByteArray data = d->file.read(size);
+    if (verbose())
+        logMessage("READ " + data.toHex());
     d->trkReadBuffer.append(data);
     const ushort len = isValidTrkResult(d->trkReadBuffer, d->serialFrame);
     if (!len) {
@@ -315,8 +317,8 @@ void TrkDevice::tryTrkRead()
     TrkResult r;
     QByteArray rawData;
     while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) {
-        if (d->verbose)
-            qDebug() << "Read TrkResult " << r.data.toHex();
+        if (verbose())
+            logMessage("Read TrkResult " + r.data.toHex());
         emit messageReceived(r);
         if (!rawData.isEmpty())
             emit rawDataReceived(rawData);
@@ -547,7 +549,7 @@ bool TrkWriteQueueDevice::trkWriteRawMessage(const TrkMessage &msg)
 {
     const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, serialFrame());
     if (verbose())
-         qDebug() << ("WRITE: " + stringFromArray(ba));
+         logMessage("WRITE: " + stringFromArray(ba));
     QString errorMessage;
     const bool rc = write(ba, &errorMessage);
     if (!rc)
@@ -610,7 +612,7 @@ void TrkWriteQueueIODevice::setSerialFrame(bool f)
 
 bool TrkWriteQueueIODevice::verbose() const
 {
-    return d->verbose;
+    return true || d->verbose;
 }
 
 void TrkWriteQueueIODevice::setVerbose(bool b)
@@ -659,7 +661,7 @@ bool TrkWriteQueueIODevice::trkWriteRawMessage(const TrkMessage &msg)
 {
     const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, serialFrame());
     if (verbose())
-         qDebug() << ("WRITE: " + stringFromArray(ba));
+        logMessage("WRITE: " + stringFromArray(ba));
     const bool ok = d->device->write(ba) != -1;
     if (!ok) {
         const QString msg = QString::fromLatin1("Unable to write %1 bytes: %2:").arg(ba.size()).arg(d->device->errorString());
@@ -674,8 +676,8 @@ void TrkWriteQueueIODevice::tryTrkRead()
     if (!bytesAvailable)
         return;
     const QByteArray newData = d->device->read(bytesAvailable);
-    if (d->verbose)
-        qDebug() << "READ " << newData.toHex();
+    //if (verbose())
+        logMessage("READ " + newData.toHex());
     d->readBuffer.append(newData);
     TrkResult r;
     QByteArray rawData;
diff --git a/tests/manual/trk/trkdevice.h b/tests/manual/trk/trkdevice.h
index 61b382ad5766bdc0a89d2dbfe2fc7a8160169f5d..7b2a5dbcd38fd2b1286353d5db6ba94126fc4300 100644
--- a/tests/manual/trk/trkdevice.h
+++ b/tests/manual/trk/trkdevice.h
@@ -80,13 +80,14 @@ public:
     bool write(const QByteArray &data, QString *errorMessage);
 
 signals:
-    void messageReceived(const trk::TrkResult&);
+    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 &s);
-
+    void error(const QString &msg);
+    void logMessage(const QString &msg);
+    
 protected:
-    void emitError(const QString &);
+    void emitError(const QString &msg);
     virtual void timerEvent(QTimerEvent *ev);
 
 private:
@@ -127,6 +128,9 @@ public:
     // Send an Ack synchronously, bypassing the queue
     bool sendTrkAck(unsigned char token);
 
+signals:
+    void logMessage(const QString &msg);
+
 private slots:
     void slotHandleResult(const trk::TrkResult &);
 
@@ -175,6 +179,8 @@ signals:
     void messageReceived(const trk::TrkResult&);
     // Emitted with the contents of messages enclosed in 07e, not for log output
     void rawDataReceived(const QByteArray &data);
+    void logMessage(const QString &msg);
+
 
 protected:
     virtual void timerEvent(QTimerEvent *ev);
diff --git a/tests/manual/trk/trkdevicex.cpp b/tests/manual/trk/trkdevicex.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..31382de3f03c237a043171487cf419c1d0388abf
--- /dev/null
+++ b/tests/manual/trk/trkdevicex.cpp
@@ -0,0 +1,562 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "trkdevicex.h"
+#include "trkutils.h"
+
+#include <QtCore/QString>
+#include <QtCore/QDebug>
+#include <QtCore/QQueue>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QSharedPointer>
+
+#ifdef Q_OS_WIN
+#  include <windows.h>
+#else
+#  include <QtCore/QFile>
+
+#  include <stdio.h>
+#  include <sys/ioctl.h>
+#  include <termios.h>
+#  include <errno.h>
+#  include <string.h>
+#endif
+
+enum { TimerInterval = 100 };
+
+#ifdef Q_OS_WIN
+
+// Format windows error from GetLastError() value: TODO: Use the one provided by the utisl 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("<unknown error>");
+    }
+    return rc;
+}
+
+// Non-blocking replacement for win-api ReadFile function
+BOOL WINAPI TryReadFile(HANDLE          hFile,
+                        LPVOID          lpBuffer,
+                        DWORD           nNumberOfBytesToRead,
+                        LPDWORD         lpNumberOfBytesRead,
+                        LPOVERLAPPED    lpOverlapped)
+{
+    COMSTAT comStat;
+    if (!ClearCommError(hFile, NULL, &comStat)){
+        logMessage("ClearCommError() failed");
+        return FALSE;
+    }
+    if (comStat.cbInQue == 0) {
+        *lpNumberOfBytesRead = 0;
+        return FALSE;
+    }
+    return ReadFile(hFile,
+                    lpBuffer,
+                    qMin(comStat.cbInQue, nNumberOfBytesToRead),
+                    lpNumberOfBytesRead,
+                    lpOverlapped);
+}
+#endif
+
+namespace trk {
+
+///////////////////////////////////////////////////////////////////////
+//
+// TrkMessage
+//
+///////////////////////////////////////////////////////////////////////
+
+/* A message to be send to TRK, triggering a callback on receipt
+ * of the answer. */
+struct TrkMessage
+{
+    typedef TrkFunctor1<const TrkResult &> Callback;
+
+    explicit TrkMessage(byte code = 0u, byte token = 0u,
+                        Callback callback = Callback());
+
+    byte code;
+    byte token;
+    QByteArray data;
+    QVariant cookie;
+    Callback callback;
+    bool invokeOnNAK;
+};
+
+TrkMessage::TrkMessage(byte c, byte t, Callback cb) :
+    code(c),
+    token(t),
+    callback(cb),
+    invokeOnNAK(false)
+{
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// TrkWriteQueue
+//
+///////////////////////////////////////////////////////////////////////
+
+/* Mixin class that manages a write queue of Trk messages. */
+class TrkWriteQueue
+{
+public:
+    typedef TrkDevice::Callback Callback;   
+
+    TrkWriteQueue();
+
+    // Enqueue messages.
+    void queueTrkMessage(byte code, Callback callback,
+                        const QByteArray &data, const QVariant &cookie,
+                        bool invokeOnNAK);
+    void queueTrkInitialPing();
+
+    // Call this from the device read notification with the results.
+    void slotHandleResult(const TrkResult &result);
+
+    // This can be called periodically in a timer to retrieve
+    // the pending messages to be sent.
+    bool pendingMessage(TrkMessage *message);
+    // Notify the queue about the success of the write operation
+    // after taking the pendingMessage off.
+    void notifyWriteResult(bool ok);
+
+private:
+    typedef QMap<byte, TrkMessage> TokenMessageMap;
+
+    byte nextTrkWriteToken();
+
+    byte trkWriteToken;
+    QQueue<TrkMessage> trkWriteQueue;
+    TokenMessageMap writtenTrkMessages;
+    bool trkWriteBusy;
+};
+
+TrkWriteQueue::TrkWriteQueue() :
+    trkWriteToken(0),
+    trkWriteBusy(false)
+{
+}
+
+byte TrkWriteQueue::nextTrkWriteToken()
+{
+    ++trkWriteToken;
+    if (trkWriteToken == 0)
+        ++trkWriteToken;
+    return trkWriteToken;
+}
+
+void TrkWriteQueue::queueTrkMessage(byte code, Callback callback,
+    const QByteArray &data, const QVariant &cookie, bool invokeOnNAK)
+{
+    const byte token = code == TRK_WRITE_QUEUE_NOOP_CODE ?
+                                byte(0) : nextTrkWriteToken();
+    TrkMessage msg(code, token, callback);
+    msg.data = data;
+    msg.cookie = cookie;
+    msg.invokeOnNAK = invokeOnNAK;
+    trkWriteQueue.append(msg);
+}
+
+bool TrkWriteQueue::pendingMessage(TrkMessage *message)
+{
+    // Invoked from timer, try to flush out message queue
+    if (trkWriteBusy || trkWriteQueue.isEmpty())
+        return false;
+    // Handle the noop message, just invoke CB
+    if (trkWriteQueue.front().code == TRK_WRITE_QUEUE_NOOP_CODE) {
+        TrkMessage noopMessage = trkWriteQueue.dequeue();
+        if (noopMessage.callback) {
+            TrkResult result;
+            result.code = noopMessage.code;
+            result.token = noopMessage.token;
+            result.data = noopMessage.data;
+            result.cookie = noopMessage.cookie;
+            noopMessage.callback(result);
+        }
+    }
+    // Check again for real messages
+    if (trkWriteQueue.isEmpty())
+        return false;
+    if (message)
+        *message = trkWriteQueue.front();
+    return true;
+}
+
+void TrkWriteQueue::notifyWriteResult(bool ok)
+{
+    // On success, dequeue message and await result
+    if (ok) {        
+        TrkMessage firstMsg = trkWriteQueue.dequeue();
+        writtenTrkMessages.insert(firstMsg.token, firstMsg);
+        trkWriteBusy = true;
+    }
+}
+
+void TrkWriteQueue::slotHandleResult(const TrkResult &result)
+{
+    trkWriteBusy = false;
+    if (result.code != TrkNotifyAck && result.code != TrkNotifyNak)
+        return;
+    // Find which request the message belongs to and invoke callback
+    // if ACK or on NAK if desired.
+    const TokenMessageMap::iterator it = writtenTrkMessages.find(result.token);
+    if (it == writtenTrkMessages.end())
+        return;
+    const bool invokeCB = it.value().callback
+                          && (result.code == TrkNotifyAck || it.value().invokeOnNAK);
+
+    if (invokeCB) {
+        TrkResult result1 = result;
+        result1.cookie = it.value().cookie;
+        it.value().callback(result1);
+    }
+    writtenTrkMessages.erase(it);
+}
+
+void TrkWriteQueue::queueTrkInitialPing()
+{
+    // Ping, reset sequence count
+    trkWriteQueue.append(TrkMessage(0, 0));
+}
+
+struct TrkDevicePrivate {
+    TrkDevicePrivate();
+#ifdef Q_OS_WIN
+    HANDLE hdevice;
+#else
+    QFile file;
+#endif
+
+    QByteArray trkReadBuffer;
+    bool trkWriteBusy;
+    int timerId;
+    bool serialFrame;
+    bool verbose;
+    QString errorString;
+};
+
+///////////////////////////////////////////////////////////////////////
+//
+// TrkDevice
+//
+///////////////////////////////////////////////////////////////////////
+
+TrkDevicePrivate::TrkDevicePrivate() :
+#ifdef Q_OS_WIN
+    hdevice(INVALID_HANDLE_VALUE),
+#endif
+    trkWriteBusy(false),
+    timerId(-1),
+    serialFrame(true),
+    verbose(false)
+{
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// TrkDevice
+//
+///////////////////////////////////////////////////////////////////////
+
+TrkDevice::TrkDevice(QObject *parent) :
+    QObject(parent),
+    d(new TrkDevicePrivate),
+    qd(new TrkWriteQueue)
+{
+    connect(this, SIGNAL(messageReceived(trk::TrkResult)),
+        this, SLOT(slotHandleResult(trk::TrkResult)));
+}
+
+bool TrkDevice::open(const QString &port, QString *errorMessage)
+{
+    close();
+#ifdef Q_OS_WIN
+    d->hdevice = CreateFile(port.toStdWString().c_str(),
+                           GENERIC_READ | GENERIC_WRITE,
+                           0,
+                           NULL,
+                           OPEN_EXISTING,
+                           FILE_ATTRIBUTE_NORMAL,
+                           NULL);
+
+    if (INVALID_HANDLE_VALUE == d->hdevice) {
+        *errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port, winErrorMessage(GetLastError()));
+        return false;
+    }
+    d->timerId = startTimer(TimerInterval);
+    return true;
+#else
+    d->file.setFileName(port);
+    if (!d->file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) {
+        *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(port, d->file.errorString());
+        return false;
+    }
+
+    struct termios termInfo;
+    if (tcgetattr(d->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->file.handle(), TCSAFLUSH, &termInfo) < 0) {
+        *errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno)));
+        return false;
+    }
+    d->timerId = startTimer(TimerInterval);
+    return true;
+#endif
+}
+
+
+TrkDevice::~TrkDevice()
+{
+    close();
+    delete d;
+    delete qd;
+}
+
+void TrkDevice::close()
+{
+    if (!isOpen())
+        return;
+    if (d->timerId != -1) {
+        killTimer(d->timerId);
+        d->timerId = -1;
+    }
+#ifdef Q_OS_WIN
+    CloseHandle(d->hdevice);
+    d->hdevice = INVALID_HANDLE_VALUE;
+#else
+    d->file.close();
+#endif
+    if (verbose())
+        logMessage("Close");
+}
+
+bool TrkDevice::isOpen() const
+{
+#ifdef Q_OS_WIN
+    return d->hdevice != INVALID_HANDLE_VALUE;
+#else
+    return d->file.isOpen();
+#endif
+}
+
+QString TrkDevice::errorString() const
+{
+    return d->errorString;
+}
+
+bool TrkDevice::serialFrame() const
+{
+    return d->serialFrame;
+}
+
+void TrkDevice::setSerialFrame(bool f)
+{
+    d->serialFrame = f;
+}
+
+bool TrkDevice::verbose() const
+{
+    return true || d->verbose;
+}
+
+void TrkDevice::setVerbose(bool b)
+{
+    d->verbose = b;
+}
+
+bool TrkDevice::write(const QByteArray &data, QString *errorMessage)
+{
+#ifdef Q_OS_WIN
+    DWORD charsWritten;
+    if (!WriteFile(d->hdevice, data.data(), data.size(), &charsWritten, NULL)) {
+        *errorMessage = QString::fromLatin1("Error writing data: %1").arg(winErrorMessage(GetLastError()));
+        return false;
+    }
+    FlushFileBuffers(d->hdevice);
+    return true;
+#else
+    if (d->file.write(data) == -1 || !d->file.flush()) {
+        *errorMessage = QString::fromLatin1("Cannot write: %1").arg(d->file.errorString());
+        return false;
+    }
+    return  true;
+#endif
+}
+
+#ifndef Q_OS_WIN
+static inline int bytesAvailable(int fileNo)
+{
+    int numBytes;
+    const int rc = ioctl(fileNo, FIONREAD, &numBytes);
+    if (rc < 0)
+        numBytes=0;
+    return numBytes;
+}
+#endif
+
+void TrkDevice::tryTrkRead()
+{
+#ifdef Q_OS_WIN
+    const DWORD BUFFERSIZE = 1024;
+    char buffer[BUFFERSIZE];
+    DWORD charsRead;
+    DWORD totalCharsRead = 0;
+
+    while (TryReadFile(d->hdevice, buffer, BUFFERSIZE, &charsRead, NULL)) {
+        totalCharsRead += charsRead;
+        d->trkReadBuffer.append(buffer, charsRead);
+        if (isValidTrkResult(d->trkReadBuffer, d->serialFrame))
+            break;
+    }
+    if (verbose() && totalCharsRead)
+        logMessage("Read" + d->trkReadBuffer.toHex());
+    if (!totalCharsRead)
+        return;
+    const ushort len = isValidTrkResult(d->trkReadBuffer, d->serialFrame);
+    if (!len) {
+        const QString msg = QString::fromLatin1("Partial message: %1").arg(stringFromArray(d->trkReadBuffer));
+        emitError(msg);
+        return;
+    }
+#else
+    const int size = bytesAvailable(d->file.handle());
+    if (!size)
+        return;
+    const QByteArray data = d->file.read(size);
+    if (verbose())
+        logMessage("trk: <- " + stringFromArray(data));
+    d->trkReadBuffer.append(data);
+    const ushort len = isValidTrkResult(d->trkReadBuffer, d->serialFrame);
+    if (!len) {
+        if (d->trkReadBuffer.size() > 10) {
+            const QString msg = QString::fromLatin1("Unable to extract message from '%1' '%2'").
+                             arg(QLatin1String(d->trkReadBuffer.toHex())).arg(QString::fromAscii(d->trkReadBuffer));
+            emitError(msg);
+        }
+        return;
+    }
+#endif // Q_OS_WIN
+    TrkResult r;
+    QByteArray rawData;
+    while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) {
+        //if (verbose())
+        //    logMessage("Read TrkResult " + r.data.toHex());
+        emit messageReceived(r);
+        if (!rawData.isEmpty())
+            emit rawDataReceived(rawData);
+    }
+}
+
+void TrkDevice::timerEvent(QTimerEvent *)
+{
+    tryTrkWrite();
+    tryTrkRead();
+}
+
+void TrkDevice::emitError(const QString &s)
+{
+    d->errorString = s;
+    qWarning("%s\n", qPrintable(s));
+    emit error(s);
+}
+
+void TrkDevice::sendTrkMessage(byte code, Callback callback,
+     const QByteArray &data, const QVariant &cookie, bool invokeOnNAK)
+{
+    qd->queueTrkMessage(code, callback, data, cookie, invokeOnNAK);
+}
+
+void TrkDevice::sendTrkInitialPing()
+{
+    qd->queueTrkInitialPing();
+}
+
+bool TrkDevice::sendTrkAck(byte token)
+{
+    // The acknowledgement must not be queued!
+    TrkMessage msg(0x80, token);
+    msg.token = token;
+    msg.data.append('\0');
+    return trkWriteRawMessage(msg);
+    // 01 90 00 07 7e 80 01 00 7d 5e 7e
+}
+
+void TrkDevice::tryTrkWrite()
+{
+    TrkMessage message;
+    if (!qd->pendingMessage(&message))
+        return;
+    const bool success = trkWriteRawMessage(message);
+    qd->notifyWriteResult(success);
+}
+
+bool TrkDevice::trkWriteRawMessage(const TrkMessage &msg)
+{
+    const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, serialFrame());
+    if (verbose())
+         logMessage("trk: -> " + stringFromArray(ba));
+    QString errorMessage;
+    const bool rc = write(ba, &errorMessage);
+    if (!rc)
+        emitError(errorMessage);
+    return rc;
+}
+
+void TrkDevice::slotHandleResult(const TrkResult &result)
+{
+    qd->slotHandleResult(result);
+}
+
+} // namespace trk
+
diff --git a/tests/manual/trk/trkdevicex.h b/tests/manual/trk/trkdevicex.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d0e9da0dcc62c0cf9bc925f26f194c645d8e7fe
--- /dev/null
+++ b/tests/manual/trk/trkdevicex.h
@@ -0,0 +1,132 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef TRKDEVICE_H
+#define TRKDEVICE_H
+
+#include "trkfunctor.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtCore/QByteArray>
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+QT_END_NAMESPACE
+
+namespace trk {
+
+struct TrkResult;
+struct TrkMessage;
+struct TrkDevicePrivate;
+class TrkWriteQueue;
+struct TrkWriteQueueIODevicePrivate;
+
+/* 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 <length>" frames, which is currently the case for serial ports. 
+ * Contains 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 };
+
+class 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;
+    void close();
+
+    QString errorString() const;
+
+    bool serialFrame() const;
+    void setSerialFrame(bool f);
+
+    bool verbose() const;
+    void setVerbose(bool b);
+
+    bool write(const QByteArray &data, QString *errorMessage);
+
+    // Construct as 'TrkWriteQueueDevice::Callback(instance, &Klass::method);'
+    typedef TrkFunctor1<const TrkResult &> Callback;
+
+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);
+    
+protected:
+    void emitError(const QString &msg);
+    virtual void timerEvent(QTimerEvent *ev);
+
+public:
+    void tryTrkRead();
+
+    // Enqueue a message with a notification callback.
+    void sendTrkMessage(unsigned char code,
+                        Callback callBack = Callback(),
+                        const QByteArray &data = QByteArray(),
+                        const QVariant &cookie = QVariant(),
+                        // Invoke callback on receiving NAK, too.
+                        bool invokeOnNAK = false);
+
+    // Enqeue an initial ping
+    void sendTrkInitialPing();
+
+    // Send an Ack synchronously, bypassing the queue
+    bool sendTrkAck(unsigned char token);
+
+private slots:
+    void slotHandleResult(const trk::TrkResult &);
+
+private:
+    void tryTrkWrite();
+    bool trkWriteRawMessage(const TrkMessage &msg);
+
+    TrkDevicePrivate *d;
+    TrkWriteQueue *qd;
+};
+
+} // namespace trk
+
+#endif // TRKDEVICE_H