forked from qt-creator/qt-creator
Trk: Add device class.
This commit is contained in:
@@ -1059,7 +1059,7 @@ void Adapter::tryTrkRead()
|
||||
while (TryReadFile(m_winComDevice, buffer, BUFFERSIZE, &charsRead, NULL)) {
|
||||
m_trkReadQueue.append(buffer, charsRead);
|
||||
totalCharsRead += charsRead;
|
||||
if (isValidTrkResult(m_trkReadQueue))
|
||||
if (isValidTrkResult(m_trkReadQueue, m_serialFrame))
|
||||
break;
|
||||
}
|
||||
if (!totalCharsRead)
|
||||
@@ -1074,8 +1074,9 @@ void Adapter::tryTrkRead()
|
||||
return;
|
||||
}
|
||||
|
||||
while (!m_trkReadQueue.isEmpty())
|
||||
handleResult(extractResult(&m_trkReadQueue, m_serialFrame));
|
||||
TrkResult r;
|
||||
while (extractResult(&m_trkReadQueue, m_serialFrame, &r))
|
||||
handleResult(r);
|
||||
|
||||
m_trkWriteBusy = false;
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "launcher.h"
|
||||
#include "trkutils.h"
|
||||
#include "trkdevice.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QDateTime>
|
||||
@@ -37,60 +38,6 @@
|
||||
#include <QtCore/QQueue>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <stdio.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <termios.h>
|
||||
# include <errno.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#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)){
|
||||
qDebug() << "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 {
|
||||
|
||||
struct TrkMessage {
|
||||
@@ -104,12 +51,7 @@ struct TrkMessage {
|
||||
|
||||
struct LauncherPrivate {
|
||||
LauncherPrivate();
|
||||
#ifdef Q_OS_WIN
|
||||
HANDLE m_hdevice;
|
||||
#else
|
||||
QFile m_file;
|
||||
#endif
|
||||
|
||||
TrkDevice m_device;
|
||||
QString m_trkServerName;
|
||||
QByteArray m_trkReadBuffer;
|
||||
|
||||
@@ -128,18 +70,13 @@ struct LauncherPrivate {
|
||||
QString m_copySrcFileName;
|
||||
QString m_copyDstFileName;
|
||||
QString m_installFileName;
|
||||
bool m_serialFrame;
|
||||
int m_verbose;
|
||||
};
|
||||
|
||||
LauncherPrivate::LauncherPrivate() :
|
||||
#ifdef Q_OS_WIN
|
||||
m_hdevice(0),
|
||||
#endif
|
||||
m_trkWriteToken(0),
|
||||
m_trkWriteBusy(false),
|
||||
m_timerId(-1),
|
||||
m_serialFrame(true),
|
||||
m_verbose(0)
|
||||
{
|
||||
}
|
||||
@@ -149,6 +86,7 @@ LauncherPrivate::LauncherPrivate() :
|
||||
Launcher::Launcher() :
|
||||
d(new LauncherPrivate)
|
||||
{
|
||||
connect(&d->m_device, SIGNAL(messageReceived(TrkResult)), this, SLOT(handleResult(TrkResult)));
|
||||
}
|
||||
|
||||
Launcher::~Launcher()
|
||||
@@ -180,7 +118,12 @@ void Launcher::setInstallFileName(const QString &name)
|
||||
|
||||
void Launcher::setSerialFrame(bool b)
|
||||
{
|
||||
d->m_serialFrame = b;
|
||||
d->m_device.setSerialFrame(b);
|
||||
}
|
||||
|
||||
bool Launcher::serialFrame() const
|
||||
{
|
||||
return d->m_device.serialFrame();
|
||||
}
|
||||
|
||||
bool Launcher::startServer(QString *errorMessage)
|
||||
@@ -190,7 +133,7 @@ bool Launcher::startServer(QString *errorMessage)
|
||||
.arg(d->m_trkServerName, d->m_fileName, d->m_copySrcFileName, d->m_copyDstFileName, d->m_installFileName);
|
||||
logMessage(msg);
|
||||
}
|
||||
if (!openTrkPort(d->m_trkServerName, errorMessage))
|
||||
if (!d->m_device.open(d->m_trkServerName, errorMessage))
|
||||
return false;
|
||||
d->m_timerId = startTimer(100);
|
||||
sendTrkInitialPing();
|
||||
@@ -210,6 +153,7 @@ bool Launcher::startServer(QString *errorMessage)
|
||||
void Launcher::setVerbose(int v)
|
||||
{
|
||||
d->m_verbose = v;
|
||||
d->m_device.setVerbose(v > 1);
|
||||
}
|
||||
|
||||
void Launcher::installAndRun()
|
||||
@@ -226,60 +170,11 @@ void Launcher::logMessage(const QString &msg)
|
||||
qDebug() << "ADAPTER: " << qPrintable(msg);
|
||||
}
|
||||
|
||||
bool Launcher::openTrkPort(const QString &port, QString *errorMessage)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
d->m_hdevice = CreateFile(port.toStdWString().c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == d->m_hdevice){
|
||||
*errorMessage = QString::fromLatin1("Could not open device '%1': %2").arg(port, winErrorMessage(GetLastError()));
|
||||
logMessage(*errorMessage);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
d->m_file.setFileName(port);
|
||||
if (!d->m_file.open(QIODevice::ReadWrite|QIODevice::Unbuffered)) {
|
||||
*errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(port, d->m_file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct termios termInfo;
|
||||
if (tcgetattr(d->m_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->m_file.handle(), TCSAFLUSH, &termInfo) < 0) {
|
||||
*errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Launcher::timerEvent(QTimerEvent *)
|
||||
{
|
||||
if (d->m_verbose>1)
|
||||
qDebug(".");
|
||||
tryTrkWrite();
|
||||
tryTrkRead();
|
||||
}
|
||||
|
||||
byte Launcher::nextTrkWriteToken()
|
||||
@@ -333,7 +228,7 @@ void Launcher::sendTrkAck(byte token)
|
||||
msg.data.append('\0');
|
||||
// The acknowledgement must not be queued!
|
||||
//queueMessage(msg);
|
||||
trkWrite(msg);
|
||||
trkWriteRawMessage(msg);
|
||||
// 01 90 00 07 7e 80 01 00 7d 5e 7e
|
||||
}
|
||||
|
||||
@@ -353,80 +248,25 @@ void Launcher::tryTrkWrite()
|
||||
trkWrite(msg);
|
||||
}
|
||||
|
||||
void Launcher::trkWriteRawMessage(const TrkMessage &msg)
|
||||
{
|
||||
const QByteArray ba = frameMessage(msg.code, msg.token, msg.data, serialFrame());
|
||||
logMessage("WRITE: " + stringFromArray(ba));
|
||||
QString errorMessage;
|
||||
if (!d->m_device.write(ba, &errorMessage))
|
||||
logMessage(errorMessage);
|
||||
}
|
||||
|
||||
void Launcher::trkWrite(const TrkMessage &msg)
|
||||
{
|
||||
QByteArray ba = frameMessage(msg.code, msg.token, msg.data, d->m_serialFrame);
|
||||
|
||||
d->m_writtenTrkMessages.insert(msg.token, msg);
|
||||
d->m_trkWriteBusy = true;
|
||||
|
||||
logMessage("WRITE: " + stringFromArray(ba));
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
DWORD charsWritten;
|
||||
if (!WriteFile(d->m_hdevice, ba.data(), ba.size(), &charsWritten, NULL))
|
||||
logMessage("WRITE ERROR: ");
|
||||
|
||||
//logMessage("WRITE: " + stringFromArray(ba));
|
||||
FlushFileBuffers(d->m_hdevice);
|
||||
#else
|
||||
if (d->m_file.write(ba) == -1 || !d->m_file.flush())
|
||||
logMessage(QString::fromLatin1("Cannot write: %1").arg(d->m_file.errorString()));
|
||||
#endif
|
||||
trkWriteRawMessage(msg);
|
||||
}
|
||||
|
||||
#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 Launcher::tryTrkRead()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
const DWORD BUFFERSIZE = 1024;
|
||||
char buffer[BUFFERSIZE];
|
||||
DWORD charsRead;
|
||||
|
||||
while (TryReadFile(d->m_hdevice, buffer, BUFFERSIZE, &charsRead, NULL)) {
|
||||
d->m_trkReadQueue.append(buffer, charsRead);
|
||||
if (isValidTrkResult(d->m_trkReadQueue, d->m_serialFrame))
|
||||
break;
|
||||
}
|
||||
const ushort len = isValidTrkResult(d->m_trkReadQueue, d->m_serialFrame);
|
||||
if (!len) {
|
||||
logMessage("Partial message: " + stringFromArray(d->m_trkReadQueue));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
const int size = bytesAvailable(d->m_file.handle());
|
||||
if (!size)
|
||||
return;
|
||||
const QByteArray data = d->m_file.read(size);
|
||||
d->m_trkReadQueue.append(data);
|
||||
const ushort len = isValidTrkResult(d->m_trkReadQueue, d->m_serialFrame);
|
||||
if (!len) {
|
||||
if (d->m_trkReadQueue.size() > 10) {
|
||||
logMessage(QString::fromLatin1("Unable to extract message from '%1' '%2'").
|
||||
arg(QLatin1String(d->m_trkReadQueue.toHex())).arg(QString::fromAscii(d->m_trkReadQueue)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
logMessage(QString::fromLatin1("READ: %1 bytes %2").arg(len).arg(stringFromArray(d->m_trkReadQueue)));
|
||||
handleResult(extractResult(&d->m_trkReadQueue, d->m_serialFrame));
|
||||
|
||||
d->m_trkWriteBusy = false;
|
||||
}
|
||||
|
||||
|
||||
void Launcher::handleResult(const TrkResult &result)
|
||||
{
|
||||
d->m_trkWriteBusy = false;
|
||||
QByteArray prefix = "READ BUF: ";
|
||||
QByteArray str = result.toString().toUtf8();
|
||||
if (result.isDebugOutput) { // handle application output
|
||||
@@ -518,10 +358,13 @@ void Launcher::handleResult(const TrkResult &result)
|
||||
break;
|
||||
}
|
||||
case TrkNotifyDeleted: { // NotifyDeleted
|
||||
logMessage(prefix + "NOTE: LIBRARY UNLOAD: " + str);
|
||||
const ushort itemType = (unsigned char)result.data.at(1);
|
||||
const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0);
|
||||
const QString name = len ? QString::fromAscii(result.data.mid(13, len)) : QString();
|
||||
logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
|
||||
arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
|
||||
arg(name));
|
||||
sendTrkAck(result.token);
|
||||
const char *data = result.data.data();
|
||||
ushort itemType = extractShort(data);
|
||||
if (itemType == 0) { // process
|
||||
sendTrkMessage(TrkDisconnect, CB(waitForTrkFinished));
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@ public:
|
||||
bool startServer(QString *errorMessage);
|
||||
void setVerbose(int v);
|
||||
void setSerialFrame(bool b);
|
||||
bool serialFrame() const;
|
||||
|
||||
signals:
|
||||
void copyingStarted();
|
||||
@@ -65,8 +66,10 @@ signals:
|
||||
public slots:
|
||||
void terminate();
|
||||
|
||||
private slots:
|
||||
void handleResult(const TrkResult &data);
|
||||
|
||||
private:
|
||||
bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server
|
||||
void sendTrkMessage(unsigned char code,
|
||||
TrkCallBack callBack = 0,
|
||||
const QByteArray &data = QByteArray(),
|
||||
@@ -77,6 +80,7 @@ private:
|
||||
void tryTrkRead();
|
||||
// actually writes a message to the device
|
||||
void trkWrite(const TrkMessage &msg);
|
||||
void trkWriteRawMessage(const TrkMessage &msg);
|
||||
// convienience messages
|
||||
void sendTrkInitialPing();
|
||||
void sendTrkAck(unsigned char token);
|
||||
@@ -99,8 +103,6 @@ private:
|
||||
void waitForTrkFinished(const TrkResult &data);
|
||||
|
||||
void handleAndReportCreateProcess(const TrkResult &result);
|
||||
void handleResult(const TrkResult &data);
|
||||
|
||||
void copyFileToRemote();
|
||||
void installRemotePackageSilently(const QString &filename);
|
||||
void installAndRun();
|
||||
|
323
tests/manual/trk/trkdevice.cpp
Normal file
323
tests/manual/trk/trkdevice.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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 "trkdevice.h"
|
||||
#include "trkutils.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#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)){
|
||||
qDebug() << "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 {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
TrkDevicePrivate::TrkDevicePrivate() :
|
||||
#ifdef Q_OS_WIN
|
||||
hdevice(INVALID_HANDLE_VALUE),
|
||||
#endif
|
||||
trkWriteBusy(false),
|
||||
timerId(-1),
|
||||
serialFrame(true),
|
||||
verbose(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TrkDevice::TrkDevice(QObject *parent) :
|
||||
QObject(parent),
|
||||
d(new TrkDevicePrivate)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void TrkDevice::close()
|
||||
{
|
||||
if (!isOpen())
|
||||
return;
|
||||
if (d->timerId != -1) {
|
||||
killTimer(d->timerId);
|
||||
d->timerId = -1;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
CloseHandle(d->hdevice);
|
||||
#else
|
||||
d->file.close();
|
||||
#endif
|
||||
if (d->verbose)
|
||||
qDebug() << "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 d->verbose;
|
||||
}
|
||||
|
||||
void TrkDevice::setVerbose(bool b)
|
||||
{
|
||||
d->verbose = b;
|
||||
}
|
||||
|
||||
bool TrkDevice::write(const QByteArray &data, QString *errorMessage)
|
||||
{
|
||||
if (d->verbose)
|
||||
qDebug() << ">WRITE" << data.toHex();
|
||||
#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 (d->verbose && totalCharsRead)
|
||||
qDebug() << "Read" << d->trkReadBuffer.toHex();
|
||||
if (!totalCharsRead)
|
||||
return;
|
||||
const ushort len = isValidTrkResult(d->trkReadBuffer, d->serialFrame);
|
||||
if (!len) {
|
||||
d->errorString = QString::fromLatin1("Partial message: %1").arg(stringFromArray(d->trkReadBuffer));
|
||||
qWarning("%s\n", qPrintable(d->errorString));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
const int size = bytesAvailable(d->file.handle());
|
||||
if (!size)
|
||||
return;
|
||||
const QByteArray data = d->file.read(size);
|
||||
d->trkReadBuffer.append(data);
|
||||
const ushort len = isValidTrkResult(d->trkReadBuffer, d->serialFrame);
|
||||
if (!len) {
|
||||
if (d->trkReadBuffer.size() > 10) {
|
||||
d->errorString = QString::fromLatin1("Unable to extract message from '%1' '%2'").
|
||||
arg(QLatin1String(d->trkReadBuffer.toHex())).arg(QString::fromAscii(d->trkReadBuffer));
|
||||
qWarning("%s\n", qPrintable(d->errorString));
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
TrkResult r;
|
||||
while (extractResult(&d->trkReadBuffer, d->serialFrame, &r)) {
|
||||
if (d->verbose)
|
||||
qDebug() << "Read TrkResult " << r.data.toHex();
|
||||
emit messageReceived(r);
|
||||
}
|
||||
}
|
||||
|
||||
void TrkDevice::timerEvent(QTimerEvent *)
|
||||
{
|
||||
tryTrkRead();
|
||||
}
|
||||
|
||||
} // namespace trk
|
84
tests/manual/trk/trkdevice.h
Normal file
84
tests/manual/trk/trkdevice.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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 <QtCore/QObject>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
namespace trk {
|
||||
|
||||
struct TrkResult;
|
||||
struct TrkDevicePrivate;
|
||||
|
||||
/* TrkDevice: Implements a Windows COM or Linux device for
|
||||
* Trk communications. Provides synchronous write and asynchronous
|
||||
* read operation.
|
||||
* The serialFrames property specifies whether packets are encapsulated in
|
||||
* "0x90 <length>" frames, which is currently the case for serial ports. */
|
||||
|
||||
class TrkDevice : public QObject
|
||||
{
|
||||
Q_DISABLE_COPY(TrkDevice)
|
||||
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);
|
||||
|
||||
signals:
|
||||
void messageReceived(const TrkResult&);
|
||||
|
||||
private:
|
||||
void tryTrkRead();
|
||||
virtual void timerEvent(QTimerEvent *ev);
|
||||
|
||||
TrkDevicePrivate *d;
|
||||
};
|
||||
|
||||
} // namespace trk
|
||||
|
||||
#endif // TRKDEVICE_H
|
@@ -1,6 +1,8 @@
|
||||
DEFINES += DEBUG_TRK=0
|
||||
INCLUDEPATH *= $$PWD
|
||||
SOURCES += $$PWD/launcher.cpp \
|
||||
$$PWD/trkutils.cpp
|
||||
$$PWD/trkutils.cpp \
|
||||
$$PWD/trkdevice.cpp
|
||||
HEADERS += $$PWD/trkutils.h \
|
||||
$$PWD/trkdevice.h \
|
||||
$$PWD/launcher.h
|
||||
|
@@ -298,8 +298,11 @@ void TrkServer::readFromAdapter()
|
||||
if (packet != m_adapterReadBuffer)
|
||||
logMessage("buffer: " + stringFromArray(m_adapterReadBuffer));
|
||||
|
||||
while (!m_adapterReadBuffer.isEmpty())
|
||||
handleAdapterMessage(extractResult(&m_adapterReadBuffer, m_serialFrame));
|
||||
while (!m_adapterReadBuffer.isEmpty()) {
|
||||
TrkResult r;
|
||||
while (extractResult(&m_adapterReadBuffer, m_serialFrame, &r))
|
||||
handleAdapterMessage(r);
|
||||
}
|
||||
}
|
||||
|
||||
void TrkServer::writeToAdapter(byte command, byte token, const QByteArray &data)
|
||||
|
@@ -50,6 +50,14 @@ TrkResult::TrkResult() :
|
||||
{
|
||||
}
|
||||
|
||||
void TrkResult::clear()
|
||||
{
|
||||
code = token= 0;
|
||||
isDebugOutput = false;
|
||||
data.clear();
|
||||
cookie = QVariant();
|
||||
}
|
||||
|
||||
QString TrkResult::toString() const
|
||||
{
|
||||
QString res = stringFromByte(code) + "[" + stringFromByte(token);
|
||||
@@ -114,20 +122,20 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame)
|
||||
return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size();
|
||||
}
|
||||
|
||||
TrkResult extractResult(QByteArray *buffer, bool serialFrame)
|
||||
bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result)
|
||||
{
|
||||
TrkResult result;
|
||||
result->clear();
|
||||
const ushort len = isValidTrkResult(*buffer, serialFrame);
|
||||
if (!len)
|
||||
return result;
|
||||
return false;
|
||||
// handle receiving application output, which is not a regular command
|
||||
const int delimiterPos = serialFrame ? 4 : 0;
|
||||
if (buffer->at(delimiterPos) != 0x7e) {
|
||||
result.isDebugOutput = true;
|
||||
result.data = buffer->mid(delimiterPos, len);
|
||||
result.data.replace("\r\n", "\n");
|
||||
result->isDebugOutput = true;
|
||||
result->data = buffer->mid(delimiterPos, len);
|
||||
result->data.replace("\r\n", "\n");
|
||||
*buffer->remove(0, delimiterPos + len);
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
// FIXME: what happens if the length contains 0xfe?
|
||||
// Assume for now that it passes unencoded!
|
||||
@@ -140,14 +148,14 @@ TrkResult extractResult(QByteArray *buffer, bool serialFrame)
|
||||
if (sum != 0xff)
|
||||
logMessage("*** CHECKSUM ERROR: " << byte(sum));
|
||||
|
||||
result.code = data.at(0);
|
||||
result.token = data.at(1);
|
||||
result.data = data.mid(2, data.size() - 3);
|
||||
result->code = data.at(0);
|
||||
result->token = data.at(1);
|
||||
result->data = data.mid(2, data.size() - 3);
|
||||
//logMessage(" REST BUF: " << stringFromArray(*buffer));
|
||||
//logMessage(" CURR DATA: " << stringFromArray(data));
|
||||
//QByteArray prefix = "READ BUF: ";
|
||||
//logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data());
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
ushort extractShort(const char *data)
|
||||
|
@@ -172,6 +172,7 @@ struct Breakpoint
|
||||
struct TrkResult
|
||||
{
|
||||
TrkResult();
|
||||
void clear();
|
||||
QString toString() const;
|
||||
// 0 for no error.
|
||||
int errorCode() const;
|
||||
@@ -187,7 +188,7 @@ struct TrkResult
|
||||
// the serial frame [0x01 0x90 <len>] and 0x7e encoded7d(ba) 0x7e
|
||||
QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame);
|
||||
ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame);
|
||||
TrkResult extractResult(QByteArray *buffer, bool serialFrame);
|
||||
bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r);
|
||||
QByteArray errorMessage(byte code);
|
||||
QByteArray hexNumber(uint n, int digits = 0);
|
||||
uint swapEndian(uint in);
|
||||
|
Reference in New Issue
Block a user