In progress: making TcfTrkDevice connections persistant

This commit is contained in:
Tom Sutcliffe
2011-02-04 12:08:19 +01:00
committed by Pawel Polanski
parent 813778ac23
commit ca622b32e9
10 changed files with 243 additions and 84 deletions

View File

@@ -43,7 +43,7 @@
#include "qt4symbiantarget.h" #include "qt4symbiantarget.h"
#include "qt4target.h" #include "qt4target.h"
#include "qtoutputformatter.h" #include "qtoutputformatter.h"
#include "virtualserialdevice.h" #include "symbiandevicemanager.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -65,11 +65,10 @@ using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal; using namespace Qt4ProjectManager::Internal;
using namespace Coda; using namespace Coda;
enum { debug = 0 }; enum { debug = 1 };
CodaRunControl::CodaRunControl(RunConfiguration *runConfiguration, const QString &mode) : CodaRunControl::CodaRunControl(RunConfiguration *runConfiguration, const QString &mode) :
S60RunControlBase(runConfiguration, mode), S60RunControlBase(runConfiguration, mode),
m_codaDevice(0),
m_port(0), m_port(0),
m_state(StateUninit) m_state(StateUninit)
{ {
@@ -89,12 +88,6 @@ CodaRunControl::CodaRunControl(RunConfiguration *runConfiguration, const QString
} }
} }
CodaRunControl::~CodaRunControl()
{
if (m_codaDevice)
m_codaDevice->deleteLater();
}
bool CodaRunControl::doStart() bool CodaRunControl::doStart()
{ {
if (m_address.isEmpty() && m_serialPort.isEmpty()) { if (m_address.isEmpty() && m_serialPort.isEmpty()) {
@@ -117,31 +110,32 @@ bool CodaRunControl::setupLauncher()
{ {
QTC_ASSERT(!m_codaDevice, return false); QTC_ASSERT(!m_codaDevice, return false);
m_codaDevice = new CodaDevice;
if (debug)
m_codaDevice->setVerbose(debug);
connect(m_codaDevice, SIGNAL(error(QString)), this, SLOT(slotError(QString)));
connect(m_codaDevice, SIGNAL(logMessage(QString)), this, SLOT(slotTrkLogMessage(QString)));
connect(m_codaDevice, SIGNAL(tcfEvent(Coda::CodaEvent)), this, SLOT(slotCodaEvent(Coda::CodaEvent)));
connect(m_codaDevice, SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString)));
if (m_serialPort.length()) { if (m_serialPort.length()) {
const QSharedPointer<SymbianUtils::VirtualSerialDevice> serialDevice(new SymbianUtils::VirtualSerialDevice(m_serialPort)); // We get the port from SymbianDeviceManager
appendMessage(tr("Conecting to '%2'...").arg(m_serialPort), NormalMessageFormat); appendMessage(tr("Connecting to '%2'...").arg(m_serialPort), NormalMessageFormat);
m_codaDevice->setSerialFrame(true); m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPort);
m_codaDevice->setDevice(serialDevice);
bool ok = serialDevice->open(QIODevice::ReadWrite); bool ok = m_codaDevice && m_tcfTrkDevice->device()->isOpen();
if (!ok) { if (!ok) {
appendMessage(tr("Couldn't open serial device: %1").arg(serialDevice->errorString()), ErrorMessageFormat); appendMessage(tr("Couldn't open serial device: %1").arg(m_tcfTrkDevice->device()->errorString()), ErrorMessageFormat);
return false; return false;
} }
connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)), connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const SymbianUtils::SymbianDevice)),
this, SLOT(deviceRemoved(SymbianUtils::SymbianDevice))); this, SLOT(deviceRemoved(SymbianUtils::SymbianDevice)));
connect(m_tcfTrkDevice.data(), SIGNAL(error(QString)), this, SLOT(slotError(QString)));
connect(m_tcfTrkDevice.data(), SIGNAL(logMessage(QString)), this, SLOT(slotTrkLogMessage(QString)));
connect(m_tcfTrkDevice.data(), SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)), this, SLOT(slotTcftrkEvent(tcftrk::TcfTrkEvent)));
connect(m_tcfTrkDevice.data(), SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString)));
m_state = StateConnecting; m_state = StateConnecting;
m_codaDevice->sendSerialPing(false); m_codaDevice->sendSerialPing(false);
QTimer::singleShot(4000, this, SLOT(checkForTimeout())); QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
} else { } else {
// For TCP we don't use device manager, we just set it up directly
m_codaDevice = QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice);
connect(m_codaDevice.data(), SIGNAL(error(QString)), this, SLOT(slotError(QString)));
connect(m_codaDevice.data(), SIGNAL(logMessage(QString)), this, SLOT(slotTrkLogMessage(QString)));
connect(m_codaDevice.data(), SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)), this, SLOT(slotTcftrkEvent(tcftrk::TcfTrkEvent)));
const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket); const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket);
m_codaDevice->setDevice(codaSocket); m_codaDevice->setDevice(codaSocket);
codaSocket->connectToHost(m_address, m_port); codaSocket->connectToHost(m_address, m_port);
@@ -149,6 +143,7 @@ bool CodaRunControl::setupLauncher()
appendMessage(tr("Connecting to %1:%2...").arg(m_address).arg(m_port), NormalMessageFormat); appendMessage(tr("Connecting to %1:%2...").arg(m_address).arg(m_port), NormalMessageFormat);
QTimer::singleShot(4000, this, SLOT(checkForTimeout())); QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
} }
if (debug) m_tcfTrkDevice->setVerbose(1);
return true; return true;
} }
@@ -325,9 +320,10 @@ void CodaRunControl::handleCreateProcess(const CodaCommandResult &result)
void CodaRunControl::finishRunControl() void CodaRunControl::finishRunControl()
{ {
m_runningProcessId.clear(); m_runningProcessId.clear();
if (m_codaDevice) if (m_codaDevice) {
m_codaDevice->deleteLater(); disconnect(m_codaDevice.data(), 0, this, 0);
m_codaDevice = 0; SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice);
}
m_state = StateUninit; m_state = StateUninit;
emit finished(); emit finished();
} }

