Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline

This commit is contained in:
dt
2009-09-03 17:54:36 +02:00
6 changed files with 893 additions and 154 deletions

View File

@@ -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);
*/
//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)

View File

@@ -7,9 +7,9 @@ win32:CONFIG+=console
HEADERS += \
trkutils.h \
trkdevice.h \
trkdevicex.h \
SOURCES += \
runner.cpp \
trkutils.cpp \
trkdevice.cpp \
trkdevicex.cpp \

View File

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

View File

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

View File

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

View File

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