forked from qt-creator/qt-creator
		
	
		
			
				
	
	
		
			582 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			582 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**************************************************************************
 | |
| **
 | |
| ** This file is part of Qt Creator
 | |
| **
 | |
| ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 | |
| **
 | |
| ** Contact: Nokia Corporation (qt-info@nokia.com)
 | |
| **
 | |
| ** No Commercial Usage
 | |
| **
 | |
| ** This file contains pre-release code and may not be distributed.
 | |
| ** You may use this file in accordance with the terms and conditions
 | |
| ** contained in the Technology Preview License Agreement accompanying
 | |
| ** this package.
 | |
| **
 | |
| ** GNU Lesser General Public License Usage
 | |
| **
 | |
| ** Alternatively, 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.
 | |
| **
 | |
| ** If you have questions regarding the use of this file, please contact
 | |
| ** Nokia at qt-info@nokia.com.
 | |
| **
 | |
| **************************************************************************/
 | |
| 
 | |
| #include "codaclientapplication.h"
 | |
| 
 | |
| #ifdef HAS_SERIALPORT
 | |
| #include  "virtualserialdevice.h"
 | |
| #endif
 | |
| 
 | |
| #include "codadevice.h"
 | |
| #include <QtNetwork/QTcpSocket>
 | |
| #include <QtCore/QFile>
 | |
| #include <QtCore/QFileInfo>
 | |
| 
 | |
| #include <cstdio>
 | |
| 
 | |
| static const char usageC[] =
 | |
| "\n%1 v0.1 built "__DATE__"\n\n"
 | |
| "Test client for Symbian CODA\n\n"
 | |
| "Usage:\n"
 | |
| "%1 ping            connection   Note: For serial connections ONLY.\n"
 | |
| "%1 launch [-d]     connection binary uid [--] [arguments]\n"
 | |
| "%1 install[-s]     connection remote-sis-file [targetdrive]\n"
 | |
| "%1 put    [c size] connection local-file remote-file\n"
 | |
| "%1 stat            connection remote-file\n\n"
 | |
| "'connection': address[:port] or serial-port\n\n"
 | |
| "Options:\n"
 | |
| "-d            Launch: Launch under Debug control (wait for termination)\n"
 | |
| "-c [size]     Put: Chunk size in KB (default %2KB)\n"
 | |
| "-s            Install: Silent installation\n\n"
 | |
| "Notes:\n"
 | |
| "UIDs take the form '0xfdaa278'. The target directory for sis-files on a\n"
 | |
| "device typically is 'c:\\data'. CODA's default port is %3.\n\n"
 | |
| "Example session:\n"
 | |
| "%1 put     192.168.0.42 test.sis c:\\data\\test.sis\n"
 | |
| "%1 stat    192.168.0.42 c:\\data\\test.sis\n"
 | |
| "%1 install 192.168.0.42 c:\\data\\test.sis c:\n"
 | |
| "%1 launch  192.168.0.42 c:\\sys\\bin\\test.exe  0x34f2b\n"
 | |
| "%1 ping    /dev/ttyUSB1\n";
 | |
| 
 | |
| static const unsigned short defaultPort = 65029;
 | |
| static const quint64  defaultChunkSize = 10240;
 | |
| 
 | |
| static inline bool isSerialPort(const QString &address)
 | |
| {
 | |
|     return address.startsWith(QLatin1String("/dev"))
 | |
|         || address.startsWith(QLatin1String("com"), Qt::CaseInsensitive)
 | |
|         || address.startsWith(QLatin1String("tty"), Qt::CaseInsensitive)
 | |
|         || address.startsWith(QLatin1Char('\\'));
 | |
| }
 | |
| 
 | |
| static inline QString fixSlashes(QString s)
 | |
