From 3d23d269291ceb0b162fabd0552a2ec3639a094c Mon Sep 17 00:00:00 2001 From: Pawel Polanski Date: Wed, 2 Mar 2011 09:38:17 +0100 Subject: [PATCH] CODA: Added support for device info button in project settings (for CODA serial connections) --- src/plugins/debugger/gdb/codagdbadapter.cpp | 4 +- .../qt-s60/codaruncontrol.cpp | 6 +- .../qt-s60/s60deployconfigurationwidget.cpp | 222 +++++++++++++++++- .../qt-s60/s60deployconfigurationwidget.h | 11 + .../qt-s60/s60deploystep.cpp | 6 +- src/shared/symbianutils/codadevice.cpp | 53 ++++- src/shared/symbianutils/codadevice.h | 19 +- src/shared/symbianutils/json.cpp | 39 +++ src/shared/symbianutils/json.h | 2 + .../symbianutils/symbiandevicemanager.cpp | 108 ++++++++- .../symbianutils/symbiandevicemanager.h | 45 +++- 11 files changed, 487 insertions(+), 28 deletions(-) diff --git a/src/plugins/debugger/gdb/codagdbadapter.cpp b/src/plugins/debugger/gdb/codagdbadapter.cpp index 9eb53c934a2..ed32b6e4a9e 100644 --- a/src/plugins/debugger/gdb/codagdbadapter.cpp +++ b/src/plugins/debugger/gdb/codagdbadapter.cpp @@ -1043,7 +1043,7 @@ void CodaGdbAdapter::startAdapter() m_codaSocketIODevice = codaSocket; } else { m_codaDevice = SymbianUtils::SymbianDeviceManager::instance() - ->getTcfPort(parameters.remoteChannel); + ->getCodaDevice(parameters.remoteChannel); bool ok = m_codaDevice && m_codaDevice->device()->isOpen(); if (!ok) { @@ -1233,7 +1233,7 @@ void CodaGdbAdapter::cleanup() // Ensure process is stopped after being suspended. sendRunControlTerminateCommand(); disconnect(m_codaDevice.data(), 0, this, 0); - SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); + SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice); } } diff --git a/src/plugins/qt4projectmanager/qt-s60/codaruncontrol.cpp b/src/plugins/qt4projectmanager/qt-s60/codaruncontrol.cpp index 3dd0474289f..00f57c365bd 100644 --- a/src/plugins/qt4projectmanager/qt-s60/codaruncontrol.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/codaruncontrol.cpp @@ -117,7 +117,7 @@ bool CodaRunControl::setupLauncher() if (m_serialPort.length()) { // We get the port from SymbianDeviceManager appendMessage(tr("Connecting to '%1'...").arg(m_serialPort), NormalMessageFormat); - m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPort); + m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(m_serialPort); bool ok = m_codaDevice && m_codaDevice->device()->isOpen(); if (!ok) { @@ -333,7 +333,7 @@ void CodaRunControl::finishRunControl() m_runningProcessId.clear(); if (m_codaDevice) { disconnect(m_codaDevice.data(), 0, this, 0); - SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); + SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice); } m_state = StateUninit; emit finished(); @@ -344,7 +344,7 @@ QMessageBox *CodaRunControl::createCodaWaitingMessageBox(QWidget *parent) const QString title = tr("Waiting for CODA"); const QString text = tr("Qt Creator is waiting for the CODA application to connect.
" "Please make sure the application is running on " - "your mobile phone and the right IP address and port are " + "your mobile phone and the right IP address and/or port are " "configured in the project settings."); QMessageBox *mb = new QMessageBox(QMessageBox::Information, title, text, QMessageBox::Cancel, parent); return mb; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp index 7fd63accec7..bccf9cdd9f4 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "trkruncontrol.h" @@ -74,6 +75,8 @@ namespace Internal { const char STARTING_DRIVE_LETTER = 'C'; const char LAST_DRIVE_LETTER = 'Z'; +static const quint32 CODA_UID = 0x20021f96; + QString formatDriveText(const S60DeployConfiguration::DeviceDrive &drive) { char driveLetter = QChar::toUpper(static_cast(drive.first)); @@ -84,6 +87,39 @@ QString formatDriveText(const S60DeployConfiguration::DeviceDrive &drive) return QString("%1:%2 kB").arg(driveLetter).arg(drive.second); } +void startTable(QString &text) +{ + const char startTableC[] = ""; + if (text.contains(startTableC)) + return; + text.append(startTableC); +} + +void finishTable(QString &text) +{ + const char stopTableC[] = "
"; + text.replace(stopTableC, QLatin1String("")); + text.append(stopTableC); +} + +void addToTable(QTextStream &stream, const QString &key, const QString &value) +{ + const char tableRowStartC[] = ""; + const char tableRowSeparatorC[] = ""; + const char tableRowEndC[] = ""; + stream << tableRowStartC << key << tableRowSeparatorC << value << tableRowEndC; +} + +void addErrorToTable(QTextStream &stream, const QString &key, const QString &value) +{ + const char tableRowStartC[] = ""; + const char tableRowSeparatorC[] = ""; + const char tableRowEndC[] = ""; + const char errorSpanStartC[] = ""; + const char errorSpanEndC[] = ""; + stream << tableRowStartC << errorSpanStartC << key << tableRowSeparatorC << value << errorSpanEndC << tableRowEndC; +} + S60DeployConfigurationWidget::S60DeployConfigurationWidget(QWidget *parent) : ProjectExplorer::DeployConfigurationWidget(parent), m_detailsWidget(new Utils::DetailsWidget), @@ -188,6 +224,7 @@ void S60DeployConfigurationWidget::init(ProjectExplorer::DeployConfiguration *dc QHBoxLayout *infoHBoxLayout = new QHBoxLayout; m_deviceInfoLabel->setWordWrap(true); m_deviceInfoLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + m_deviceInfoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); infoHBoxLayout->addWidget(m_deviceInfoLabel); infoHBoxLayout->addWidget(m_deviceInfoButton); m_deviceInfoButton->setIcon(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation)); @@ -306,7 +343,8 @@ void S60DeployConfigurationWidget::updateSerialDevices() const QString newPortName = device(newIndex).portName(); m_deployConfiguration->setSerialPortName(newPortName); } - if (m_deployConfiguration->communicationChannel() != S60DeployConfiguration::CommunicationTrkSerialConnection) + if (m_deployConfiguration->communicationChannel() != S60DeployConfiguration::CommunicationTrkSerialConnection + && m_deployConfiguration->communicationChannel() != S60DeployConfiguration::CommunicationCodaSerialConnection) m_deviceInfoButton->setEnabled(false); } @@ -455,10 +493,10 @@ void S60DeployConfigurationWidget::slotWaitingForTrkClosed() void S60DeployConfigurationWidget::updateDeviceInfo() { - //TODO: No CODA device info! Implement it when it is available if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationTrkSerialConnection) { QTC_ASSERT(!m_infoLauncher, return) - setDeviceInfoLabel(tr("Connecting...")); + + setDeviceInfoLabel(tr("Connecting...")); // Do a launcher run with the ping protocol. Prompt to connect and // go asynchronous afterwards to pop up launch trk box if a timeout occurs. QString message; @@ -496,9 +534,185 @@ void S60DeployConfigurationWidget::updateDeviceInfo() } // Wait for either timeout or results m_deviceInfoButton->setEnabled(false); + } else if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationCodaSerialConnection) { + setDeviceInfoLabel(tr("Connecting...")); + const SymbianUtils::SymbianDevice commDev = currentDevice(); + m_codaInfoDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(commDev.portName()); + if (!m_codaInfoDevice->device()->isOpen()) { + setDeviceInfoLabel(m_codaInfoDevice->device()->errorString(), true); + return; + } + //TODO error handling - for now just throw the command at coda + m_codaInfoDevice->sendSymbianOsDataGetQtVersionCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getQtVersionCommandResult)); + m_deviceInfoButton->setEnabled(false); } else - setDeviceInfoLabel(tr("Information about the device is not available when using CODA."), true); + setDeviceInfoLabel(tr("Currently there is no information about device for this connection type."), true); } + void S60DeployConfigurationWidget::getQtVersionCommandResult(const Coda::CodaCommandResult &result) + { + if (result.type == Coda::CodaCommandResult::FailReply) { + setDeviceInfoLabel(tr("No device information available"), true); + m_deviceInfoButton->setEnabled(true); + return; + } else if (result.type == Coda::CodaCommandResult::CommandErrorReply){ + QString message; + startTable(message); + QTextStream str(&message); + addErrorToTable(str, tr("Qt version: "), tr("Not installed on device")); + finishTable(message); + setDeviceInfoLabel(message, false); + } else { + QString resultString; + if (result.values.count()) { + QHash obj = result.values[0].toVariant().toHash(); + QString ver = obj.value("qVersion").toString(); + + startTable(resultString); + QTextStream str(&resultString); + addToTable(str, tr("Qt version: "), ver); + QString systemVersion; + + int symVer = obj.value("symbianVersion").toInt(); + // Ugh why won't QSysInfo define these on non-symbian builds... + switch (symVer) { + case 10: + systemVersion.append("Symbian OS v9.2"); + break; + case 20: + systemVersion.append("Symbian OS v9.3"); + break; + case 30: + systemVersion.append("Symbian OS v9.4 / Symbian^1"); + break; + case 40: + systemVersion.append("Symbian^2"); + break; + case 50: + systemVersion.append("Symbian^3"); + break; + case 60: + systemVersion.append("Symbian^4"); + break; + default: + systemVersion.append(tr("Unrecognised Symbian version 0x%1").arg(symVer, 0, 16)); + break; + } + systemVersion.append(", "); + int s60Ver = obj.value("s60Version").toInt(); + switch (s60Ver) { + case 10: + systemVersion.append("S60 3rd Edition Feature Pack 1"); + break; + case 20: + systemVersion.append("S60 3rd Edition Feature Pack 2"); + break; + case 30: + systemVersion.append("S60 5th Edition"); + break; + case 40: + systemVersion.append("S60 5th Edition Feature Pack 1"); + break; + case 50: + systemVersion.append("S60 5th Edition Feature Pack 2"); + break; + default: + systemVersion.append(tr("Unrecognised S60 version 0x%1").arg(symVer, 0, 16)); + break; + } + addToTable(str, tr("OS version: "), systemVersion); + finishTable(resultString); + } + setDeviceInfoLabel(resultString); + } + m_codaInfoDevice->sendSymbianOsDataGetRomInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getRomInfoResult)); + } + + void S60DeployConfigurationWidget::getRomInfoResult(const Coda::CodaCommandResult &result) + { + if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) { + QString resultString = m_deviceInfoLabel->text(); + startTable(resultString); + QTextStream str(&resultString); + + QVariantHash obj = result.values[0].toVariant().toHash(); + QString romVersion = obj.value("romVersion", tr("unknown")).toString(); + romVersion.replace('\n', " "); // The ROM string is split across multiple lines, for some reason. + addToTable(str, tr("ROM version: "), romVersion); + + QString pr = obj.value("prInfo").toString(); + if (pr.length()) + addToTable(str, tr("Release:"), pr); + finishTable(resultString); + setDeviceInfoLabel(resultString); + } + + QList packagesOfInterest; + packagesOfInterest.append(CODA_UID); + m_codaInfoDevice->sendSymbianInstallGetPackageInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getInstalledPackagesResult), packagesOfInterest); + } + + void S60DeployConfigurationWidget::getInstalledPackagesResult(const Coda::CodaCommandResult &result) + { + if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) { + QString resultString = m_deviceInfoLabel->text(); + startTable(resultString); + QTextStream str(&resultString); + + QVariantList resultsList = result.values[0].toVariant().toList(); + foreach (const QVariant& var, resultsList) { + QVariantHash obj = var.toHash(); + if (obj.value("uid").toString().toUInt(0, 16) == CODA_UID) { + if (!obj.value("error").isNull()) { + // How can coda not be installed? Presumably some UID wrongness... + addErrorToTable(str, tr("CODA version: "), tr("Error reading CODA version")); + } else { + QVariantList version = obj.value("version").toList(); + addToTable(str, tr("CODA version: "), + QString("%1.%2.%3").arg(version[0].toInt()) + .arg(version[1].toInt()) + .arg(version[2].toInt())); + } + } + } + finishTable(resultString); + setDeviceInfoLabel(resultString); + } + + QStringList keys; + keys << QLatin1String("EDisplayXPixels"); + keys << QLatin1String("EDisplayYPixels"); + //keys << "EMemoryRAMFree"; + m_codaInfoDevice->sendSymbianOsDataGetHalInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getHalResult), keys); + } + + void S60DeployConfigurationWidget::getHalResult(const Coda::CodaCommandResult &result) + { + if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) { + QString resultString = m_deviceInfoLabel->text(); + QVariantList resultsList = result.values[0].toVariant().toList(); + int x = 0; + int y = 0; + foreach (const QVariant& var, resultsList) { + QVariantHash obj = var.toHash(); + if (obj.value("name").toString() == "EDisplayXPixels") + x = obj.value("value").toInt(); + else if (obj.value("name").toString() == "EDisplayYPixels") + y = obj.value("value").toInt(); + } + if (x && y) { + startTable(resultString); + QTextStream str(&resultString); + addToTable(str, tr("Screen size: "), QString("%1x%2").arg(x).arg(y)); + finishTable(resultString); + setDeviceInfoLabel(resultString); + } + } + + // Done with collecting info + m_deviceInfoButton->setEnabled(true); + SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaInfoDevice); + } + } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.h b/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.h index 2feb862f21b..30be5f4d88c 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60deployconfigurationwidget.h @@ -61,6 +61,11 @@ namespace SymbianUtils { class SymbianDevice; } +namespace Coda { + class CodaDevice; + struct CodaCommandResult; +} + namespace Qt4ProjectManager { namespace Internal { @@ -102,6 +107,11 @@ private: QWidget * createCommunicationChannel(); + void getQtVersionCommandResult(const Coda::CodaCommandResult &result); + void getRomInfoResult(const Coda::CodaCommandResult &result); + void getInstalledPackagesResult(const Coda::CodaCommandResult &result); + void getHalResult(const Coda::CodaCommandResult &result); + S60DeployConfiguration *m_deployConfiguration; Utils::DetailsWidget *m_detailsWidget; QComboBox *m_serialPortsCombo; @@ -117,6 +127,7 @@ private: Utils::IpAddressLineEdit *m_ipAddress; QRadioButton *m_trkRadioButton; QRadioButton *m_codaRadioButton; + QSharedPointer m_codaInfoDevice; }; } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp b/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp index a774965522a..9835bca70bc 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60deploystep.cpp @@ -317,7 +317,7 @@ void S60DeployStep::stop() } else { if (m_codaDevice) { disconnect(m_codaDevice.data(), 0, this, 0); - SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); + SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice); } } emit finished(false); @@ -384,7 +384,7 @@ void S60DeployStep::startDeployment() } } else if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) { appendMessage(tr("Deploying application to '%1'...").arg(m_serialPortFriendlyName), false); - m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPortName); + m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(m_serialPortName); bool ok = m_codaDevice && m_codaDevice->device()->isOpen(); if (!ok) { QString deviceError = tr("No such port"); @@ -442,7 +442,7 @@ void S60DeployStep::run(QFutureInterface &fi) if (m_codaDevice) { disconnect(m_codaDevice.data(), 0, this, 0); - SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); + SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice); } delete m_eventLoop; diff --git a/src/shared/symbianutils/codadevice.cpp b/src/shared/symbianutils/codadevice.cpp index 3dbbe6735bb..ccf9ebe1661 100644 --- a/src/shared/symbianutils/codadevice.cpp +++ b/src/shared/symbianutils/codadevice.cpp @@ -936,8 +936,6 @@ void CodaDevice::sendProcessStartCommand(const CodaCallback &callBack, const QString sysBin = QLatin1String("c:/sys/bin"); const QString binaryFileName = slashPos == -1 ? binaryIn : binaryIn.mid(slashPos + 1); - // Fixup: Does argv[0] convention exist on Symbian? - arguments.push_front(binaryFileName); if (workingDirectory.isEmpty()) workingDirectory = sysBin; @@ -1316,8 +1314,7 @@ void CodaDevice::sendRegistersSetCommand(const CodaCallback &callBack, value, cookie); } -//static const char outputListenerIDC[] = "org.eclipse.cdt.debug.edc.ui.ProgramOutputConsoleLogger"; -static const char outputListenerIDC[] = "ProgramOutputConsoleLogger"; //TODO: this one might be the correct one +static const char outputListenerIDC[] = "ProgramOutputConsoleLogger"; void CodaDevice::sendLoggingAddListenerCommand(const CodaCallback &callBack, const QVariant &cookie) @@ -1346,6 +1343,34 @@ void CodaDevice::sendSymbianOsDataFindProcessesCommand(const CodaCallback &callB sendCodaMessage(MessageWithReply, SymbianOSData, "findRunningProcesses", data, callBack, cookie); } +void CodaDevice::sendSymbianOsDataGetQtVersionCommand(const CodaCallback &callBack, + const QVariant &cookie) +{ + sendCodaMessage(MessageWithReply, SymbianOSData, "getQtVersion", QByteArray(), callBack, cookie); +} + +void CodaDevice::sendSymbianOsDataGetRomInfoCommand(const CodaCallback &callBack, + const QVariant &cookie) +{ + sendCodaMessage(MessageWithReply, SymbianOSData, "getRomInfo", QByteArray(), callBack, cookie); +} + +void CodaDevice::sendSymbianOsDataGetHalInfoCommand(const CodaCallback &callBack, + const QStringList &keys, + const QVariant &cookie) +{ + QByteArray data; + JsonInputStream str(data); + str << '['; + for (int i = 0; i < keys.count(); ++i) { + if (i) + str << ','; + str << keys[i]; + } + str << ']'; + sendCodaMessage(MessageWithReply, SymbianOSData, "getHalInfo", data, callBack, cookie); +} + void Coda::CodaDevice::sendFileSystemOpenCommand(const Coda::CodaCallback &callBack, const QByteArray &name, unsigned flags, @@ -1409,4 +1434,24 @@ void Coda::CodaDevice::sendSymbianInstallUIInstallCommand(const Coda::CodaCallba str << file; sendCodaMessage(MessageWithReply, SymbianInstallService, "installWithUI", data, callBack, cookie); } + +void Coda::CodaDevice::sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack, + const QList &packages, + const QVariant &cookie) +{ + QByteArray data; + JsonInputStream str(data); + str << '['; + for (int i = 0; i < packages.count(); ++i) { + if (i) + str << ','; + QString pkgString; + pkgString.setNum(packages[i], 16); + str << pkgString; + } + str << ']'; + sendCodaMessage(MessageWithReply, SymbianInstallService, "getPackageInfo", data, callBack, cookie); +} + + } // namespace Coda diff --git a/src/shared/symbianutils/codadevice.h b/src/shared/symbianutils/codadevice.h index 4d1032c54ec..48c0dcd9161 100644 --- a/src/shared/symbianutils/codadevice.h +++ b/src/shared/symbianutils/codadevice.h @@ -131,11 +131,6 @@ http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Services * Commands can be sent along with callbacks that are passed a * CodaCommandResult and an opaque QVariant cookie. In addition, events are emitted. * - * Note: As of 11.8.2010, TCF Trk 4.0.5 does not currently support 'Registers::getm' - * (get multiple registers). So, CodaDevice emulates it by sending a sequence of - * single commands. As soon as 'Registers::getm' is natively supported, all code - * related to 'FakeRegisterGetm' should be removed. The workaround requires that - * the register name is known. * CODA notes: * - Commands are accepted only after receiving the Locator Hello event * - Serial communication initiation sequence: @@ -351,6 +346,10 @@ public: const QByteArray &file, const QVariant &cookie = QVariant()); + void sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack, + const QList &packages, + const QVariant &cookie = QVariant()); + void sendLoggingAddListenerCommand(const CodaCallback &callBack, const QVariant &cookie = QVariant()); @@ -363,6 +362,16 @@ public: const QByteArray &uid, const QVariant &cookie = QVariant()); + void sendSymbianOsDataGetQtVersionCommand(const CodaCallback &callBack, + const QVariant &cookie = QVariant()); + + void sendSymbianOsDataGetRomInfoCommand(const CodaCallback &callBack, + const QVariant &cookie = QVariant()); + + void sendSymbianOsDataGetHalInfoCommand(const CodaCallback &callBack, + const QStringList &keys = QStringList(), + const QVariant &cookie = QVariant()); + // Settings void sendSettingsEnableLogCommand(); diff --git a/src/shared/symbianutils/json.cpp b/src/shared/symbianutils/json.cpp index 980fa741161..b52d381731e 100644 --- a/src/shared/symbianutils/json.cpp +++ b/src/shared/symbianutils/json.cpp @@ -415,6 +415,45 @@ QByteArray JsonValue::toString(bool multiline, int indent) const return result; } + +QVariant JsonValue::toVariant() const +{ + switch (m_type) { + case String: + return QString(m_data); + case Number: { + bool ok; + qint64 val = QString(m_data).toLongLong(&ok); + if (ok) + return val; + return QVariant(); + } + case Object: { + QHash hash; + for (int i = 0; i < m_children.size(); ++i) { + QString name(m_children[i].name()); + QVariant val = m_children[i].toVariant(); + hash.insert(name, val); + } + return hash; + } + case Array: { + QList list; + for (int i = 0; i < m_children.size(); ++i) { + list.append(m_children[i].toVariant()); + } + return list; + } + case Boolean: + return data() == QByteArray("true"); + case Invalid: + case NullObject: + default: + return QVariant(); + } +} + + void JsonValue::fromString(const QByteArray &ba) { const char *from = ba.constBegin(); diff --git a/src/shared/symbianutils/json.h b/src/shared/symbianutils/json.h index 6ab556e12a1..8dfa475a73b 100644 --- a/src/shared/symbianutils/json.h +++ b/src/shared/symbianutils/json.h @@ -87,6 +87,8 @@ public: void fromString(const QByteArray &str); void setStreamOutput(const QByteArray &name, const QByteArray &content); + QVariant toVariant() const; + private: static QByteArray parseCString(const char *&from, const char *to); static QByteArray parseNumber(const char *&from, const char *to); diff --git a/src/shared/symbianutils/symbiandevicemanager.cpp b/src/shared/symbianutils/symbiandevicemanager.cpp index 79dab3ad14e..5d340b5062d 100644 --- a/src/shared/symbianutils/symbiandevicemanager.cpp +++ b/src/shared/symbianutils/symbiandevicemanager.cpp @@ -355,7 +355,7 @@ SymbianDeviceManager::TrkDevicePtr return rc; } -CodaDevicePtr SymbianDeviceManager::getTcfPort(const QString &port) +CodaDevicePtr SymbianDeviceManager::getCodaDevice(const QString &port) { ensureInitialized(); const int idx = findByPortName(port); @@ -419,7 +419,7 @@ void SymbianDeviceManager::customEvent(QEvent *event) } } -void SymbianDeviceManager::releaseTcfPort(CodaDevicePtr &port) +void SymbianDeviceManager::releaseCodaDevice(CodaDevicePtr &port) { if (port) { // Check if this was the last reference to the port, if so close it after a short delay @@ -613,4 +613,106 @@ SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm) return d; } -} // namespace SymbianUtilsInternal +OstChannel *SymbianDeviceManager::getOstChannel(const QString &port, uchar channelId) +{ + CodaDevicePtr coda = getCodaDevice(port); + if (coda.isNull() || !coda->device()->isOpen()) + return 0; + return new OstChannel(coda, channelId); +} + +struct OstChannelPrivate +{ + CodaDevicePtr m_codaPtr; + QByteArray m_dataBuffer; + uchar m_channelId; + bool m_hasReceivedData; +}; + +OstChannel::OstChannel(const CodaDevicePtr &codaPtr, uchar channelId) + : d(new OstChannelPrivate) +{ + d->m_codaPtr = codaPtr; + d->m_channelId = channelId; + d->m_hasReceivedData = false; + connect(codaPtr.data(), SIGNAL(unknownEvent(uchar, QByteArray)), this, SLOT(ostDataReceived(uchar,QByteArray))); + connect(codaPtr->device().data(), SIGNAL(aboutToClose()), this, SLOT(deviceAboutToClose())); + QIODevice::open(ReadWrite|Unbuffered); +} + +void OstChannel::close() +{ + QIODevice::close(); + if (d && d->m_codaPtr.data()) { + disconnect(d->m_codaPtr.data(), 0, this, 0); + SymbianDeviceManager::instance()->releaseCodaDevice(d->m_codaPtr); + } +} + +OstChannel::~OstChannel() +{ + close(); + delete d; +} + +void OstChannel::flush() +{ + //TODO d->m_codaPtr->device()- +} + +qint64 OstChannel::bytesAvailable() const +{ + return d->m_dataBuffer.size(); +} + +bool OstChannel::isSequential() const +{ + return true; +} + +qint64 OstChannel::readData(char *data, qint64 maxSize) +{ + qint64 amount = qMin(maxSize, (qint64)d->m_dataBuffer.size()); + qMemCopy(data, d->m_dataBuffer.constData(), amount); + d->m_dataBuffer.remove(0, amount); + return amount; +} + +qint64 OstChannel::writeData(const char *data, qint64 maxSize) +{ + static const qint64 KMaxOstPayload = 1022; + // If necessary, split the packet up + while (maxSize) { + QByteArray dataBuf = QByteArray::fromRawData(data, qMin(KMaxOstPayload, maxSize)); + d->m_codaPtr->writeCustomData(d->m_channelId, dataBuf); + data += dataBuf.length(); + maxSize -= dataBuf.length(); + } + return maxSize; +} + +void OstChannel::ostDataReceived(uchar channelId, const QByteArray &aData) +{ + if (channelId == d->m_channelId) { + d->m_hasReceivedData = true; + d->m_dataBuffer.append(aData); + emit readyRead(); + } +} + +Coda::CodaDevice& OstChannel::codaDevice() const +{ + return *d->m_codaPtr; +} + +bool OstChannel::hasReceivedData() const +{ + return isOpen() && d->m_hasReceivedData; +} + +void OstChannel::deviceAboutToClose() +{ + close(); +} + +} // namespace SymbianUtils diff --git a/src/shared/symbianutils/symbiandevicemanager.h b/src/shared/symbianutils/symbiandevicemanager.h index 6b12340a446..35753f86124 100644 --- a/src/shared/symbianutils/symbiandevicemanager.h +++ b/src/shared/symbianutils/symbiandevicemanager.h @@ -36,7 +36,7 @@ #include "symbianutils_global.h" -#include +#include #include #include @@ -56,6 +56,7 @@ namespace SymbianUtils { struct SymbianDeviceManagerPrivate; class SymbianDeviceData; +class OstChannel; enum DeviceCommunicationType { SerialPortCommunication = 0, @@ -152,11 +153,15 @@ public: // Gets the CodaDevice, 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 CodaDevice::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 - CodaDevicePtr getTcfPort(const QString &port); + // Caller should call releaseCodaDevice if they want the port to auto-close itself + CodaDevicePtr getCodaDevice(const QString &port); + + // Note this function makes no guarantee that someone else isn't already listening on this channel id, or that there is anything on the other end + // Returns NULL if the port couldn't be opened + OstChannel *getOstChannel(const QString &port, uchar channelId); // Caller is responsible for disconnecting any signals from aPort - do not assume the CodaDevice will be deleted as a result of this call. On return aPort will be clear()ed. - void releaseTcfPort(CodaDevicePtr &aPort); + void releaseCodaDevice(CodaDevicePtr &aPort); int findByPortName(const QString &p) const; QString friendlyNameForPort(const QString &port) const; @@ -188,6 +193,38 @@ private: SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &); +struct OstChannelPrivate; + +class SYMBIANUTILS_EXPORT OstChannel : public QIODevice +{ + Q_OBJECT + +public: + void close(); + ~OstChannel(); + void flush(); + + qint64 bytesAvailable() const; + bool isSequential() const; + bool hasReceivedData() const; + + Coda::CodaDevice &codaDevice() const; + +private slots: + void ostDataReceived(uchar channelId, const QByteArray &aData); + void deviceAboutToClose(); + +private: + OstChannel(const CodaDevicePtr &codaPtr, uchar channelId); + Q_DISABLE_COPY(OstChannel) + qint64 readData(char *data, qint64 maxSize); + qint64 writeData(const char *data, qint64 maxSize); + +private: + OstChannelPrivate *d; + friend class SymbianDeviceManager; +}; + } // namespace SymbianUtils #endif // SYMBIANDEVICEMANAGER_H