diff options
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 |