| {
 | |
|     s.replace(QLatin1Char('/'), QLatin1Char('\\'));
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| CodaClientApplication::CodaClientApplication(int &argc, char **argv) :
 | |
|     QCoreApplication(argc, argv),
 | |
|     m_mode(Invalid),
 | |
|     m_port(defaultPort),
 | |
|     m_launchUID(0),
 | |
|     m_launchDebug(false),
 | |
|     m_installTargetDrive(QLatin1String("C:")),
 | |
|     m_installSilently(false),
 | |
|     m_putWriteOk(false),
 | |
|     m_statFstatOk(false),
 | |
|     m_putLastChunkSize(0),
 | |
|     m_putChunkSize(defaultChunkSize),
 | |
|     m_verbose(0)
 | |
| {
 | |
|     setApplicationName(QLatin1String("codaclient"));
 | |
| }
 | |
| 
 | |
| CodaClientApplication::~CodaClientApplication()
 | |
| {
 | |
| }
 | |
| 
 | |
| QString CodaClientApplication::usage()
 | |
| {
 | |
|     return QString::fromLatin1(usageC)
 | |
|             .arg(QCoreApplication::applicationName())
 | |
|             .arg(defaultChunkSize / 1024).arg(defaultPort);
 | |
| }
 | |
| 
 | |
| static inline CodaClientApplication::Mode modeArg(const QString &a)
 | |
| {
 | |
|     if (a == QLatin1String("launch"))
 | |
|         return CodaClientApplication::Launch;
 | |
|     if (a == QLatin1String("ping"))
 | |
|         return CodaClientApplication::Ping;
 | |
|     if (a == QLatin1String("install"))
 | |
|         return CodaClientApplication::Install;
 | |
|     if (a == QLatin1String("put"))
 | |
|         return CodaClientApplication::Put;
 | |
|     if (a == QLatin1String("stat"))
 | |
|         return CodaClientApplication::Stat;
 | |
|     return CodaClientApplication::Invalid;
 | |
| }
 | |
| 
 | |
| bool CodaClientApplication::parseArgument(const QString &a, int argNumber, QString *errorMessage)
 | |
| {
 | |
|     switch (argNumber) {
 | |
|     case 1:
 | |
|         m_mode = modeArg(a);
 | |
|         if (m_mode == Invalid) {
 | |
|             *errorMessage = QLatin1String("Invalid mode");
 | |
|             return false;
 | |
|         }
 | |
|         return true;
 | |
|     case 2:  { // Address/port
 | |
|         m_address = a;
 | |
|         const int colonPos = m_address.indexOf(':');
 | |
|         if (colonPos != -1) {
 | |
|             m_port = m_address.mid(colonPos + 1).toUInt();
 | |
|             m_address.truncate(colonPos);
 | |
|         }
 | |
|     }
 | |
|         break;
 | |
|     case 3:
 | |
|         switch (m_mode) {
 | |
|         case Launch:
 | |
|             m_launchBinary = fixSlashes(a);
 | |
|             break;
 | |
|         case Install:
 | |
|             m_installSisFile = a;
 | |
|             break;
 | |
|         case Put:
 | |
|             m_putLocalFile = a;
 | |
|             break;
 | |
|         case Stat:
 | |
|             m_statRemoteFile = fixSlashes(a);
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|         return true;
 | |
|     case 4:
 | |
|         switch (m_mode) {
 | |
|         case Launch:
 | |
|             m_launchUID = a.toUInt(0, 0);
 | |
|             if (!m_launchUID) {
 | |
|                 *errorMessage = QLatin1String("Invalid UID");
 | |
|                 return false;
 | |
|             }
 | |
|             break;
 | |
|         case Install:
 | |
|             m_installTargetDrive = a;
 | |
|             break;
 | |
|         case Put:
 | |
|             m_putRemoteFile = fixSlashes(a);
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|         return true;
 | |
| 
 | |
|     default:
 | |
|         if (m_mode == Launch)
 | |
|             m_launchArgs.push_back(a);
 | |
|         break;
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| CodaClientApplication::ParseArgsResult CodaClientApplication::parseArguments(QString *errorMessage)
 | |
| {
 | |
|     int argNumber = 1;
 | |
|     const QStringList args = QCoreApplication::arguments();
 | |
|     const QStringList::const_iterator cend = args.constEnd();
 | |
|     QStringList::const_iterator it = args.constBegin();
 | |
|     bool optionsEnd = false;
 | |
|     for (++it; it != cend; ++it) {
 | |
|         if (!optionsEnd  && *it == QLatin1String("--")) {
 | |
|             optionsEnd = true;
 | |
|             continue;
 | |
|         }
 | |
|         if (!optionsEnd &&  it->startsWith(QLatin1Char('-')) && it->size() == 2) {
 | |
|             switch (it->at(1).toAscii()) {
 | |
|             case 'v':
 | |
|                 m_verbose++;
 | |
|                 break;
 | |
|             case 'd':
 | |
|                 m_launchDebug = true;
 | |
|                 break;
 | |
|             case 's':
 | |
|                 m_installSilently = true;
 | |
|                 break;
 | |
|             case 'c':
 | |
|                 if (++it == cend) {
 | |
|                     *errorMessage = QString::fromLatin1("Parameter missing for -c");
 | |
|                     return ParseArgsError;
 | |
|                 }
 | |
|                 m_putChunkSize = it->toULongLong() * 1024;
 | |
|                 if (!m_putChunkSize) {
 | |
|                     *errorMessage = QString::fromLatin1("Invalid chunk size.");
 | |
|                     return ParseArgsError;
 | |
|                 }
 | |
|                 break;
 | |
|             default:
 | |
|                 *errorMessage = QString::fromLatin1("Invalid option %1").arg(*it);
 | |
|                 return ParseArgsError;
 | |
|             }
 | |
|         } else {
 | |
|             if (!parseArgument(*it, argNumber++, errorMessage))
 | |
|                 return ParseArgsError;
 | |
|         }
 | |
|     } //for loop
 | |
|     // Basic Check & init
 | |
|     switch (m_mode) {
 | |
|     case Invalid:
 | |
|         return ParseArgsError;
 | |
|     case Launch:
 | |
|         if (m_address.isEmpty() || !m_launchUID || m_launchBinary.isEmpty()) {
 | |
|             *errorMessage = QString::fromLatin1("Not enough parameters for launch.");
 | |
|             return ParseInitError;
 | |
|         }
 | |
|         break;
 | |
|     case Ping:
 | |
|         if (m_address.isEmpty()) {
 | |
|             *errorMessage = QString::fromLatin1("Not enough parameters for ping.");
 | |
|             return ParseInitError;
 | |
|         }
 | |
|         if (!isSerialPort(m_address)) {
 | |
|             *errorMessage = QString::fromLatin1("'ping' not supported for TCP/IP.");
 | |
|             return ParseInitError;
 | |
|         }
 | |
|         break;
 | |
|     case Install:
 | |
|         if (m_address.isEmpty() || m_installSisFile.isEmpty()) {
 | |
|             *errorMessage = QString::fromLatin1("Not enough parameters for install.");
 | |
|             return ParseInitError;
 | |
|         }
 | |
|         break;
 | |
|     case Put: {
 | |
|         if (m_address.isEmpty() || m_putLocalFile.isEmpty() || m_putRemoteFile.isEmpty()) {
 | |
|             *errorMessage = QString::fromLatin1("Not enough parameters for put.");
 | |
|             return ParseInitError;
 | |
|         }
 | |
|         const QFileInfo fi(m_putLocalFile);
 | |
|         if (!fi.isFile() || !fi.isReadable()) {
 | |
|             *errorMessage = QString::fromLatin1("Local file '%1' not readable.").arg(m_putLocalFile);
 | |
|             return ParseInitError;
 | |
|         }
 | |
|     }
 | |
|         break;
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
|     return ParseArgsOk;
 | |
| }
 | |
| 
 | |
| bool CodaClientApplication::start()
 | |
| {
 | |
|     m_startTime.start();
 | |
|     switch (m_mode) {
 | |
|     case Ping:
 | |
|         break;
 | |
|     case Launch: {
 | |
|         const QString args = m_launchArgs.join(QString(QLatin1Char(' ')));
 | |
|         std::printf("Launching 0x%x '%s '%s' (debug: %d)\n",
 | |
|                     m_launchUID, qPrintable(m_launchBinary),
 | |
|                     qPrintable(args), m_launchDebug);
 | |
|     }
 | |
|         break;
 | |
|     case Install:
 | |
|         std::printf("Installing '%s' to '%s'\n",
 | |
|                     qPrintable(m_installSisFile), qPrintable(m_installTargetDrive));
 | |
|         break;
 | |
|     case Put:
 | |
|         std::printf("Copying '%s' to '%s' in chunks of %lluKB\n",
 | |
|                     qPrintable(m_putLocalFile), qPrintable(m_putRemoteFile),
 | |
|                     m_putChunkSize / 1024);
 | |
|         break;
 | |
|     case Stat:
 | |
|         std::printf("Retrieving attributes of '%s'\n", qPrintable(m_statRemoteFile));
 | |
|         break;
 | |
|     case Invalid:
 | |
|         break;
 | |
|     }
 | |
|     // Start connection
 | |
|     m_trkDevice.reset(new Coda::CodaDevice);
 | |
|     m_trkDevice->setVerbose(m_verbose);
 | |
|     connect(m_trkDevice.data(), SIGNAL(error(QString)),
 | |
|         this, SLOT(slotError(QString)));
 | |
|     connect(m_trkDevice.data(), SIGNAL(logMessage(QString)),
 | |
|         this, SLOT(slotTrkLogMessage(QString)));
 | |
|     connect(m_trkDevice.data(), SIGNAL(tcfEvent(Coda::CodaEvent)),
 | |
|         this, SLOT(slotCodaEvent(Coda::CodaEvent)));
 | |
|     connect(m_trkDevice.data(), SIGNAL(serialPong(QString)),
 | |
|             this, SLOT(slotSerialPong(QString)));
 | |
|     if (isSerialPort(m_address)) {
 | |
| #ifdef HAS_SERIALPORT
 | |
|         // Serial
 | |
|         const QSharedPointer<QIODevice> serialPort(new SymbianUtils::VirtualSerialDevice(m_address));
 | |
|         std::printf("Opening port %s...\n", qPrintable(m_address));
 | |
|         m_trkDevice->setSerialFrame(true);
 | |
|         m_trkDevice->setDevice(serialPort); // Grab all data from start
 | |
|         if (!serialPort->open(QIODevice::ReadWrite)) {
 | |
|             std::fprintf(stderr, "Cannot open port: %s", qPrintable(serialPort->errorString()));
 | |
|             return false;
 | |
|         }
 | |
|         // Initiate communication
 | |
|         m_trkDevice->sendSerialPing(m_mode == Ping);
 | |
| #else
 | |
|         std::fprintf(stderr, "Not implemented\n");
 | |
|         return false;
 | |
| #endif
 | |
|     } else {
 | |
|         // TCP/IP
 | |
|         const QSharedPointer<QTcpSocket> codaSocket(new QTcpSocket);
 | |
|         m_trkDevice->setDevice(codaSocket);
 | |
|         codaSocket->connectToHost(m_address, m_port);
 | |
|         std::printf("Connecting to %s:%hu...\n", qPrintable(m_address), m_port);
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::slotError(const QString &e)
 | |
| {
 | |
|     std::fprintf(stderr, "Error: %s\n", qPrintable(e));
 | |
|     doExit(-1);
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::slotTrkLogMessage(const QString &m)
 | |
| {
 | |
|     printTimeStamp();
 | |
|     std::printf("%s\n", qPrintable(m));
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::handleCreateProcess(const Coda::CodaCommandResult &result)
 | |
| {
 | |
|     const bool ok = result.type == Coda::CodaCommandResult::SuccessReply;
 | |
|     if (ok) {
 | |
|         printTimeStamp();
 | |
|         std::printf("Launch succeeded: %s\n", qPrintable(result.toString()));
 | |
|         if (!m_launchDebug)
 | |
|             doExit(0);
 | |
|     } else {
 | |
|         std::fprintf(stderr, "Launch failed: %s\n", qPrintable(result.toString()));
 | |
|         doExit(-1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::handleFileSystemOpen(const Coda::CodaCommandResult &result)
 | |
| {
 | |
|     if (result.type != Coda::CodaCommandResult::SuccessReply) {
 | |
|         std::fprintf(stderr, "Open remote file failed: %s\n", qPrintable(result.toString()));
 | |
|         doExit(-1);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (result.values.size() < 1 || result.values.at(0).data().isEmpty()) {
 | |
|         std::fprintf(stderr, "Internal error: No filehandle obtained\n");
 | |
|         doExit(-1);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_remoteFileHandle = result.values.at(0).data();
 | |
| 
 | |
|     if (m_mode == Stat) {
 | |
|         m_trkDevice->sendFileSystemFstatCommand(Coda::CodaCallback(this, &CodaClientApplication::handleFileSystemFStat),
 | |
|                                                m_remoteFileHandle);
 | |
|         return;
 | |
|     }
 | |
|     // Put.
 | |
|     m_putFile.reset(new QFile(m_putLocalFile));
 | |
|     if (!m_putFile->open(QIODevice::ReadOnly)) { // Should not fail, was checked before
 | |
|         std::fprintf(stderr, "Open local file failed: %s\n", qPrintable(m_putFile->errorString()));
 | |
|         doExit(-1);
 | |
|         return;
 | |
|     }
 | |
|     putSendNextChunk();
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::putSendNextChunk()
 | |
| {
 | |
|     // Read and send off next chunk
 | |
|     const quint64 pos = m_putFile->pos();
 | |
|     const QByteArray data = m_putFile->read(m_putChunkSize);
 | |
|     if (data.isEmpty()) {
 | |
|         m_putWriteOk = true;
 | |
|         closeRemoteFile();
 | |
|     } else {
 | |
|         m_putLastChunkSize = data.size();
 | |
|         printTimeStamp();
 | |
|         std::printf("Writing %llu bytes to remote file '%s' at %llu\n",
 | |
|                     m_putLastChunkSize,
 | |
|                     m_remoteFileHandle.constData(), pos);
 | |
|         m_trkDevice->sendFileSystemWriteCommand(Coda::CodaCallback(this, &CodaClientApplication::handleFileSystemWrite),
 | |
|                                                 m_remoteFileHandle, data, unsigned(pos));
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::closeRemoteFile()
 | |
| {
 | |
|     m_trkDevice->sendFileSystemCloseCommand(Coda::CodaCallback(this, &CodaClientApplication::handleFileSystemClose),
 | |
|                                             m_remoteFileHandle);
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::handleFileSystemWrite(const Coda::CodaCommandResult &result)
 | |
| {
 | |
|     // Close remote file even if copy fails
 | |
|     m_putWriteOk = result;
 | |
|     if (!m_putWriteOk)
 | |
|         std::fprintf(stderr, "Writing data failed: %s\n", qPrintable(result.toString()));
 | |
|     if (!m_putWriteOk || m_putLastChunkSize < m_putChunkSize) {
 | |
|         closeRemoteFile();
 | |
|     } else {
 | |
|         putSendNextChunk();
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::handleFileSystemFStat(const Coda::CodaCommandResult &result)
 | |
| {
 | |
|     m_statFstatOk = result.type == Coda::CodaCommandResult::SuccessReply;
 | |
|     // Close remote file even if copy fails
 | |
|     if (m_statFstatOk) {
 | |
|         const Coda::CodaStatResponse statr = Coda::CodaDevice::parseStat(result);
 | |
|         printTimeStamp();
 | |
|         std::printf("File: %s\nSize: %llu bytes\nAccessed: %s\nModified: %s\n",
 | |
|                     qPrintable(m_statRemoteFile), statr.size,
 | |
|                     qPrintable(statr.accessTime.toString(Qt::LocalDate)),
 | |
|                     qPrintable(statr.modTime.toString(Qt::LocalDate)));
 | |
|     } else {
 | |
|         std::fprintf(stderr, "FStat failed: %s\n", qPrintable(result.toString()));
 | |
|     }
 | |
|     closeRemoteFile();
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::handleFileSystemClose(const Coda::CodaCommandResult &result)
 | |
| {
 | |
|     if (result.type == Coda::CodaCommandResult::SuccessReply) {
 | |
|         printTimeStamp();
 | |
|         std::printf("File closed.\n");
 | |
|         const bool ok = m_mode == Put ? m_putWriteOk : m_statFstatOk;
 | |
|         doExit(ok ? 0 : -1);
 | |
|     } else {
 | |
|         std::fprintf(stderr, "File close failed: %s\n", qPrintable(result.toString()));
 | |
|         doExit(-1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::handleSymbianInstall(const Coda::CodaCommandResult &result)
 | |
| {
 | |
|     if (result.type == Coda::CodaCommandResult::SuccessReply) {
 | |
|         printTimeStamp();
 | |
|         std::printf("Installation succeeded\n.");
 | |
|         doExit(0);
 | |
|     } else {
 | |
|         std::fprintf(stderr, "Installation failed: %s\n", qPrintable(result.toString()));
 | |
|         doExit(-1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::slotCodaEvent (const Coda::CodaEvent &ev)
 | |
| {
 | |
|     printTimeStamp();
 | |
|     std::printf("Event: %s\n", qPrintable(ev.toString()));
 | |
|     switch (ev.type()) {
 | |
|     case Coda::CodaEvent::LocatorHello: // Commands accepted now
 | |
|         switch (m_mode) {
 | |
|         case Ping:
 | |
|             break;
 | |
|         case Launch:
 | |
|             m_trkDevice->sendProcessStartCommand(Coda::CodaCallback(this, &CodaClientApplication::handleCreateProcess),
 | |
|                                                  m_launchBinary, m_launchUID, m_launchArgs, QString(), m_launchDebug);
 | |
|             break;
 | |
|         case Install:
 | |
|             if (m_installSilently) {
 | |
|                 m_trkDevice->sendSymbianInstallSilentInstallCommand(Coda::CodaCallback(this, &CodaClientApplication::handleSymbianInstall),
 | |
|                                                                     m_installSisFile.toAscii(), m_installTargetDrive.toAscii());
 | |
|             } else {
 | |
|                 m_trkDevice->sendSymbianInstallUIInstallCommand(Coda::CodaCallback(this, &CodaClientApplication::handleSymbianInstall),
 | |
|                                                                 m_installSisFile.toAscii());
 | |
|             }
 | |
|             break;
 | |
|         case Put: {
 | |
|             const unsigned flags =
 | |
|                     Coda::CodaDevice::FileSystem_TCF_O_WRITE
 | |
|                     |Coda::CodaDevice::FileSystem_TCF_O_CREAT
 | |
|                     |Coda::CodaDevice::FileSystem_TCF_O_TRUNC;
 | |
|             m_putWriteOk = false;
 | |
|             m_trkDevice->sendFileSystemOpenCommand(Coda::CodaCallback(this, &CodaClientApplication::handleFileSystemOpen),
 | |
|                                                    m_putRemoteFile.toAscii(), flags);
 | |
| }
 | |
|             break;
 | |
|         case Stat: {
 | |
|             const unsigned flags = Coda::CodaDevice::FileSystem_TCF_O_READ;
 | |
|             m_statFstatOk = false;
 | |
|             m_trkDevice->sendFileSystemOpenCommand(Coda::CodaCallback(this, &CodaClientApplication::handleFileSystemOpen),
 | |
|                                                    m_statRemoteFile.toAscii(), flags);
 | |
| }
 | |
|             break;
 | |
|         case Invalid:
 | |
|             break;
 | |
|         }
 | |
|         break;
 | |
|     case Coda::CodaEvent::RunControlModuleLoadSuspended:  {
 | |
|         // Debug mode start: Continue:
 | |
|         const Coda::CodaRunControlModuleLoadContextSuspendedEvent &me =
 | |
|                 static_cast<const Coda::CodaRunControlModuleLoadContextSuspendedEvent &>(ev);
 | |
|         if (me.info().requireResume) {
 | |
|             printTimeStamp();
 | |
|             std::printf("Continuing...\n");
 | |
|             m_trkDevice->sendRunControlResumeCommand(Coda::CodaCallback(), me.id());
 | |
|         }
 | |
|     }
 | |
|         break;
 | |
|     case Coda::CodaEvent::RunControlContextRemoved: // App terminated in debug mode
 | |
|         doExit(0);
 | |
|         break;
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::slotSerialPong(const QString &v)
 | |
| {
 | |
|     printTimeStamp();
 | |
|     std::printf("Pong from '%s'\n", qPrintable(v));
 | |
|     if (m_mode == Ping)
 | |
|         doExit(0);
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::doExit(int ex)
 | |
| {
 | |
|     if (!m_trkDevice.isNull()) {
 | |
|         const QSharedPointer<QIODevice> dev = m_trkDevice->device();
 | |
|         if (!dev.isNull()) {
 | |
|             if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(dev.data())) {
 | |
|                 if (socket->state() == QAbstractSocket::ConnectedState)
 | |
|                     socket->disconnectFromHost();
 | |
|             } else {
 | |
|                 if (dev->isOpen())
 | |
|                     dev->close();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     printTimeStamp();
 | |
|     std::printf("Exiting (%d)\n", ex);
 | |
|     exit(ex);
 | |
| }
 | |
| 
 | |
| void CodaClientApplication::printTimeStamp()
 | |
| {
 | |
|     const int elapsedMS = m_startTime.elapsed();
 | |
|     const int secs = elapsedMS / 1000;
 | |
|     const int msecs = elapsedMS % 1000;
 | |
|     std::printf("%4d.%03ds: ", secs, msecs);
 | |
| }
 |