View File

@@ -60,7 +60,6 @@ class CodaRunControl : public S60RunControlBase
Q_OBJECT Q_OBJECT
public: public:
CodaRunControl(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode); CodaRunControl(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode);
~CodaRunControl();
virtual bool isRunning() const; virtual bool isRunning() const;
static QMessageBox *createCodaWaitingMessageBox(QWidget *parent = 0); static QMessageBox *createCodaWaitingMessageBox(QWidget *parent = 0);
@@ -104,7 +103,7 @@ private:
StateProcessRunning StateProcessRunning
}; };
Coda::CodaDevice *m_codaDevice; QSharedPointer<Coda::CodaDevice> m_codaDevice;
QString m_address; QString m_address;
unsigned short m_port; unsigned short m_port;

View File

@@ -48,7 +48,6 @@
#include <symbianutils/launcher.h> #include <symbianutils/launcher.h>
#include <symbianutils/symbiandevicemanager.h> #include <symbianutils/symbiandevicemanager.h>
#include <symbianutils/virtualserialdevice.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
@@ -108,7 +107,6 @@ S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc,
m_releaseDeviceAfterLauncherFinish(bs->m_releaseDeviceAfterLauncherFinish), m_releaseDeviceAfterLauncherFinish(bs->m_releaseDeviceAfterLauncherFinish),
m_handleDeviceRemoval(bs->m_handleDeviceRemoval), m_handleDeviceRemoval(bs->m_handleDeviceRemoval),
m_launcher(0), m_launcher(0),
m_trkDevice(0),
m_eventLoop(0), m_eventLoop(0),
m_state(StateUninit), m_state(StateUninit),
m_putWriteOk(false), m_putWriteOk(false),
@@ -127,7 +125,6 @@ S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc):
m_releaseDeviceAfterLauncherFinish(true), m_releaseDeviceAfterLauncherFinish(true),
m_handleDeviceRemoval(true), m_handleDeviceRemoval(true),
m_launcher(0), m_launcher(0),
m_trkDevice(0),
m_eventLoop(0), m_eventLoop(0),
m_state(StateUninit), m_state(StateUninit),
m_putWriteOk(false), m_putWriteOk(false),
@@ -151,7 +148,6 @@ S60DeployStep::~S60DeployStep()
{ {
delete m_timer; delete m_timer;
delete m_launcher; delete m_launcher;
delete m_trkDevice;
delete m_eventLoop; delete m_eventLoop;
} }
@@ -294,8 +290,7 @@ void S60DeployStep::start()
return; return;
} }
if (!trkClient) { if (!trkClient) {
QTC_ASSERT(!m_trkDevice, return); QTC_ASSERT(!m_codaDevice.data(), return);
m_trkDevice = new Coda::CodaDevice;
if (m_address.isEmpty() && !serialConnection) { if (m_address.isEmpty() && !serialConnection) {
errorMessage = tr("No address for a device has been defined. Please define an address and try again."); errorMessage = tr("No address for a device has been defined. Please define an address and try again.");
reportError(errorMessage); reportError(errorMessage);
@@ -320,8 +315,8 @@ void S60DeployStep::stop()
m_launcher->terminate(); m_launcher->terminate();
} else { } else {
if (m_trkDevice) { if (m_trkDevice) {
delete m_trkDevice; disconnect(m_trkDevice.data(), 0, this, 0);
m_trkDevice = 0; SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_trkDevice);
} }
} }
emit finished(false); emit finished(false);
@@ -345,10 +340,10 @@ void S60DeployStep::setupConnections()
connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int))); connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(setCopyProgress(int))); connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(setCopyProgress(int)));
} else { } else {
connect(m_trkDevice, SIGNAL(error(QString)), this, SLOT(slotError(QString))); connect(m_codaDevice.data(), SIGNAL(error(QString)), this, SLOT(slotError(QString)));
connect(m_trkDevice, SIGNAL(logMessage(QString)), this, SLOT(slotTrkLogMessage(QString))); connect(m_codaDevice.data(), SIGNAL(logMessage(QString)), this, SLOT(slotTrkLogMessage(QString)));
connect(m_trkDevice, SIGNAL(tcfEvent(Coda::CodaEvent)), this, SLOT(slotCodaEvent(Coda::CodaEvent)), Qt::DirectConnection); connect(m_codaDevice.data(), SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)), this, SLOT(slotTcftrkEvent(tcftrk::TcfTrkEvent)), Qt::DirectConnection);
connect(m_trkDevice, SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString))); connect(m_codaDevice.data(), SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString)));
connect(this, SIGNAL(manualInstallation()), this, SLOT(showManualInstallationInfo())); connect(this, SIGNAL(manualInstallation()), this, SLOT(showManualInstallationInfo()));
} }
} }
@@ -357,13 +352,14 @@ void S60DeployStep::startDeployment()
{ {
if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) { if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) {
QTC_ASSERT(m_launcher, return); QTC_ASSERT(m_launcher, return);
} else {
QTC_ASSERT(m_trkDevice, return);
} }
QTC_ASSERT(!m_trkDevice.data(), return);
setupConnections(); // We need to defer setupConnections() in the case of CommunicationCodaSerialConnection
//setupConnections();
if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) { if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) {
setupConnections();
QStringList copyDst; QStringList copyDst;
foreach (const QString &signedPackage, m_signedPackages) foreach (const QString &signedPackage, m_signedPackages)
copyDst << QString::fromLatin1("%1:\\Data\\%2").arg(m_installationDrive).arg(QFileInfo(signedPackage).fileName()); copyDst << QString::fromLatin1("%1:\\Data\\%2").arg(m_installationDrive).arg(QFileInfo(signedPackage).fileName());
@@ -386,22 +382,25 @@ void S60DeployStep::startDeployment()
stop(); stop();
} }
} else if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) { } else if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) {
const QSharedPointer<SymbianUtils::VirtualSerialDevice> serialDevice(new SymbianUtils::VirtualSerialDevice(m_serialPortName));
appendMessage(tr("Deploying application to '%1'...").arg(m_serialPortFriendlyName), false); appendMessage(tr("Deploying application to '%1'...").arg(m_serialPortFriendlyName), false);
m_trkDevice->setSerialFrame(true); m_trkDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPortName);
m_trkDevice->setDevice(serialDevice); bool ok = m_trkDevice && m_trkDevice->device()->isOpen();
bool ok = serialDevice->open(QIODevice::ReadWrite);
if (!ok) { if (!ok) {
reportError(tr("Couldn't open serial device: %1").arg(serialDevice->errorString())); QString deviceError = tr("No such port");
if (m_trkDevice) deviceError = m_trkDevice->device()->errorString();
reportError(tr("Couldn't open serial device: %1").arg(deviceError));
stop(); stop();
return; return;
} }
setupConnections();
m_state = StateConnecting; m_state = StateConnecting;
m_trkDevice->sendSerialPing(false); m_trkDevice->sendSerialPing(false);
QTimer::singleShot(4000, this, SLOT(checkForTimeout())); QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
} else { } else {
m_codaDevice = QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice);
setupConnections();
const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket); const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket);
m_trkDevice->setDevice(codaSocket); m_codaDevice->setDevice(codaSocket);
codaSocket->connectToHost(m_address, m_port); codaSocket->connectToHost(m_address, m_port);
m_state = StateConnecting; m_state = StateConnecting;
appendMessage(tr("Connecting to %1:%2...").arg(m_address).arg(m_port), false); appendMessage(tr("Connecting to %1:%2...").arg(m_address).arg(m_port), false);
@@ -440,8 +439,10 @@ void S60DeployStep::run(QFutureInterface<bool> &fi)
delete m_timer; delete m_timer;
m_timer = 0; m_timer = 0;
delete m_trkDevice; if (m_trkDevice) {
m_trkDevice = 0; disconnect(m_trkDevice.data(), 0, this, 0);
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_trkDevice);
}
delete m_eventLoop; delete m_eventLoop;
m_eventLoop = 0; m_eventLoop = 0;

