forked from qt-creator/qt-creator
		
	Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline
This commit is contained in:
		@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,9 @@ win32:CONFIG+=console
 | 
			
		||||
 | 
			
		||||
HEADERS += \
 | 
			
		||||
    trkutils.h \
 | 
			
		||||
    trkdevice.h \
 | 
			
		||||
    trkdevicex.h \
 | 
			
		||||
 | 
			
		||||
SOURCES += \
 | 
			
		||||
    runner.cpp \
 | 
			
		||||
    trkutils.cpp \
 | 
			
		||||
    trkdevice.cpp \
 | 
			
		||||
    trkdevicex.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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										562
									
								
								tests/manual/trk/trkdevicex.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										562
									
								
								tests/manual/trk/trkdevicex.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										132
									
								
								tests/manual/trk/trkdevicex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								tests/manual/trk/trkdevicex.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Reference in New Issue
	
	Block a user