diff options
author | Alessandro Portale <[email protected]> | 2012-08-22 13:27:25 +0200 |
---|---|---|
committer | Alessandro Portale <[email protected]> | 2012-08-22 13:42:42 +0200 |
commit | ae23d50576ac076aeb22a3d56abdb5e2c1d9b327 (patch) | |
tree | c3849a2481be618e6635e27e80e7263d687480e2 /src/shared | |
parent | c107b10bae60abc483793ec1da55266b77630fcb (diff) |
Removal of Symbian support
Qt Creator's support for Symbian was at its peak in version
2.4.x. Nobody really verified it in Qt Creator 2.5 or 2.6.
It is most likely rotten. Let's remove it!
Also, the Symbian support code was spread throughout the whole
Qt Creator code base. The plugin interfaces evolved in the
meantime and target platforms like Android or QNX have 99% of
their code in separate plugins.
In case anyone wants to revive Symbian support in Qt Creator,
please create a plugin for it.
Change-Id: I56a758a3e2fd5b8c64d9aeb8f63d8e916c4883be
Reviewed-by: Alessandro Portale <[email protected]>
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/json/json_global.h | 2 | ||||
-rw-r--r-- | src/shared/proparser/spec_post.prf | 7 | ||||
-rw-r--r-- | src/shared/symbianutils/callback.h | 149 | ||||
-rw-r--r-- | src/shared/symbianutils/codadevice.cpp | 1479 | ||||
-rw-r--r-- | src/shared/symbianutils/codadevice.h | 432 | ||||
-rw-r--r-- | src/shared/symbianutils/codamessage.cpp | 592 | ||||
-rw-r--r-- | src/shared/symbianutils/codamessage.h | 327 | ||||
-rw-r--r-- | src/shared/symbianutils/codautils.cpp | 591 | ||||
-rw-r--r-- | src/shared/symbianutils/codautils.h | 158 | ||||
-rw-r--r-- | src/shared/symbianutils/codautils_p.h | 51 | ||||
-rw-r--r-- | src/shared/symbianutils/symbiandevicemanager.cpp | 804 | ||||
-rw-r--r-- | src/shared/symbianutils/symbiandevicemanager.h | 208 | ||||
-rw-r--r-- | src/shared/symbianutils/symbianutils.pri | 42 | ||||
-rw-r--r-- | src/shared/symbianutils/symbianutils_global.h | 44 | ||||
-rw-r--r-- | src/shared/symbianutils/virtualserialdevice.cpp | 78 | ||||
-rw-r--r-- | src/shared/symbianutils/virtualserialdevice.h | 115 | ||||
-rw-r--r-- | src/shared/symbianutils/virtualserialdevice_posix.cpp | 338 | ||||
-rw-r--r-- | src/shared/symbianutils/virtualserialdevice_win.cpp | 362 |
18 files changed, 1 insertions, 5778 deletions
diff --git a/src/shared/json/json_global.h b/src/shared/json/json_global.h index 93caeaac876..910bb0948b9 100644 --- a/src/shared/json/json_global.h +++ b/src/shared/json/json_global.h @@ -41,4 +41,4 @@ # define JSON_EXPORT Q_DECL_IMPORT #endif -#endif // SYMBIANUTILS_GLOBAL_H +#endif // JSON_GLOBAL_H diff --git a/src/shared/proparser/spec_post.prf b/src/shared/proparser/spec_post.prf index 7560f95c415..fcc7314ce55 100644 --- a/src/shared/proparser/spec_post.prf +++ b/src/shared/proparser/spec_post.prf @@ -15,11 +15,6 @@ isEmpty(QMAKE_PLATFORM) { |equals(MAKEFILE_GENERATOR, XCODE)) { } else:equals(MAKEFILE_GENERATOR, GBUILD) { TARGET_PLATFORM = unix - } else:if(equals(MAKEFILE_GENERATOR, SYMBIAN_ABLD) \ - |equals(MAKEFILE_GENERATOR, SYMBIAN_SBSV2) \ - |equals(MAKEFILE_GENERATOR, SYMBIAN_UNIX) \ - |equals(MAKEFILE_GENERATOR, SYMBIAN_MINGW)) { - TARGET_PLATFORM = symbian } else { error("Qmake spec sets an invalid MAKEFILE_GENERATOR.") } @@ -30,8 +25,6 @@ isEmpty(QMAKE_PLATFORM) { QMAKE_PLATFORM = mac macx unix else:equals(TARGET_PLATFORM, win32): \ QMAKE_PLATFORM = win32 - else:equals(TARGET_PLATFORM, symbian): \ - QMAKE_PLATFORM = symbian unix else: \ error("Qmake spec sets an invalid TARGET_PLATFORM.") } diff --git a/src/shared/symbianutils/callback.h b/src/shared/symbianutils/callback.h deleted file mode 100644 index 40a86769258..00000000000 --- a/src/shared/symbianutils/callback.h +++ /dev/null @@ -1,149 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef DEBUGGER_CALLBACK_H -#define DEBUGGER_CALLBACK_H - -#include "symbianutils_global.h" - -namespace Coda { -namespace Internal { - -/* Helper class for the 1-argument functor: - * Cloneable base class for the implementation which is - * invokeable with the argument. */ -template <class Argument> -class CallbackImplBase -{ - Q_DISABLE_COPY(CallbackImplBase) -public: - CallbackImplBase() {} - virtual CallbackImplBase *clone() const = 0; - virtual void invoke(Argument a) = 0; - virtual ~CallbackImplBase() {} -}; - -/* Helper class for the 1-argument functor: Implementation for - * a class instance with a member function pointer. */ -template <class Class, class Argument> -class CallbackMemberPtrImpl : public CallbackImplBase<Argument> -{ -public: - typedef void (Class::*MemberFuncPtr)(Argument); - - CallbackMemberPtrImpl(Class *instance, - MemberFuncPtr memberFunc) : - m_instance(instance), - m_memberFunc(memberFunc) {} - - virtual CallbackImplBase<Argument> *clone() const - { - return new CallbackMemberPtrImpl<Class, Argument>(m_instance, m_memberFunc); - } - - virtual void invoke(Argument a) - { (m_instance->*m_memberFunc)(a); } -private: - Class *m_instance; - MemberFuncPtr m_memberFunc; -}; - -} // namespace Internal - -/* Default-constructible, copyable 1-argument functor providing an - * operator()(Argument) that invokes a member function of a class: - * \code -class Foo { -public: - void print(const std::string &); -}; -... -Foo foo; -Callback<const std::string &> f1(&foo, &Foo::print); -f1("test"); -\endcode */ - -template <class Argument> -class Callback -{ -public: - Callback() : m_impl(0) {} - - template <class Class> - Callback(Class *instance, void (Class::*memberFunc)(Argument)) : - m_impl(new Internal::CallbackMemberPtrImpl<Class,Argument>(instance, memberFunc)) - {} - - ~Callback() - { - clean(); - } - - Callback(const Callback &rhs) : - m_impl(0) - { - if (rhs.m_impl) - m_impl = rhs.m_impl->clone(); - } - - Callback &operator=(const Callback &rhs) - { - if (this != &rhs) { - clean(); - if (rhs.m_impl) - m_impl = rhs.m_impl->clone(); - } - return *this; - } - - bool isNull() const { return m_impl == 0; } - operator bool() const { return !isNull(); } - - void operator()(Argument a) - { - if (m_impl) - m_impl->invoke(a); - } - -private: - void clean() - { - if (m_impl) { - delete m_impl; - m_impl = 0; - } - } - - Internal::CallbackImplBase<Argument> *m_impl; -}; - -} // namespace Coda - -#endif // DEBUGGER_CALLBACK_H diff --git a/src/shared/symbianutils/codadevice.cpp b/src/shared/symbianutils/codadevice.cpp deleted file mode 100644 index 3a22ec9ae10..00000000000 --- a/src/shared/symbianutils/codadevice.cpp +++ /dev/null @@ -1,1479 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "codadevice.h" -#include "json.h" -#include "codautils.h" - -#include <QAbstractSocket> -#include <QDebug> -#include <QVector> -#include <QQueue> -#include <QTextStream> -#include <QDateTime> -#include <QFileInfo> - -enum { debug = 0 }; - -static const char tcpMessageTerminatorC[] = "\003\001"; - -// Serial Ping: 0xfc,0x1f -static const char serialPingC[] = "\xfc\x1f"; -// Serial Pong: 0xfc,0xf1, followed by version info -static const char serialPongC[] = "\xfc\xf1"; - -static const char locatorAnswerC[] = "E\0Locator\0Hello\0[\"Locator\"]"; - -/* Serial messages > (1K - 2) have to chunked in order to pass the USB - * router as '0xfe char(chunkCount - 1) data' ... '0x0 char(chunkCount - 2) data' - * ... '0x0 0x0 last-data' */ -static const unsigned serialChunkLength = 0x400; // 1K max USB router -static const int maxSerialMessageLength = 0x10000; // given chunking scheme - -static const char validProtocolIdStart = (char)0x90; -static const char validProtocolIdEnd = (char)0x95; -static const char codaProtocolId = (char)0x92; -static const unsigned char serialChunkingStart = 0xfe; -static const unsigned char serialChunkingContinuation = 0x0; -enum { SerialChunkHeaderSize = 2 }; - -// Create USB router frame -static inline void encodeSerialFrame(const QByteArray &data, QByteArray *target, char protocolId) -{ - target->append(char(0x01)); - target->append(protocolId); - appendShort(target, ushort(data.size()), Coda::BigEndian); - target->append(data); -} - -// Split in chunks of 1K according to CODA protocol chunking -static inline QByteArray encodeUsbSerialMessage(const QByteArray &dataIn) -{ - // Reserve 2 header bytes - static const int chunkSize = serialChunkLength - SerialChunkHeaderSize; - const int size = dataIn.size(); - QByteArray frame; - // Do we need to split? - if (size < chunkSize) { // Nope, all happy. - frame.reserve(size + 4); - encodeSerialFrame(dataIn, &frame, codaProtocolId); - return frame; - } - // Split. - unsigned chunkCount = size / chunkSize; - if (size % chunkSize) - chunkCount++; - if (debug) - qDebug("Serial: Splitting message of %d bytes into %u chunks of %d", size, chunkCount, chunkSize); - - frame.reserve((4 + serialChunkLength) * chunkCount); - int pos = 0; - for (unsigned c = chunkCount - 1; pos < size ; c--) { - QByteArray chunk; // chunk with long message start/continuation code - chunk.reserve(serialChunkLength); - chunk.append(pos ? serialChunkingContinuation : serialChunkingStart); - chunk.append(char(static_cast<unsigned char>(c))); // Avoid any signedness issues. - const int chunkEnd = qMin(pos + chunkSize, size); - chunk.append(dataIn.mid(pos, chunkEnd - pos)); - encodeSerialFrame(chunk, &frame, codaProtocolId); - pos = chunkEnd; - } - if (debug > 1) - qDebug("Serial chunked:\n%s", qPrintable(Coda::formatData(frame))); - return frame; -} - -using namespace Json; -namespace Coda { -// ------------- CodaCommandError - -CodaCommandError::CodaCommandError() : timeMS(0), code(0), alternativeCode(0) -{ -} - -void CodaCommandError::clear() -{ - timeMS = 0; - code = alternativeCode = 0; - format.clear(); - alternativeOrganization.clear(); -} - -QDateTime CodaCommandResult::codaTimeToQDateTime(quint64 codaTimeMS) -{ - const QDateTime time(QDate(1970, 1, 1)); - return time.addMSecs(codaTimeMS); -} - -void CodaCommandError::write(QTextStream &str) const -{ - if (isError()) { - if (debug && timeMS) - str << CodaCommandResult::codaTimeToQDateTime(timeMS).toString(Qt::ISODate) << ": "; - str << "'" << format << '\'' //for symbian the format is the real error message - << " Code: " << code; - if (!alternativeOrganization.isEmpty()) - str << " ('" << alternativeOrganization << "', code: " << alternativeCode << ')'; - } else{ - str << "<No error>"; - } -} - -QString CodaCommandError::toString() const -{ - QString rc; - QTextStream str(&rc); - write(str); - return rc; -} - -bool CodaCommandError::isError() const -{ - return timeMS != 0 || code != 0 || !format.isEmpty() || alternativeCode != 0; -} - -/* {"Time":1277459762255,"Code":1,"AltCode":-6,"AltOrg":"POSIX","Format":"Unknown error: -6"} */ -bool CodaCommandError::parse(const QVector<JsonValue> &values) -{ - // Parse an arbitrary hash (that could as well be a command response) - // and check for error elements. It looks like sometimes errors are appended - // to other values. - unsigned errorKeyCount = 0; - clear(); - do { - if (values.isEmpty()) - break; - // Errors are mostly appended, except for FileSystem::open, in which case - // a string "null" file handle (sic!) follows the error. - const int last = values.size() - 1; - const int checkIndex = last == 1 && values.at(last).data() == "null" ? - last - 1 : last; - if (values.at(checkIndex).type() != JsonValue::Object) - break; - foreach (const JsonValue &c, values.at(checkIndex).children()) { - if (c.name() == "Time") { - timeMS = c.data().toULongLong(); - errorKeyCount++; - } else if (c.name() == "Code") { - code = c.data().toLongLong(); - errorKeyCount++; - } else if (c.name() == "Format") { - format = c.data(); - errorKeyCount++; - } else if (c.name() == "AltCode") { - alternativeCode = c.data().toULongLong(); - errorKeyCount++; - } else if (c.name() == "AltOrg") { - alternativeOrganization = c.data(); - errorKeyCount++; - } - } - } while (false); - const bool errorFound = errorKeyCount >= 2u; // Should be at least 'Time', 'Code'. - if (!errorFound) - clear(); - if (debug) { - qDebug("CodaCommandError::parse: Found error %d (%u): ", errorFound, errorKeyCount); - if (!values.isEmpty()) - qDebug() << values.back().toString(); - } - return errorFound; -} - -// ------------ CodaCommandResult - -CodaCommandResult::CodaCommandResult(Type t) : - type(t), service(LocatorService) -{ -} - -CodaCommandResult::CodaCommandResult(char typeChar, Services s, - const QByteArray &r, - const QVector<JsonValue> &v, - const QVariant &ck) : - type(FailReply), service(s), request(r), values(v), cookie(ck) -{ - switch (typeChar) { - case 'N': - type = FailReply; - break; - case 'P': - type = ProgressReply; - break; - case 'R': - type = commandError.parse(values) ? CommandErrorReply : SuccessReply; - break; - default: - qWarning("Unknown CODA's reply type '%c'", typeChar); - } -} - -QString CodaCommandResult::errorString() const -{ - QString rc; - QTextStream str(&rc); - - switch (type) { - case SuccessReply: - case ProgressReply: - str << "<No error>"; - return rc; - case FailReply: - str << "NAK"; - return rc; - case CommandErrorReply: - commandError.write(str); - break; - } - if (debug) { - // Append the failed command for reference - str << " (Command was: '"; - QByteArray printableRequest = request; - printableRequest.replace('\0', '|'); - str << printableRequest << "')"; - } - return rc; -} - -QString CodaCommandResult::toString() const -{ - QString rc; - QTextStream str(&rc); - str << "Command answer "; - switch (type) { - case SuccessReply: - str << "[success]"; - break; - case CommandErrorReply: - str << "[command error]"; - break; - case FailReply: - str << "[fail (NAK)]"; - break; - case ProgressReply: - str << "[progress]"; - break; - } - str << ", " << values.size() << " values(s) to request: '"; - QByteArray printableRequest = request; - printableRequest.replace('\0', '|'); - str << printableRequest << "' "; - if (cookie.isValid()) - str << " cookie: " << cookie.toString(); - str << '\n'; - for (int i = 0, count = values.size(); i < count; i++) - str << '#' << i << ' ' << values.at(i).toString() << '\n'; - if (type == CommandErrorReply) - str << "Error: " << errorString(); - return rc; -} - -CodaStatResponse::CodaStatResponse() : size(0) -{ -} - -struct CodaSendQueueEntry -{ - typedef CodaDevice::MessageType MessageType; - - explicit CodaSendQueueEntry(MessageType mt, - int tok, - Services s, - const QByteArray &d, - const CodaCallback &cb= CodaCallback(), - const QVariant &ck = QVariant()) : - messageType(mt), service(s), data(d), token(tok), cookie(ck), callback(cb) {} - - MessageType messageType; - Services service; - QByteArray data; - int token; - QVariant cookie; - CodaCallback callback; - unsigned specialHandling; -}; - -struct CodaDevicePrivate { - typedef CodaDevice::IODevicePtr IODevicePtr; - typedef QHash<int, CodaSendQueueEntry> TokenWrittenMessageMap; - - CodaDevicePrivate(); - - const QByteArray m_tcpMessageTerminator; - - IODevicePtr m_device; - unsigned m_verbose; - QByteArray m_readBuffer; - QByteArray m_serialBuffer; // for chunked messages - int m_token; - QQueue<CodaSendQueueEntry> m_sendQueue; - TokenWrittenMessageMap m_writtenMessages; - QVector<QByteArray> m_registerNames; - QVector<QByteArray> m_fakeGetMRegisterValues; - bool m_serialFrame; - bool m_serialPingOnly; -}; - -CodaDevicePrivate::CodaDevicePrivate() : - m_tcpMessageTerminator(tcpMessageTerminatorC), - m_verbose(0), m_token(0), m_serialFrame(false), m_serialPingOnly(false) -{ -} - -CodaDevice::CodaDevice(QObject *parent) : - QObject(parent), d(new CodaDevicePrivate) -{ - if (debug) setVerbose(true); -} - -CodaDevice::~CodaDevice() -{ - delete d; -} - -QVector<QByteArray> CodaDevice::registerNames() const -{ - return d->m_registerNames; -} - -void CodaDevice::setRegisterNames(const QVector<QByteArray>& n) -{ - d->m_registerNames = n; - if (d->m_verbose) { - QString msg; - QTextStream str(&msg); - const int count = n.size(); - str << "Registers (" << count << "): "; - for (int i = 0; i < count; i++) - str << '#' << i << '=' << n.at(i) << ' '; - emitLogMessage(msg); - } -} - -CodaDevice::IODevicePtr CodaDevice::device() const -{ - return d->m_device; -} - -CodaDevice::IODevicePtr CodaDevice::takeDevice() -{ - const IODevicePtr old = d->m_device; - if (!old.isNull()) { - old.data()->disconnect(this); - d->m_device = IODevicePtr(); - } - d->m_readBuffer.clear(); - d->m_token = 0; - d->m_sendQueue.clear(); - return old; -} - -void CodaDevice::setDevice(const IODevicePtr &dp) -{ - if (dp.data() == d->m_device.data()) - return; - if (dp.isNull()) { - emitLogMessage(QLatin1String("Internal error: Attempt to set NULL device.")); - return; - } - takeDevice(); - d->m_device = dp; - connect(dp.data(), SIGNAL(readyRead()), this, SLOT(slotDeviceReadyRead())); - if (QAbstractSocket *s = qobject_cast<QAbstractSocket *>(dp.data())) { - connect(s, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotDeviceError())); - connect(s, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(slotDeviceSocketStateChanged())); - } -} - -void CodaDevice::slotDeviceError() -{ - const QString message = d->m_device->errorString(); - emitLogMessage(message); - emit error(message); -} - -void CodaDevice::slotDeviceSocketStateChanged() -{ - if (const QAbstractSocket *s = qobject_cast<const QAbstractSocket *>(d->m_device.data())) { - const QAbstractSocket::SocketState st = s->state(); - switch (st) { - case QAbstractSocket::UnconnectedState: - emitLogMessage(QLatin1String("Unconnected")); - break; - case QAbstractSocket::HostLookupState: - emitLogMessage(QLatin1String("HostLookupState")); - break; - case QAbstractSocket::ConnectingState: - emitLogMessage(QLatin1String("Connecting")); - break; - case QAbstractSocket::ConnectedState: - emitLogMessage(QLatin1String("Connected")); - break; - case QAbstractSocket::ClosingState: - emitLogMessage(QLatin1String("Closing")); - break; - default: - emitLogMessage(QString::fromLatin1("State %1").arg(st)); - break; - } - } -} - -static inline QString debugMessage(QByteArray message, const char *prefix = 0) -{ - const bool isBinary = !message.isEmpty() && message.at(0) < 0; - if (isBinary) { - message = message.toHex(); // Some serial special message - } else { - message.replace('\0', '|'); - } - const QString messageS = QString::fromLatin1(message); - return prefix ? - (QLatin1String(prefix) + messageS) : messageS; -} - -void CodaDevice::slotDeviceReadyRead() -{ - const QByteArray newData = d->m_device->readAll(); - d->m_readBuffer += newData; - if (debug) - qDebug("ReadBuffer: %s", qPrintable(Coda::stringFromArray(newData))); - if (d->m_serialFrame) { - deviceReadyReadSerial(); - } else { - deviceReadyReadTcp(); - } -} - -// Find a serial header in input stream '0x1', '0x92', 'lenH', 'lenL' -// and return message position and size. -QPair<int, int> CodaDevice::findSerialHeader(QByteArray &in) -{ - static const char header1 = 0x1; - // Header should in theory always be at beginning of - // buffer. Warn if there are bogus data in-between. - - while (in.size() >= 4) { - if (in.at(0) == header1 && in.at(1) == codaProtocolId) { - // Good packet - const int length = Coda::extractShort(in.constData() + 2); - return QPair<int, int>(4, length); - } else if (in.at(0) == header1 && in.at(1) >= validProtocolIdStart && in.at(1) <= validProtocolIdEnd) { - // We recognise it but it's not a CODA message - emit it for any interested party to handle - const int length = Coda::extractShort(in.constData() + 2); - if (4 + length <= in.size()) { - // We have all the data - QByteArray data(in.mid(4, length)); - emit unknownEvent(in.at(1), 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(Coda::stringFromArray(bad)), nextHeader); - 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() -{ - do { - // Extract message (pos,len) - const QPair<int, int> messagePos = findSerialHeader(d->m_readBuffer); - if (messagePos.first < 0) - break; - // Do we have the complete message? - const int messageEnd = messagePos.first + messagePos.second; - if (messageEnd > d->m_readBuffer.size()) - break; - processSerialMessage(d->m_readBuffer.mid(messagePos.first, messagePos.second)); - d->m_readBuffer.remove(0, messageEnd); - } while (!d->m_readBuffer.isEmpty()); - checkSendQueue(); // Send off further messages -} - -void CodaDevice::processSerialMessage(const QByteArray &message) -{ - if (debug > 1) - qDebug("Serial message: %s",qPrintable(Coda::stringFromArray(message))); - if (message.isEmpty()) - return; - // Is thing a ping/pong response - const int size = message.size(); - if (message.startsWith(serialPongC)) { - const QString version = QString::fromLatin1(message.mid(sizeof(serialPongC) - 1)); - emitLogMessage(QString::fromLatin1("Serial connection from '%1'").arg(version)); - emit serialPong(version); - // Answer with locator. - if (!d->m_serialPingOnly) - writeMessage(QByteArray(locatorAnswerC, sizeof(locatorAnswerC))); - return; - } - // Check for long message (see top, '0xfe #number, data' or '0x0 #number, data') - // TODO: This is currently untested. - const unsigned char *dataU = reinterpret_cast<const unsigned char *>(message.constData()); - const bool isLongMessageStart = size > SerialChunkHeaderSize - && *dataU == serialChunkingStart; - const bool isLongMessageContinuation = size > SerialChunkHeaderSize - && *dataU == serialChunkingContinuation; - if (isLongMessageStart || isLongMessageContinuation) { - const unsigned chunkNumber = *++dataU; - if (isLongMessageStart) { // Start new buffer - d->m_serialBuffer.clear(); - d->m_serialBuffer.reserve( (chunkNumber + 1) * serialChunkLength); - } - d->m_serialBuffer.append(message.mid(SerialChunkHeaderSize, size - SerialChunkHeaderSize)); - // Last chunk? - Process - if (!chunkNumber) { - processMessage(d->m_serialBuffer); - d->m_serialBuffer.clear(); - d->m_serialBuffer.squeeze(); - } - } else { - processMessage(message); // Normal, unchunked message - } -} - -void CodaDevice::deviceReadyReadTcp() -{ - // Take complete message off front of readbuffer. - do { - const int messageEndPos = d->m_readBuffer.indexOf(d->m_tcpMessageTerminator); - if (messageEndPos == -1) - break; - if (messageEndPos == 0) { - // CODA 4.0.5 emits empty messages on errors. - emitLogMessage(QString::fromLatin1("An empty CODA message has been received.")); - } else { - processMessage(d->m_readBuffer.left(messageEndPos)); - } - d->m_readBuffer.remove(0, messageEndPos + d->m_tcpMessageTerminator.size()); - } while (!d->m_readBuffer.isEmpty()); - checkSendQueue(); // Send off further messages -} - -void CodaDevice::processMessage(const QByteArray &message) -{ - if (debug) - qDebug("Read %d bytes:\n%s", message.size(), qPrintable(formatData(message))); - if (const int errorCode = parseMessage(message)) { - emitLogMessage(QString::fromLatin1("Parse error %1 : %2"). - arg(errorCode).arg(debugMessage(message))); - if (debug) - qDebug("Parse error %d for %d bytes:\n%s", errorCode, - message.size(), qPrintable(formatData(message))); - } -} - -// Split \0-terminated message into tokens, skipping the initial type character -static inline QVector<QByteArray> splitMessage(const QByteArray &message) -{ - QVector<QByteArray> tokens; - tokens.reserve(7); - const int messageSize = message.size(); - for (int pos = 2; pos < messageSize; ) { - const int nextPos = message.indexOf('\0', pos); - if (nextPos == -1) - break; - tokens.push_back(message.mid(pos, nextPos - pos)); - pos = nextPos + 1; - } - return tokens; -} - -int CodaDevice::parseMessage(const QByteArray &message) -{ - if (d->m_verbose) - emitLogMessage(debugMessage(message, "CODA ->")); - // Special JSON parse error message or protocol format error. - // The port is usually closed after receiving it. - // "\3\2{"Time":1276096098255,"Code":3,"Format": "Protocol format error"}" - if (message.startsWith("\003\002")) { - QByteArray text = message.mid(2); - const QString errorMessage = QString::fromLatin1("Parse error received: %1").arg(QString::fromAscii(text)); - emit error(errorMessage); - return 0; - } - if (message.size() < 4 || message.at(1) != '\0') - return 1; - // Split into tokens - const char type = message.at(0); - const QVector<QByteArray> tokens = splitMessage(message); - switch (type) { - case 'E': - return parseCodaEvent(tokens); - case 'R': // Command replies - case 'N': - case 'P': - return parseCodaCommandReply(type, tokens); - default: - emitLogMessage(QString::fromLatin1("Unhandled message type: %1").arg(debugMessage(message))); - return 756; - } - return 0; -} - -int CodaDevice::parseCodaCommandReply(char type, const QVector<QByteArray> &tokens) -{ - typedef CodaDevicePrivate::TokenWrittenMessageMap::iterator TokenWrittenMessageMapIterator; - // Find the corresponding entry in the written messages hash. - const int tokenCount = tokens.size(); - if (tokenCount < 1) - return 234; - bool tokenOk; - const int token = tokens.at(0).toInt(&tokenOk); - if (!tokenOk) - return 235; - const TokenWrittenMessageMapIterator it = d->m_writtenMessages.find(token); - if (it == d->m_writtenMessages.end()) { - qWarning("CodaDevice: Internal error: token %d not found for '%s'", - token, qPrintable(joinByteArrays(tokens))); - return 236; - } - - CodaSendQueueEntry entry = it.value(); // FIXME: const? - d->m_writtenMessages.erase(it); - - // No callback: remove entry from map, happy - const unsigned specialHandling = entry.specialHandling; - if (!entry.callback && specialHandling == 0u) - return 0; - - // Parse values into JSON - QVector<JsonValue> values; - values.reserve(tokenCount); - for (int i = 1; i < tokenCount; i++) { - if (!tokens.at(i).isEmpty()) { // Strange: Empty tokens occur. - const JsonValue value(tokens.at(i)); - if (value.isValid()) { - values.push_back(value); - } else { - qWarning("JSON parse error for reply to command token %d: #%d '%s'", - token, i, tokens.at(i).constData()); - return -1; - } - } - } - // Construct result and invoke callback, remove entry from map. - CodaCommandResult result(type, entry.service, entry.data, values, entry.cookie); - if (entry.callback) - entry.callback(result); - - return 0; -} - -int CodaDevice::parseCodaEvent(const QVector<QByteArray> &tokens) -{ - // Event: Ignore the periodical heartbeat event, answer 'Hello', - // emit signal for the rest - if (tokens.size() < 3) - return 433; - const Services service = serviceFromName(tokens.at(0).constData()); - if (service == LocatorService && tokens.at(1) == "peerHeartBeat") - return 0; - QVector<JsonValue> values; - for (int i = 2; i < tokens.size(); i++) { - const JsonValue value(tokens.at(i)); - if (!value.isValid()) - return 434; - values.push_back(value); - } - // Parse known events, emit signals - QScopedPointer<CodaEvent> knownEvent(CodaEvent::parseEvent(service, tokens.at(1), values)); - if (!knownEvent.isNull()) { - // Answer hello event (WLAN) - if (knownEvent->type() == CodaEvent::LocatorHello) - if (!d->m_serialFrame) - writeMessage(QByteArray(locatorAnswerC, sizeof(locatorAnswerC))); - emit codaEvent(*knownEvent); - } - emit genericCodaEvent(service, tokens.at(1), values); - - if (debug || d->m_verbose) { - QString msg; - QTextStream str(&msg); - if (knownEvent.isNull()) { - str << "Event: " << tokens.at(0) << ' ' << tokens.at(1) << '\n'; - foreach(const JsonValue &val, values) - str << " " << val.toString() << '\n'; - } else { - str << knownEvent->toString(); - } - emitLogMessage(msg); - } - - return 0; -} - -unsigned CodaDevice::verbose() const -{ - return d->m_verbose; -} - -bool CodaDevice::serialFrame() const -{ - return d->m_serialFrame; -} - -void CodaDevice::setSerialFrame(bool s) -{ - d->m_serialFrame = s; -} - -void CodaDevice::setVerbose(unsigned v) -{ - d->m_verbose = v; -} - -void CodaDevice::emitLogMessage(const QString &m) -{ - if (debug) - qWarning("%s", qPrintable(m)); - emit logMessage(m); -} - -bool CodaDevice::checkOpen() -{ - if (d->m_device.isNull()) { - emitLogMessage(QLatin1String("Internal error: No device set on CodaDevice.")); - return false; - } - if (!d->m_device->isOpen()) { - emitLogMessage(QLatin1String("Internal error: Device not open in CodaDevice.")); - return false; - } - return true; -} - -void CodaDevice::sendSerialPing(bool pingOnly) -{ - if (!checkOpen()) - return; - - d->m_serialPingOnly = pingOnly; - setSerialFrame(true); - writeMessage(QByteArray(serialPingC, qstrlen(serialPingC)), false); - if (d->m_verbose) - emitLogMessage(QLatin1String("Ping...")); -} - -void CodaDevice::sendCodaMessage(MessageType mt, Services service, const char *command, - const char *commandParameters, // may contain '\0' - int commandParametersLength, - const CodaCallback &callBack, - const QVariant &cookie) - -{ - if (!checkOpen()) - return; - // Format the message - const int token = d->m_token++; - QByteArray data; - data.reserve(30 + commandParametersLength); - data.append('C'); - data.append('\0'); - data.append(QByteArray::number(token)); - data.append('\0'); - data.append(serviceName(service)); - data.append('\0'); - data.append(command); - data.append('\0'); - if (commandParametersLength) - data.append(commandParameters, commandParametersLength); - const CodaSendQueueEntry entry(mt, token, service, data, callBack, cookie); - d->m_sendQueue.enqueue(entry); - checkSendQueue(); -} - -void CodaDevice::sendCodaMessage(MessageType mt, Services service, const char *command, - const QByteArray &commandParameters, - const CodaCallback &callBack, - const QVariant &cookie) -{ - sendCodaMessage(mt, service, command, commandParameters.constData(), commandParameters.size(), - callBack, cookie); -} - -// Enclose in message frame and write. -void CodaDevice::writeMessage(QByteArray data, bool ensureTerminating0) -{ - if (!checkOpen()) - return; - - if (d->m_serialFrame && data.size() > maxSerialMessageLength) { - qCritical("Attempt to send large message (%d bytes) exceeding the " - "limit of %d bytes over serial channel. Skipping.", - data.size(), maxSerialMessageLength); - return; - } - - if (d->m_verbose) - emitLogMessage(debugMessage(data, "CODA <-")); - - // Ensure \0-termination which easily gets lost in QByteArray CT. - if (ensureTerminating0 && !data.endsWith('\0')) - data.append('\0'); - if (d->m_serialFrame) { - data = encodeUsbSerialMessage(data); - } else { - data += d->m_tcpMessageTerminator; - } - - if (debug > 1) - qDebug("Writing:\n%s", qPrintable(formatData(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(); -} - -void CodaDevice::writeCustomData(char protocolId, const QByteArray &data) -{ - if (!checkOpen()) - return; - - if (!d->m_serialFrame) { - qWarning("Ignoring request to send data to non-serial CodaDevice"); - return; - } - if (data.length() > 0xFFFF) { - qWarning("Ignoring request to send too large packet, of size %d", data.length()); - return; - } - QByteArray framedData; - encodeSerialFrame(data, &framedData, protocolId); - device()->write(framedData); -} - -void CodaDevice::checkSendQueue() -{ - // Fire off messages or invoke noops until a message with reply is found - // and an entry to writtenMessages is made. - while (d->m_writtenMessages.empty()) { - if (d->m_sendQueue.isEmpty()) - break; - CodaSendQueueEntry entry = d->m_sendQueue.dequeue(); - switch (entry.messageType) { - case MessageWithReply: - d->m_writtenMessages.insert(entry.token, entry); - writeMessage(entry.data); - break; - case MessageWithoutReply: - writeMessage(entry.data); - break; - case NoopMessage: // Invoke the noop-callback for synchronization - if (entry.callback) { - CodaCommandResult noopResult(CodaCommandResult::SuccessReply); - noopResult.cookie = entry.cookie; - entry.callback(noopResult); - } - break; - } - } -} - -// Fix slashes -static inline QString fixFileName(QString in) -{ - in.replace(QLatin1Char('/'), QLatin1Char('\\')); - return in; -} - -// Start a process (consisting of a non-reply setSettings and start). -void CodaDevice::sendProcessStartCommand(const CodaCallback &callBack, - const QString &binaryIn, - unsigned uid, - QStringList arguments, - QString workingDirectory, - bool debugControl, - const QStringList &additionalLibraries, - const QVariant &cookie) -{ - // Obtain the bin directory, expand by c:/sys/bin if missing - const QChar backSlash('\\'); - int slashPos = binaryIn.lastIndexOf(QLatin1Char('/')); - if (slashPos == -1) - slashPos = binaryIn.lastIndexOf(backSlash); - const QString sysBin = QLatin1String("c:/sys/bin"); - const QString binaryFileName = slashPos == -1 ? binaryIn : binaryIn.mid(slashPos + 1); - - if (workingDirectory.isEmpty()) - workingDirectory = sysBin; - - // Format settings with empty dummy parameter - QByteArray setData; - JsonInputStream setStr(setData); - setStr << "" << '\0' - << '[' << "exeToLaunch" << ',' << "addExecutables" << ',' << "addLibraries" << ',' << "logUserTraces" << ',' << "attachAllWithLibraries" << ']' - << '\0' << '[' - << binaryFileName << ',' - << '{' << binaryFileName << ':' << QString::number(uid, 16) << '}' << ',' - << additionalLibraries << ',' << true << ',' << false - << ']'; - sendCodaMessage( -#if 1 - MessageWithReply, // CODA 4.0.5 onwards -#else - MessageWithoutReply, // CODA 4.0.2 -#endif - SettingsService, "set", setData); - - QByteArray startData; - JsonInputStream startStr(startData); - startStr << "" //We don't really know the drive of the working dir - << '\0' << binaryFileName << '\0' << arguments << '\0' - << QStringList() << '\0' // Env is an array ["PATH=value"] (non-standard) - << debugControl; - sendCodaMessage(MessageWithReply, ProcessesService, "start", startData, callBack, cookie); -} - -void CodaDevice::sendRunProcessCommand(const CodaCallback &callBack, - const QString &processName, - QStringList arguments, - const QVariant &cookie) -{ - QByteArray startData; - JsonInputStream startStr(startData); - startStr << "" //We don't really know the drive of the working dir - << '\0' << processName << '\0' << arguments << '\0' - << QStringList() << '\0' // Env is an array ["PATH=value"] (non-standard) - << false; // Don't attach debugger - sendCodaMessage(MessageWithReply, ProcessesService, "start", startData, callBack, cookie); -} - -void CodaDevice::sendSettingsEnableLogCommand() -{ - - QByteArray setData; - JsonInputStream setStr(setData); - setStr << "" << '\0' - << '[' << "logUserTraces" << ']' - << '\0' << '[' - << true - << ']'; - sendCodaMessage( -#if 1 - MessageWithReply, // CODA 4.0.5 onwards -#else - MessageWithoutReply, // CODA 4.0.2 -#endif - SettingsService, "set", setData); -} - -void CodaDevice::sendProcessTerminateCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << id; - sendCodaMessage(MessageWithReply, ProcessesService, "terminate", data, callBack, cookie); -} - -void CodaDevice::sendRunControlTerminateCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << id; - sendCodaMessage(MessageWithReply, RunControlService, "terminate", data, callBack, cookie); -} - -// Non-standard: Remove executable from settings -void CodaDevice::sendSettingsRemoveExecutableCommand(const QString &binaryIn, - unsigned uid, - const QStringList &additionalLibraries, - const QVariant &cookie) -{ - QByteArray setData; - JsonInputStream setStr(setData); - setStr << "" << '\0' - << '[' << "removedExecutables" << ',' << "removedLibraries" << ']' - << '\0' << '[' - << '{' << QFileInfo(binaryIn).fileName() << ':' << QString::number(uid, 16) << '}' << ',' - << additionalLibraries - << ']'; - sendCodaMessage(MessageWithoutReply, SettingsService, "set", setData, CodaCallback(), cookie); -} - -void CodaDevice::sendRunControlResumeCommand(const CodaCallback &callBack, - const QByteArray &id, - RunControlResumeMode mode, - unsigned count, - quint64 rangeStart, - quint64 rangeEnd, - const QVariant &cookie) -{ - QByteArray resumeData; - JsonInputStream str(resumeData); - str << id << '\0' << int(mode) << '\0' << count; - switch (mode) { - case RM_STEP_OVER_RANGE: - case RM_STEP_INTO_RANGE: - case RM_REVERSE_STEP_OVER_RANGE: - case RM_REVERSE_STEP_INTO_RANGE: - str << '\0' << '{' << "RANGE_START" << ':' << rangeStart - << ',' << "RANGE_END" << ':' << rangeEnd << '}'; - break; - default: - break; - } - sendCodaMessage(MessageWithReply, RunControlService, "resume", resumeData, callBack, cookie); -} - -void CodaDevice::sendRunControlSuspendCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << id; - sendCodaMessage(MessageWithReply, RunControlService, "suspend", data, callBack, cookie); -} - -void CodaDevice::sendRunControlResumeCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie) -{ - sendRunControlResumeCommand(callBack, id, RM_RESUME, 1, 0, 0, cookie); -} - -void CodaDevice::sendBreakpointsAddCommand(const CodaCallback &callBack, - const Breakpoint &bp, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << bp; - sendCodaMessage(MessageWithReply, BreakpointsService, "add", data, callBack, cookie); -} - -void CodaDevice::sendBreakpointsRemoveCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie) -{ - sendBreakpointsRemoveCommand(callBack, QVector<QByteArray>(1, id), cookie); -} - -void CodaDevice::sendBreakpointsRemoveCommand(const CodaCallback &callBack, - const QVector<QByteArray> &ids, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << ids; - sendCodaMessage(MessageWithReply, BreakpointsService, "remove", data, callBack, cookie); -} - -void CodaDevice::sendBreakpointsEnableCommand(const CodaCallback &callBack, - const QByteArray &id, - bool enable, - const QVariant &cookie) -{ - sendBreakpointsEnableCommand(callBack, QVector<QByteArray>(1, id), enable, cookie); -} - -void CodaDevice::sendBreakpointsEnableCommand(const CodaCallback &callBack, - const QVector<QByteArray> &ids, - bool enable, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << ids; - sendCodaMessage(MessageWithReply, BreakpointsService, - enable ? "enable" : "disable", - data, callBack, cookie); -} - -void CodaDevice::sendMemorySetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - quint64 start, const QByteArray& data, - const QVariant &cookie) -{ - QByteArray getData; - JsonInputStream str(getData); - // start/word size/mode. Mode should ideally be 1 (continue on error?) - str << contextId << '\0' << start << '\0' << 1 << '\0' << data.size() << '\0' << 1 - << '\0' << data.toBase64(); - sendCodaMessage(MessageWithReply, MemoryService, "set", getData, callBack, cookie); -} - -void CodaDevice::sendMemoryGetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - quint64 start, quint64 size, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - // start/word size/mode. Mode should ideally be 1 (continue on error?) - str << contextId << '\0' << start << '\0' << 1 << '\0' << size << '\0' << 1; - sendCodaMessage(MessageWithReply, MemoryService, "get", data, callBack, cookie); -} - -QByteArray CodaDevice::parseMemoryGet(const CodaCommandResult &r) -{ - if (r.type != CodaCommandResult::SuccessReply || r.values.size() < 1) - return QByteArray(); - const JsonValue &memoryV = r.values.front(); - - if (memoryV.type() != JsonValue::String || memoryV.data().size() < 2 - || !memoryV.data().endsWith('=')) - return QByteArray(); - // Catch errors reported as hash: - // R.4."TlVMTA==".{"Time":1276786871255,"Code":1,"AltCode":-38,"AltOrg":"POSIX","Format":"BadDescriptor"} - // Not sure what to make of it. - if (r.values.size() >= 2 && r.values.at(1).type() == JsonValue::Object) - qWarning("CodaDevice::parseMemoryGet(): Error retrieving memory: %s", r.values.at(1).toString(false).constData()); - // decode - const QByteArray memory = QByteArray::fromBase64(memoryV.data()); - if (memory.isEmpty()) - qWarning("Base64 decoding of %s failed.", memoryV.data().constData()); - if (debug) - qDebug("CodaDevice::parseMemoryGet: received %d bytes", memory.size()); - return memory; -} - -// Parse register children (array of names) -QVector<QByteArray> CodaDevice::parseRegisterGetChildren(const CodaCommandResult &r) -{ - QVector<QByteArray> rc; - if (!r || r.values.size() < 1 || r.values.front().type() != JsonValue::Array) - return rc; - const JsonValue &front = r.values.front(); - rc.reserve(front.childCount()); - foreach(const JsonValue &v, front.children()) - rc.push_back(v.data()); - return rc; -} - -CodaStatResponse CodaDevice::parseStat(const CodaCommandResult &r) -{ - CodaStatResponse rc; - if (!r || r.values.size() < 1 || r.values.front().type() != JsonValue::Object) - return rc; - foreach(const JsonValue &v, r.values.front().children()) { - if (v.name() == "Size") { - rc.size = v.data().toULongLong(); - } else if (v.name() == "ATime") { - if (const quint64 atime = v.data().toULongLong()) - rc.accessTime = CodaCommandResult::codaTimeToQDateTime(atime); - } else if (v.name() == "MTime") { - if (const quint64 mtime = v.data().toULongLong()) - rc.modTime = CodaCommandResult::codaTimeToQDateTime(mtime); - } - } - return rc; -} - -void CodaDevice::sendRegistersGetChildrenCommand(const CodaCallback &callBack, - const QByteArray &contextId, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << contextId; - sendCodaMessage(MessageWithReply, RegistersService, "getChildren", data, callBack, cookie); -} - -// Format id of register get request (needs contextId containing process and thread) -static inline QByteArray registerId(const QByteArray &contextId, QByteArray id) -{ - QByteArray completeId = contextId; - if (!completeId.isEmpty()) - completeId.append('.'); - completeId.append(id); - return completeId; -} - -// Format parameters of register get request -static inline QByteArray registerGetData(const QByteArray &contextId, QByteArray id) -{ - QByteArray data; - JsonInputStream str(data); - str << registerId(contextId, id); - return data; -} - -void CodaDevice::sendRegistersGetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - QByteArray id, - const QVariant &cookie) -{ - sendCodaMessage(MessageWithReply, RegistersService, "get", - registerGetData(contextId, id), callBack, cookie); -} - -void CodaDevice::sendRegistersGetMCommand(const CodaCallback &callBack, - const QByteArray &contextId, - const QVector<QByteArray> &ids, - const QVariant &cookie) -{ - // Format the register ids as a JSON list - QByteArray data; - JsonInputStream str(data); - str << '['; - const int count = ids.size(); - for (int r = 0; r < count; r++) { - if (r) - str << ','; - // TODO: When 8-byte floating-point registers are supported, query for register length based on register id - str << '[' << registerId(contextId, ids.at(r)) << ',' << '0' << ',' << '4' << ']'; - } - str << ']'; - sendCodaMessage(MessageWithReply, RegistersService, "getm", data, callBack, cookie); -} - -void CodaDevice::sendRegistersGetMRangeCommand(const CodaCallback &callBack, - const QByteArray &contextId, - unsigned start, unsigned count) -{ - const unsigned end = start + count; - if (end > (unsigned)d->m_registerNames.size()) { - qWarning("CodaDevice: No register name set for index %u (size: %d).", end, d->m_registerNames.size()); - return; - } - - QVector<QByteArray> ids; - ids.reserve(count); - for (unsigned i = start; i < end; ++i) - ids.push_back(d->m_registerNames.at(i)); - sendRegistersGetMCommand(callBack, contextId, ids, QVariant(start)); -} - -// Set register -void CodaDevice::sendRegistersSetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - QByteArray id, - const QByteArray &value, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - if (!contextId.isEmpty()) { - id.prepend('.'); - id.prepend(contextId); - } - str << id << '\0' << value.toBase64(); - sendCodaMessage(MessageWithReply, RegistersService, "set", data, callBack, cookie); -} - -// Set register -void CodaDevice::sendRegistersSetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - unsigned registerNumber, - const QByteArray &value, - const QVariant &cookie) -{ - if (registerNumber >= (unsigned)d->m_registerNames.size()) { - qWarning("CodaDevice: No register name set for index %u (size: %d).", registerNumber, d->m_registerNames.size()); - return; - } - sendRegistersSetCommand(callBack, contextId, - d->m_registerNames[registerNumber], - value, cookie); -} - -static const char outputListenerIDC[] = "ProgramOutputConsoleLogger"; - -void CodaDevice::sendLoggingAddListenerCommand(const CodaCallback &callBack, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << outputListenerIDC; - sendCodaMessage(MessageWithReply, LoggingService, "addListener", data, callBack, cookie); -} - -void CodaDevice::sendSymbianUninstallCommand(const Coda::CodaCallback &callBack, - const quint32 package, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - QString string = QString::number(package, 16); - str << string; - sendCodaMessage(MessageWithReply, SymbianInstallService, "uninstall", data, callBack, cookie); -} - -void CodaDevice::sendSymbianOsDataGetThreadsCommand(const CodaCallback &callBack, - const QVariant &cookie) -{ - QByteArray data; - sendCodaMessage(MessageWithReply, SymbianOSData, "getThreads", data, callBack, cookie); -} - -void CodaDevice::sendSymbianOsDataFindProcessesCommand(const CodaCallback &callBack, - const QByteArray &processName, - const QByteArray &uid, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << processName << '\0' << uid; - 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, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << name << '\0' << flags << '\0' << '{' << '}'; - sendCodaMessage(MessageWithReply, FileSystemService, "open", data, callBack, cookie); -} - -void Coda::CodaDevice::sendFileSystemFstatCommand(const CodaCallback &callBack, - const QByteArray &handle, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << handle; - sendCodaMessage(MessageWithReply, FileSystemService, "fstat", data, callBack, cookie); -} - -void Coda::CodaDevice::sendFileSystemWriteCommand(const Coda::CodaCallback &callBack, - const QByteArray &handle, - const QByteArray &dataIn, - unsigned offset, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << handle << '\0' << offset << '\0' << dataIn.toBase64(); - sendCodaMessage(MessageWithReply, FileSystemService, "write", data, callBack, cookie); -} - -void Coda::CodaDevice::sendFileSystemCloseCommand(const Coda::CodaCallback &callBack, - const QByteArray &handle, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << handle; - sendCodaMessage(MessageWithReply, FileSystemService, "close", data, callBack, cookie); -} - -void Coda::CodaDevice::sendSymbianInstallSilentInstallCommand(const Coda::CodaCallback &callBack, - const QByteArray &file, - const QByteArray &targetDrive, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << file << '\0' << targetDrive; - sendCodaMessage(MessageWithReply, SymbianInstallService, "install", data, callBack, cookie); -} - -void Coda::CodaDevice::sendSymbianInstallUIInstallCommand(const Coda::CodaCallback &callBack, - const QByteArray &file, - const QVariant &cookie) -{ - QByteArray data; - JsonInputStream str(data); - str << file; - sendCodaMessage(MessageWithReply, SymbianInstallService, "installWithUI", data, callBack, cookie); -} - -void Coda::CodaDevice::sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack, - const QList<quint32> &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); -} - -void Coda::CodaDevice::sendDebugSessionControlSessionStartCommand(const Coda::CodaCallback &callBack, - const QVariant &cookie) -{ - sendCodaMessage(MessageWithReply, DebugSessionControl, "sessionStart", QByteArray(), callBack, cookie); -} - -void Coda::CodaDevice::sendDebugSessionControlSessionEndCommand(const Coda::CodaCallback &callBack, - const QVariant &cookie) -{ - sendCodaMessage(MessageWithReply, DebugSessionControl, "sessionEnd ", QByteArray(), callBack, cookie); -} - -} // namespace Coda diff --git a/src/shared/symbianutils/codadevice.h b/src/shared/symbianutils/codadevice.h deleted file mode 100644 index 9a49cd527cd..00000000000 --- a/src/shared/symbianutils/codadevice.h +++ /dev/null @@ -1,432 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef CODAENGINE_H -#define CODAENGINE_H - -#include "symbianutils_global.h" -#include "codamessage.h" -#include "callback.h" -#include "json.h" - -#include <QObject> -#include <QSharedPointer> -#include <QVector> -#include <QVariant> -#include <QStringList> -#include <QDateTime> - -QT_BEGIN_NAMESPACE -class QIODevice; -class QTextStream; -QT_END_NAMESPACE - -namespace Coda { - -struct CodaDevicePrivate; -struct Breakpoint; - -/* Command error handling in CODA: - * 1) 'Severe' errors (JSON format, parameter format): Coda emits a - * nonstandard message (\3\2 error parameters) and closes the connection. - * 2) Protocol errors: 'N' without error message is returned. - * 3) Errors in command execution: 'R' with a CODA error hash is returned - * (see CodaCommandError). */ - -/* Error code return in 'R' reply to command - * (see top of 'Services' documentation). */ -struct SYMBIANUTILS_EXPORT CodaCommandError { - CodaCommandError(); - void clear(); - bool isError() const; - operator bool() const { return isError(); } - QString toString() const; - void write(QTextStream &str) const; - bool parse(const QVector<Json::JsonValue> &values); - - quint64 timeMS; // Since 1.1.1970 - qint64 code; - QByteArray format; // message - // 'Alternative' meaning, like altOrg="POSIX"/altCode=<some errno> - QByteArray alternativeOrganization; - qint64 alternativeCode; -}; - -/* Answer to a CODA command passed to the callback. */ -struct SYMBIANUTILS_EXPORT CodaCommandResult { - enum Type - { - SuccessReply, // 'R' and no error -> all happy. - CommandErrorReply, // 'R' with CodaCommandError received - ProgressReply, // 'P', progress indicator - FailReply // 'N' Protocol NAK, severe error - }; - - explicit CodaCommandResult(Type t = SuccessReply); - explicit CodaCommandResult(char typeChar, Services service, - const QByteArray &request, - const QVector<Json::JsonValue> &values, - const QVariant &cookie); - - QString toString() const; - QString errorString() const; - operator bool() const { return type == SuccessReply || type == ProgressReply; } - - static QDateTime codaTimeToQDateTime(quint64 codaTimeMS); - - Type type; - Services service; - QByteArray request; - CodaCommandError commandError; - QVector<Json::JsonValue> values; - QVariant cookie; -}; - -// Response to stat/fstat -struct SYMBIANUTILS_EXPORT CodaStatResponse -{ - CodaStatResponse(); - - quint64 size; - QDateTime modTime; - QDateTime accessTime; -}; - -typedef Coda::Callback<const CodaCommandResult &> CodaCallback; - -/* CodaDevice: CODA communication helper using an asynchronous QIODevice - * implementing the CODA protocol according to: -http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Specification.html -http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Services.html - * Commands can be sent along with callbacks that are passed a - * CodaCommandResult and an opaque QVariant cookie. In addition, events are emitted. - * - * CODA notes: - * - Commands are accepted only after receiving the Locator Hello event - * - Serial communication initiation sequence: - * Send serial ping from host sendSerialPing() -> receive pong response with - * version information -> Send Locator Hello Event -> Receive Locator Hello Event - * -> Commands are accepted. - * - WLAN communication initiation sequence: - * Receive Locator Hello Event from CODA -> Commands are accepted. - */ - -class SYMBIANUTILS_EXPORT CodaDevice : public QObject -{ - Q_PROPERTY(unsigned verbose READ verbose WRITE setVerbose) - Q_PROPERTY(bool serialFrame READ serialFrame WRITE setSerialFrame) - Q_OBJECT -public: - // Flags for FileSystem:open - enum FileSystemOpenFlags - { - FileSystem_TCF_O_READ = 0x00000001, - FileSystem_TCF_O_WRITE = 0x00000002, - FileSystem_TCF_O_APPEND = 0x00000004, - FileSystem_TCF_O_CREAT = 0x00000008, - FileSystem_TCF_O_TRUNC = 0x00000010, - FileSystem_TCF_O_EXCL = 0x00000020 - }; - - enum MessageType - { - MessageWithReply, - MessageWithoutReply, /* Non-standard: "Settings:set" command does not reply */ - NoopMessage - }; - - typedef QSharedPointer<QIODevice> IODevicePtr; - - explicit CodaDevice(QObject *parent = 0); - virtual ~CodaDevice(); - - unsigned verbose() const; - bool serialFrame() const; - void setSerialFrame(bool); - - // Mapping of register names to indices for multi-requests. - // Register names can be retrieved via 'Registers:getChildren' (requires - // context id to be stripped). - QVector<QByteArray> registerNames() const; - void setRegisterNames(const QVector<QByteArray>& n); - - IODevicePtr device() const; - IODevicePtr takeDevice(); - void setDevice(const IODevicePtr &dp); - - // Serial Only: Initiate communication. Will emit serialPong() signal with version. - void sendSerialPing(bool pingOnly = false); - - // Send with parameters from string (which may contain '\0'). - void sendCodaMessage(MessageType mt, Services service, const char *command, - const char *commandParameters, int commandParametersLength, - const CodaCallback &callBack = CodaCallback(), - const QVariant &cookie = QVariant()); - - void sendCodaMessage(MessageType mt, Services service, const char *command, - const QByteArray &commandParameters, - const CodaCallback &callBack = CodaCallback(), - const QVariant &cookie = QVariant()); - - // Convenience messages: Start a process - void sendProcessStartCommand(const CodaCallback &callBack, - const QString &binary, - unsigned uid, - QStringList arguments = QStringList(), - QString workingDirectory = QString(), - bool debugControl = true, - const QStringList &additionalLibraries = QStringList(), - const QVariant &cookie = QVariant()); - - // Just launch a process, don't attempt to attach the debugger to it - void sendRunProcessCommand(const CodaCallback &callBack, - const QString &processName, - QStringList arguments = QStringList(), - const QVariant &cookie = QVariant()); - - // Preferred over Processes:Terminate by CODA. - void sendRunControlTerminateCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie = QVariant()); - - // TODO: In CODA 4.1.13 the Terminate option does order CODA to kill - // a process and CODA reports contextRemoved but does not kill the process - void sendProcessTerminateCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie = QVariant()); - - // Non-standard: Remove executable from settings. - // Probably needs to be called after stopping. This command has no response. - void sendSettingsRemoveExecutableCommand(const QString &binaryIn, - unsigned uid, - const QStringList &additionalLibraries = QStringList(), - const QVariant &cookie = QVariant()); - - void sendRunControlSuspendCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie = QVariant()); - - // Resume / Step (see RunControlResumeMode). - void sendRunControlResumeCommand(const CodaCallback &callBack, - const QByteArray &id, - RunControlResumeMode mode, - unsigned count /* = 1, currently ignored. */, - quint64 rangeStart, quint64 rangeEnd, - const QVariant &cookie = QVariant()); - - // Convenience to resume a suspended process - void sendRunControlResumeCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie = QVariant()); - - void sendBreakpointsAddCommand(const CodaCallback &callBack, - const Breakpoint &b, - const QVariant &cookie = QVariant()); - - void sendBreakpointsRemoveCommand(const CodaCallback &callBack, - const QByteArray &id, - const QVariant &cookie = QVariant()); - - void sendBreakpointsRemoveCommand(const CodaCallback &callBack, - const QVector<QByteArray> &id, - const QVariant &cookie = QVariant()); - - void sendBreakpointsEnableCommand(const CodaCallback &callBack, - const QByteArray &id, - bool enable, - const QVariant &cookie = QVariant()); - - void sendBreakpointsEnableCommand(const CodaCallback &callBack, - const QVector<QByteArray> &id, - bool enable, - const QVariant &cookie = QVariant()); - - - void sendMemoryGetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - quint64 start, quint64 size, - const QVariant &cookie = QVariant()); - - void sendMemorySetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - quint64 start, const QByteArray& data, - const QVariant &cookie = QVariant()); - - // Get register names (children of context). - // It is possible to recurse from thread id down to single registers. - void sendRegistersGetChildrenCommand(const CodaCallback &callBack, - const QByteArray &contextId, - const QVariant &cookie = QVariant()); - - // Register get - void sendRegistersGetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - QByteArray id, - const QVariant &cookie); - - void sendRegistersGetMCommand(const CodaCallback &callBack, - const QByteArray &contextId, - const QVector<QByteArray> &ids, - const QVariant &cookie = QVariant()); - - // Convenience to get a range of register "R0" .. "R<n>". - // Cookie will be an int containing "start". - void sendRegistersGetMRangeCommand(const CodaCallback &callBack, - const QByteArray &contextId, - unsigned start, unsigned count); - - // Set register - void sendRegistersSetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - QByteArray ids, - const QByteArray &value, // binary value - const QVariant &cookie = QVariant()); - // Set register - void sendRegistersSetCommand(const CodaCallback &callBack, - const QByteArray &contextId, - unsigned registerNumber, - const QByteArray &value, // binary value - const QVariant &cookie = QVariant()); - - // File System - void sendFileSystemOpenCommand(const CodaCallback &callBack, - const QByteArray &name, - unsigned flags = FileSystem_TCF_O_READ, - const QVariant &cookie = QVariant()); - - void sendFileSystemFstatCommand(const CodaCallback &callBack, - const QByteArray &handle, - const QVariant &cookie = QVariant()); - - void sendFileSystemWriteCommand(const CodaCallback &callBack, - const QByteArray &handle, - const QByteArray &data, - unsigned offset = 0, - const QVariant &cookie = QVariant()); - - void sendFileSystemCloseCommand(const CodaCallback &callBack, - const QByteArray &handle, - const QVariant &cookie = QVariant()); - - // Symbian Install - void sendSymbianInstallSilentInstallCommand(const CodaCallback &callBack, - const QByteArray &file, - const QByteArray &targetDrive, - const QVariant &cookie = QVariant()); - - void sendSymbianInstallUIInstallCommand(const CodaCallback &callBack, - const QByteArray &file, - const QVariant &cookie = QVariant()); - - void sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack, - const QList<quint32> &packages, - const QVariant &cookie = QVariant()); - - void sendLoggingAddListenerCommand(const CodaCallback &callBack, - const QVariant &cookie = QVariant()); - - void sendSymbianUninstallCommand(const Coda::CodaCallback &callBack, - const quint32 package, - const QVariant &cookie = QVariant()); - - // SymbianOs Data - void sendSymbianOsDataGetThreadsCommand(const CodaCallback &callBack, - const QVariant &cookie = QVariant()); - - void sendSymbianOsDataFindProcessesCommand(const CodaCallback &callBack, - const QByteArray &processName, - 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()); - - // DebugSessionControl - void sendDebugSessionControlSessionStartCommand(const CodaCallback &callBack, - const QVariant &cookie = QVariant()); - - void sendDebugSessionControlSessionEndCommand(const CodaCallback &callBack, - const QVariant &cookie = QVariant()); - - // Settings - void sendSettingsEnableLogCommand(); - - void writeCustomData(char protocolId, const QByteArray &aData); - - static QByteArray parseMemoryGet(const CodaCommandResult &r); - static QVector<QByteArray> parseRegisterGetChildren(const CodaCommandResult &r); - static CodaStatResponse parseStat(const CodaCommandResult &r); - -signals: - void genericCodaEvent(int service, const QByteArray &name, const QVector<Json::JsonValue> &value); - void codaEvent(const Coda::CodaEvent &knownEvent); - void unknownEvent(uchar protocolId, const QByteArray& data); - void serialPong(const QString &codaVersion); - - void logMessage(const QString &); - void error(const QString &); - -public slots: - void setVerbose(unsigned v); - -private slots: - void slotDeviceError(); - void slotDeviceSocketStateChanged(); - void slotDeviceReadyRead(); - -private: - void deviceReadyReadSerial(); - void deviceReadyReadTcp(); - - bool checkOpen(); - void checkSendQueue(); - void writeMessage(QByteArray data, bool ensureTerminating0 = true); - void emitLogMessage(const QString &); - inline int parseMessage(const QByteArray &); - void processMessage(const QByteArray &message); - inline void processSerialMessage(const QByteArray &message); - int parseCodaCommandReply(char type, const QVector<QByteArray> &tokens); - int parseCodaEvent(const QVector<QByteArray> &tokens); - -private: - QPair<int, int> findSerialHeader(QByteArray &in); - CodaDevicePrivate *d; -}; - -} // namespace Coda - -#endif // CODAENGINE_H diff --git a/src/shared/symbianutils/codamessage.cpp b/src/shared/symbianutils/codamessage.cpp deleted file mode 100644 index e680eb5ed8b..00000000000 --- a/src/shared/symbianutils/codamessage.cpp +++ /dev/null @@ -1,592 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "codamessage.h" -#include "json.h" - -#include <QString> -#include <QTextStream> - -// Names matching the enum -static const char *serviceNamesC[] = -{ "Locator", "RunControl", "Processes", "Memory", "Settings", "Breakpoints", - "Registers", "Logging", "FileSystem", "SymbianInstall", "SymbianOSData", - "DebugSessionControl", - "UnknownService"}; - -using namespace Json; -namespace Coda { - -SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep) -{ - QString rc; - const int count = a.size(); - for (int i = 0; i < count; i++) { - if (i) - rc += QLatin1Char(sep); - rc += QString::fromUtf8(a.at(i)); - } - return rc; -} - -static inline bool jsonToBool(const JsonValue& js) -{ - return js.type() == JsonValue::Boolean && js.data() == "true"; -} - -SYMBIANUTILS_EXPORT const char *serviceName(Services s) -{ - return serviceNamesC[s]; -} - -SYMBIANUTILS_EXPORT Services serviceFromName(const char *n) -{ - const int count = sizeof(serviceNamesC)/sizeof(char *); - for (int i = 0; i < count; i++) - if (!qstrcmp(serviceNamesC[i], n)) - return static_cast<Services>(i); - return UnknownService; -} - -SYMBIANUTILS_EXPORT QString formatData(const QByteArray &a) -{ - const int columns = 16; - QString rc; - QTextStream str(&rc); - str.setIntegerBase(16); - str.setPadChar(QLatin1Char('0')); - const unsigned char *start = reinterpret_cast<const unsigned char *>(a.constData()); - const unsigned char *end = start + a.size(); - for (const unsigned char *p = start; p < end ; ) { - str << "0x"; - str.setFieldWidth(4); - str << (p - start); - str.setFieldWidth(0); - str << ' '; - QString asc; - int c = 0; - for ( ; c < columns && p < end; c++, p++) { - const unsigned u = *p; - str.setFieldWidth(2); - str << u; - str.setFieldWidth(0); - str << ' '; - switch (u) { - case '\n': - asc += QLatin1String("\\n"); - break; - case '\r': - asc += QLatin1String("\\r"); - break; - case '\t': - asc += QLatin1String("\\t"); - break; - default: - if (u >= 32 && u < 128) { - asc += QLatin1Char(' '); - asc += QLatin1Char(u); - } else { - asc += QLatin1String(" ."); - } - break; - } - } - if (const int remainder = columns - c) - str << QString(3 * remainder, QLatin1Char(' ')); - str << ' ' << asc << '\n'; - } - return rc; -} - -// ----------- RunControlContext -RunControlContext::RunControlContext() : - flags(0), resumeFlags(0) -{ -} - -void RunControlContext::clear() -{ - flags =0; - resumeFlags = 0; - id.clear(); - osid.clear(); - parentId.clear(); -} - -RunControlContext::Type RunControlContext::typeFromCodaId(const QByteArray &id) -{ - // "p12" or "p12.t34"? - return id.contains(".t") ? Thread : Process; -} - -unsigned RunControlContext::processId() const -{ - return processIdFromTcdfId(id); -} - -unsigned RunControlContext::threadId() const -{ - return threadIdFromTcdfId(id); -} - -unsigned RunControlContext::processIdFromTcdfId(const QByteArray &id) -{ - // Cut out process id from "p12" or "p12.t34"? - if (!id.startsWith('p')) - return 0; - const int dotPos = id.indexOf('.'); - const int pLen = dotPos == -1 ? id.size() : dotPos; - return id.mid(1, pLen - 1).toUInt(); -} - -unsigned RunControlContext::threadIdFromTcdfId(const QByteArray &id) -{ - const int tPos = id.indexOf(".t"); - return tPos != -1 ? id.mid(tPos + 2).toUInt() : uint(0); -} - -QByteArray RunControlContext::codaId(unsigned processId, unsigned threadId /* = 0 */) -{ - QByteArray rc("p"); - rc += QByteArray::number(processId); - if (threadId) { - rc += ".t"; - rc += QByteArray::number(threadId); - } - return rc; -} - -RunControlContext::Type RunControlContext::type() const -{ - return RunControlContext::typeFromCodaId(id); -} - -bool RunControlContext::parse(const JsonValue &val) -{ - clear(); - if (val.type() != JsonValue::Object) - return false; - foreach(const JsonValue &c, val.children()) { - if (c.name() == "ID") { - id = c.data(); - } else if (c.name() == "OSID") { - osid = c.data(); - } else if (c.name() == "ParentID") { - parentId = c.data(); - } else if (c.name() == "IsContainer") { - if (jsonToBool(c)) - flags |= Container; - } else if (c.name() == "CanTerminate") { - if (jsonToBool(c)) - flags |= CanTerminate; - } else if (c.name() == "CanResume") { - resumeFlags = c.data().toUInt(); - } else if (c.name() == "HasState") { - if (jsonToBool(c)) - flags |= HasState; - } else if (c.name() == "CanSuspend") { - if (jsonToBool(c)) - flags |= CanSuspend; - } - } - return true; -} - -QString RunControlContext::toString() const -{ - QString rc; - QTextStream str(&rc); - format(str); - return rc; -} - -void RunControlContext::format(QTextStream &str) const -{ - str << " id='" << id << "' osid='" << osid - << "' parentId='" << parentId <<"' "; - if (flags & Container) - str << "[container] "; - if (flags & HasState) - str << "[has state] "; - if (flags & CanSuspend) - str << "[can suspend] "; - if (flags & CanSuspend) - str << "[can terminate] "; - str.setIntegerBase(16); - str << " resume_flags: 0x" << resumeFlags; - str.setIntegerBase(10); -} - -// ------ ModuleLoadEventInfo -ModuleLoadEventInfo::ModuleLoadEventInfo() : - loaded(false), codeAddress(0), dataAddress(0), requireResume(false) -{ -} - -void ModuleLoadEventInfo::clear() -{ - loaded = requireResume = false; - codeAddress = dataAddress =0; -} - -bool ModuleLoadEventInfo::parse(const JsonValue &val) -{ - clear(); - if (val.type() != JsonValue::Object) - return false; - foreach(const JsonValue &c, val.children()) { - if (c.name() == "Name") { - name = c.data(); - } else if (c.name() == "File") { - file = c.data(); - } else if (c.name() == "CodeAddress") { - codeAddress = c.data().toULongLong(); - } else if (c.name() == "DataAddress") { - dataAddress = c.data().toULongLong(); - } else if (c.name() == "Loaded") { - loaded = jsonToBool(c); - } else if (c.name() == "RequireResume") { - requireResume =jsonToBool(c); - } - } - return true; -} -void ModuleLoadEventInfo::format(QTextStream &str) const -{ - str << "name='" << name << "' file='" << file << "' " << - (loaded ? "[loaded] " : "[not loaded] "); - if (requireResume) - str << "[requires resume] "; - str.setIntegerBase(16); - str << " code: 0x" << codeAddress << " data: 0x" << dataAddress; - str.setIntegerBase(10); -} - -// ---------------------- Breakpoint - -// Types matching enum -static const char *breakPointTypesC[] = {"Software", "Hardware", "Auto"}; - -Breakpoint::Breakpoint(quint64 loc) : - type(Auto), enabled(true), ignoreCount(0), location(loc), size(1), thumb(true) -{ - if (loc) - id = idFromLocation(location); -} - -void Breakpoint::setContextId(unsigned processId, unsigned threadId) -{ - contextIds = QVector<QByteArray>(1, RunControlContext::codaId(processId, threadId)); -} - -QByteArray Breakpoint::idFromLocation(quint64 loc) -{ - return QByteArray("BP_0x") + QByteArray::number(loc, 16); -} - -QString Breakpoint::toString() const -{ - QString rc; - QTextStream str(&rc); - str.setIntegerBase(16); - str << "Breakpoint '" << id << "' " << breakPointTypesC[type] << " for contexts '" - << joinByteArrays(contextIds, ',') << "' at 0x" << location; - str.setIntegerBase(10); - str << " size " << size; - if (enabled) - str << " [enabled]"; - if (thumb) - str << " [thumb]"; - if (ignoreCount) - str << " IgnoreCount " << ignoreCount; - return rc; -} - -JsonInputStream &operator<<(JsonInputStream &str, const Breakpoint &b) -{ - if (b.contextIds.isEmpty()) - qWarning("Coda::Breakpoint: No context ids specified"); - - str << '{' << "ID" << ':' << QString::fromUtf8(b.id) << ',' - << "BreakpointType" << ':' << breakPointTypesC[b.type] << ',' - << "Enabled" << ':' << b.enabled << ',' - << "IgnoreCount" << ':' << b.ignoreCount << ',' - << "ContextIds" << ':' << b.contextIds << ',' - << "Location" << ':' << QString::number(b.location) << ',' - << "Size" << ':' << b.size << ',' - << "THUMB_BREAKPOINT" << ':' << b.thumb - << '}'; - return str; -} - -// --- Events -CodaEvent::CodaEvent(Type type) : m_type(type) -{ -} - -CodaEvent::~CodaEvent() -{ -} - -CodaEvent::Type CodaEvent::type() const -{ - return m_type; -} - -QString CodaEvent::toString() const -{ - return QString(); -} - -static const char sharedLibrarySuspendReasonC[] = "Shared Library"; - -CodaEvent *CodaEvent::parseEvent(Services s, const QByteArray &nameBA, const QVector<JsonValue> &values) -{ - switch (s) { - case LocatorService: - if (nameBA == "Hello" && values.size() == 1 && values.front().type() == JsonValue::Array) { - QStringList services; - foreach (const JsonValue &jv, values.front().children()) - services.push_back(QString::fromUtf8(jv.data())); - return new CodaLocatorHelloEvent(services); - } - break; - case RunControlService: - if (values.empty()) - return 0; - // "id/PC/Reason/Data" - if (nameBA == "contextSuspended" && values.size() == 4) { - const QByteArray idBA = values.at(0).data(); - const quint64 pc = values.at(1).data().toULongLong(); - const QByteArray reasonBA = values.at(2).data(); - QByteArray messageBA; - // Module load: Special - if (reasonBA == sharedLibrarySuspendReasonC) { - ModuleLoadEventInfo info; - if (!info.parse(values.at(3))) - return 0; - return new CodaRunControlModuleLoadContextSuspendedEvent(idBA, reasonBA, pc, info); - } else { - // hash containing a 'message'-key with a verbose crash message. - if (values.at(3).type() == JsonValue::Object && values.at(3).childCount() - && values.at(3).children().at(0).type() == JsonValue::String) - messageBA = values.at(3).children().at(0).data(); - } - return new CodaRunControlContextSuspendedEvent(idBA, reasonBA, messageBA, pc); - } // "contextSuspended" - if (nameBA == "contextAdded") - return CodaRunControlContextAddedEvent::parseEvent(values); - if (nameBA == "contextRemoved" && values.front().type() == JsonValue::Array) { - QVector<QByteArray> ids; - foreach(const JsonValue &c, values.front().children()) - ids.push_back(c.data()); - return new CodaRunControlContextRemovedEvent(ids); - } - break; - case LoggingService: - if ((nameBA == "writeln" || nameBA == "write" /*not yet used*/) && values.size() >= 2) - return new CodaLoggingWriteEvent(values.at(0).data(), values.at(1).data()); - break; - case ProcessesService: - if (nameBA == "exited" && values.size() >= 2) - return new CodaProcessExitedEvent(values.at(0).data()); - break; - default: - break; - } - return 0; -} - -// -------------- CodaServiceHelloEvent -CodaLocatorHelloEvent::CodaLocatorHelloEvent(const QStringList &s) : - CodaEvent(LocatorHello), - m_services(s) -{ -} - -QString CodaLocatorHelloEvent::toString() const -{ - return QLatin1String("ServiceHello: ") + m_services.join(QLatin1String(", ")); -} - -// -------------- Logging event - -CodaLoggingWriteEvent::CodaLoggingWriteEvent(const QByteArray &console, const QByteArray &message) : - CodaEvent(LoggingWriteEvent), m_console(console), m_message(message) -{ -} - -QString CodaLoggingWriteEvent::toString() const -{ - return QString::fromUtf8(m_message); -} - -// -------------- CodaIdEvent -CodaIdEvent::CodaIdEvent(Type t, const QByteArray &id) : - CodaEvent(t), m_id(id) -{ -} - -// ---------- CodaIdsEvent -CodaIdsEvent::CodaIdsEvent(Type t, const QVector<QByteArray> &ids) : - CodaEvent(t), m_ids(ids) -{ -} - -QString CodaIdsEvent::joinedIdString(const char sep) const -{ - return joinByteArrays(m_ids, sep); -} - -// ---------------- CodaRunControlContextAddedEvent -CodaRunControlContextAddedEvent::CodaRunControlContextAddedEvent(const RunControlContexts &c) : - CodaEvent(RunControlContextAdded), m_contexts(c) -{ -} - -CodaRunControlContextAddedEvent - *CodaRunControlContextAddedEvent::parseEvent(const QVector<JsonValue> &values) -{ - // Parse array of contexts - if (values.size() < 1 || values.front().type() != JsonValue::Array) - return 0; - - RunControlContexts contexts; - foreach (const JsonValue &v, values.front().children()) { - RunControlContext context; - if (context.parse(v)) - contexts.push_back(context); - } - return new CodaRunControlContextAddedEvent(contexts); -} - -QString CodaRunControlContextAddedEvent::toString() const -{ - QString rc; - QTextStream str(&rc); - str << "RunControl: " << m_contexts.size() << " context(s) " - << (type() == RunControlContextAdded ? "added" : "removed") - << '\n'; - foreach (const RunControlContext &c, m_contexts) { - c.format(str); - str << '\n'; - } - return rc; -} - -// --------------- CodaRunControlContextRemovedEvent -CodaRunControlContextRemovedEvent::CodaRunControlContextRemovedEvent(const QVector<QByteArray> &ids) : - CodaIdsEvent(RunControlContextRemoved, ids) -{ -} - -QString CodaRunControlContextRemovedEvent::toString() const -{ - return QLatin1String("RunControl: Removed contexts '") + joinedIdString() + ("'."); -} - -// --------------- CodaRunControlContextSuspendedEvent -CodaRunControlContextSuspendedEvent::CodaRunControlContextSuspendedEvent(const QByteArray &id, - const QByteArray &reason, - const QByteArray &message, - quint64 pc) : - CodaIdEvent(RunControlSuspended, id), m_pc(pc), m_reason(reason), m_message(message) -{ -} - -CodaRunControlContextSuspendedEvent::CodaRunControlContextSuspendedEvent(Type t, - const QByteArray &id, - const QByteArray &reason, - quint64 pc) : - CodaIdEvent(t, id), m_pc(pc), m_reason(reason) -{ -} - -void CodaRunControlContextSuspendedEvent::format(QTextStream &str) const -{ - str.setIntegerBase(16); - str << "RunControl: '" << idString() << "' suspended at 0x" - << m_pc << ": '" << m_reason << "'."; - str.setIntegerBase(10); - if (!m_message.isEmpty()) - str << " (" <<m_message << ')'; -} - -QString CodaRunControlContextSuspendedEvent::toString() const -{ - QString rc; - QTextStream str(&rc); - format(str); - return rc; -} - -CodaRunControlContextSuspendedEvent::Reason CodaRunControlContextSuspendedEvent::reason() const -{ - if (m_reason == sharedLibrarySuspendReasonC) - return ModuleLoad; - if (m_reason == "Breakpoint") - return BreakPoint; - // 'Data abort exception'/'Thread has panicked' ... unfortunately somewhat unspecific. - if (m_reason.contains("Exception") || m_reason.contains("panick")) - return Crash; - return Other; -} - -CodaRunControlModuleLoadContextSuspendedEvent::CodaRunControlModuleLoadContextSuspendedEvent(const QByteArray &id, - const QByteArray &reason, - quint64 pc, - const ModuleLoadEventInfo &mi) : - CodaRunControlContextSuspendedEvent(RunControlModuleLoadSuspended, id, reason, pc), - m_mi(mi) -{ -} - -QString CodaRunControlModuleLoadContextSuspendedEvent::toString() const -{ - QString rc; - QTextStream str(&rc); - CodaRunControlContextSuspendedEvent::format(str); - str << ' '; - m_mi.format(str); - return rc; -} - -// -------------- CodaIdEvent -CodaProcessExitedEvent::CodaProcessExitedEvent(const QByteArray &id) : - CodaEvent(ProcessExitedEvent), m_id(id) -{ -} - -QString CodaProcessExitedEvent::toString() const -{ - return QString("Process \"%1\" exited").arg(idString()); -} - -} // namespace Coda diff --git a/src/shared/symbianutils/codamessage.h b/src/shared/symbianutils/codamessage.h deleted file mode 100644 index 27a106c2395..00000000000 --- a/src/shared/symbianutils/codamessage.h +++ /dev/null @@ -1,327 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef CODAMESSAGE_H -#define CODAMESSAGE_H - -#include "symbianutils_global.h" -#include "json_global.h" - -#include <QStringList> -#include <QVector> - -QT_BEGIN_NAMESPACE -class QTextStream; -QT_END_NAMESPACE - -namespace Json { -class JsonValue; -class JsonInputStream; -} - -namespace Coda { - -enum Services { - LocatorService, - RunControlService, - ProcessesService, - MemoryService, - SettingsService, // non-standard, CODA specific - BreakpointsService, - RegistersService, - LoggingService, // non-standard, CODA specific - FileSystemService, - SymbianInstallService, // non-standard, CODA specific - SymbianOSData, // non-standard, CODA specific - DebugSessionControl, // non-standard, CODA specific - UnknownService -}; // Note: Check string array 'serviceNamesC' of same size when modifying this. - -// Modes of RunControl/'Resume' (see EDF documentation). -// As of 24.6.2010, RM_RESUME, RM_STEP_OVER, RM_STEP_INTO, -// RM_STEP_OVER_RANGE, RM_STEP_INTO_RANGE are supported with -// RANG_START/RANGE_END parameters. -enum RunControlResumeMode { - RM_RESUME = 0, - RM_STEP_OVER = 1, RM_STEP_INTO = 2, - RM_STEP_OVER_LINE = 3, RM_STEP_INTO_LINE = 4, - RM_STEP_OUT = 5, RM_REVERSE_RESUME = 6, - RM_REVERSE_STEP_OVER = 7, RM_REVERSE_STEP_INTO = 8, - RM_REVERSE_STEP_OVER_LINE = 9, RM_REVERSE_STEP_INTO_LINE = 10, - RM_REVERSE_STEP_OUT = 11, RM_STEP_OVER_RANGE = 12, - RM_STEP_INTO_RANGE = 13, RM_REVERSE_STEP_OVER_RANGE = 14, - RM_REVERSE_STEP_INTO_RANGE = 15 -}; - -SYMBIANUTILS_EXPORT const char *serviceName(Services s); -SYMBIANUTILS_EXPORT Services serviceFromName(const char *); - -// Debug helpers -SYMBIANUTILS_EXPORT QString formatData(const QByteArray &a); -SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep = ','); - -// Context used in 'RunControl contextAdded' events and in reply -// to 'Processes start'. Could be thread or process. -struct SYMBIANUTILS_EXPORT RunControlContext { - enum Flags { - Container = 0x1, HasState = 0x2, CanSuspend = 0x4, - CanTerminate = 0x8 - }; - enum Type { Process, Thread }; - - RunControlContext(); - Type type() const; - unsigned processId() const; - unsigned threadId() const; - - void clear(); - bool parse(const Json::JsonValue &v); - void format(QTextStream &str) const; - QString toString() const; - - // Helper for converting the CODA ids ("p12" or "p12.t34") - static Type typeFromCodaId(const QByteArray &id); - static unsigned processIdFromTcdfId(const QByteArray &id); - static unsigned threadIdFromTcdfId(const QByteArray &id); - static QByteArray codaId(unsigned processId, unsigned threadId = 0); - - unsigned flags; - unsigned resumeFlags; - QByteArray id; // "p434.t699" - QByteArray osid; // Non-standard: Process or thread id - QByteArray parentId; // Parent process id of a thread. -}; - -// Module load information occurring with 'RunControl contextSuspended' events -struct SYMBIANUTILS_EXPORT ModuleLoadEventInfo { - ModuleLoadEventInfo(); - void clear(); - bool parse(const Json::JsonValue &v); - void format(QTextStream &str) const; - - QByteArray name; - QByteArray file; - bool loaded; - quint64 codeAddress; - quint64 dataAddress; - bool requireResume; -}; - -// Breakpoint as supported by Coda source June 2010 -// TODO: Add watchpoints,etc once they are implemented -struct SYMBIANUTILS_EXPORT Breakpoint { - enum Type { Software, Hardware, Auto }; - - explicit Breakpoint(quint64 loc = 0); - void setContextId(unsigned processId, unsigned threadId = 0); - QString toString() const; - - static QByteArray idFromLocation(quint64 loc); // Automagically determine from location - - Type type; - bool enabled; - int ignoreCount; - QVector<QByteArray> contextIds; // Process or thread ids. - QByteArray id; // Id of the breakpoint; - quint64 location; - unsigned size; - bool thumb; -}; - -Json::JsonInputStream &operator<<(Json::JsonInputStream &str, const Breakpoint &b); - -// Event hierarchy -class SYMBIANUTILS_EXPORT CodaEvent -{ - Q_DISABLE_COPY(CodaEvent) - -public: - enum Type { None, - LocatorHello, - RunControlContextAdded, - RunControlContextRemoved, - RunControlSuspended, - RunControlBreakpointSuspended, - RunControlModuleLoadSuspended, - RunControlResumed, - LoggingWriteEvent, // Non-standard - ProcessExitedEvent // Non-standard - }; - - virtual ~CodaEvent(); - - Type type() const; - virtual QString toString() const; - - static CodaEvent *parseEvent(Services s, const QByteArray &name, const QVector<Json::JsonValue> &val); - -protected: - explicit CodaEvent(Type type = None); - -private: - const Type m_type; -}; - -// ServiceHello -class SYMBIANUTILS_EXPORT CodaLocatorHelloEvent : public CodaEvent { -public: - explicit CodaLocatorHelloEvent(const QStringList &); - - const QStringList &services() const { return m_services; } - virtual QString toString() const; - -private: - QStringList m_services; -}; - -// Logging event (non-standard, CODA specific) -class SYMBIANUTILS_EXPORT CodaLoggingWriteEvent : public CodaEvent { -public: - explicit CodaLoggingWriteEvent(const QByteArray &console, const QByteArray &message); - - QByteArray message() const { return m_message; } - QByteArray console() const { return m_console; } - - virtual QString toString() const; - -private: - const QByteArray m_console; - const QByteArray m_message; -}; - -// Base for events that just have one id as parameter -// (simple suspend) -class SYMBIANUTILS_EXPORT CodaIdEvent : public CodaEvent { -protected: - explicit CodaIdEvent(Type t, const QByteArray &id); -public: - QByteArray id() const { return m_id; } - QString idString() const { return QString::fromUtf8(m_id); } - -private: - const QByteArray m_id; -}; - -// Base for events that just have some ids as parameter -// (context removed) -class SYMBIANUTILS_EXPORT CodaIdsEvent : public CodaEvent { -protected: - explicit CodaIdsEvent(Type t, const QVector<QByteArray> &ids); - -public: - QVector<QByteArray> ids() const { return m_ids; } - QString joinedIdString(const char sep = ',') const; - -private: - const QVector<QByteArray> m_ids; -}; - -// RunControlContextAdded -class SYMBIANUTILS_EXPORT CodaRunControlContextAddedEvent : public CodaEvent { -public: - typedef QVector<RunControlContext> RunControlContexts; - - explicit CodaRunControlContextAddedEvent(const RunControlContexts &c); - - const RunControlContexts &contexts() const { return m_contexts; } - virtual QString toString() const; - - static CodaRunControlContextAddedEvent *parseEvent(const QVector<Json::JsonValue> &val); - -private: - const RunControlContexts m_contexts; -}; - -// RunControlContextRemoved -class SYMBIANUTILS_EXPORT CodaRunControlContextRemovedEvent : public CodaIdsEvent { -public: - explicit CodaRunControlContextRemovedEvent(const QVector<QByteArray> &id); - virtual QString toString() const; -}; - -// Simple RunControlContextSuspended (process/thread) -class SYMBIANUTILS_EXPORT CodaRunControlContextSuspendedEvent : public CodaIdEvent { -public: - enum Reason { BreakPoint, ModuleLoad, Crash, Other } ; - - explicit CodaRunControlContextSuspendedEvent(const QByteArray &id, - const QByteArray &reason, - const QByteArray &message, - quint64 pc = 0); - virtual QString toString() const; - - quint64 pc() const { return m_pc; } - QByteArray reasonID() const { return m_reason; } - Reason reason() const; - QByteArray message() const { return m_message; } - -protected: - explicit CodaRunControlContextSuspendedEvent(Type t, - const QByteArray &id, - const QByteArray &reason, - quint64 pc = 0); - void format(QTextStream &str) const; - -private: - const quint64 m_pc; - const QByteArray m_reason; - const QByteArray m_message; -}; - -// RunControlContextSuspended due to module load -class SYMBIANUTILS_EXPORT CodaRunControlModuleLoadContextSuspendedEvent : public CodaRunControlContextSuspendedEvent { -public: - explicit CodaRunControlModuleLoadContextSuspendedEvent(const QByteArray &id, - const QByteArray &reason, - quint64 pc, - const ModuleLoadEventInfo &mi); - - virtual QString toString() const; - const ModuleLoadEventInfo &info() const { return m_mi; } - -private: - const ModuleLoadEventInfo m_mi; -}; - -// Process exited event -class SYMBIANUTILS_EXPORT CodaProcessExitedEvent : public CodaEvent { -public: - explicit CodaProcessExitedEvent(const QByteArray &id); - - QByteArray id() const { return m_id; } - QString idString() const { return QString::fromUtf8(m_id); } - virtual QString toString() const; - -private: - const QByteArray m_id; -}; - -} // namespace Coda -#endif // CODAMESSAGE_H diff --git a/src/shared/symbianutils/codautils.cpp b/src/shared/symbianutils/codautils.cpp deleted file mode 100644 index b8588542ea4..00000000000 --- a/src/shared/symbianutils/codautils.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "codautils.h" -#include <ctype.h> - -#include <QCoreApplication> -#include <QDebug> -#include <QDate> -#include <QDateTime> -#include <QTime> - -#define logMessage(s) do { qDebug() << "CODACLIENT: " << s; } while (0) - -namespace Coda { - -Library::Library() : codeseg(0), dataseg(0), pid(0) -{ -} - -Library::Library(const CodaResult &result) : codeseg(0), dataseg(0), pid(0) -{ - if (result.data.size() < 20) { - qWarning("Invalid CODA creation notification received."); - return; - } - - const char *data = result.data.constData(); - pid = extractInt(data + 2); - codeseg = extractInt(data + 10); - dataseg = extractInt(data + 14); - const uint len = extractShort(data + 18); - name = result.data.mid(20, len); -} - -CodaAppVersion::CodaAppVersion() -{ - reset(); -} - -void CodaAppVersion::reset() -{ - codaMajor = codaMinor = protocolMajor = protocolMinor = 0; -} - -Session::Session() -{ - reset(); -} - -void Session::reset() -{ - cpuMajor = 0; - cpuMinor = 0; - bigEndian = 0; - defaultTypeSize = 0; - fpTypeSize = 0; - extended1TypeSize = 0; - extended2TypeSize = 0; - pid = 0; - mainTid = 0; - tid = 0; - codeseg = 0; - dataseg = 0; - - libraries.clear(); - codaAppVersion.reset(); -} - -static QString formatCpu(int major, int minor) -{ - //: CPU description of an S60 device - //: %1 major verison, %2 minor version - //: %3 real name of major verison, %4 real name of minor version - const QString str = QCoreApplication::translate("Coda::Session", "CPU: v%1.%2%3%4"); - QString majorStr; - QString minorStr; - switch (major) { - case 0x04: - majorStr = " ARM"; - break; - } - switch (minor) { - case 0x00: - minorStr = " 920T"; - break; - } - return str.arg(major).arg(minor).arg(majorStr).arg(minorStr); - } - -QString formatCodaVersion(const CodaAppVersion &version) -{ - QString str = QCoreApplication::translate("Coda::Session", - "CODA: v%1.%2 CODA protocol: v%3.%4"); - str = str.arg(version.codaMajor).arg(version.codaMinor); - return str.arg(version.protocolMajor).arg(version.protocolMinor); -} - -QString Session::deviceDescription(unsigned verbose) const -{ - if (!cpuMajor) - return QString(); - - //: s60description - //: description of an S60 device - //: %1 CPU description, %2 endianness - //: %3 default type size (if any), %4 float size (if any) - //: %5 Coda version - QString msg = QCoreApplication::translate("Coda::Session", "%1, %2%3%4, %5"); - QString endianness = bigEndian - ? QCoreApplication::translate("Coda::Session", "big endian") - : QCoreApplication::translate("Coda::Session", "little endian"); - msg = msg.arg(formatCpu(cpuMajor, cpuMinor)).arg(endianness); - QString defaultTypeSizeStr; - QString fpTypeSizeStr; - if (verbose && defaultTypeSize) - //: will be inserted into s60description - defaultTypeSizeStr = QCoreApplication::translate("Coda::Session", ", type size: %1").arg(defaultTypeSize); - if (verbose && fpTypeSize) - //: will be inserted into s60description - fpTypeSizeStr = QCoreApplication::translate("Coda::Session", ", float size: %1").arg(fpTypeSize); - msg = msg.arg(defaultTypeSizeStr).arg(fpTypeSizeStr); - return msg.arg(formatCodaVersion(codaAppVersion)); -} - -QByteArray Session::gdbLibraryList() const -{ - const int count = libraries.size(); - QByteArray response = "l<library-list>"; - for (int i = 0; i != count; ++i) { - const Coda::Library &lib = libraries.at(i); - response += "<library name=\""; - response += lib.name; - response += "\">"; - response += "<section address=\"0x"; - response += Coda::hexNumber(lib.codeseg); - response += "\"/>"; - response += "<section address=\"0x"; - response += Coda::hexNumber(lib.dataseg); - response += "\"/>"; - response += "<section address=\"0x"; - response += Coda::hexNumber(lib.dataseg); - response += "\"/>"; - response += "</library>"; - } - response += "</library-list>"; - return response; -} - -QByteArray Session::gdbQsDllInfo(int start, int count) const -{ - // Happens with gdb 6.4.50.20060226-cvs / CodeSourcery. - // Never made it into FSF gdb that got qXfer:libraries:read instead. - // http://sourceware.org/ml/gdb/2007-05/msg00038.html - // Name=hexname,TextSeg=textaddr[,DataSeg=dataaddr] - const int libraryCount = libraries.size(); - const int end = count < 0 ? libraryCount : qMin(libraryCount, start + count); - QByteArray response(1, end == libraryCount ? 'l' : 'm'); - for (int i = start; i < end; ++i) { - if (i != start) - response += ';'; - const Library &lib = libraries.at(i); - response += "Name="; - response += lib.name.toHex(); - response += ",TextSeg="; - response += hexNumber(lib.codeseg); - response += ",DataSeg="; - response += hexNumber(lib.dataseg); - } - return response; -} - -QString Session::toString() const -{ - QString rc; - QTextStream str(&rc); - str << "Session: " << deviceDescription(false) << '\n' - << "pid: " << pid << "main thread: " << mainTid - << " current thread: " << tid << ' '; - str.setIntegerBase(16); - str << " code: 0x" << codeseg << " data: 0x" << dataseg << '\n'; - if (const int libCount = libraries.size()) { - str << "Libraries:\n"; - for (int i = 0; i < libCount; i++) - str << " #" << i << ' ' << libraries.at(i).name - << " code: 0x" << libraries.at(i).codeseg - << " data: 0x" << libraries.at(i).dataseg << '\n'; - } - if (const int moduleCount = modules.size()) { - str << "Modules:\n"; - for (int i = 0; i < moduleCount; i++) - str << " #" << i << ' ' << modules.at(i) << '\n'; - } - str.setIntegerBase(10); - if (!addressToBP.isEmpty()) { - typedef QHash<uint, uint>::const_iterator BP_ConstIterator; - str << "Breakpoints:\n"; - const BP_ConstIterator cend = addressToBP.constEnd(); - for (BP_ConstIterator it = addressToBP.constBegin(); it != cend; ++it) { - str.setIntegerBase(16); - str << " 0x" << it.key(); - str.setIntegerBase(10); - str << ' ' << it.value() << '\n'; - } - } - - return rc; -} - -// -------------- - -QByteArray decode7d(const QByteArray &ba) -{ - QByteArray res; - res.reserve(ba.size()); - for (int i = 0; i < ba.size(); ++i) { - byte c = byte(ba.at(i)); - if (c == 0x7d) { - ++i; - c = 0x20 ^ byte(ba.at(i)); - } - res.append(c); - } - return res; -} - -QByteArray encode7d(const QByteArray &ba) -{ - QByteArray res; - res.reserve(ba.size() + 2); - for (int i = 0; i < ba.size(); ++i) { - byte c = byte(ba.at(i)); - if (c == 0x7e || c == 0x7d) { - res.append(0x7d); - res.append(0x20 ^ c); - } else { - res.append(c); - } - } - return res; -} - -// FIXME: Use the QByteArray based version below? -static inline QString stringFromByte(byte c) -{ - return QString::fromLatin1("%1").arg(c, 2, 16, QChar('0')); -} - -SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen) -{ - QString str; - QString ascii; - const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen); - for (int i = 0; i < size; ++i) { - const int c = byte(ba.at(i)); - str += QString::fromAscii("%1 ").arg(c, 2, 16, QChar('0')); - ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); - } - if (size != ba.size()) { - str += QLatin1String("..."); - ascii += QLatin1String("..."); - } - return str + QLatin1String(" ") + ascii; -} - -SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) -{ - QByteArray ba = QByteArray::number(n, 16); - if (digits == 0 || ba.size() == digits) - return ba; - return QByteArray(digits - ba.size(), '0') + ba; -} - -SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits) -{ - return "0x" + hexNumber(n, digits); -} - -CodaResult::CodaResult() : - code(0), - token(0), - isDebugOutput(false) -{ -} - -void CodaResult::clear() -{ - code = token= 0; - isDebugOutput = false; - data.clear(); - cookie = QVariant(); -} - -QString CodaResult::toString() const -{ - QString res = stringFromByte(code); - res += QLatin1String(" ["); - res += stringFromByte(token); - res += QLatin1Char(']'); - res += QLatin1Char(' '); - res += stringFromArray(data); - return res; -} - -QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame) -{ - byte s = command + token; - for (int i = 0; i != data.size(); ++i) - s += data.at(i); - byte checksum = 255 - (s & 0xff); - //int x = s + ~s; - //logMessage("check: " << s << checksum << x; - - QByteArray response; - response.reserve(data.size() + 3); - response.append(char(command)); - response.append(char(token)); - response.append(data); - response.append(char(checksum)); - - QByteArray encodedData = encode7d(response); - - QByteArray ba; - ba.reserve(encodedData.size() + 6); - if (serialFrame) { - ba.append(char(0x01)); - ba.append(char(0x90)); - const ushort encodedSize = encodedData.size() + 2; // 2 x 0x7e - appendShort(&ba, encodedSize, BigEndian); - } - ba.append(char(0x7e)); - ba.append(encodedData); - ba.append(char(0x7e)); - - return ba; -} - -/* returns 0 if array doesn't represent a result, -otherwise returns the length of the result data */ -ushort isValidCodaResult(const QByteArray &buffer, bool serialFrame, ushort& mux) -{ - if (serialFrame) { - // Serial protocol with length info - if (buffer.length() < 4) - return 0; - mux = extractShort(buffer.data()); - const ushort len = extractShort(buffer.data() + 2); - return (buffer.size() >= len + 4) ? len : ushort(0); - } - // Frameless protocol without length info - const char delimiter = char(0x7e); - const int firstDelimiterPos = buffer.indexOf(delimiter); - // Regular message delimited by 0x7e..0x7e - if (firstDelimiterPos == 0) { - mux = MuxCoda; - const int endPos = buffer.indexOf(delimiter, firstDelimiterPos + 1); - return endPos != -1 ? endPos + 1 - firstDelimiterPos : 0; - } - // Some ASCII log message up to first delimiter or all - return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size(); -} - -bool extractResult(QByteArray *buffer, bool serialFrame, CodaResult *result, bool &linkEstablishmentMode, QByteArray *rawData) -{ - result->clear(); - if(rawData) - rawData->clear(); - ushort len = isValidCodaResult(*buffer, serialFrame, result->multiplex); - // handle receiving application output, which is not a regular command - const int delimiterPos = serialFrame ? 4 : 0; - if (linkEstablishmentMode) { - //when "hot connecting" a device, we can receive partial frames. - //this code resyncs by discarding data until a CODA frame is found - while (buffer->length() > delimiterPos - && result->multiplex != MuxTextTrace - && !(result->multiplex == MuxCoda && buffer->at(delimiterPos) == 0x7e)) { - buffer->remove(0,1); - len = isValidCodaResult(*buffer, serialFrame, result->multiplex); - } - } - if (!len) - return false; - if (buffer->at(delimiterPos) != 0x7e) { - result->isDebugOutput = true; - result->data = buffer->mid(delimiterPos, len); - buffer->remove(0, delimiterPos + len); - return true; - } - // FIXME: what happens if the length contains 0xfe? - // Assume for now that it passes unencoded! - const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2)); - if(rawData) - *rawData = data; - buffer->remove(0, delimiterPos + len); - - byte sum = 0; - for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum - sum += byte(data.at(i)); - if (sum != 0xff) - logMessage("*** CHECKSUM ERROR: " << byte(sum)); - - result->code = data.at(0); - result->token = data.at(1); - result->data = data.mid(2, data.size() - 3); - //logMessage(" REST BUF: " << stringFromArray(*buffer)); - //logMessage(" CURR DATA: " << stringFromArray(data)); - //QByteArray prefix = "READ BUF: "; - //logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data()); - linkEstablishmentMode = false; //have received a good CODA packet, therefore in sync - return true; -} - -SYMBIANUTILS_EXPORT ushort extractShort(const char *data) -{ - return byte(data[0]) * 256 + byte(data[1]); -} - -SYMBIANUTILS_EXPORT uint extractInt(const char *data) -{ - uint res = byte(data[0]); - res *= 256; res += byte(data[1]); - res *= 256; res += byte(data[2]); - res *= 256; res += byte(data[3]); - return res; -} - -SYMBIANUTILS_EXPORT quint64 extractInt64(const char *data) -{ - quint64 res = byte(data[0]); - res <<= 8; res += byte(data[1]); - res <<= 8; res += byte(data[2]); - res <<= 8; res += byte(data[3]); - res <<= 8; res += byte(data[4]); - res <<= 8; res += byte(data[5]); - res <<= 8; res += byte(data[6]); - res <<= 8; res += byte(data[7]); - return res; -} - -SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba) -{ - QString res; - char buf[10]; - for (int i = 0, n = ba.size(); i != n; ++i) { - const byte c = ba.at(i); - if (isprint(c)) { - res += c; - } else { - qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c)); - res += buf; - } - } - return res; -} - -SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness endian) -{ - if (endian == BigEndian) { - ba->append(s / 256); - ba->append(s % 256); - } else { - ba->append(s % 256); - ba->append(s / 256); - } -} - -SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness endian) -{ - const uchar b3 = i % 256; i /= 256; - const uchar b2 = i % 256; i /= 256; - const uchar b1 = i % 256; i /= 256; - const uchar b0 = i; - ba->reserve(ba->size() + 4); - if (endian == BigEndian) { - ba->append(b0); - ba->append(b1); - ba->append(b2); - ba->append(b3); - } else { - ba->append(b3); - ba->append(b2); - ba->append(b1); - ba->append(b0); - } -} - -void appendString(QByteArray *ba, const QByteArray &str, Endianness endian, bool appendNullTerminator) -{ - const int fullSize = str.size() + (appendNullTerminator ? 1 : 0); - appendShort(ba, fullSize, endian); // count the terminating \0 - ba->append(str); - if (appendNullTerminator) - ba->append('\0'); -} - -void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness endian) -{ - // convert the QDateTime to UTC and append its representation to QByteArray - // format is the same as in FAT file system - dateTime = dateTime.toUTC(); - const QTime utcTime = dateTime.time(); - const QDate utcDate = dateTime.date(); - uint fatDateTime = (utcTime.hour() << 11 | utcTime.minute() << 5 | utcTime.second()/2) << 16; - fatDateTime |= (utcDate.year()-1980) << 9 | utcDate.month() << 5 | utcDate.day(); - appendInt(ba, fatDateTime, endian); -} - -QByteArray errorMessage(byte code) -{ - switch (code) { - case 0x00: return "No error"; - case 0x01: return "Generic error in CWDS message"; - case 0x02: return "Unexpected packet size in send msg"; - case 0x03: return "Internal error occurred in CWDS"; - case 0x04: return "Escape followed by frame flag"; - case 0x05: return "Bad FCS in packet"; - case 0x06: return "Packet too long"; - case 0x07: return "Sequence ID not expected (gap in sequence)"; - - case 0x10: return "Command not supported"; - case 0x11: return "Command param out of range"; - case 0x12: return "An option was not supported"; - case 0x13: return "Read/write to invalid memory"; - case 0x14: return "Read/write invalid registers"; - case 0x15: return "Exception occurred in CWDS"; - case 0x16: return "Targeted system or thread is running"; - case 0x17: return "Breakpoint resources (HW or SW) exhausted"; - case 0x18: return "Requested breakpoint conflicts with existing one"; - - case 0x20: return "General OS-related error"; - case 0x21: return "Request specified invalid process"; - case 0x22: return "Request specified invalid thread"; - } - return "Unknown error"; -} - -uint swapEndian(uint in) -{ - return (in>>24) | ((in<<8) & 0x00FF0000) | ((in>>8) & 0x0000FF00) | (in<<24); -} - -int CodaResult::errorCode() const -{ - // NAK means always error, else data sized 1 with a non-null element - const bool isNAK = code == 0xff; - if (data.size() != 1 && !isNAK) - return 0; - if (const int errorCode = data.at(0)) - return errorCode; - return isNAK ? 0xff : 0; -} - -QString CodaResult::errorString() const -{ - // NAK means always error, else data sized 1 with a non-null element - if (code == 0xff) - return "NAK"; - if (data.size() < 1) - return "Unknown error packet"; - return errorMessage(data.at(0)); -} - -} // namespace Coda - diff --git a/src/shared/symbianutils/codautils.h b/src/shared/symbianutils/codautils.h deleted file mode 100644 index c1f1d862435..00000000000 --- a/src/shared/symbianutils/codautils.h +++ /dev/null @@ -1,158 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef DEBUGGER_CODA_UTILS -#define DEBUGGER_CODA_UTILS - -#include "symbianutils_global.h" - -#include <QByteArray> -#include <QHash> -#include <QStringList> -#include <QVariant> - -QT_BEGIN_NAMESPACE -class QDateTime; -QT_END_NAMESPACE - -namespace Coda { - -typedef unsigned char byte; -struct CodaResult; - -enum SerialMultiplexor { - MuxRaw = 0, - MuxTextTrace = 0x0102, - MuxCoda = 0x0190 -}; - -inline byte extractByte(const char *data) { return *data; } -SYMBIANUTILS_EXPORT ushort extractShort(const char *data); -SYMBIANUTILS_EXPORT uint extractInt(const char *data); -SYMBIANUTILS_EXPORT quint64 extractInt64(const char *data); - -SYMBIANUTILS_EXPORT QString quoteUnprintableLatin1(const QByteArray &ba); - -// produces "xx xx xx " -SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen = - 1); - -enum Endianness -{ - LittleEndian, - BigEndian, - TargetByteOrder = BigEndian -}; - -SYMBIANUTILS_EXPORT void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder); -SYMBIANUTILS_EXPORT void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder); -SYMBIANUTILS_EXPORT void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true); - -struct SYMBIANUTILS_EXPORT Library -{ - Library(); - explicit Library(const CodaResult &r); - - QByteArray name; - uint codeseg; - uint dataseg; - //library addresses are valid for a given process (depending on memory model, they might be loaded at the same address in all processes or not) - uint pid; -}; - -struct SYMBIANUTILS_EXPORT CodaAppVersion -{ - CodaAppVersion(); - void reset(); - - int codaMajor; - int codaMinor; - int protocolMajor; - int protocolMinor; -}; - -struct SYMBIANUTILS_EXPORT Session -{ - Session(); - void reset(); - QString deviceDescription(unsigned verbose) const; - QString toString() const; - // Answer to qXfer::libraries - QByteArray gdbLibraryList() const; - // Answer to qsDllInfo, can be sent chunk-wise. - QByteArray gdbQsDllInfo(int start = 0, int count = -1) const; - - // CODA feedback - byte cpuMajor; - byte cpuMinor; - byte bigEndian; - byte defaultTypeSize; - byte fpTypeSize; - byte extended1TypeSize; - byte extended2TypeSize; - CodaAppVersion codaAppVersion; - uint pid; - uint mainTid; - uint tid; - uint codeseg; - uint dataseg; - QHash<uint, uint> addressToBP; - - typedef QList<Library> Libraries; - Libraries libraries; - - // Gdb request - QStringList modules; -}; - -struct SYMBIANUTILS_EXPORT CodaResult -{ - CodaResult(); - void clear(); - QString toString() const; - // 0 for no error. - int errorCode() const; - QString errorString() const; - - ushort multiplex; - byte code; - byte token; - QByteArray data; - QVariant cookie; - bool isDebugOutput; -}; - -SYMBIANUTILS_EXPORT QByteArray errorMessage(byte code); -SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits = 0); -SYMBIANUTILS_EXPORT QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too -SYMBIANUTILS_EXPORT uint swapEndian(uint in); - -} // namespace Coda - -#endif // DEBUGGER_CODA_UTILS diff --git a/src/shared/symbianutils/codautils_p.h b/src/shared/symbianutils/codautils_p.h deleted file mode 100644 index 8466ba314b3..00000000000 --- a/src/shared/symbianutils/codautils_p.h +++ /dev/null @@ -1,51 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef DEBUGGER_CODA_PRIVATE_UTILS -#define DEBUGGER_CODA_PRIVATE_UTILS - -#include "codautils.h" -#include "symbianutils_global.h" - -QT_BEGIN_NAMESPACE -class QDateTime; -QT_END_NAMESPACE - -namespace Coda { - -void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness = TargetByteOrder); -// returns a QByteArray containing optionally -// the serial frame [0x01 0x90 <len>] and 0x7e encoded7d(ba) 0x7e -QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame); -bool extractResult(QByteArray *buffer, bool serialFrame, CodaResult *r, bool& linkEstablishmentMode, QByteArray *rawData = 0); - -} // namespace Coda - -#endif // DEBUGGER_CODA_PRIVATE_UTILS diff --git a/src/shared/symbianutils/symbiandevicemanager.cpp b/src/shared/symbianutils/symbiandevicemanager.cpp deleted file mode 100644 index dca77825ef4..00000000000 --- a/src/shared/symbianutils/symbiandevicemanager.cpp +++ /dev/null @@ -1,804 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "symbiandevicemanager.h" -#include "codadevice.h" -#include "virtualserialdevice.h" - -#include <QCoreApplication> -#include <QEvent> -#include <QSettings> -#include <QStringList> -#include <QFileInfo> -#include <QDebug> -#include <QTextStream> -#include <QSharedData> -#include <QScopedPointer> -#include <QSignalMapper> -#include <QThread> -#include <QWaitCondition> -#include <QTimer> - -#ifdef Q_OS_MACX -#include <CoreFoundation/CoreFoundation.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/serial/IOSerialKeys.h> -#include <IOKit/usb/USBSpec.h> - -// 10.5 doesn't have kUSBProductString or kUSBVendorString -#ifndef kUSBProductString -#define kUSBProductString "USB Product Name" -#endif -#ifndef kUSBVendorString -#define kUSBVendorString "USB Vendor Name" -#endif - -#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3) -#include <IOKit/serial/ioss.h> -#endif -#include <IOKit/IOBSD.h> -#endif - -namespace SymbianUtils { - -enum { debug = 0 }; - -static const char REGKEY_CURRENT_CONTROL_SET[] = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet"; -static const char USBSER[] = "Services/usbser/Enum"; - -const char *SymbianDeviceManager::linuxBlueToothDeviceRootC = "/dev/rfcomm"; - -// ------------- SymbianDevice -class SymbianDeviceData : public QSharedData { -public: - SymbianDeviceData(); - ~SymbianDeviceData(); - - bool isOpen() const; - void forcedClose(); - - QString portName; - QString friendlyName; - QString deviceDesc; - QString manufacturer; - QString additionalInformation; - - DeviceCommunicationType type; - QSharedPointer<Coda::CodaDevice> codaDevice; - int deviceAcquired; -}; - -SymbianDeviceData::SymbianDeviceData() : - type(SerialPortCommunication), - deviceAcquired(0) -{ -} - -bool SymbianDeviceData::isOpen() const -{ - return codaDevice && codaDevice->device()->isOpen(); -} - -SymbianDeviceData::~SymbianDeviceData() -{ - forcedClose(); -} - -void SymbianDeviceData::forcedClose() -{ - // Close the device when unplugging. Should devices be in 'acquired' state, - // their owners should hit on write failures. - // Apart from the <shared item> destructor, also called by the devicemanager - // to ensure it also happens if other shared instances are still around. - if (isOpen()) { - if (deviceAcquired) - qWarning("Device on '%s' unplugged while an operation is in progress.", - qPrintable(portName)); - codaDevice->device()->close(); - } -} - -SymbianDevice::SymbianDevice(SymbianDeviceData *data) : - m_data(data) -{ -} - -SymbianDevice::SymbianDevice() : - m_data(new SymbianDeviceData) -{ -} -SymbianDevice::SymbianDevice(const SymbianDevice &rhs) : - m_data(rhs.m_data) -{ -} - -SymbianDevice &SymbianDevice::operator=(const SymbianDevice &rhs) -{ - if (this != &rhs) - m_data = rhs.m_data; - return *this; -} - -SymbianDevice::~SymbianDevice() -{ -} - -void SymbianDevice::forcedClose() -{ - m_data->forcedClose(); -} - -QString SymbianDevice::portName() const -{ - return m_data->portName; -} - -QString SymbianDevice::friendlyName() const -{ - return m_data->friendlyName; -} - -QString SymbianDevice::additionalInformation() const -{ - return m_data->additionalInformation; -} - -void SymbianDevice::setAdditionalInformation(const QString &a) -{ - m_data->additionalInformation = a; -} - -QString SymbianDevice::deviceDesc() const -{ - return m_data->deviceDesc; -} - -QString SymbianDevice::manufacturer() const -{ - return m_data->manufacturer; -} - -DeviceCommunicationType SymbianDevice::type() const -{ - return m_data->type; -} - -bool SymbianDevice::isNull() const -{ - return m_data->portName.isEmpty(); -} - -bool SymbianDevice::isOpen() const -{ - return m_data->isOpen(); -} - -QString SymbianDevice::toString() const -{ - QString rc; - QTextStream str(&rc); - format(str); - return rc; -} - -void SymbianDevice::format(QTextStream &str) const -{ - str << (m_data->type == BlueToothCommunication ? "Bluetooth: " : "Serial: ") - << m_data->portName; - if (!m_data->friendlyName.isEmpty()) { - str << " (" << m_data->friendlyName; - if (!m_data->deviceDesc.isEmpty()) - str << " / " << m_data->deviceDesc; - str << ')'; - } - if (!m_data->manufacturer.isEmpty()) - str << " [" << m_data->manufacturer << ']'; -} - -// Compare by port and friendly name -int SymbianDevice::compare(const SymbianDevice &rhs) const -{ - if (const int prc = m_data->portName.compare(rhs.m_data->portName)) - return prc; - if (const int frc = m_data->friendlyName.compare(rhs.m_data->friendlyName)) - return frc; - return 0; -} - -SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &cd) -{ - d.nospace() << cd.toString(); - return d; -} - -// ------------- SymbianDeviceManagerPrivate -struct SymbianDeviceManagerPrivate { - SymbianDeviceManagerPrivate() : - m_initialized(false), - m_devicesLock(QMutex::Recursive) - { -#ifdef Q_OS_MACX - m_deviceListChangedNotification = 0; -#endif - } - - bool m_initialized; - SymbianDeviceManager::SymbianDeviceList m_devices; - QMutex m_devicesLock; // Used for protecting access to m_devices and serialising getCodaDevice/delayedClosePort - // The following 2 variables are needed to manage requests for a CODA port not coming from the main thread - int m_constructCodaPortEventType; - QMutex m_codaPortWaitMutex; -#ifdef Q_OS_MACX - IONotificationPortRef m_deviceListChangedNotification; -#endif -}; - -class QConstructCodaPortEvent : public QEvent -{ -public: - QConstructCodaPortEvent(QEvent::Type eventId, const QString &portName, CodaDevicePtr *device, QWaitCondition *waiter) : - QEvent(eventId), m_portName(portName), m_device(device), m_waiter(waiter) - {} - - QString m_portName; - CodaDevicePtr* m_device; - QWaitCondition *m_waiter; -}; - - -SymbianDeviceManager::SymbianDeviceManager(QObject *parent) : - QObject(parent), - d(new SymbianDeviceManagerPrivate) -{ - d->m_constructCodaPortEventType = QEvent::registerEventType(); -} - -SymbianDeviceManager::~SymbianDeviceManager() -{ -#ifdef Q_OS_MACX - if (d && d->m_deviceListChangedNotification) - IONotificationPortDestroy(d->m_deviceListChangedNotification); -#endif - delete d; -} - -SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::devices() const -{ - ensureInitialized(); - QMutexLocker lock(&d->m_devicesLock); - return d->m_devices; -} - -QString SymbianDeviceManager::toString() const -{ - QMutexLocker lock(&d->m_devicesLock); - QString rc; - QTextStream str(&rc); - str << d->m_devices.size() << " devices:\n"; - const int count = d->m_devices.size(); - for (int i = 0; i < count; i++) { - str << '#' << i << ' '; - d->m_devices.at(i).format(str); - str << '\n'; - } - return rc; -} - -int SymbianDeviceManager::findByPortName(const QString &p) const -{ - ensureInitialized(); - const int count = d->m_devices.size(); - for (int i = 0; i < count; i++) - if (d->m_devices.at(i).portName() == p) - return i; - return -1; -} - -QString SymbianDeviceManager::friendlyNameForPort(const QString &port) const -{ - QMutexLocker lock(&d->m_devicesLock); - const int idx = findByPortName(port); - return idx == -1 ? QString() : d->m_devices.at(idx).friendlyName(); -} - -CodaDevicePtr SymbianDeviceManager::getCodaDevice(const QString &port) -{ - ensureInitialized(); - QMutexLocker lock(&d->m_devicesLock); - 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 CodaDevicePtr(); - } - SymbianDevice& device = d->m_devices[idx]; - CodaDevicePtr& devicePtr = device.m_data->codaDevice; - if (devicePtr.isNull() || !devicePtr->device()->isOpen()) { - // Check we instanciate in the correct thread - we can't afford to create the CodaDevice (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 main thread - d->m_codaPortWaitMutex.lock(); - QWaitCondition waiter; - QCoreApplication::postEvent(this, new QConstructCodaPortEvent((QEvent::Type)d->m_constructCodaPortEventType, port, &devicePtr, &waiter)); - waiter.wait(&d->m_codaPortWaitMutex); - // When the wait returns (due to the wakeAll in SymbianDeviceManager::customEvent), the CodaDevice will be fully set up - d->m_codaPortWaitMutex.unlock(); - } else { - // We're in the main thread, just set it up directly - constructCodaPort(devicePtr, port); - } - // We still carry on in the case we failed to open so the client can access the IODevice's errorString() - } - if (devicePtr->device()->isOpen()) - device.m_data->deviceAcquired++; - return devicePtr; -} - -void SymbianDeviceManager::constructCodaPort(CodaDevicePtr& device, const QString& portName) -{ - QMutexLocker locker(&d->m_codaPortWaitMutex); - if (device.isNull()) { - device = QSharedPointer<Coda::CodaDevice>(new Coda::CodaDevice); - const QSharedPointer<SymbianUtils::VirtualSerialDevice> serialDevice(new SymbianUtils::VirtualSerialDevice(portName)); - device->setSerialFrame(true); - device->setDevice(serialDevice); - } - if (!device->device()->isOpen()) { - bool ok = device->device().staticCast<SymbianUtils::VirtualSerialDevice>()->open(QIODevice::ReadWrite); - if (!ok && debug) { - qDebug("SymbianDeviceManager: Failed to open port %s", qPrintable(portName)); - } - } -} - -void SymbianDeviceManager::customEvent(QEvent *event) -{ - if (event->type() == d->m_constructCodaPortEventType) { - QConstructCodaPortEvent* constructEvent = static_cast<QConstructCodaPortEvent*>(event); - constructCodaPort(*constructEvent->m_device, constructEvent->m_portName); - constructEvent->m_waiter->wakeAll(); // Should only ever be one thing waiting on this - } -} - -void SymbianDeviceManager::releaseCodaDevice(CodaDevicePtr &port) -{ - if (port) { - QMutexLocker(&d->m_devicesLock); - // Check if this was the last reference to the port, if so close it after a short delay - foreach (const SymbianDevice& device, d->m_devices) { - if (device.m_data->codaDevice.data() == port.data()) { - if (device.m_data->deviceAcquired > 0) - device.m_data->deviceAcquired--; - if (device.m_data->deviceAcquired == 0) { - if (debug) - qDebug("Starting timer to close port %s", qPrintable(device.m_data->portName)); - QTimer::singleShot(1000, this, SLOT(delayedClosePort())); - } - break; - } - } - port.clear(); - } -} - -void SymbianDeviceManager::delayedClosePort() -{ - // Find any coda ports that are still open but have a reference count of zero, and delete them - QMutexLocker(&d->m_devicesLock); - foreach (const SymbianDevice& device, d->m_devices) { - Coda::CodaDevice* codaDevice = device.m_data->codaDevice.data(); - if (codaDevice && device.m_data->deviceAcquired == 0 && codaDevice->device()->isOpen()) { - if (debug) - qDebug("Closing device %s", qPrintable(device.m_data->portName)); - device.m_data->codaDevice->device()->close(); - } - } -} - -void SymbianDeviceManager::update() -{ - update(true); -} - -void SymbianDeviceManager::setAdditionalInformation(const QString &port, const QString &ai) -{ - const int idx = findByPortName(port); - if (idx != -1) - d->m_devices[idx].setAdditionalInformation(ai); -} - -void SymbianDeviceManager::ensureInitialized() const -{ - if (!d->m_initialized) // Flag is set in update() - const_cast<SymbianDeviceManager*>(this)->update(false); -} - -void SymbianDeviceManager::update(bool emitSignals) -{ - QMutexLocker lock(&d->m_devicesLock); - - static int n = 0; - typedef SymbianDeviceList::iterator SymbianDeviceListIterator; - - if (debug) - qDebug(">SerialDeviceLister::update(#%d, signals=%d)\n%s", n++, int(emitSignals), - qPrintable(toString())); - - d->m_initialized = true; - // Get ordered new list - SymbianDeviceList newDevices = serialPorts() + blueToothDevices(); - if (newDevices.size() > 1) - qStableSort(newDevices.begin(), newDevices.end()); - if (d->m_devices == newDevices) { // Happy, nothing changed. - if (debug) - qDebug("<SerialDeviceLister::update: unchanged\n"); - return; - } - // Merge the lists and emit the respective added/removed signals, assuming - // no one can plug a different device on the same port at the speed of lightning - SymbianDeviceList removedDevices; - if (!d->m_devices.isEmpty()) { - // Find deleted devices - for (SymbianDeviceListIterator oldIt = d->m_devices.begin(); oldIt != d->m_devices.end(); ) { - if (newDevices.contains(*oldIt)) { - ++oldIt; - } else { - SymbianDevice toBeDeleted = *oldIt; - toBeDeleted.forcedClose(); - oldIt = d->m_devices.erase(oldIt); - removedDevices.append(toBeDeleted); - } - } - } - SymbianDeviceList addedDevices; - if (!newDevices.isEmpty()) { - // Find new devices and insert in order - foreach(const SymbianDevice &newDevice, newDevices) { - if (!d->m_devices.contains(newDevice)) { - d->m_devices.append(newDevice); - addedDevices.append(newDevice); - } - } - if (d->m_devices.size() > 1) - qStableSort(d->m_devices.begin(), d->m_devices.end()); - } - - lock.unlock(); - if (emitSignals) { - foreach (const SymbianDevice &device, removedDevices) { - emit deviceRemoved(device); - } - foreach (const SymbianDevice &device, addedDevices) { - emit deviceAdded(device); - } - emit updated(); - } - - if (debug) - qDebug("<SerialDeviceLister::update\n%s\n", qPrintable(toString())); -} - -#ifdef Q_OS_MACX -QString CFStringToQString(CFStringRef cfstring) -{ - QString result; - int len = CFStringGetLength(cfstring); - result.resize(len); - CFStringGetCharacters(cfstring, CFRangeMake(0, len), reinterpret_cast<UniChar *>(result.data())); - return result; -} - -void deviceListChanged(void *refCon, io_iterator_t iter) -{ - // The way we're structured, it's easier to rescan rather than take advantage of the finer-grained device addition and removal info that OS X gives us - io_object_t obj; - while ((obj = IOIteratorNext(iter))) IOObjectRelease(obj); - static_cast<SymbianDeviceManager *>(refCon)->update(); -} - -#endif - -SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::serialPorts() const -{ - SymbianDeviceList rc; -#if defined(Q_OS_WIN) - const QSettings registry(REGKEY_CURRENT_CONTROL_SET, QSettings::NativeFormat); - const QString usbSerialRootKey = QLatin1String(USBSER) + QLatin1Char('/'); - const int count = registry.value(usbSerialRootKey + QLatin1String("Count")).toInt(); - for (int i = 0; i < count; ++i) { - QString driver = registry.value(usbSerialRootKey + QString::number(i)).toString(); - if (driver.contains(QLatin1String("JAVACOMM"))) { - driver.replace(QLatin1Char('\\'), QLatin1Char('/')); - const QString driverRootKey = QLatin1String("Enum/") + driver + QLatin1Char('/'); - if (debug > 1) - qDebug() << "SerialDeviceLister::serialPorts(): Checking " << i << count - << REGKEY_CURRENT_CONTROL_SET << usbSerialRootKey << driverRootKey; - QScopedPointer<SymbianDeviceData> device(new SymbianDeviceData); - device->type = SerialPortCommunication; - device->friendlyName = registry.value(driverRootKey + QLatin1String("FriendlyName")).toString(); - device->portName = registry.value(driverRootKey + QLatin1String("Device Parameters/PortName")).toString(); - device->deviceDesc = registry.value(driverRootKey + QLatin1String("DeviceDesc")).toString(); - device->manufacturer = registry.value(driverRootKey + QLatin1String("Mfg")).toString(); - rc.append(SymbianDevice(device.take())); - } - } -#elif defined(Q_OS_MACX) - CFMutableDictionaryRef classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); - if (!classesToMatch) return rc; - - CFDictionarySetValue(classesToMatch, - CFSTR(kIOSerialBSDTypeKey), - CFSTR(kIOSerialBSDAllTypes)); - - // Setup notifier if necessary - if (d->m_deviceListChangedNotification == 0) { - d->m_deviceListChangedNotification = IONotificationPortCreate(kIOMasterPortDefault); - if (d->m_deviceListChangedNotification) { - CFRunLoopSourceRef runloopSource = IONotificationPortGetRunLoopSource(d->m_deviceListChangedNotification); - CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); - // IOServiceAddMatchingNotification eats a reference each time we call it, so make sure it's still valid for the IOServiceGetMatchingServices later - CFRetain(classesToMatch); - CFRetain(classesToMatch); - io_iterator_t devicesAddedIterator; - io_iterator_t devicesRemovedIterator; - IOServiceAddMatchingNotification(d->m_deviceListChangedNotification, kIOMatchedNotification, classesToMatch, &deviceListChanged, (void*)this, &devicesAddedIterator); - IOServiceAddMatchingNotification(d->m_deviceListChangedNotification, kIOTerminatedNotification, classesToMatch, &deviceListChanged, (void*)this, &devicesRemovedIterator); - // Arm the iterators - we're not interested in the lists at this point, and the API rather expects that we will be - io_object_t obj; - while ((obj = IOIteratorNext(devicesAddedIterator))) IOObjectRelease(obj); - while ((obj = IOIteratorNext(devicesRemovedIterator))) IOObjectRelease(obj); - } - } - io_iterator_t matchingServices; - kern_return_t kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &matchingServices); - if (kernResult != KERN_SUCCESS) { - if (debug) - qDebug("IOServiceGetMatchingServices returned %d", kernResult); - return rc; - } - - io_object_t serialPort; - kernResult = KERN_FAILURE; - while ((serialPort = IOIteratorNext(matchingServices))) { - // Check if it's Bluetooth or USB, and if so we can apply additional filters to weed out things that definitely aren't valid ports - io_object_t parent, grandparent; - kernResult = IORegistryEntryGetParentEntry(serialPort, kIOServicePlane, &parent); - bool match = true; - DeviceCommunicationType deviceType = SerialPortCommunication; - CFStringRef name = NULL; - if (kernResult == KERN_SUCCESS) { - kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &grandparent); - if (kernResult == KERN_SUCCESS) { - CFStringRef className = IOObjectCopyClass(grandparent); - if (CFStringCompare(className, CFSTR("IOBluetoothSerialClient"), 0) == 0) { - // CODA doesn't support bluetooth - match = false; - } - else if (CFStringCompare(className, CFSTR("AppleUSBCDCACMData"), 0) == 0) { - match = false; - CFNumberRef interfaceNumber = (CFNumberRef)IORegistryEntrySearchCFProperty(grandparent, kIOServicePlane, CFSTR(kUSBInterfaceNumber), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); - if (interfaceNumber) { - int val; - if (CFNumberGetValue(interfaceNumber, kCFNumberIntType, &val) && val == 4) match = true; - CFRelease(interfaceNumber); - } - if (match) { - CFStringRef deviceName = (CFStringRef)IORegistryEntrySearchCFProperty(grandparent, kIOServicePlane, CFSTR(kUSBProductString), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); - CFStringRef vendorName = (CFStringRef)IORegistryEntrySearchCFProperty(grandparent, kIOServicePlane, CFSTR(kUSBVendorString), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively); - if (deviceName && vendorName) name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@"), vendorName, deviceName); - if (deviceName) CFRelease(deviceName); - if (vendorName) CFRelease(vendorName); - } - } - else { - // We don't expect CODA on any other type of serial port - match = false; - } - CFRelease(className); - IOObjectRelease(grandparent); - } - IOObjectRelease(parent); - } - - if (match) { - CFStringRef devPath = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, 0); - if (name == NULL) - name = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIOTTYBaseNameKey), kCFAllocatorDefault, 0); - QScopedPointer<SymbianDeviceData> device(new SymbianDeviceData); - device->type = deviceType; - device->friendlyName = CFStringToQString(name); - device->portName = CFStringToQString(devPath); - - CFRelease(devPath); - CFRelease(name); - rc.append(SymbianDevice(device.take())); - } - IOObjectRelease(serialPort); - } - IOObjectRelease(matchingServices); -#endif - return rc; -} - -SymbianDeviceManager::SymbianDeviceList SymbianDeviceManager::blueToothDevices() const -{ - SymbianDeviceList rc; -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) - // Bluetooth devices are created on connection. List the existing ones - // or at least the first one. - const QString prefix = QLatin1String(linuxBlueToothDeviceRootC); - const QString blueToothfriendlyFormat = QLatin1String("Bluetooth device (%1)"); - for (int d = 0; d < 4; d++) { - QScopedPointer<SymbianDeviceData> device(new SymbianDeviceData); - device->type = BlueToothCommunication; - device->portName = prefix + QString::number(d); - if (d == 0 || QFileInfo(device->portName).exists()) { - device->friendlyName = blueToothfriendlyFormat.arg(device->portName); - rc.push_back(SymbianDevice(device.take())); - } - } - // New kernel versions support /dev/ttyUSB0, /dev/ttyUSB1. - static const char *usbTtyDevices[] = { - "/dev/ttyUSB3", "/dev/ttyUSB2", "/dev/ttyUSB1", "/dev/ttyUSB0", - "/dev/ttyACM3", "/dev/ttyACM2", "/dev/ttyACM1", "/dev/ttyACM0"}; - const int usbTtyCount = sizeof(usbTtyDevices)/sizeof(const char *); - for (int d = 0; d < usbTtyCount; d++) { - const QString ttyUSBDevice = QLatin1String(usbTtyDevices[d]); - if (QFileInfo(ttyUSBDevice).exists()) { - SymbianDeviceData *device = new SymbianDeviceData; - device->type = SerialPortCommunication; - device->portName = ttyUSBDevice; - device->friendlyName = QString::fromLatin1("USB/Serial device (%1)").arg(device->portName); - rc.push_back(SymbianDevice(device)); - } - } -#endif - return rc; -} - -Q_GLOBAL_STATIC(SymbianDeviceManager, symbianDeviceManager) - -SymbianDeviceManager *SymbianDeviceManager::instance() -{ - return symbianDeviceManager(); -} - -SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm) -{ - d.nospace() << sdm.toString(); - return d; -} - -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 = 1024; - // If necessary, split the packet up - qint64 remainder = maxSize; - while (remainder) { - QByteArray dataBuf = QByteArray::fromRawData(data, qMin(KMaxOstPayload, remainder)); - d->m_codaPtr->writeCustomData(d->m_channelId, dataBuf); - data += dataBuf.length(); - remainder -= 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 deleted file mode 100644 index e3d257e4394..00000000000 --- a/src/shared/symbianutils/symbiandevicemanager.h +++ /dev/null @@ -1,208 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef SYMBIANDEVICEMANAGER_H -#define SYMBIANDEVICEMANAGER_H - -#include "symbianutils_global.h" - -#include <QIODevice> -#include <QExplicitlySharedDataPointer> -#include <QSharedPointer> - -QT_BEGIN_NAMESPACE -class QDebug; -class QTextStream; -QT_END_NAMESPACE - -namespace Coda { - class CodaDevice; -} - -namespace SymbianUtils { - -struct SymbianDeviceManagerPrivate; -class SymbianDeviceData; -class OstChannel; - -enum DeviceCommunicationType { - SerialPortCommunication = 0, - BlueToothCommunication = 1 -}; - -typedef QSharedPointer<Coda::CodaDevice> CodaDevicePtr; - -// SymbianDevice: Explicitly shared device data and a CodaDevice -// instance that can be acquired (exclusively) for use. -// A device removal from the manager will result in the -// device being closed. -class SYMBIANUTILS_EXPORT SymbianDevice { - explicit SymbianDevice(SymbianDeviceData *data); - friend class SymbianDeviceManager; - -public: - SymbianDevice(); - SymbianDevice(const SymbianDevice &rhs); - SymbianDevice &operator=(const SymbianDevice &rhs); - ~SymbianDevice(); - int compare(const SymbianDevice &rhs) const; - - DeviceCommunicationType type() const; - bool isNull() const; - QString portName() const; - QString friendlyName() const; - QString additionalInformation() const; - void setAdditionalInformation(const QString &); - - bool isOpen() const; - - // Windows only. - QString deviceDesc() const; - QString manufacturer() const; - - void format(QTextStream &str) const; - QString toString() const; - -private: - void forcedClose(); - - QExplicitlySharedDataPointer<SymbianDeviceData> m_data; -}; - -SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDevice &); - -inline bool operator==(const SymbianDevice &d1, const SymbianDevice &d2) - { return d1.compare(d2) == 0; } -inline bool operator!=(const SymbianDevice &d1, const SymbianDevice &d2) - { return d1.compare(d2) != 0; } -inline bool operator<(const SymbianDevice &d1, const SymbianDevice &d2) - { return d1.compare(d2) < 0; } - -/* SymbianDeviceManager: Singleton that maintains a list of Symbian devices. - * and emits change signals. - * On Windows, the update slot must be connected to a [delayed] signal - * emitted from an event handler listening for WM_DEVICECHANGE. - * Device removal will result in the device being closed. */ -class SYMBIANUTILS_EXPORT SymbianDeviceManager : public QObject -{ - Q_OBJECT -public: - typedef QList<SymbianDevice> SymbianDeviceList; - - static const char *linuxBlueToothDeviceRootC; - - // Do not use this constructor, it is just public for Q_GLOBAL_STATIC - explicit SymbianDeviceManager(QObject *parent = 0); - virtual ~SymbianDeviceManager(); - - // Singleton access. - static SymbianDeviceManager *instance(); - - SymbianDeviceList devices() const; - QString toString() const; - - //// The CODA code prefers to set up the CodaDevice object itself, so we let it and just handle opening the underlying QIODevice and keeping track of the CodaDevice - //// Returns true if port was opened successfully. - - // 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 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 releaseCodaDevice(CodaDevicePtr &aPort); - - int findByPortName(const QString &p) const; - QString friendlyNameForPort(const QString &port) const; - -public slots: - void update(); - void setAdditionalInformation(const QString &port, const QString &ai); - -signals: - void deviceRemoved(const SymbianUtils::SymbianDevice &d); - void deviceAdded(const SymbianUtils::SymbianDevice &d); - void updated(); - -private slots: - void delayedClosePort(); - -private: - void ensureInitialized() const; - void update(bool emitSignals); - SymbianDeviceList serialPorts() const; - SymbianDeviceList blueToothDevices() const; - void customEvent(QEvent *event); - void constructCodaPort(CodaDevicePtr& device, const QString& portName); - - SymbianDeviceManagerPrivate *d; -}; - -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); - qint64 readData(char *data, qint64 maxSize); - qint64 writeData(const char *data, qint64 maxSize); - -private: - OstChannelPrivate *d; - friend class SymbianDeviceManager; -}; - -} // namespace SymbianUtils - -#endif // SYMBIANDEVICEMANAGER_H diff --git a/src/shared/symbianutils/symbianutils.pri b/src/shared/symbianutils/symbianutils.pri deleted file mode 100644 index 0bcddde9812..00000000000 --- a/src/shared/symbianutils/symbianutils.pri +++ /dev/null @@ -1,42 +0,0 @@ -INCLUDEPATH *= $$PWD - -QT += network -win32 { - greaterThan(QT_MAJOR_VERSION, 4) { - QT += core-private - } else { - include(../../private_headers.pri) - } -} - -# Input -HEADERS += $$PWD/symbianutils_global.h \ - $$PWD/callback.h \ - $$PWD/codautils.h \ - $$PWD/codautils_p.h \ - $$PWD/symbiandevicemanager.h \ - $$PWD/codadevice.h \ - $$PWD/codamessage.h \ - $$PWD/virtualserialdevice.h - -SOURCES += $$PWD/codautils.cpp \ - $$PWD/symbiandevicemanager.cpp \ - $$PWD/codadevice.cpp \ - $$PWD/codamessage.cpp \ - $$PWD/virtualserialdevice.cpp - -DEFINES += HAS_SERIALPORT -win32:SOURCES += $$PWD/virtualserialdevice_win.cpp -unix:SOURCES += $$PWD/virtualserialdevice_posix.cpp - -macx:LIBS += -framework IOKit -framework CoreFoundation -include(../../shared/json/json.pri) - -DEFINES += JSON_INCLUDE_PRI - -contains(CONFIG, dll) { - DEFINES += SYMBIANUTILS_BUILD_LIB -} else { - DEFINES += SYMBIANUTILS_BUILD_STATIC_LIB -} - diff --git a/src/shared/symbianutils/symbianutils_global.h b/src/shared/symbianutils/symbianutils_global.h deleted file mode 100644 index fa9b02a4331..00000000000 --- a/src/shared/symbianutils/symbianutils_global.h +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef SYMBIANUTILS_GLOBAL_H -#define SYMBIANUTILS_GLOBAL_H - -#include <qglobal.h> - -#if defined(SYMBIANUTILS_BUILD_LIB) -# define SYMBIANUTILS_EXPORT Q_DECL_EXPORT -#elif defined(SYMBIANUTILS_BUILD_STATIC_LIB) || defined(SYMBIANUTILS_INCLUDE_PRI) -# define SYMBIANUTILS_EXPORT -#else -# define SYMBIANUTILS_EXPORT Q_DECL_IMPORT -#endif - -#endif // SYMBIANUTILS_GLOBAL_H diff --git a/src/shared/symbianutils/virtualserialdevice.cpp b/src/shared/symbianutils/virtualserialdevice.cpp deleted file mode 100644 index 64007eb3c7e..00000000000 --- a/src/shared/symbianutils/virtualserialdevice.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "virtualserialdevice.h" -#include <QThread> -#include <QWaitCondition> - -namespace SymbianUtils { - -bool VirtualSerialDevice::isSequential() const -{ - return true; -} - -VirtualSerialDevice::VirtualSerialDevice(const QString &aPortName, QObject *parent) : - QIODevice(parent), portName(aPortName), lock(QMutex::NonRecursive), emittingBytesWritten(false), waiterForBytesWritten(NULL) -{ - platInit(); -} - -const QString& VirtualSerialDevice::getPortName() const -{ - return portName; -} - -void VirtualSerialDevice::close() -{ - if (isOpen()) { - QMutexLocker locker(&lock); - delete waiterForBytesWritten; - waiterForBytesWritten = NULL; - QIODevice::close(); - platClose(); - } -} - -void VirtualSerialDevice::emitBytesWrittenIfNeeded(QMutexLocker& locker, qint64 len) -{ - if (waiterForBytesWritten) { - waiterForBytesWritten->wakeAll(); - } - if (!emittingBytesWritten) { - emittingBytesWritten = true; - locker.unlock(); - emit bytesWritten(len); - locker.relock(); - emittingBytesWritten = false; - } -} - -} // namespace SymbianUtils diff --git a/src/shared/symbianutils/virtualserialdevice.h b/src/shared/symbianutils/virtualserialdevice.h deleted file mode 100644 index a4e295cecb6..00000000000 --- a/src/shared/symbianutils/virtualserialdevice.h +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef VIRTUALSERIALPORT_H -#define VIRTUALSERIALPORT_H - -#include <QIODevice> -#include <QString> -#include <QMutex> - -QT_BEGIN_NAMESPACE -class QWaitCondition; -QT_END_NAMESPACE - -#include "symbianutils_global.h" - -namespace SymbianUtils { - -class VirtualSerialDevicePrivate; - -class SYMBIANUTILS_EXPORT VirtualSerialDevice : public QIODevice -{ - Q_OBJECT -public: - explicit VirtualSerialDevice(const QString &name, QObject *parent = 0); - ~VirtualSerialDevice(); - - bool open(OpenMode mode); - void close(); - const QString &getPortName() const; - void flush(); - - qint64 bytesAvailable() const; - bool isSequential() const; - bool waitForBytesWritten(int msecs); - bool waitForReadyRead(int msecs); - -protected: - qint64 readData(char *data, qint64 maxSize); - qint64 writeData(const char *data, qint64 maxSize); - -private: - void platInit(); - void platClose(); - void emitBytesWrittenIfNeeded(QMutexLocker &locker, qint64 len); - -private: - QString portName; - mutable QMutex lock; - QList<QByteArray> pendingWrites; - bool emittingBytesWritten; - QWaitCondition* waiterForBytesWritten; - VirtualSerialDevicePrivate *d; - -// Platform-specific stuff -#ifdef Q_OS_WIN -private: - qint64 writeNextBuffer(QMutexLocker &locker); - void doWriteCompleted(QMutexLocker &locker); -private slots: - void writeCompleted(); - void commEventOccurred(); -#endif - -#ifdef Q_OS_UNIX -private: - bool tryWrite(const char *data, qint64 maxSize, qint64 &bytesWritten); - enum FlushPendingOption { - NothingSpecial = 0, - StopAfterWritingOneBuffer = 1, - EmitBytesWrittenAsync = 2 // Needed so we don't emit bytesWritten signal directly from writeBytes - }; - Q_DECLARE_FLAGS(FlushPendingOptions, FlushPendingOption) - bool tryFlushPendingBuffers(QMutexLocker& locker, FlushPendingOptions flags = NothingSpecial); - -private slots: - void writeHasUnblocked(int fileHandle); - -signals: - void AsyncCall_emitBytesWrittenIfNeeded(qint64 len); - -#endif - -}; - -} // namespace SymbianUtils - -#endif // VIRTUALSERIALPORT_H diff --git a/src/shared/symbianutils/virtualserialdevice_posix.cpp b/src/shared/symbianutils/virtualserialdevice_posix.cpp deleted file mode 100644 index a51f059e5da..00000000000 --- a/src/shared/symbianutils/virtualserialdevice_posix.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include <stdio.h> -#include <fcntl.h> -#include <errno.h> -#include <termios.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <QSocketNotifier> -#include <QTimer> -#include <QThread> -#include <QWaitCondition> -#include "virtualserialdevice.h" - -namespace SymbianUtils { - -class VirtualSerialDevicePrivate -{ -public: - int portHandle; - QSocketNotifier* readNotifier; - QSocketNotifier* writeUnblockedNotifier; -}; - -void VirtualSerialDevice::platInit() -{ - d = new VirtualSerialDevicePrivate; - d->portHandle = -1; - d->readNotifier = NULL; - d->writeUnblockedNotifier = NULL; - connect(this, SIGNAL(AsyncCall_emitBytesWrittenIfNeeded(qint64)), this, SIGNAL(bytesWritten(qint64)), Qt::QueuedConnection); -} - -bool VirtualSerialDevice::open(OpenMode mode) -{ - if (isOpen()) return true; - - d->portHandle = ::open(portName.toAscii().constData(), O_RDWR | O_NONBLOCK | O_NOCTTY); - if (d->portHandle == -1) { - setErrorString(tr("The port %1 could not be opened: %2 (POSIX error %3)"). - arg(portName, QString::fromLocal8Bit(strerror(errno))).arg(errno)); - return false; - } - - struct termios termInfo; - if (tcgetattr(d->portHandle, &termInfo) < 0) { - setErrorString(tr("Unable to retrieve terminal settings of port %1: %2 (POSIX error %3)"). - arg(portName, QString::fromLocal8Bit(strerror(errno))).arg(errno)); - close(); - return false; - } - cfmakeraw(&termInfo); - // Turn off terminal echo as not get messages back, among other things - termInfo.c_cflag |= CREAD|CLOCAL; - termInfo.c_cc[VTIME] = 0; - termInfo.c_lflag &= (~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG)); - termInfo.c_iflag &= (~(INPCK|IGNPAR|PARMRK|ISTRIP|ICRNL|IXANY|IXON|IXOFF)); - termInfo.c_oflag &= (~OPOST); - termInfo.c_cc[VMIN] = 0; - termInfo.c_cc[VINTR] = _POSIX_VDISABLE; - termInfo.c_cc[VQUIT] = _POSIX_VDISABLE; - termInfo.c_cc[VSTART] = _POSIX_VDISABLE; - termInfo.c_cc[VSTOP] = _POSIX_VDISABLE; - termInfo.c_cc[VSUSP] = _POSIX_VDISABLE; - - if (tcsetattr(d->portHandle, TCSAFLUSH, &termInfo) < 0) { - setErrorString(tr("Unable to apply terminal settings to port %1: %2 (POSIX error %3)"). - arg(portName, QString::fromLocal8Bit(strerror(errno))).arg(errno)); - close(); - return false; - } - - d->readNotifier = new QSocketNotifier(d->portHandle, QSocketNotifier::Read); - connect(d->readNotifier, SIGNAL(activated(int)), this, SIGNAL(readyRead())); - - d->writeUnblockedNotifier = new QSocketNotifier(d->portHandle, QSocketNotifier::Write); - d->writeUnblockedNotifier->setEnabled(false); - connect(d->writeUnblockedNotifier, SIGNAL(activated(int)), this, SLOT(writeHasUnblocked(int))); - - bool ok = QIODevice::open(mode | QIODevice::Unbuffered); - if (!ok) close(); - return ok; -} - -void VirtualSerialDevice::platClose() -{ - delete d->readNotifier; - d->readNotifier = NULL; - - delete d->writeUnblockedNotifier; - d->writeUnblockedNotifier = NULL; - - ::close(d->portHandle); - d->portHandle = -1; -} - -VirtualSerialDevice::~VirtualSerialDevice() -{ - close(); - delete d; -} - -qint64 VirtualSerialDevice::bytesAvailable() const -{ - QMutexLocker locker(&lock); - if (!isOpen()) return 0; - - int avail = 0; - d->readNotifier->setEnabled(false); - int res = ioctl(d->portHandle, FIONREAD, &avail); - d->readNotifier->setEnabled(true); - if (res == -1) { - return 0; - } - return (qint64)avail + QIODevice::bytesAvailable(); -} - -qint64 VirtualSerialDevice::readData(char *data, qint64 maxSize) -{ - QMutexLocker locker(&lock); - d->readNotifier->setEnabled(false); - int result = ::read(d->portHandle, data, maxSize); - d->readNotifier->setEnabled(true); - if (result == -1 && errno == EAGAIN) - result = 0; // To Qt, 0 here means nothing ready right now, and -1 is reserved for permanent errors - return result; -} - -qint64 VirtualSerialDevice::writeData(const char *data, qint64 maxSize) -{ - QMutexLocker locker(&lock); - qint64 bytesWritten; - bool needToWait = tryFlushPendingBuffers(locker, EmitBytesWrittenAsync); - if (!needToWait) { - needToWait = tryWrite(data, maxSize, bytesWritten); - if (needToWait && bytesWritten > 0) { - // Wrote some of the buffer, adjust pointers to point to the remainder that needs queueing - data += bytesWritten; - maxSize -= bytesWritten; - } - } - - if (needToWait) { - pendingWrites.append(QByteArray(data, maxSize)); - d->writeUnblockedNotifier->setEnabled(true); - // Now wait for the writeUnblocked signal or for a call to waitForBytesWritten - return bytesWritten + maxSize; - } else { - //emitBytesWrittenIfNeeded(locker, bytesWritten); - // Can't emit bytesWritten directly from writeData - means clients end up recursing - emit AsyncCall_emitBytesWrittenIfNeeded(bytesWritten); - return bytesWritten; - } -} - -/* Returns true if EAGAIN encountered. - * if error occurred (other than EAGAIN) returns -1 in bytesWritten - * lock must be held. Doesn't emit signals or set notifiers. - */ -bool VirtualSerialDevice::tryWrite(const char *data, qint64 maxSize, qint64& bytesWritten) -{ - // Must be locked - bytesWritten = 0; - while (maxSize > 0) { - int result = ::write(d->portHandle, data, maxSize); - if (result == -1) { - if (errno == EAGAIN) - return true; // Need to wait - setErrorString(tr("Cannot write to port %1: %2 (POSIX error %3)"). - arg(portName, QString::fromLocal8Bit(strerror(errno))).arg(errno)); - - bytesWritten = -1; - return false; - } else { - if (result == 0) - qWarning("%s: Zero bytes written to port %s!", Q_FUNC_INFO, qPrintable(portName)); - bytesWritten += result; - maxSize -= result; - data += result; - } - } - return false; // If we reach here we've successfully written all the data without blocking -} - -/* Returns true if EAGAIN encountered. Emits (or queues) bytesWritten for any buffers written. - * If stopAfterWritingOneBuffer is true, return immediately if a single buffer is written, rather than - * attempting to drain the whole queue. - * Doesn't modify notifier. - */ -bool VirtualSerialDevice::tryFlushPendingBuffers(QMutexLocker& locker, FlushPendingOptions flags) -{ - while (pendingWrites.count() > 0) { - // Try writing everything we've got, until we hit EAGAIN - const QByteArray& data = pendingWrites[0]; - qint64 bytesWritten; - bool needToWait = tryWrite(data.constData(), data.size(), bytesWritten); - if (needToWait) { - if (bytesWritten > 0) { - // We wrote some of the data, update the pending queue - QByteArray remainder = data.mid(bytesWritten); - pendingWrites.removeFirst(); - pendingWrites.insert(0, remainder); - } - return needToWait; - } else { - pendingWrites.removeFirst(); - if (flags & EmitBytesWrittenAsync) { - emit AsyncCall_emitBytesWrittenIfNeeded(bytesWritten); - } else { - emitBytesWrittenIfNeeded(locker, bytesWritten); - } - if (flags & StopAfterWritingOneBuffer) return false; - // Otherwise go round loop again - } - } - return false; // no EAGAIN encountered -} - -void VirtualSerialDevice::writeHasUnblocked(int fileHandle) -{ - Q_ASSERT(fileHandle == d->portHandle); - (void)fileHandle; // Compiler shutter-upper - d->writeUnblockedNotifier->setEnabled(false); - - QMutexLocker locker(&lock); - bool needToWait = tryFlushPendingBuffers(locker); - if (needToWait) d->writeUnblockedNotifier->setEnabled(true); -} - -// Copy of qt_safe_select from /qt/src/corelib/kernel/qeventdispatcher_unix.cpp -// But without the timeout correction -int safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, - const struct timeval *orig_timeout) -{ - if (!orig_timeout) { - // no timeout -> block forever - register int ret; - do { - ret = select(nfds, fdread, fdwrite, fdexcept, 0); - } while (ret == -1 && errno == EINTR); - return ret; - } - - timeval timeout = *orig_timeout; - - int ret; - forever { - ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeout); - if (ret != -1 || errno != EINTR) - return ret; - } -} - -bool VirtualSerialDevice::waitForBytesWritten(int msecs) -{ - QMutexLocker locker(&lock); - if (pendingWrites.count() == 0) return false; - - if (QThread::currentThread() != thread()) { - // Wait for signal from main thread - unsigned long timeout = msecs; - if (msecs == -1) timeout = ULONG_MAX; - if (waiterForBytesWritten == NULL) - waiterForBytesWritten = new QWaitCondition; - return waiterForBytesWritten->wait(&lock, timeout); - } - - d->writeUnblockedNotifier->setEnabled(false); - forever { - fd_set writeSet; - FD_ZERO(&writeSet); - FD_SET(d->portHandle, &writeSet); - - struct timeval timeout; - if (msecs != -1) { - timeout.tv_sec = msecs / 1000; - timeout.tv_usec = (msecs % 1000) * 1000; - } - int ret = safe_select(d->portHandle+1, NULL, &writeSet, NULL, msecs == -1 ? NULL : &timeout); - - if (ret == 0) { - // Timeout - return false; - } else if (ret < 0) { - setErrorString(tr("The function select() returned an error on port %1: %2 (POSIX error %3)"). - arg(portName, QString::fromLocal8Bit(strerror(errno))).arg(errno)); - return false; - } else { - bool needToWait = tryFlushPendingBuffers(locker, StopAfterWritingOneBuffer); - if (needToWait) { - // go round the select again - } else { - return true; - } - } - } -} - -void VirtualSerialDevice::flush() -{ - while (waitForBytesWritten(-1)) { /* loop */ } - tcflush(d->portHandle, TCIOFLUSH); -} - -bool VirtualSerialDevice::waitForReadyRead(int msecs) -{ - return QIODevice::waitForReadyRead(msecs); //TODO -} - -} // namespace SymbianUtils diff --git a/src/shared/symbianutils/virtualserialdevice_win.cpp b/src/shared/symbianutils/virtualserialdevice_win.cpp deleted file mode 100644 index de528d7c897..00000000000 --- a/src/shared/symbianutils/virtualserialdevice_win.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "virtualserialdevice.h" -#include <windows.h> -#if QT_VERSION >= 0x050000 -# include <QWinEventNotifier> -#else -# include <private/qwineventnotifier_p.h> -#endif -#include <QThread> -#include <QWaitCondition> - -namespace SymbianUtils { - -class VirtualSerialDevicePrivate -{ -public: - HANDLE portHandle; - OVERLAPPED writeOverlapped; - OVERLAPPED commEventOverlapped; - DWORD commEventMask; - QWinEventNotifier *writeCompleteNotifier; - QWinEventNotifier *commEventNotifier; -}; - -void VirtualSerialDevice::platInit() -{ - d = new VirtualSerialDevicePrivate; - d->portHandle = INVALID_HANDLE_VALUE; - d->writeCompleteNotifier = NULL; - memset(&d->writeOverlapped, 0, sizeof(OVERLAPPED)); - d->commEventNotifier = NULL; - memset(&d->commEventOverlapped, 0, sizeof(OVERLAPPED)); -} - -QString windowsPortName(const QString& port) -{ - // Add the \\.\ to the name if it's a COM port and doesn't already have it - QString winPortName(port); - if (winPortName.startsWith(QLatin1String("COM"))) { - winPortName.prepend("\\\\.\\"); - } - return winPortName; -} - -// Copied from \creator\src\libs\utils\winutils.cpp -QString winErrorMessage(unsigned long error) -{ - // Some of the windows error messages are a bit too obscure - switch (error) - { - case ERROR_FILE_NOT_FOUND: - case ERROR_NOT_FOUND: - return VirtualSerialDevice::tr("Port not found"); - break; - case ERROR_ACCESS_DENIED: - return VirtualSerialDevice::tr("Port in use"); - case ERROR_SEM_TIMEOUT: // Bluetooth ports sometimes return this - return VirtualSerialDevice::tr("Timed out"); - case ERROR_NETWORK_UNREACHABLE: - return VirtualSerialDevice::tr("Port unreachable"); // I don't know what this error indicates... from observation, that the windows Bluetooth stack has got itself into a state and needs resetting - default: - break; - } - - QString rc = QString::fromLatin1("#%1: ").arg(error); - ushort *lpMsgBuf; - - const int len = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL); - if (len) { - rc = QString::fromUtf16(lpMsgBuf, len); - LocalFree(lpMsgBuf); - } else { - rc += QString::fromLatin1("<unknown error>"); - } - return rc.trimmed(); -} - -bool VirtualSerialDevice::open(OpenMode mode) -{ - Q_ASSERT(QThread::currentThread() == thread()); - if (isOpen()) return true; - - d->portHandle = CreateFileA(windowsPortName(portName).toAscii(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (d->portHandle == INVALID_HANDLE_VALUE) { - setErrorString(tr("The port %1 could not be opened: %2"). - arg(portName, winErrorMessage(GetLastError()))); - return false; - } - - DCB commState; - memset(&commState, 0, sizeof(DCB)); - commState.DCBlength = sizeof(DCB); - bool ok = GetCommState(d->portHandle, &commState); - if (ok) { - commState.BaudRate = CBR_115200; - commState.fBinary = TRUE; - commState.fParity = FALSE; - commState.fOutxCtsFlow = FALSE; - commState.fOutxDsrFlow = FALSE; - commState.fInX = FALSE; - commState.fOutX = FALSE; - commState.fNull = FALSE; - commState.fAbortOnError = FALSE; - commState.fDsrSensitivity = FALSE; - commState.fDtrControl = DTR_CONTROL_DISABLE; - commState.ByteSize = 8; - commState.Parity = NOPARITY; - commState.StopBits = ONESTOPBIT; - ok = SetCommState(d->portHandle, &commState); - } - if (!ok) { - qWarning("%s setting comm state", qPrintable(winErrorMessage(GetLastError()))); - } - - // http://msdn.microsoft.com/en-us/library/aa363190(v=vs.85).aspx says this means - // "the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received" - COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = MAXDWORD; - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(d->portHandle, &timeouts); - - d->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - d->writeCompleteNotifier = new QWinEventNotifier(d->writeOverlapped.hEvent, this); - connect(d->writeCompleteNotifier, SIGNAL(activated(HANDLE)), this, SLOT(writeCompleted())); - - // This is how we implement readyRead notifications - d->commEventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - d->commEventNotifier = new QWinEventNotifier(d->commEventOverlapped.hEvent, this); - connect(d->commEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(commEventOccurred())); - - if (!SetCommMask(d->portHandle, EV_RXCHAR)) { - // What to do? - qWarning("%s: Could not set comm mask, err=%d", Q_FUNC_INFO, (int)GetLastError()); - } - bool result = WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped); - Q_ASSERT(result == false); // Can't see how it would make sense to be anything else... - (void)result; // For release build - if (GetLastError() != ERROR_IO_PENDING) { - setErrorString(tr("An error occurred while waiting for read notifications from %1: %2"). - arg(portName, winErrorMessage(GetLastError()))); - close(); - return false; - } - - ok = QIODevice::open(mode); - if (!ok) close(); - return ok; -} - -void VirtualSerialDevice::platClose() -{ - delete d->writeCompleteNotifier; - d->writeCompleteNotifier = NULL; - CloseHandle(d->writeOverlapped.hEvent); - d->writeOverlapped.hEvent = INVALID_HANDLE_VALUE; - - delete d->commEventNotifier; - d->commEventNotifier = NULL; - d->commEventOverlapped.hEvent = INVALID_HANDLE_VALUE; - - CloseHandle(d->portHandle); - d->portHandle = INVALID_HANDLE_VALUE; -} - -VirtualSerialDevice::~VirtualSerialDevice() -{ - close(); - delete d; -} - -qint64 VirtualSerialDevice::bytesAvailable() const -{ - QMutexLocker locker(&lock); - if (!isOpen()) return 0; - - qint64 avail = 0; - COMSTAT Status; - if (ClearCommError(d->portHandle, NULL, &Status)) { - avail = Status.cbInQue; - } - return avail + QIODevice::bytesAvailable(); -} - -void VirtualSerialDevice::commEventOccurred() -{ - DWORD event = d->commEventMask; - if (event & EV_RXCHAR) { - emit readyRead(); - } - ResetEvent(d->commEventOverlapped.hEvent); - WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped); -} - -qint64 VirtualSerialDevice::readData(char *data, qint64 maxSize) -{ - QMutexLocker locker(&lock); - // We do our reads synchronously - OVERLAPPED readOverlapped; - memset(&readOverlapped, 0, sizeof(OVERLAPPED)); - DWORD bytesRead; - BOOL done = ReadFile(d->portHandle, data, maxSize, &bytesRead, &readOverlapped); - if (done) return (qint64)bytesRead; - - if (GetLastError() == ERROR_IO_PENDING) { - // Note the TRUE to wait for the read to complete - done = GetOverlappedResult(d->portHandle, &readOverlapped, &bytesRead, TRUE); - if (done) return (qint64)bytesRead; - } - - // If we reach here an error has occurred - setErrorString(tr("An error occurred while reading from %1: %2"). - arg(portName, winErrorMessage(GetLastError()))); - return -1; -} - - -qint64 VirtualSerialDevice::writeData(const char *data, qint64 maxSize) -{ - QMutexLocker locker(&lock); - - pendingWrites.append(QByteArray(data, maxSize)); // Can't see a way of doing async io safely without having to copy here... - if (pendingWrites.count() == 1) { - return writeNextBuffer(locker); - } else { - return maxSize; - } -} - -qint64 VirtualSerialDevice::writeNextBuffer(QMutexLocker& locker) -{ - Q_UNUSED(locker) - // Must be locked on entry - qint64 bufLen = pendingWrites[0].length(); - BOOL ok = WriteFile(d->portHandle, pendingWrites[0].constData(), bufLen, NULL, &d->writeOverlapped); - if (ok || GetLastError() == ERROR_IO_PENDING) { - // Apparently it can return true for a small asynchronous write... - // Hopefully it still gets signalled in the same way! - - // Wait for signal via writeCompleted - return bufLen; - } - else { - setErrorString(tr("An error occurred while writing to %1: %2"). - arg(portName, winErrorMessage(GetLastError()))); - pendingWrites.removeFirst(); - return -1; - } -} - -void VirtualSerialDevice::writeCompleted() -{ - QMutexLocker locker(&lock); - if (pendingWrites.count() == 0) { - qWarning("%s: writeCompleted called when there are no pending writes on %s!", - Q_FUNC_INFO, qPrintable(portName)); - return; - } - - doWriteCompleted(locker); -} - -void VirtualSerialDevice::doWriteCompleted(QMutexLocker &locker) -{ - // Must be locked on entry - ResetEvent(d->writeOverlapped.hEvent); - - qint64 len = pendingWrites.first().length(); - pendingWrites.removeFirst(); - - if (pendingWrites.count() > 0) { - // Get the next write started before notifying in case client calls waitForBytesWritten in their slot - writeNextBuffer(locker); - } - - emitBytesWrittenIfNeeded(locker, len); -} - -bool VirtualSerialDevice::waitForBytesWritten(int msecs) -{ - QMutexLocker locker(&lock); - if (pendingWrites.count() == 0) return false; - - if (QThread::currentThread() != thread()) { - // Wait for signal from main thread - unsigned long timeout = msecs; - if (msecs == -1) timeout = ULONG_MAX; - if (waiterForBytesWritten == NULL) - waiterForBytesWritten = new QWaitCondition; - return waiterForBytesWritten->wait(&lock, timeout); - } - - DWORD waitTime = msecs; - if (msecs == -1) waitTime = INFINITE; // Ok these are probably bitwise the same, but just to prove I've thought about it... - DWORD result = WaitForSingleObject(d->writeOverlapped.hEvent, waitTime); // Do I need WaitForSingleObjectEx and worry about alertable states? - if (result == WAIT_TIMEOUT) { - return false; - } - else if (result == WAIT_OBJECT_0) { - DWORD bytesWritten; - BOOL ok = GetOverlappedResult(d->portHandle, &d->writeOverlapped, &bytesWritten, TRUE); - if (!ok) { - setErrorString(tr("An error occurred while syncing on waitForBytesWritten for %1: %2"). - arg(portName, winErrorMessage(GetLastError()))); - return false; - } - Q_ASSERT(bytesWritten == (DWORD)pendingWrites.first().length()); - - doWriteCompleted(locker); - return true; - } - else { - setErrorString(QString("An error occurred in waitForBytesWritten() for %1: %2"). - arg(portName, winErrorMessage(GetLastError()))); - return false; - } -} - -void VirtualSerialDevice::flush() -{ - while (waitForBytesWritten(-1)) { /* loop */ } -} - -bool VirtualSerialDevice::waitForReadyRead(int msecs) -{ - return QIODevice::waitForReadyRead(msecs); //TODO -} - -} // namespace SymbianUtils |