forked from qt-creator/qt-creator
In progress: making TcfTrkDevice connections persistant
This commit is contained in:
committed by
Pawel Polanski
parent
813778ac23
commit
ca622b32e9
@@ -43,7 +43,7 @@
|
||||
#include "qt4symbiantarget.h"
|
||||
#include "qt4target.h"
|
||||
#include "qtoutputformatter.h"
|
||||
#include "virtualserialdevice.h"
|
||||
#include "symbiandevicemanager.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -65,11 +65,10 @@ using namespace Qt4ProjectManager;
|
||||
using namespace Qt4ProjectManager::Internal;
|
||||
using namespace Coda;
|
||||
|
||||
enum { debug = 0 };
|
||||
enum { debug = 1 };
|
||||
|
||||
CodaRunControl::CodaRunControl(RunConfiguration *runConfiguration, const QString &mode) :
|
||||
S60RunControlBase(runConfiguration, mode),
|
||||
m_codaDevice(0),
|
||||
m_port(0),
|
||||
m_state(StateUninit)
|
||||
{
|
||||
@@ -89,12 +88,6 @@ CodaRunControl::CodaRunControl(RunConfiguration *runConfiguration, const QString
|
||||
}
|
||||
}
|
||||
|
||||
CodaRunControl::~CodaRunControl()
|
||||
{
|
||||
if (m_codaDevice)
|
||||
m_codaDevice->deleteLater();
|
||||
}
|
||||
|
||||
bool CodaRunControl::doStart()
|
||||
{
|
||||
if (m_address.isEmpty() && m_serialPort.isEmpty()) {
|
||||
@@ -117,31 +110,32 @@ bool CodaRunControl::setupLauncher()
|
||||
{
|
||||
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()) {
|
||||
const QSharedPointer<SymbianUtils::VirtualSerialDevice> serialDevice(new SymbianUtils::VirtualSerialDevice(m_serialPort));
|
||||
appendMessage(tr("Conecting to '%2'...").arg(m_serialPort), NormalMessageFormat);
|
||||
m_codaDevice->setSerialFrame(true);
|
||||
m_codaDevice->setDevice(serialDevice);
|
||||
bool ok = serialDevice->open(QIODevice::ReadWrite);
|
||||
// We get the port from SymbianDeviceManager
|
||||
appendMessage(tr("Connecting to '%2'...").arg(m_serialPort), NormalMessageFormat);
|
||||
m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPort);
|
||||
|
||||
bool ok = m_codaDevice && m_tcfTrkDevice->device()->isOpen();
|
||||
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;
|
||||
}
|
||||
connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(const 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_codaDevice->sendSerialPing(false);
|
||||
QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
|
||||
} 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);
|
||||
m_codaDevice->setDevice(codaSocket);
|
||||
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);
|
||||
QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
|
||||
}
|
||||
if (debug) m_tcfTrkDevice->setVerbose(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -325,9 +320,10 @@ void CodaRunControl::handleCreateProcess(const CodaCommandResult &result)
|
||||
void CodaRunControl::finishRunControl()
|
||||
{
|
||||
m_runningProcessId.clear();
|
||||
if (m_codaDevice)
|
||||
m_codaDevice->deleteLater();
|
||||
m_codaDevice = 0;
|
||||
if (m_codaDevice) {
|
||||
disconnect(m_codaDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice);
|
||||
}
|
||||
m_state = StateUninit;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ class CodaRunControl : public S60RunControlBase
|
||||
Q_OBJECT
|
||||
public:
|
||||
CodaRunControl(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode);
|
||||
~CodaRunControl();
|
||||
virtual bool isRunning() const;
|
||||
|
||||
static QMessageBox *createCodaWaitingMessageBox(QWidget *parent = 0);
|
||||
@@ -104,7 +103,7 @@ private:
|
||||
StateProcessRunning
|
||||
};
|
||||
|
||||
Coda::CodaDevice *m_codaDevice;
|
||||
QSharedPointer<Coda::CodaDevice> m_codaDevice;
|
||||
|
||||
QString m_address;
|
||||
unsigned short m_port;
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
|
||||
#include <symbianutils/launcher.h>
|
||||
#include <symbianutils/symbiandevicemanager.h>
|
||||
#include <symbianutils/virtualserialdevice.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtGui/QMessageBox>
|
||||
@@ -108,7 +107,6 @@ S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc,
|
||||
m_releaseDeviceAfterLauncherFinish(bs->m_releaseDeviceAfterLauncherFinish),
|
||||
m_handleDeviceRemoval(bs->m_handleDeviceRemoval),
|
||||
m_launcher(0),
|
||||
m_trkDevice(0),
|
||||
m_eventLoop(0),
|
||||
m_state(StateUninit),
|
||||
m_putWriteOk(false),
|
||||
@@ -127,7 +125,6 @@ S60DeployStep::S60DeployStep(ProjectExplorer::BuildStepList *bc):
|
||||
m_releaseDeviceAfterLauncherFinish(true),
|
||||
m_handleDeviceRemoval(true),
|
||||
m_launcher(0),
|
||||
m_trkDevice(0),
|
||||
m_eventLoop(0),
|
||||
m_state(StateUninit),
|
||||
m_putWriteOk(false),
|
||||
@@ -151,7 +148,6 @@ S60DeployStep::~S60DeployStep()
|
||||
{
|
||||
delete m_timer;
|
||||
delete m_launcher;
|
||||
delete m_trkDevice;
|
||||
delete m_eventLoop;
|
||||
}
|
||||
|
||||
@@ -294,8 +290,7 @@ void S60DeployStep::start()
|
||||
return;
|
||||
}
|
||||
if (!trkClient) {
|
||||
QTC_ASSERT(!m_trkDevice, return);
|
||||
m_trkDevice = new Coda::CodaDevice;
|
||||
QTC_ASSERT(!m_codaDevice.data(), return);
|
||||
if (m_address.isEmpty() && !serialConnection) {
|
||||
errorMessage = tr("No address for a device has been defined. Please define an address and try again.");
|
||||
reportError(errorMessage);
|
||||
@@ -320,8 +315,8 @@ void S60DeployStep::stop()
|
||||
m_launcher->terminate();
|
||||
} else {
|
||||
if (m_trkDevice) {
|
||||
delete m_trkDevice;
|
||||
m_trkDevice = 0;
|
||||
disconnect(m_trkDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_trkDevice);
|
||||
}
|
||||
}
|
||||
emit finished(false);
|
||||
@@ -345,10 +340,10 @@ void S60DeployStep::setupConnections()
|
||||
connect(m_launcher, SIGNAL(stateChanged(int)), this, SLOT(slotLauncherStateChanged(int)));
|
||||
connect(m_launcher, SIGNAL(copyProgress(int)), this, SLOT(setCopyProgress(int)));
|
||||
} else {
|
||||
connect(m_trkDevice, SIGNAL(error(QString)), this, SLOT(slotError(QString)));
|
||||
connect(m_trkDevice, SIGNAL(logMessage(QString)), this, SLOT(slotTrkLogMessage(QString)));
|
||||
connect(m_trkDevice, SIGNAL(tcfEvent(Coda::CodaEvent)), this, SLOT(slotCodaEvent(Coda::CodaEvent)), Qt::DirectConnection);
|
||||
connect(m_trkDevice, SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString)));
|
||||
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)), Qt::DirectConnection);
|
||||
connect(m_codaDevice.data(), SIGNAL(serialPong(QString)), this, SLOT(slotSerialPong(QString)));
|
||||
connect(this, SIGNAL(manualInstallation()), this, SLOT(showManualInstallationInfo()));
|
||||
}
|
||||
}
|
||||
@@ -357,13 +352,14 @@ void S60DeployStep::startDeployment()
|
||||
{
|
||||
if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) {
|
||||
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) {
|
||||
setupConnections();
|
||||
QStringList copyDst;
|
||||
foreach (const QString &signedPackage, m_signedPackages)
|
||||
copyDst << QString::fromLatin1("%1:\\Data\\%2").arg(m_installationDrive).arg(QFileInfo(signedPackage).fileName());
|
||||
@@ -386,22 +382,25 @@ void S60DeployStep::startDeployment()
|
||||
stop();
|
||||
}
|
||||
} 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);
|
||||
m_trkDevice->setSerialFrame(true);
|
||||
m_trkDevice->setDevice(serialDevice);
|
||||
bool ok = serialDevice->open(QIODevice::ReadWrite);
|
||||
m_trkDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPortName);
|
||||
bool ok = m_trkDevice && m_trkDevice->device()->isOpen();
|
||||
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();
|
||||
return;
|
||||
}
|
||||
setupConnections();
|
||||
m_state = StateConnecting;
|
||||
m_trkDevice->sendSerialPing(false);
|
||||
QTimer::singleShot(4000, this, SLOT(checkForTimeout()));
|
||||
} else {
|
||||
m_codaDevice = QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice);
|
||||
setupConnections();
|
||||
const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket);
|
||||
m_trkDevice->setDevice(codaSocket);
|
||||
m_codaDevice->setDevice(codaSocket);
|
||||
codaSocket->connectToHost(m_address, m_port);
|
||||
m_state = StateConnecting;
|
||||
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;
|
||||
m_timer = 0;
|
||||
|
||||
delete m_trkDevice;
|
||||
m_trkDevice = 0;
|
||||
if (m_trkDevice) {
|
||||
disconnect(m_trkDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_trkDevice);
|
||||
}
|
||||
|
||||
delete m_eventLoop;
|
||||
m_eventLoop = 0;
|
||||
|
||||
@@ -201,7 +201,8 @@ private:
|
||||
QFutureInterface<bool> *m_futureInterface; //not owned
|
||||
|
||||
trk::Launcher *m_launcher;
|
||||
Coda::CodaDevice *m_trkDevice;
|
||||
|
||||
QSharedPointer<Coda::CodaDevice> m_codaDevice;
|
||||
|
||||
QEventLoop *m_eventLoop;
|
||||
bool m_deployResult;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
enum { debug = 0 };
|
||||
enum { debug = 1 };
|
||||
|
||||
static const char tcpMessageTerminatorC[] = "\003\001";
|
||||
|
||||
@@ -347,6 +347,7 @@ CodaDevicePrivate::CodaDevicePrivate() :
|
||||
CodaDevice::CodaDevice(QObject *parent) :
|
||||
QObject(parent), d(new CodaDevicePrivate)
|
||||
{
|
||||
if (debug) setVerbose(true);
|
||||
}
|
||||
|
||||
CodaDevice::~CodaDevice()
|
||||
@@ -470,26 +471,45 @@ void CodaDevice::slotDeviceReadyRead()
|
||||
|
||||
// Find a serial header in input stream '0x1', '0x92', 'lenH', 'lenL'
|
||||
// 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 header2 = char(0x92);
|
||||
const char header2tracecore = char(0x91);
|
||||
// Header should in theory always be at beginning of
|
||||
// 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);
|
||||
return QPair<int, int>(pos + 4, length);
|
||||
}
|
||||
// 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>(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
|
||||
}
|
||||
}
|
||||
return QPair<int, int>(-1, -1); // No more data, or not enough for a complete header
|
||||
}
|
||||
|
||||
void CodaDevice::deviceReadyReadSerial()
|
||||
@@ -767,6 +787,9 @@ void CodaDevice::sendSerialPing(bool pingOnly)
|
||||
if (!checkOpen())
|
||||
return;
|
||||
|
||||
dumpObjectInfo();
|
||||
d->m_device->dumpObjectInfo();
|
||||
|
||||
d->m_serialPingOnly = pingOnly;
|
||||
setSerialFrame(true);
|
||||
writeMessage(QByteArray(serialPingC, qstrlen(serialPingC)), false);
|
||||
@@ -839,7 +862,9 @@ void CodaDevice::writeMessage(QByteArray data, bool ensureTerminating0)
|
||||
if (debug > 1)
|
||||
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()))
|
||||
as->flush();
|
||||
}
|
||||
|
||||
@@ -367,6 +367,7 @@ public:
|
||||
signals:
|
||||
void genericTcfEvent(int service, const QByteArray &name, const QVector<JsonValue> &value);
|
||||
void tcfEvent(const Coda::CodaEvent &knownEvent);
|
||||
void traceCoreEvent(const QByteArray& data);
|
||||
void serialPong(const QString &codaVersion);
|
||||
|
||||
void logMessage(const QString &);
|
||||
@@ -393,6 +394,9 @@ private:
|
||||
inline void processSerialMessage(const QByteArray &message);
|
||||
int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens);
|
||||
int parseTcfEvent(const QVector<QByteArray> &tokens);
|
||||
|
||||
private:
|
||||
QPair<int, int> findSerialHeader(QByteArray &in);
|
||||
CodaDevicePrivate *d;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "symbiandevicemanager.h"
|
||||
#include "trkdevice.h"
|
||||
#include "tcftrkdevice.h"
|
||||
#include "virtualserialdevice.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QStringList>
|
||||
@@ -42,6 +44,8 @@
|
||||
#include <QtCore/QSharedData>
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QSignalMapper>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QWaitCondition>
|
||||
|
||||
namespace SymbianUtils {
|
||||
|
||||
@@ -58,7 +62,7 @@ public:
|
||||
SymbianDeviceData();
|
||||
~SymbianDeviceData();
|
||||
|
||||
inline bool isOpen() const { return !device.isNull() && device->isOpen(); }
|
||||
bool isOpen() const;
|
||||
void forcedClose();
|
||||
|
||||
QString portName;
|
||||
@@ -69,6 +73,7 @@ public:
|
||||
|
||||
DeviceCommunicationType type;
|
||||
QSharedPointer<trk::TrkDevice> device;
|
||||
QSharedPointer<tcftrk::TcfTrkDevice> tcfdevice;
|
||||
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()
|
||||
{
|
||||
forcedClose();
|
||||
@@ -93,7 +110,8 @@ void SymbianDeviceData::forcedClose()
|
||||
if (deviceAcquired)
|
||||
qWarning("Device on '%s' unplugged while an operation is in progress.",
|
||||
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
|
||||
struct SymbianDeviceManagerPrivate {
|
||||
SymbianDeviceManagerPrivate() : m_initialized(false), m_destroyReleaseMapper(0) {}
|
||||
SymbianDeviceManagerPrivate() : m_initialized(false) /*, m_destroyReleaseMapper(0),*/ {}
|
||||
|
||||
bool m_initialized;
|
||||
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) :
|
||||
QObject(parent),
|
||||
d(new SymbianDeviceManagerPrivate)
|
||||
{
|
||||
d->m_constructTcfPortEventType = QEvent::registerEventType();
|
||||
}
|
||||
|
||||
SymbianDeviceManager::~SymbianDeviceManager()
|
||||
@@ -318,6 +353,85 @@ SymbianDeviceManager::TrkDevicePtr
|
||||
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()
|
||||
{
|
||||
update(true);
|
||||
|
||||
@@ -48,6 +48,9 @@ QT_END_NAMESPACE
|
||||
namespace trk {
|
||||
class TrkDevice;
|
||||
}
|
||||
namespace tcftrk {
|
||||
class TcfTrkDevice;
|
||||
}
|
||||
|
||||
namespace SymbianUtils {
|
||||
|
||||
@@ -59,6 +62,8 @@ enum DeviceCommunicationType {
|
||||
BlueToothCommunication = 1
|
||||
};
|
||||
|
||||
typedef QSharedPointer<tcftrk::TcfTrkDevice> TcfTrkDevicePtr;
|
||||
|
||||
// SymbianDevice: Explicitly shared device data and a TrkDevice
|
||||
// instance that can be acquired (exclusively) for use.
|
||||
// A device removal from the manager will result in the
|
||||
@@ -82,13 +87,6 @@ public:
|
||||
QString additionalInformation() const;
|
||||
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;
|
||||
|
||||
// Windows only.
|
||||
@@ -99,6 +97,14 @@ public:
|
||||
QString toString() const;
|
||||
|
||||
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();
|
||||
|
||||
QExplicitlySharedDataPointer<SymbianDeviceData> m_data;
|
||||
@@ -137,15 +143,27 @@ public:
|
||||
SymbianDeviceList devices() 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);
|
||||
|
||||
//// 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;
|
||||
QString friendlyNameForPort(const QString &port) const;
|
||||
|
||||
public slots:
|
||||
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 setAdditionalInformation(const QString &port, const QString &ai);
|
||||
|
||||
@@ -159,6 +177,8 @@ private:
|
||||
void update(bool emitSignals);
|
||||
SymbianDeviceList serialPorts() const;
|
||||
SymbianDeviceList blueToothDevices() const;
|
||||
void customEvent(QEvent *event);
|
||||
void constructTcfPort(TcfTrkDevicePtr& device, const QString& portName);
|
||||
|
||||
SymbianDeviceManagerPrivate *d;
|
||||
};
|
||||
|
||||
@@ -23,10 +23,9 @@ const QString& VirtualSerialDevice::getPortName() const
|
||||
void VirtualSerialDevice::close()
|
||||
{
|
||||
if (isOpen()) {
|
||||
Q_ASSERT(thread() == QThread::currentThread()); // My brain will explode otherwise
|
||||
QMutexLocker locker(&lock);
|
||||
delete waiterForBytesWritten;
|
||||
waiterForBytesWritten = NULL;
|
||||
QMutexLocker locker(&lock);
|
||||
QIODevice::close();
|
||||
platClose();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user