summaryrefslogtreecommitdiff
path: root/tests/manual/trk
diff options
context:
space:
mode:
authorhjk <qtc-committer@nokia.com>2009-09-03 13:32:26 +0200
committerhjk <qtc-committer@nokia.com>2009-09-03 17:24:31 +0200
commit5859b410640391d516cc1dd99032200c8a285ace (patch)
tree583e4853be937fab837c95d057411bb2ef0883ff /tests/manual/trk
parent94348d8ed2f070312f58b85a6211108430b3af0a (diff)
downloadqt-creator-5859b410640391d516cc1dd99032200c8a285ace.tar.gz
debugger: work on trk runner
Diffstat (limited to 'tests/manual/trk')
-rwxr-xr-xtests/manual/trk/runner.cpp303
-rw-r--r--tests/manual/trk/runner.pro4
-rw-r--r--tests/manual/trk/trkdevice.cpp32
-rw-r--r--tests/manual/trk/trkdevice.h14
-rw-r--r--tests/manual/trk/trkdevicex.cpp562
-rw-r--r--tests/manual/trk/trkdevicex.h132
6 files changed, 893 insertions, 154 deletions
diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp
index 45cc4ba9ba..eeb080ca0d 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 0bf878e420..4ced7ccd71 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 6746e5b1f6..b0e5c2f814 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 61b382ad57..7b2a5dbcd3 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 0000000000..31382de3f0
--- /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 0000000000..9d0e9da0dc
--- /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