View File

@@ -201,7 +201,8 @@ private:
QFutureInterface<bool> *m_futureInterface; //not owned QFutureInterface<bool> *m_futureInterface; //not owned
trk::Launcher *m_launcher; trk::Launcher *m_launcher;
Coda::CodaDevice *m_trkDevice;
QSharedPointer<Coda::CodaDevice> m_codaDevice;
QEventLoop *m_eventLoop; QEventLoop *m_eventLoop;
bool m_deployResult; bool m_deployResult;

View File

@@ -43,7 +43,7 @@
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
enum { debug = 0 }; enum { debug = 1 };
static const char tcpMessageTerminatorC[] = "\003\001"; static const char tcpMessageTerminatorC[] = "\003\001";
@@ -347,6 +347,7 @@ CodaDevicePrivate::CodaDevicePrivate() :
CodaDevice::CodaDevice(QObject *parent) : CodaDevice::CodaDevice(QObject *parent) :
QObject(parent), d(new CodaDevicePrivate) QObject(parent), d(new CodaDevicePrivate)
{ {
if (debug) setVerbose(true);
} }
CodaDevice::~CodaDevice() CodaDevice::~CodaDevice()
@@ -470,26 +471,45 @@ void CodaDevice::slotDeviceReadyRead()
// Find a serial header in input stream '0x1', '0x92', 'lenH', 'lenL' // Find a serial header in input stream '0x1', '0x92', 'lenH', 'lenL'
// and return message position and size. // and return message position and size.
static inline QPair<int, int> findSerialHeader(const QByteArray &in) QPair<int, int> TcfTrkDevice::findSerialHeader(QByteArray &in)
{ {
const int size = in.size();
const char header1 = 0x1; const char header1 = 0x1;
const char header2 = char(0x92); const char header2 = char(0x92);
const char header2tracecore = char(0x91);
// Header should in theory always be at beginning of // Header should in theory always be at beginning of
// buffer. Warn if there are bogus data in-between. // buffer. Warn if there are bogus data in-between.
for (int pos = 0; pos < size; ) {
if (pos + 4 < size && in.at(pos) == header1 && in.at(pos + 1) == header2) { while (in.size() >= 4) {
if (in.at(0) == header1 && in.at(1) == header2) {
// Good packet
const int length = trk::extractShort(in.constData() + 2); const int length = trk::extractShort(in.constData() + 2);
return QPair<int, int>(pos + 4, length); return QPair<int, int>(4, length);
} else if (in.at(0) == header1 && in.at(1) == header2tracecore) {
// We recognise it but it's not a TCF message - emit it for any interested party to handle
const int length = trk::extractShort(in.constData() + 2);
if (4 + length <= in.size()) {
// We have all the data
QByteArray data(in.mid(4, length));
emit traceCoreEvent(data);
in.remove(0, 4+length);
// and continue
} else {
// If we don't have all this packet, there can't be any data following it, so return now
// and wait for more data
return QPair<int, int>(-1, -1);
}
} else {
// Bad data - log it, remove it, and go round again
int nextHeader = in.indexOf(header1, 1);
QByteArray bad = in.mid(0, nextHeader);
qWarning("Bogus data received on serial line: %s\n"
"Frame Header at: %d", qPrintable(trk::stringFromArray(bad)), nextHeader);
d->m_device->write(bad); // Backatcha - TOMSCI TESTING
in.remove(0, bad.length());
// and continue
} }
// Find next
pos = in.indexOf(header1, pos + 1);
qWarning("Bogus data received on serial line: %s\n"
"Frame Header at: %d", qPrintable(trk::stringFromArray(in)), pos);
if (pos < 0)
break;
} }
return QPair<int, int>(-1, -1); return QPair<int, int>(-1, -1); // No more data, or not enough for a complete header
} }
void CodaDevice::deviceReadyReadSerial() void CodaDevice::deviceReadyReadSerial()
@@ -767,6 +787,9 @@ void CodaDevice::sendSerialPing(bool pingOnly)
if (!checkOpen()) if (!checkOpen())
return; return;
dumpObjectInfo();
d->m_device->dumpObjectInfo();
d->m_serialPingOnly = pingOnly; d->m_serialPingOnly = pingOnly;
setSerialFrame(true); setSerialFrame(true);
writeMessage(QByteArray(serialPingC, qstrlen(serialPingC)), false); writeMessage(QByteArray(serialPingC, qstrlen(serialPingC)), false);
@@ -839,7 +862,9 @@ void CodaDevice::writeMessage(QByteArray data, bool ensureTerminating0)
if (debug > 1) if (debug > 1)
qDebug("Writing:\n%s", qPrintable(formatData(data))); qDebug("Writing:\n%s", qPrintable(formatData(data)));
d->m_device->write(data); int result = d->m_device->write(data);
if (result < data.length())
qWarning("Failed to write all data! result=%d", result);
if (QAbstractSocket *as = qobject_cast<QAbstractSocket *>(d->m_device.data())) if (QAbstractSocket *as = qobject_cast<QAbstractSocket *>(d->m_device.data()))
as->flush(); as->flush();
} }

