Added some support for QML debugging over USB. Fixed some issues with -qmljsdebugger option.

Not fully working over USB yet, there are some handshaking issues that need to be addressed. WLAN might be improved due to the -qmljsdebugger fixes, but not tested.
This commit is contained in:
Tom Sutcliffe
2011-02-23 12:10:51 +01:00
committed by Kai Koehne
parent ed79c97d83
commit 48fef07a08
4 changed files with 163 additions and 11 deletions

View File

@@ -45,12 +45,14 @@
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h> #include <QtCore/qstringlist.h>
#include <symbiandevicemanager.h>
namespace QmlJsDebugClient { namespace QmlJsDebugClient {
const int protocolVersion = 1; const int protocolVersion = 1;
const QString serverId = QLatin1String("QDeclarativeDebugServer"); const QString serverId = QLatin1String("QDeclarativeDebugServer");
const QString clientId = QLatin1String("QDeclarativeDebugClient"); const QString clientId = QLatin1String("QDeclarativeDebugClient");
static const uchar KQmlOstProtocolId = 0x94;
class QDeclarativeDebugClientPrivate class QDeclarativeDebugClientPrivate
{ {
@@ -69,20 +71,23 @@ public:
QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c); QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c);
QDeclarativeDebugConnection *q; QDeclarativeDebugConnection *q;
QPacketProtocol *protocol; QPacketProtocol *protocol;
QIODevice *device; // Currently either a QTcpSocket or a SymbianUtils::OstChannel
bool gotHello; bool gotHello;
QStringList serverPlugins; QStringList serverPlugins;
QHash<QString, QDeclarativeDebugClient *> plugins; QHash<QString, QDeclarativeDebugClient *> plugins;
void advertisePlugins(); void advertisePlugins();
void connectDeviceSignals();
public Q_SLOTS: public Q_SLOTS:
void connected(); void connected();
void readyRead(); void readyRead();
void deviceAboutToClose();
}; };
QDeclarativeDebugConnectionPrivate::QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c) QDeclarativeDebugConnectionPrivate::QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c)
: QObject(c), q(c), protocol(0), gotHello(false) : QObject(c), q(c), protocol(0), gotHello(false), device(0)
{ {
protocol = new QPacketProtocol(q, this); protocol = new QPacketProtocol(q, this);
QObject::connect(c, SIGNAL(connected()), this, SLOT(connected())); QObject::connect(c, SIGNAL(connected()), this, SLOT(connected()));
@@ -190,8 +195,15 @@ void QDeclarativeDebugConnectionPrivate::readyRead()
} }
} }
void QDeclarativeDebugConnectionPrivate::deviceAboutToClose()
{
// This is nasty syntax but we want to emit our own aboutToClose signal (by calling QIODevice::close())
// without calling the underlying device close fn as that would cause an infinite loop
q->QIODevice::close();
}
QDeclarativeDebugConnection::QDeclarativeDebugConnection(QObject *parent) QDeclarativeDebugConnection::QDeclarativeDebugConnection(QObject *parent)
: QTcpSocket(parent), d(new QDeclarativeDebugConnectionPrivate(this)) : QIODevice(parent), d(new QDeclarativeDebugConnectionPrivate(this))
{ {
} }
@@ -206,9 +218,112 @@ QDeclarativeDebugConnection::~QDeclarativeDebugConnection()
bool QDeclarativeDebugConnection::isConnected() const bool QDeclarativeDebugConnection::isConnected() const
{ {
return state() == ConnectedState; return state() == QAbstractSocket::ConnectedState;
} }
qint64 QDeclarativeDebugConnection::readData(char *data, qint64 maxSize)
{
return d->device->read(data, maxSize);
}
qint64 QDeclarativeDebugConnection::writeData(const char *data, qint64 maxSize)
{
return d->device->write(data, maxSize);
}
qint64 QDeclarativeDebugConnection::bytesAvailable() const
{
return d->device->bytesAvailable();
}
bool QDeclarativeDebugConnection::isSequential() const
{
return true;
}
void QDeclarativeDebugConnection::close()
{
if (isOpen()) {
QIODevice::close();
d->device->close();
emit stateChanged(QAbstractSocket::UnconnectedState);
}
}
// For ease of refactoring we use QAbstractSocket's states even if we're actually using a OstChannel underneath
// since serial ports have a subset of the socket states afaics
QAbstractSocket::SocketState QDeclarativeDebugConnection::state() const
{
QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
if (socket)
return socket->state();
SymbianUtils::OstChannel *ost = qobject_cast<SymbianUtils::OstChannel*>(d->device);
if (ost) {
//TODO we need some handshaking here
/*
if (ost->hasReceivedData())
return QAbstractSocket::ConnectedState;
else if (ost->isOpen())
return QAbstractSocket::ConnectingState;
*/
if (ost->isOpen()) return QAbstractSocket::ConnectedState;
}
return QAbstractSocket::UnconnectedState;
}
void QDeclarativeDebugConnection::flush()
{
QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(d->device);
if (socket) {
socket->flush();
return;
}
SymbianUtils::OstChannel *ost = qobject_cast<SymbianUtils::OstChannel*>(d->device);
if (ost) {
ost->flush();
return;
}
}
void QDeclarativeDebugConnection::connectToHost(const QString &hostName, quint16 port)
{
QTcpSocket *socket = new QTcpSocket(d);
d->device = socket;
d->connectDeviceSignals();
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)));
connect(socket, SIGNAL(connected()), this, SIGNAL(connected()));
socket->connectToHost(hostName, port);
QIODevice::open(ReadWrite | Unbuffered);
}
void QDeclarativeDebugConnection::connectToOst(const QString &port)
{
SymbianUtils::OstChannel *ost = SymbianUtils::SymbianDeviceManager::instance()->getOstChannel(port, KQmlOstProtocolId);
if (ost) {
ost->setParent(d);
d->device = ost;
d->connectDeviceSignals();
QIODevice::open(ReadWrite | Unbuffered);
emit stateChanged(QAbstractSocket::ConnectedState);
emit connected();
} else {
emit error(QAbstractSocket::HostNotFoundError);
}
}
void QDeclarativeDebugConnectionPrivate::connectDeviceSignals()
{
connect(device, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
connect(device, SIGNAL(readyRead()), q, SIGNAL(readyRead()));
connect(device, SIGNAL(aboutToClose()), this, SLOT(deviceAboutToClose()));
}
//
QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate() QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate()
: connection(0) : connection(0)
{ {

View File

@@ -49,7 +49,7 @@ QT_BEGIN_HEADER
namespace QmlJsDebugClient { namespace QmlJsDebugClient {
class QDeclarativeDebugConnectionPrivate; class QDeclarativeDebugConnectionPrivate;
class QDeclarativeDebugConnection : public QTcpSocket class QDeclarativeDebugConnection : public QIODevice
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(QDeclarativeDebugConnection) Q_DISABLE_COPY(QDeclarativeDebugConnection)
@@ -57,7 +57,25 @@ public:
QDeclarativeDebugConnection(QObject * = 0); QDeclarativeDebugConnection(QObject * = 0);
~QDeclarativeDebugConnection(); ~QDeclarativeDebugConnection();
void connectToHost(const QString &hostName, quint16 port);
void connectToOst(const QString &port);
qint64 bytesAvailable() const;
bool isConnected() const; bool isConnected() const;
QAbstractSocket::SocketState state() const;
void flush();
bool isSequential() const;
void close();
signals:
void connected();
void stateChanged(QAbstractSocket::SocketState socketState);
void error(QAbstractSocket::SocketError socketError);
private:
qint64 readData(char *data, qint64 maxSize);
qint64 writeData(const char *data, qint64 maxSize);
private: private:
QDeclarativeDebugConnectionPrivate *d; QDeclarativeDebugConnectionPrivate *d;
friend class QDeclarativeDebugClient; friend class QDeclarativeDebugClient;

View File

@@ -100,7 +100,7 @@ void QmlAdapter::closeConnection()
d->m_connectionTimer.stop(); d->m_connectionTimer.stop();
} else { } else {
if (d->m_conn) { if (d->m_conn) {
d->m_conn->disconnectFromHost(); d->m_conn->close();
} }
} }
} }
@@ -127,11 +127,23 @@ void QmlAdapter::connectToViewer()
|| (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState)) || (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
return; return;
QString address = d->m_engine.data()->startParameters().qmlServerAddress; const DebuggerStartParameters &parameters = d->m_engine.data()->startParameters();
quint16 port = d->m_engine.data()->startParameters().qmlServerPort; if (parameters.communicationChannel == DebuggerStartParameters::CommunicationChannelUsb) {
showConnectionStatusMessage( if (parameters.debugClient == DebuggerStartParameters::DebugClientTrk) {
tr("Connect to debug server %1:%2").arg(address).arg(QString::number(port))); d->m_connectionTimer.stop();
d->m_conn->connectToHost(address, port); showConnectionErrorMessage(tr("QML debugging is not supported when using TRK!"));
emit connectionStartupFailed();
return;
}
const QString &port = parameters.remoteChannel;
showConnectionStatusMessage(tr("Connecting to debug server on %1").arg(port));
d->m_conn->connectToOst(port);
} else {
const QString &address = parameters.qmlServerAddress;
quint16 port = parameters.qmlServerPort;
showConnectionStatusMessage(tr("Connecting to debug server %1:%2").arg(address).arg(QString::number(port)));
d->m_conn->connectToHost(address, port);
}
} }
void QmlAdapter::sendMessage(const QByteArray &msg) void QmlAdapter::sendMessage(const QByteArray &msg)
@@ -147,7 +159,7 @@ void QmlAdapter::sendMessage(const QByteArray &msg)
void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError) void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
{ {
showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message") showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
.arg(d->m_conn->error()).arg(d->m_conn->errorString())); .arg(socketError).arg(d->m_conn->errorString()));
// this is only an error if we are already connected and something goes wrong. // this is only an error if we are already connected and something goes wrong.
if (isConnected()) if (isConnected())

View File

@@ -465,6 +465,13 @@ static Debugger::DebuggerStartParameters s60DebuggerStartParams(const S60DeviceR
sp.serverAddress = activeDeployConf->deviceAddress(); sp.serverAddress = activeDeployConf->deviceAddress();
sp.serverPort = activeDeployConf->devicePort().toInt(); sp.serverPort = activeDeployConf->devicePort().toInt();
sp.displayName = rc->displayName(); sp.displayName = rc->displayName();
sp.qmlServerPort = rc->qmlDebugServerPort();
// TODO - is this the correct place to put this?
if (rc->useQmlDebugger()) {
if (sp.processArgs.length())
sp.processArgs.prepend(" ");
sp.processArgs.prepend(QString("-qmljsdebugger=port:%1").arg(sp.qmlServerPort));
}
sp.communicationChannel = activeDeployConf->communicationChannel() == S60DeployConfiguration::CommunicationCodaTcpConnection? sp.communicationChannel = activeDeployConf->communicationChannel() == S60DeployConfiguration::CommunicationCodaTcpConnection?
Debugger::DebuggerStartParameters::CommunicationChannelTcpIp: Debugger::DebuggerStartParameters::CommunicationChannelTcpIp: