tools/runonphone/symbianutils/trkdevice.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    50 #include <QtCore/QMap>
    50 #include <QtCore/QMap>
    51 #include <QtCore/QThread>
    51 #include <QtCore/QThread>
    52 #include <QtCore/QMutex>
    52 #include <QtCore/QMutex>
    53 #include <QtCore/QWaitCondition>
    53 #include <QtCore/QWaitCondition>
    54 #include <QtCore/QSharedPointer>
    54 #include <QtCore/QSharedPointer>
       
    55 #include <QtCore/QScopedPointer>
    55 #include <QtCore/QMetaType>
    56 #include <QtCore/QMetaType>
    56 
    57 
    57 #ifdef Q_OS_WIN
    58 #ifdef Q_OS_WIN
    58 #  include <windows.h>
    59 #  include <windows.h>
    59 #else
    60 #else
   100 
   101 
   101 #endif
   102 #endif
   102 
   103 
   103 enum { verboseTrk = 0 };
   104 enum { verboseTrk = 0 };
   104 
   105 
       
   106 static inline QString msgAccessingClosedDevice(const QString &msg)
       
   107 {
       
   108     return QString::fromLatin1("Error: Attempt to access device '%1', which is closed.").arg(msg);
       
   109 }
       
   110 
   105 namespace trk {
   111 namespace trk {
   106 
   112 
   107 ///////////////////////////////////////////////////////////////////////
   113 ///////////////////////////////////////////////////////////////////////
   108 //
   114 //
   109 // TrkMessage
   115 // TrkMessage
   153 // can use the helper invokeNoopMessage() to trigger its callback.
   159 // can use the helper invokeNoopMessage() to trigger its callback.
   154 //
   160 //
   155 ///////////////////////////////////////////////////////////////////////
   161 ///////////////////////////////////////////////////////////////////////
   156 
   162 
   157 class TrkWriteQueue
   163 class TrkWriteQueue
   158 {    
   164 {
   159     Q_DISABLE_COPY(TrkWriteQueue)
   165     Q_DISABLE_COPY(TrkWriteQueue)
   160 public:
   166 public:
   161     explicit TrkWriteQueue();
   167     explicit TrkWriteQueue();
       
   168     void clear();
   162 
   169 
   163     // Enqueue messages.
   170     // Enqueue messages.
   164     void queueTrkMessage(byte code, TrkCallback callback,
   171     void queueTrkMessage(byte code, TrkCallback callback,
   165                         const QByteArray &data, const QVariant &cookie);
   172                         const QByteArray &data, const QVariant &cookie);
   166     void queueTrkInitialPing();
   173     void queueTrkInitialPing();
   206     m_trkWriteToken(0),
   213     m_trkWriteToken(0),
   207     m_trkWriteBusy(false)
   214     m_trkWriteBusy(false)
   208 {
   215 {
   209 }
   216 }
   210 
   217 
       
   218 void TrkWriteQueue::clear()
       
   219 {
       
   220     m_trkWriteToken = 0;
       
   221     m_trkWriteBusy = false;
       
   222     m_trkWriteQueue.clear();
       
   223     const int discarded = m_writtenTrkMessages.size();
       
   224     m_writtenTrkMessages.clear();
       
   225     if (verboseTrk)
       
   226         qDebug() << "TrkWriteQueue::clear: discarded " << discarded;
       
   227 }
       
   228 
   211 byte TrkWriteQueue::nextTrkWriteToken()
   229 byte TrkWriteQueue::nextTrkWriteToken()
   212 {
   230 {
   213     ++m_trkWriteToken;
   231     ++m_trkWriteToken;
   214     if (m_trkWriteToken == 0)
   232     if (m_trkWriteToken == 0)
   215         ++m_trkWriteToken;
   233         ++m_trkWriteToken;
   216     if (verboseTrk)
   234     if (verboseTrk)
   217         qDebug() << "Write token: " << m_trkWriteToken;
   235         qDebug() << "nextTrkWriteToken:" << m_trkWriteToken;
   218     return m_trkWriteToken;
   236     return m_trkWriteToken;
   219 }
   237 }
   220 
   238 
   221 void TrkWriteQueue::queueTrkMessage(byte code, TrkCallback callback,
   239 void TrkWriteQueue::queueTrkMessage(byte code, TrkCallback callback,
   222     const QByteArray &data, const QVariant &cookie)
   240     const QByteArray &data, const QVariant &cookie)
   347 
   365 
   348 class WriterThread : public QThread
   366 class WriterThread : public QThread
   349 {
   367 {
   350     Q_OBJECT
   368     Q_OBJECT
   351     Q_DISABLE_COPY(WriterThread)
   369     Q_DISABLE_COPY(WriterThread)
   352 public:            
   370 public:
   353     explicit WriterThread(const QSharedPointer<DeviceContext> &context);
   371     explicit WriterThread(const QSharedPointer<DeviceContext> &context);
   354 
   372 
   355     // Enqueue messages.
   373     // Enqueue messages.
   356     void queueTrkMessage(byte code, TrkCallback callback,
   374     void queueTrkMessage(byte code, TrkCallback callback,
   357                         const QByteArray &data, const QVariant &cookie);
   375                         const QByteArray &data, const QVariant &cookie);
   358     void queueTrkInitialPing();
   376     void queueTrkInitialPing();
   359 
   377 
       
   378     void clearWriteQueue();
       
   379 
   360     // Call this from the device read notification with the results.
   380     // Call this from the device read notification with the results.
   361     void slotHandleResult(const TrkResult &result);
   381     void slotHandleResult(const TrkResult &result);
   362 
   382 
   363     virtual void run();
   383     virtual void run();
   364 
   384 
   372     void tryWrite();
   392     void tryWrite();
   373 
   393 
   374 private slots:
   394 private slots:
   375     void invokeNoopMessage(const trk::TrkMessage &);
   395     void invokeNoopMessage(const trk::TrkMessage &);
   376 
   396 
   377 private:    
   397 private:
   378     bool write(const QByteArray &data, QString *errorMessage);
   398     bool write(const QByteArray &data, QString *errorMessage);
   379     inline int writePendingMessage();
   399     inline int writePendingMessage();
   380 
   400 
   381     const QSharedPointer<DeviceContext> m_context;
   401     const QSharedPointer<DeviceContext> m_context;
   382     QMutex m_dataMutex;
   402     QMutex m_dataMutex;
   460 {
   480 {
   461     m_terminate = true;
   481     m_terminate = true;
   462     m_waitCondition.wakeAll();
   482     m_waitCondition.wakeAll();
   463     wait();
   483     wait();
   464     m_terminate = false;
   484     m_terminate = false;
       
   485     m_queue.clear();
   465 }
   486 }
   466 
   487 
   467 #ifdef Q_OS_WIN
   488 #ifdef Q_OS_WIN
   468 
   489 
   469 static inline QString msgTerminated(int size)
   490 static inline QString msgTerminated(int size)
   559     m_queue.queueTrkMessage(code, callback, data, cookie);
   580     m_queue.queueTrkMessage(code, callback, data, cookie);
   560     m_dataMutex.unlock();
   581     m_dataMutex.unlock();
   561     tryWrite();
   582     tryWrite();
   562 }
   583 }
   563 
   584 
       
   585 void WriterThread::clearWriteQueue()
       
   586 {
       
   587     m_dataMutex.lock();
       
   588     m_queue.clear();
       
   589     m_dataMutex.unlock();
       
   590 }
       
   591 
   564 void WriterThread::queueTrkInitialPing()
   592 void WriterThread::queueTrkInitialPing()
   565 {
   593 {
   566     m_dataMutex.lock();
   594     m_dataMutex.lock();
   567     m_queue.queueTrkInitialPing();
   595     m_queue.queueTrkInitialPing();
   568     m_dataMutex.unlock();
   596     m_dataMutex.unlock();
   589 class ReaderThreadBase : public QThread
   617 class ReaderThreadBase : public QThread
   590 {
   618 {
   591     Q_OBJECT
   619     Q_OBJECT
   592     Q_DISABLE_COPY(ReaderThreadBase)
   620     Q_DISABLE_COPY(ReaderThreadBase)
   593 public:
   621 public:
       
   622 
       
   623     int bytesPending() const { return m_trkReadBuffer.size(); }
   594 
   624 
   595 signals:
   625 signals:
   596     void messageReceived(const trk::TrkResult &result, const QByteArray &rawData);
   626     void messageReceived(const trk::TrkResult &result, const QByteArray &rawData);
   597 
   627 
   598 protected:
   628 protected:
   690     // Check if there are already bytes waiting. If not, wait for first byte
   720     // Check if there are already bytes waiting. If not, wait for first byte
   691     COMSTAT comStat;
   721     COMSTAT comStat;
   692     if (!ClearCommError(m_context->device, NULL, &comStat)){
   722     if (!ClearCommError(m_context->device, NULL, &comStat)){
   693         emit error(QString::fromLatin1("ClearCommError failed: %1").arg(winErrorMessage(GetLastError())));
   723         emit error(QString::fromLatin1("ClearCommError failed: %1").arg(winErrorMessage(GetLastError())));
   694         return -7;
   724         return -7;
   695     }    
   725     }
   696     const DWORD bytesToRead = qMax(DWORD(1), qMin(comStat.cbInQue, DWORD(BufSize)));
   726     const DWORD bytesToRead = qMax(DWORD(1), qMin(comStat.cbInQue, DWORD(BufSize)));
   697     // Trigger read
   727     // Trigger read
   698     DWORD bytesRead = 0;
   728     DWORD bytesRead = 0;
   699     if (ReadFile(m_context->device, &buffer, bytesToRead, &bytesRead, &m_context->readOverlapped)) {
   729     if (ReadFile(m_context->device, &buffer, bytesToRead, &bytesRead, &m_context->readOverlapped)) {
   700         if (bytesRead == 1) {
   730         if (bytesRead == 1) {
   706     }
   736     }
   707     const DWORD readError = GetLastError();
   737     const DWORD readError = GetLastError();
   708     if (readError != ERROR_IO_PENDING) {
   738     if (readError != ERROR_IO_PENDING) {
   709         emit error(QString::fromLatin1("Read error: %1").arg(winErrorMessage(readError)));
   739         emit error(QString::fromLatin1("Read error: %1").arg(winErrorMessage(readError)));
   710         return -1;
   740         return -1;
   711     }    
   741     }
   712     // Wait for either termination or data
   742     // Wait for either termination or data
   713     const DWORD wr = WaitForMultipleObjects(HandleCount, m_handles, false, INFINITE);
   743     const DWORD wr = WaitForMultipleObjects(HandleCount, m_handles, false, INFINITE);
   714     if (wr == WAIT_FAILED) {
   744     if (wr == WAIT_FAILED) {
   715         emit error(QString::fromLatin1("Wait failed: %1").arg(winErrorMessage(GetLastError())));
   745         emit error(QString::fromLatin1("Wait failed: %1").arg(winErrorMessage(GetLastError())));
   716         return -2;
   746         return -2;
   781     inline int tryRead();
   811     inline int tryRead();
   782 
   812 
   783     int m_terminatePipeFileDescriptors[2];
   813     int m_terminatePipeFileDescriptors[2];
   784 };
   814 };
   785 
   815 
   786 UnixReaderThread::UnixReaderThread(const QSharedPointer<DeviceContext> &context) : 
   816 UnixReaderThread::UnixReaderThread(const QSharedPointer<DeviceContext> &context) :
   787     ReaderThreadBase(context)
   817     ReaderThreadBase(context)
   788 {
   818 {
   789     m_terminatePipeFileDescriptors[0] = m_terminatePipeFileDescriptors[1] = -1;
   819     m_terminatePipeFileDescriptors[0] = m_terminatePipeFileDescriptors[1] = -1;
   790     // Set up pipes for termination. Should not fail
   820     // Set up pipes for termination. Should not fail
   791     if (pipe(m_terminatePipeFileDescriptors) < 0)
   821     if (pipe(m_terminatePipeFileDescriptors) < 0)
   875 struct TrkDevicePrivate
   905 struct TrkDevicePrivate
   876 {
   906 {
   877     TrkDevicePrivate();
   907     TrkDevicePrivate();
   878 
   908 
   879     QSharedPointer<DeviceContext> deviceContext;
   909     QSharedPointer<DeviceContext> deviceContext;
   880     QSharedPointer<WriterThread> writerThread;
   910     QScopedPointer<WriterThread> writerThread;
   881     QSharedPointer<ReaderThread> readerThread;
   911     QScopedPointer<ReaderThread> readerThread;
   882 
   912 
   883     QByteArray trkReadBuffer;
   913     QByteArray trkReadBuffer;
   884     int verbose;
   914     int verbose;
   885     QString errorString;
   915     QString errorString;
   886     QString port;
   916     QString port;
   915     delete d;
   945     delete d;
   916 }
   946 }
   917 
   947 
   918 bool TrkDevice::open(QString *errorMessage)
   948 bool TrkDevice::open(QString *errorMessage)
   919 {
   949 {
   920     if (d->verbose)
   950     if (d->verbose || verboseTrk)
   921         qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame();
   951         qDebug() << "Opening" << port() << "is open: " << isOpen() << " serialFrame=" << serialFrame();
       
   952     if (isOpen())
       
   953         return true;
   922     if (d->port.isEmpty()) {
   954     if (d->port.isEmpty()) {
   923         *errorMessage = QLatin1String("Internal error: No port set on TrkDevice");
   955         *errorMessage = QLatin1String("Internal error: No port set on TrkDevice");
   924         return false;
   956         return false;
   925     }
   957     }
   926 
       
   927     close();
       
   928 #ifdef Q_OS_WIN
   958 #ifdef Q_OS_WIN
   929     const QString fullPort = QLatin1String("\\\\.\\") + d->port;
   959     const QString fullPort = QLatin1String("\\\\.\\") + d->port;
   930     d->deviceContext->device = CreateFile(reinterpret_cast<const WCHAR*>(fullPort.utf16()),
   960     d->deviceContext->device = CreateFile(reinterpret_cast<const WCHAR*>(fullPort.utf16()),
   931                            GENERIC_READ | GENERIC_WRITE,
   961                            GENERIC_READ | GENERIC_WRITE,
   932                            0,
   962                            0,
   973     if (tcsetattr(d->deviceContext->file.handle(), TCSAFLUSH, &termInfo) < 0) {
  1003     if (tcsetattr(d->deviceContext->file.handle(), TCSAFLUSH, &termInfo) < 0) {
   974         *errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno)));
  1004         *errorMessage = QString::fromLatin1("Unable to apply terminal settings: %1 %2").arg(errno).arg(QString::fromAscii(strerror(errno)));
   975         return false;
  1005         return false;
   976     }
  1006     }
   977 #endif
  1007 #endif
   978     d->readerThread = QSharedPointer<ReaderThread>(new ReaderThread(d->deviceContext));
  1008     d->readerThread.reset(new ReaderThread(d->deviceContext));
   979     connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
  1009     connect(d->readerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
   980             Qt::QueuedConnection);
  1010             Qt::QueuedConnection);
   981     connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)),
  1011     connect(d->readerThread.data(), SIGNAL(messageReceived(trk::TrkResult,QByteArray)),
   982             this, SLOT(slotMessageReceived(trk::TrkResult,QByteArray)),
  1012             this, SLOT(slotMessageReceived(trk::TrkResult,QByteArray)),
   983             Qt::QueuedConnection);
  1013             Qt::QueuedConnection);
   984     d->readerThread->start();
  1014     d->readerThread->start();
   985 
  1015 
   986     d->writerThread = QSharedPointer<WriterThread>(new WriterThread(d->deviceContext));
  1016     d->writerThread.reset(new WriterThread(d->deviceContext));
   987     connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
  1017     connect(d->writerThread.data(), SIGNAL(error(QString)), this, SLOT(emitError(QString)),
   988             Qt::QueuedConnection);    
  1018             Qt::QueuedConnection);
   989     d->writerThread->start();    
  1019     d->writerThread->start();
   990 
  1020 
   991     if (d->verbose)
  1021     if (d->verbose || verboseTrk)
   992         qDebug() << "Opened" << d->port;
  1022         qDebug() << "Opened" << d->port << d->readerThread.data() << d->writerThread.data();
   993     return true;
  1023     return true;
   994 }
  1024 }
   995 
  1025 
   996 void TrkDevice::close()
  1026 void TrkDevice::close()
   997 {
  1027 {
       
  1028     if (verboseTrk)
       
  1029         qDebug() << "close" << d->port << " is open: " << isOpen()
       
  1030         << " read pending " << (d->readerThread.isNull() ? 0 : d->readerThread->bytesPending())
       
  1031         << sender();
   998     if (!isOpen())
  1032     if (!isOpen())
   999         return;
  1033         return;
  1000     if (d->readerThread)
  1034     if (d->readerThread)
  1001         d->readerThread->terminate();
  1035         d->readerThread->terminate();
  1002     if (d->writerThread)
  1036     if (d->writerThread)
  1008     CloseHandle(d->deviceContext->writeOverlapped.hEvent);
  1042     CloseHandle(d->deviceContext->writeOverlapped.hEvent);
  1009     d->deviceContext->readOverlapped.hEvent = d->deviceContext->writeOverlapped.hEvent = NULL;
  1043     d->deviceContext->readOverlapped.hEvent = d->deviceContext->writeOverlapped.hEvent = NULL;
  1010 #else
  1044 #else
  1011     d->deviceContext->file.close();
  1045     d->deviceContext->file.close();
  1012 #endif
  1046 #endif
       
  1047 
  1013     if (d->verbose)
  1048     if (d->verbose)
  1014         emitLogMessage("Close");
  1049         emitLogMessage("Close");
  1015 }
  1050 }
  1016 
  1051 
  1017 bool TrkDevice::isOpen() const
  1052 bool TrkDevice::isOpen() const
  1028     return d->port;
  1063     return d->port;
  1029 }
  1064 }
  1030 
  1065 
  1031 void TrkDevice::setPort(const QString &p)
  1066 void TrkDevice::setPort(const QString &p)
  1032 {
  1067 {
       
  1068     if (verboseTrk)
       
  1069         qDebug() << "setPort" << p;
  1033     d->port = p;
  1070     d->port = p;
  1034 }
  1071 }
  1035 
  1072 
  1036 QString TrkDevice::errorString() const
  1073 QString TrkDevice::errorString() const
  1037 {
  1074 {
  1043     return d->deviceContext->serialFrame;
  1080     return d->deviceContext->serialFrame;
  1044 }
  1081 }
  1045 
  1082 
  1046 void TrkDevice::setSerialFrame(bool f)
  1083 void TrkDevice::setSerialFrame(bool f)
  1047 {
  1084 {
       
  1085     if (verboseTrk)
       
  1086         qDebug() << "setSerialFrame" << f;
  1048     d->deviceContext->serialFrame = f;
  1087     d->deviceContext->serialFrame = f;
  1049 }
  1088 }
  1050 
  1089 
  1051 int TrkDevice::verbose() const
  1090 int TrkDevice::verbose() const
  1052 {
  1091 {
  1058     d->verbose = b;
  1097     d->verbose = b;
  1059 }
  1098 }
  1060 
  1099 
  1061 void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData)
  1100 void TrkDevice::slotMessageReceived(const trk::TrkResult &result, const QByteArray &rawData)
  1062 {
  1101 {
  1063     d->writerThread->slotHandleResult(result);
  1102     if (isOpen()) { // Might receive bytes after closing due to queued connections.
  1064     if (d->verbose > 1)
  1103         d->writerThread->slotHandleResult(result);
  1065         qDebug() << "Received: " << result.toString();
  1104         if (d->verbose > 1)
  1066     emit messageReceived(result);    
  1105             qDebug() << "Received: " << result.toString();
  1067     if (!rawData.isEmpty())
  1106         emit messageReceived(result);
  1068         emit rawDataReceived(rawData);
  1107         if (!rawData.isEmpty())
       
  1108             emit rawDataReceived(rawData);
       
  1109     }
  1069 }
  1110 }
  1070 
  1111 
  1071 void TrkDevice::emitError(const QString &s)
  1112 void TrkDevice::emitError(const QString &s)
  1072 {
  1113 {
  1073     d->errorString = s;
  1114     d->errorString = s;
  1074     qWarning("%s\n", qPrintable(s));
  1115     qWarning("%s\n", qPrintable(s));
  1075     emit error(s);
  1116     emit error(s);
  1076 }
  1117 }
  1077 
  1118 
       
  1119 void TrkDevice::clearWriteQueue()
       
  1120 {
       
  1121     if (isOpen())
       
  1122         d->writerThread->clearWriteQueue();
       
  1123 }
       
  1124 
  1078 void TrkDevice::sendTrkMessage(byte code, TrkCallback callback,
  1125 void TrkDevice::sendTrkMessage(byte code, TrkCallback callback,
  1079      const QByteArray &data, const QVariant &cookie)
  1126      const QByteArray &data, const QVariant &cookie)
  1080 {
  1127 {
       
  1128     if (!isOpen()) {
       
  1129         emitError(msgAccessingClosedDevice(d->port));
       
  1130         return;
       
  1131     }
  1081     if (!d->writerThread.isNull()) {
  1132     if (!d->writerThread.isNull()) {
  1082         if (d->verbose > 1) {
  1133         if (d->verbose > 1) {
  1083             QByteArray msg = "Sending:  ";
  1134             QByteArray msg = "Sending:  0x";
  1084             msg += QByteArray::number(code, 16);
  1135             msg += QByteArray::number(code, 16);
  1085             msg += ": ";
  1136             msg += ": ";
  1086             msg += stringFromArray(data).toLatin1();
  1137             msg += stringFromArray(data).toLatin1();
       
  1138             if (cookie.isValid())
       
  1139                 msg += " Cookie: " + cookie.toString().toLatin1();
  1087             qDebug("%s", msg.data());
  1140             qDebug("%s", msg.data());
  1088         }
  1141         }
  1089         d->writerThread->queueTrkMessage(code, callback, data, cookie);
  1142         d->writerThread->queueTrkMessage(code, callback, data, cookie);
  1090     }
  1143     }
  1091 }
  1144 }
  1092 
  1145 
  1093 void TrkDevice::sendTrkInitialPing()
  1146 void TrkDevice::sendTrkInitialPing()
  1094 {
  1147 {
       
  1148     if (!isOpen()) {
       
  1149         emitError(msgAccessingClosedDevice(d->port));
       
  1150         return;
       
  1151     }
  1095     if (!d->writerThread.isNull())
  1152     if (!d->writerThread.isNull())
  1096         d->writerThread->queueTrkInitialPing();
  1153         d->writerThread->queueTrkInitialPing();
  1097 }
  1154 }
  1098 
  1155 
  1099 bool TrkDevice::sendTrkAck(byte token)
  1156 bool TrkDevice::sendTrkAck(byte token)
  1100 {
  1157 {
       
  1158     if (!isOpen()) {
       
  1159         emitError(msgAccessingClosedDevice(d->port));
       
  1160         return false;
       
  1161     }
  1101     if (d->writerThread.isNull())
  1162     if (d->writerThread.isNull())
  1102         return false;
  1163         return false;
  1103     // The acknowledgement must not be queued!
  1164     // The acknowledgement must not be queued!
  1104     TrkMessage msg(0x80, token);
  1165     TrkMessage msg(0x80, token);
  1105     msg.token = token;
  1166     msg.token = token;