View File

@@ -367,6 +367,7 @@ public:
signals: signals:
void genericTcfEvent(int service, const QByteArray &name, const QVector<JsonValue> &value); void genericTcfEvent(int service, const QByteArray &name, const QVector<JsonValue> &value);
void tcfEvent(const Coda::CodaEvent &knownEvent); void tcfEvent(const Coda::CodaEvent &knownEvent);
void traceCoreEvent(const QByteArray& data);
void serialPong(const QString &codaVersion); void serialPong(const QString &codaVersion);
void logMessage(const QString &); void logMessage(const QString &);
@@ -393,6 +394,9 @@ private:
inline void processSerialMessage(const QByteArray &message); inline void processSerialMessage(const QByteArray &message);
int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens); int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens);
int parseTcfEvent(const QVector<QByteArray> &tokens); int parseTcfEvent(const QVector<QByteArray> &tokens);
private:
QPair<int, int> findSerialHeader(QByteArray &in);
CodaDevicePrivate *d; CodaDevicePrivate *d;
}; };

View File

@@ -33,6 +33,8 @@
#include "symbiandevicemanager.h" #include "symbiandevicemanager.h"
#include "trkdevice.h" #include "trkdevice.h"
#include "tcftrkdevice.h"
#include "virtualserialdevice.h"
#include <QtCore/QSettings> #include <QtCore/QSettings>
#include <QtCore/QStringList> #include <QtCore/QStringList>
@@ -42,6 +44,8 @@
#include <QtCore/QSharedData> #include <QtCore/QSharedData>
#include <QtCore/QScopedPointer> #include <QtCore/QScopedPointer>
#include <QtCore/QSignalMapper> #include <QtCore/QSignalMapper>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>
namespace SymbianUtils { namespace SymbianUtils {
@@ -58,7 +62,7 @@ public:
SymbianDeviceData(); SymbianDeviceData();
~SymbianDeviceData(); ~SymbianDeviceData();
inline bool isOpen() const { return !device.isNull() && device->isOpen(); } bool isOpen() const;
void forcedClose(); void forcedClose();
QString portName; QString portName;
@@ -69,6 +73,7 @@ public:
DeviceCommunicationType type; DeviceCommunicationType type;
QSharedPointer<trk::TrkDevice> device; QSharedPointer<trk::TrkDevice> device;
QSharedPointer<tcftrk::TcfTrkDevice> tcfdevice;
bool deviceAcquired; bool deviceAcquired;
}; };
@@ -78,6 +83,18 @@ SymbianDeviceData::SymbianDeviceData() :
{ {
} }
bool SymbianDeviceData::isOpen() const
{
if (device) {
// TRK device
return device->isOpen();
} else if (tcfdevice) {
return tcfdevice->device()->isOpen();
} else {
return false;
}
}
SymbianDeviceData::~SymbianDeviceData() SymbianDeviceData::~SymbianDeviceData()
{ {
forcedClose(); forcedClose();
@@ -93,7 +110,8 @@ void SymbianDeviceData::forcedClose()
if (deviceAcquired) if (deviceAcquired)
qWarning("Device on '%s' unplugged while an operation is in progress.", qWarning("Device on '%s' unplugged while an operation is in progress.",
qPrintable(portName)); qPrintable(portName));
device->close(); if (device) device->close();
else tcfdevice->device()->close();
} }
} }
@@ -247,17 +265,34 @@ SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd)
// ------------- SymbianDeviceManagerPrivate // ------------- SymbianDeviceManagerPrivate
struct SymbianDeviceManagerPrivate { struct SymbianDeviceManagerPrivate {
SymbianDeviceManagerPrivate() : m_initialized(false), m_destroyReleaseMapper(0) {} SymbianDeviceManagerPrivate() : m_initialized(false) /*, m_destroyReleaseMapper(0),*/ {}
bool m_initialized; bool m_initialized;
SymbianDeviceManager::SymbianDeviceList m_devices; SymbianDeviceManager::SymbianDeviceList m_devices;
QSignalMapper *m_destroyReleaseMapper; //QSignalMapper *m_destroyReleaseMapper;
// The following 2 variables are needed to manage requests for a TCF port not coming from the main thread
int m_constructTcfPortEventType;
QMutex m_tcfPortWaitMutex;
}; };
class QConstructTcfPortEvent : public QEvent
{
public:
QConstructTcfPortEvent(QEvent::Type eventId, const QString &portName, TcfTrkDevicePtr *device, QWaitCondition *waiter) :
QEvent(eventId), m_portName(portName), m_device(device), m_waiter(waiter)
{}
QString m_portName;
TcfTrkDevicePtr* m_device;
QWaitCondition *m_waiter;
};
SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : SymbianDeviceManager::SymbianDeviceManager(QObject *parent) :
QObject(parent), QObject(parent),
d(new SymbianDeviceManagerPrivate) d(new SymbianDeviceManagerPrivate)
{ {
d->m_constructTcfPortEventType = QEvent::registerEventType();
} }
SymbianDeviceManager::~SymbianDeviceManager() SymbianDeviceManager::~SymbianDeviceManager()
@@ -318,6 +353,85 @@ SymbianDeviceManager::TrkDevicePtr
return rc; return rc;
} }
TcfTrkDevicePtr SymbianDeviceManager::getTcfPort(const QString &port)
{
ensureInitialized();
const int idx = findByPortName(port);
if (idx == -1) {
qWarning("Attempt to acquire device '%s' that does not exist.", qPrintable(port));
if (debug)
qDebug() << *this;
return TcfTrkDevicePtr();
}
SymbianDevice& device = d->m_devices[idx];
if (device.m_data->device) {
qWarning("Attempting to open a port '%s' that is configured for TRK!", qPrintable(port));
return TcfTrkDevicePtr();
}
TcfTrkDevicePtr& devicePtr = device.m_data->tcfdevice;
if (devicePtr.isNull()) {
// Check we instanciate in the correct thread - we can't afford to create the TcfTrkDevice (and more specifically, open the VirtualSerialDevice) in a thread that isn't guaranteed to be long-lived.
// Therefore, if we're not in SymbianDeviceManager's thread, rejig things so it's opened in the main thread
if (QThread::currentThread() != thread()) {
// SymbianDeviceManager is owned by the current thread
d->m_tcfPortWaitMutex.lock();
QWaitCondition waiter;
QCoreApplication::postEvent(this, new QConstructTcfPortEvent((QEvent::Type)d->m_constructTcfPortEventType, port, &devicePtr, &waiter));
waiter.wait(&d->m_tcfPortWaitMutex);
// When the wait returns (due to the wakeAll in SymbianDeviceManager::customEvent), the TcfTrkDevice will be fully set up
d->m_tcfPortWaitMutex.unlock();
} else {
// We're in the main thread, just set it up directly
constructTcfPort(devicePtr, port);
}
}
if (!devicePtr->device()->isOpen()) {
bool ok = devicePtr->device().staticCast<SymbianUtils::VirtualSerialDevice>()->open(QIODevice::ReadWrite);
if (!ok && debug) {
qDebug("SymbianDeviceManager: Failed to open port %s", qPrintable(port));
}
// We still carry on in the case we failed to open so the client can access the IODevice's errorString()
}
//Q_ASSERT(QThread::currentThread() == devicePtr->thread());
return devicePtr;
}
void SymbianDeviceManager::constructTcfPort(TcfTrkDevicePtr& device, const QString& portName)
{
QMutexLocker locker(&d->m_tcfPortWaitMutex);
device = QSharedPointer<tcftrk::TcfTrkDevice>(new tcftrk::TcfTrkDevice);
const QSharedPointer<SymbianUtils::VirtualSerialDevice> serialDevice(new SymbianUtils::VirtualSerialDevice(portName));
device->setSerialFrame(true);
device->setDevice(serialDevice);
}
void SymbianDeviceManager::customEvent(QEvent *event)
{
if (event->type() == d->m_constructTcfPortEventType)
{
QConstructTcfPortEvent* constructEvent = static_cast<QConstructTcfPortEvent*>(event);
constructTcfPort(*constructEvent->m_device, constructEvent->m_portName);
constructEvent->m_waiter->wakeAll(); // Should only ever be one thing waiting on this
}
}
/*
TcfTrkDevicePtr SymbianDeviceManager::getTcfPort(const QString &host, quint16 port)
{
// No attempt to check the device list. The main purpose in doing that is to cooperatively share the port with other services, and there's no need to do that with TCP/IP as you can just use separate port numbers.
// Ok it might make it slightly quicker but I'm not going to worry about it just now
}
*/
void SymbianDeviceManager::releaseTcfPort(TcfTrkDevicePtr &aPort)
{
if (aPort) {
aPort.clear();
}
//TODO close the port after a timeer if last reference?
}
void SymbianDeviceManager::update() void SymbianDeviceManager::update()
{ {
update(true); update(true);

View File

@@ -48,6 +48,9 @@ QT_END_NAMESPACE
namespace trk { namespace trk {
class TrkDevice; class TrkDevice;
} }
namespace tcftrk {
class TcfTrkDevice;
}
namespace SymbianUtils { namespace SymbianUtils {
@@ -59,6 +62,8 @@ enum DeviceCommunicationType {
BlueToothCommunication = 1 BlueToothCommunication = 1
}; };
typedef QSharedPointer<tcftrk::TcfTrkDevice> TcfTrkDevicePtr;
// SymbianDevice: Explicitly shared device data and a TrkDevice // SymbianDevice: Explicitly shared device data and a TrkDevice
// instance that can be acquired (exclusively) for use. // instance that can be acquired (exclusively) for use.
// A device removal from the manager will result in the // A device removal from the manager will result in the
@@ -82,13 +87,6 @@ public:
QString additionalInformation() const; QString additionalInformation() const;
void setAdditionalInformation(const QString &); void setAdditionalInformation(const QString &);
// Acquire: Mark the device as 'out' and return a shared pointer
// unless it is already in use by another owner. The result should not
// be passed on further.
TrkDevicePtr acquireDevice();
// Give back a device and mark it as 'free'.
void releaseDevice(TrkDevicePtr *ptr = 0);
bool isOpen() const; bool isOpen() const;
// Windows only. // Windows only.
@@ -99,6 +97,14 @@ public:
QString toString() const; QString toString() const;
private: private:
// Acquire: Mark the device as 'out' and return a shared pointer
// unless it is already in use by another owner. The result should not
// be passed on further.
// TRK only
TrkDevicePtr acquireDevice();
// Give back a device and mark it as 'free'. TRK only.
void releaseDevice(TrkDevicePtr *ptr = 0);
void forcedClose(); void forcedClose();
QExplicitlySharedDataPointer<SymbianDeviceData> m_data; QExplicitlySharedDataPointer<SymbianDeviceData> m_data;
@@ -137,15 +143,27 @@ public:
SymbianDeviceList devices() const; SymbianDeviceList devices() const;
QString toString() const; QString toString() const;
// Acquire a device for use. See releaseDevice(). // Acquire a TRK device for use. Assuming the port is found, equivalent to devices()[findByPortName(port)].acquireDevice(). See also releaseDevice().
TrkDevicePtr acquireDevice(const QString &port); TrkDevicePtr acquireDevice(const QString &port);
//// The TCF code prefers to set up the TcfTrkDevice object itself, so we let it and just handle opening the underlying QIODevice and keeping track of the TcfTrkDevice
//// Returns true if port was opened successfully.
// Gets the TcfTrkDevice, which may or may not be open depending on what other clients have already acquired it.
// Therefore once clients have set up any signals and slots they required, they should check TcfTrkDevice::device()->isOpen()
// and if false, the open failed and they should check device()->errorString() if required.
// Caller should call releaseTcfPort if they want the port to auto-close itself
TcfTrkDevicePtr getTcfPort(const QString &port);
// Caller is responsible for disconnecting any signals from aPort - do not assume the TcfTrkDevice will be deleted as a result of this call. On return aPort will be clear()ed.
void releaseTcfPort(TcfTrkDevicePtr &aPort);
int findByPortName(const QString &p) const; int findByPortName(const QString &p) const;
QString friendlyNameForPort(const QString &port) const; QString friendlyNameForPort(const QString &port) const;
public slots: public slots:
void update(); void update();
// Relase a device, make it available for further use. // Release a device, make it available for further use. Only for use with a TRK device
void releaseDevice(const QString &port); void releaseDevice(const QString &port);
void setAdditionalInformation(const QString &port, const QString &ai); void setAdditionalInformation(const QString &port, const QString &ai);
@@ -159,6 +177,8 @@ private:
void update(bool emitSignals); void update(bool emitSignals);
SymbianDeviceList serialPorts() const; SymbianDeviceList serialPorts() const;
SymbianDeviceList blueToothDevices() const; SymbianDeviceList blueToothDevices() const;
void customEvent(QEvent *event);
void constructTcfPort(TcfTrkDevicePtr& device, const QString& portName);
SymbianDeviceManagerPrivate *d; SymbianDeviceManagerPrivate *d;
}; };

View File

@@ -15,7 +15,7 @@ HEADERS += $$PWD/symbianutils_global.h \
$$PWD/codadevice.h \ $$PWD/codadevice.h \
$$PWD/codamessage.h \ $$PWD/codamessage.h \
$$PWD/json.h \ $$PWD/json.h \
$$PWD/virtualserialdevice.h $$PWD/virtualserialdevice.h
SOURCES += $$PWD/trkutils.cpp \ SOURCES += $$PWD/trkutils.cpp \
$$PWD/trkdevice.cpp \ $$PWD/trkdevice.cpp \

View File

@@ -23,10 +23,9 @@ const QString& VirtualSerialDevice::getPortName() const
void VirtualSerialDevice::close() void VirtualSerialDevice::close()
{ {
if (isOpen()) { if (isOpen()) {
Q_ASSERT(thread() == QThread::currentThread()); // My brain will explode otherwise QMutexLocker locker(&lock);
delete waiterForBytesWritten; delete waiterForBytesWritten;
waiterForBytesWritten = NULL; waiterForBytesWritten = NULL;
QMutexLocker locker(&lock);
QIODevice::close(); QIODevice::close();
platClose(); platClose();
} }