Commit 88b77ba8 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Symbian CODA: Add ping for serial, handle reading long messages.

Some renaming and cleanup.
parent e641bfbd
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
enum { debug = 0 }; enum { debug = 0 };
static const char wlanMessageTerminatorC[] = "\003\001"; static const char tcpMessageTerminatorC[] = "\003\001";
// Serial Ping: 0xfc,0x1f // Serial Ping: 0xfc,0x1f
static const char serialPingC[] = "\xfc\x1f"; static const char serialPingC[] = "\xfc\x1f";
...@@ -50,8 +50,15 @@ static const char serialPongC[] = "\xfc\xf1"; ...@@ -50,8 +50,15 @@ static const char serialPongC[] = "\xfc\xf1";
static const char locatorAnswerC[] = "E\0Locator\0Hello\0[\"Locator\"]"; 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 unsigned serialChunkLength = 0x400; // 1K max USB router
static const int maxSerialMessageLength = 0x10000; // give chunking scheme static const int maxSerialMessageLength = 0x10000; // given chunking scheme
static const unsigned char serialChunkingStart = 0xfe;
static const unsigned char serialChunkingContinuation = 0x0;
enum { SerialChunkHeaderSize = 2 };
// Create USB router frame // Create USB router frame
static inline void encodeSerialFrame(const QByteArray &data, QByteArray *target) static inline void encodeSerialFrame(const QByteArray &data, QByteArray *target)
...@@ -65,7 +72,8 @@ static inline void encodeSerialFrame(const QByteArray &data, QByteArray *target) ...@@ -65,7 +72,8 @@ static inline void encodeSerialFrame(const QByteArray &data, QByteArray *target)
// Split in chunks of 1K according to CODA protocol chunking // Split in chunks of 1K according to CODA protocol chunking
static inline QByteArray encodeUsbSerialMessage(const QByteArray &dataIn) static inline QByteArray encodeUsbSerialMessage(const QByteArray &dataIn)
{ {
static const int chunkSize = serialChunkLength - 2; // 2 Header bytes // Reserve 2 header bytes
static const int chunkSize = serialChunkLength - SerialChunkHeaderSize;
const int size = dataIn.size(); const int size = dataIn.size();
QByteArray frame; QByteArray frame;
// Do we need to split? // Do we need to split?
...@@ -86,7 +94,7 @@ static inline QByteArray encodeUsbSerialMessage(const QByteArray &dataIn) ...@@ -86,7 +94,7 @@ static inline QByteArray encodeUsbSerialMessage(const QByteArray &dataIn)
for (unsigned c = chunkCount - 1; pos < size ; c--) { for (unsigned c = chunkCount - 1; pos < size ; c--) {
QByteArray chunk; // chunk with long message start/continuation code QByteArray chunk; // chunk with long message start/continuation code
chunk.reserve(serialChunkLength); chunk.reserve(serialChunkLength);
chunk.append(pos ? char(0) : char(0xfe)); chunk.append(pos ? serialChunkingContinuation : serialChunkingStart);
chunk.append(char(static_cast<unsigned char>(c))); // Avoid any signedness issues. chunk.append(char(static_cast<unsigned char>(c))); // Avoid any signedness issues.
const int chunkEnd = qMin(pos + chunkSize, size); const int chunkEnd = qMin(pos + chunkSize, size);
chunk.append(dataIn.mid(pos, chunkEnd - pos)); chunk.append(dataIn.mid(pos, chunkEnd - pos));
...@@ -318,22 +326,24 @@ struct TcfTrkDevicePrivate { ...@@ -318,22 +326,24 @@ struct TcfTrkDevicePrivate {
TcfTrkDevicePrivate(); TcfTrkDevicePrivate();
const QByteArray m_messageTerminator; const QByteArray m_tcpMessageTerminator;
IODevicePtr m_device; IODevicePtr m_device;
unsigned m_verbose; unsigned m_verbose;
QByteArray m_readBuffer; QByteArray m_readBuffer;
QByteArray m_serialBuffer; // for chunked messages
int m_token; int m_token;
QQueue<TcfTrkSendQueueEntry> m_sendQueue; QQueue<TcfTrkSendQueueEntry> m_sendQueue;
TokenWrittenMessageMap m_writtenMessages; TokenWrittenMessageMap m_writtenMessages;
QVector<QByteArray> m_registerNames; QVector<QByteArray> m_registerNames;
QVector<QByteArray> m_fakeGetMRegisterValues; QVector<QByteArray> m_fakeGetMRegisterValues;
bool m_serialFrame; bool m_serialFrame;
bool m_serialPingOnly;
}; };
TcfTrkDevicePrivate::TcfTrkDevicePrivate() : TcfTrkDevicePrivate::TcfTrkDevicePrivate() :
m_messageTerminator(wlanMessageTerminatorC), m_tcpMessageTerminator(tcpMessageTerminatorC),
m_verbose(0), m_token(0), m_serialFrame(false) m_verbose(0), m_token(0), m_serialFrame(false), m_serialPingOnly(false)
{ {
} }
...@@ -457,7 +467,7 @@ void TcfTrkDevice::slotDeviceReadyRead() ...@@ -457,7 +467,7 @@ void TcfTrkDevice::slotDeviceReadyRead()
if (d->m_serialFrame) { if (d->m_serialFrame) {
deviceReadyReadSerial(); deviceReadyReadSerial();
} else { } else {
deviceReadyReadWLAN(); deviceReadyReadTcp();
} }
} }
...@@ -496,31 +506,59 @@ void TcfTrkDevice::deviceReadyReadSerial() ...@@ -496,31 +506,59 @@ void TcfTrkDevice::deviceReadyReadSerial()
const int messageEnd = messagePos.first + messagePos.second; const int messageEnd = messagePos.first + messagePos.second;
if (messageEnd > d->m_readBuffer.size()) if (messageEnd > d->m_readBuffer.size())
break; break;
const QByteArray message = d->m_readBuffer.mid(messagePos.first, messagePos.second); processSerialMessage(d->m_readBuffer.mid(messagePos.first, messagePos.second));
// Is thing a ping/pong response
if (debug > 1)
qDebug("Serial message: at %d (%d bytes) of %d: %s",
messagePos.first, messagePos.second, d->m_readBuffer.size(),
qPrintable(trk::stringFromArray(message)));
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.
writeMessage(QByteArray(locatorAnswerC, sizeof(locatorAnswerC)));
} else {
processMessage(message);
}
d->m_readBuffer.remove(0, messageEnd); d->m_readBuffer.remove(0, messageEnd);
} while (d->m_readBuffer.isEmpty()); } while (d->m_readBuffer.isEmpty());
checkSendQueue(); // Send off further messages checkSendQueue(); // Send off further messages
} }
void TcfTrkDevice::deviceReadyReadWLAN() void TcfTrkDevice::processSerialMessage(const QByteArray &message)
{
if (debug > 1)
qDebug("Serial message: %s",qPrintable(trk::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 TcfTrkDevice::deviceReadyReadTcp()
{ {
// Take complete message off front of readbuffer. // Take complete message off front of readbuffer.
do { do {
const int messageEndPos = d->m_readBuffer.indexOf(d->m_messageTerminator); const int messageEndPos = d->m_readBuffer.indexOf(d->m_tcpMessageTerminator);
if (messageEndPos == -1) if (messageEndPos == -1)
break; break;
if (messageEndPos == 0) { if (messageEndPos == 0) {
...@@ -529,7 +567,7 @@ void TcfTrkDevice::deviceReadyReadWLAN() ...@@ -529,7 +567,7 @@ void TcfTrkDevice::deviceReadyReadWLAN()
} else { } else {
processMessage(d->m_readBuffer.left(messageEndPos)); processMessage(d->m_readBuffer.left(messageEndPos));
} }
d->m_readBuffer.remove(0, messageEndPos + d->m_messageTerminator.size()); d->m_readBuffer.remove(0, messageEndPos + d->m_tcpMessageTerminator.size());
} while (!d->m_readBuffer.isEmpty()); } while (!d->m_readBuffer.isEmpty());
checkSendQueue(); // Send off further messages checkSendQueue(); // Send off further messages
} }
...@@ -767,11 +805,12 @@ bool TcfTrkDevice::checkOpen() ...@@ -767,11 +805,12 @@ bool TcfTrkDevice::checkOpen()
return true; return true;
} }
void TcfTrkDevice::sendSerialPing() void TcfTrkDevice::sendSerialPing(bool pingOnly)
{ {
if (!checkOpen()) if (!checkOpen())
return; return;
d->m_serialPingOnly = pingOnly;
setSerialFrame(true); setSerialFrame(true);
writeMessage(QByteArray(serialPingC, qstrlen(serialPingC)), false); writeMessage(QByteArray(serialPingC, qstrlen(serialPingC)), false);
if (d->m_verbose) if (d->m_verbose)
...@@ -847,7 +886,7 @@ void TcfTrkDevice::writeMessage(QByteArray data, bool ensureTerminating0) ...@@ -847,7 +886,7 @@ void TcfTrkDevice::writeMessage(QByteArray data, bool ensureTerminating0)
if (d->m_serialFrame) { if (d->m_serialFrame) {
data = encodeUsbSerialMessage(data); data = encodeUsbSerialMessage(data);
} else { } else {
data += d->m_messageTerminator; data += d->m_tcpMessageTerminator;
} }
if (debug > 1) if (debug > 1)
......
...@@ -186,7 +186,7 @@ public: ...@@ -186,7 +186,7 @@ public:
void setDevice(const IODevicePtr &dp); void setDevice(const IODevicePtr &dp);
// Serial Only: Initiate communication. Will emit serialPong() signal with version. // Serial Only: Initiate communication. Will emit serialPong() signal with version.
void sendSerialPing(); void sendSerialPing(bool pingOnly = false);
// Send with parameters from string (which may contain '\0'). // Send with parameters from string (which may contain '\0').
void sendTcfTrkMessage(MessageType mt, Services service, void sendTcfTrkMessage(MessageType mt, Services service,
...@@ -367,7 +367,7 @@ private slots: ...@@ -367,7 +367,7 @@ private slots:
private: private:
void deviceReadyReadSerial(); void deviceReadyReadSerial();
void deviceReadyReadWLAN(); void deviceReadyReadTcp();
bool checkOpen(); bool checkOpen();
void checkSendQueue(); void checkSendQueue();
...@@ -375,6 +375,7 @@ private: ...@@ -375,6 +375,7 @@ private:
void emitLogMessage(const QString &); void emitLogMessage(const QString &);
inline int parseMessage(const QByteArray &); inline int parseMessage(const QByteArray &);
void processMessage(const QByteArray &message); void processMessage(const QByteArray &message);
inline void processSerialMessage(const QByteArray &message);
int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens); int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens);
int parseTcfEvent(const QVector<QByteArray> &tokens); int parseTcfEvent(const QVector<QByteArray> &tokens);
// Send with parameters from string (which may contain '\0'). // Send with parameters from string (which may contain '\0').
......
...@@ -44,11 +44,13 @@ static const char usageC[] = ...@@ -44,11 +44,13 @@ static const char usageC[] =
"\n%1 v0.1 built "__DATE__"\n\n" "\n%1 v0.1 built "__DATE__"\n\n"
"Test client for Symbian CODA\n\n" "Test client for Symbian CODA\n\n"
"Usage:\n" "Usage:\n"
"%1 launch [-d] address[:port] binary uid [--] [arguments]\n" "%1 ping connection Note: For serial connections ONLY.\n"
"%1 install[-s] address[:port] remote-sis-file [targetdrive]\n" "%1 launch [-d] connection binary uid [--] [arguments]\n"
"%1 put [c size] address[:port] local-file remote-file\n" "%1 install[-s] connection remote-sis-file [targetdrive]\n"
"%1 stat address[:port] remote-file\n" "%1 put [c size] connection local-file remote-file\n"
"\nOptions:\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" "-d Launch: Launch under Debug control (wait for termination)\n"
"-c [size] Put: Chunk size in KB (default %2KB)\n" "-c [size] Put: Chunk size in KB (default %2KB)\n"
"-s Install: Silent installation\n\n" "-s Install: Silent installation\n\n"
...@@ -59,11 +61,20 @@ static const char usageC[] = ...@@ -59,11 +61,20 @@ static const char usageC[] =
"%1 put 192.168.0.42 test.sis c:\\data\\test.sis\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 stat 192.168.0.42 c:\\data\\test.sis\n"
"%1 install 192.168.0.42 c:\\data\\test.sis c:\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 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 unsigned short defaultPort = 65029;
static const quint64 defaultChunkSize = 10240; 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) static inline QString fixSlashes(QString s)
{ {
s.replace(QLatin1Char('/'), QLatin1Char('\\')); s.replace(QLatin1Char('/'), QLatin1Char('\\'));
...@@ -102,6 +113,8 @@ static inline CodaClientApplication::Mode modeArg(const QString &a) ...@@ -102,6 +113,8 @@ static inline CodaClientApplication::Mode modeArg(const QString &a)
{ {
if (a == QLatin1String("launch")) if (a == QLatin1String("launch"))
return CodaClientApplication::Launch; return CodaClientApplication::Launch;
if (a == QLatin1String("ping"))
return CodaClientApplication::Ping;
if (a == QLatin1String("install")) if (a == QLatin1String("install"))
return CodaClientApplication::Install; return CodaClientApplication::Install;
if (a == QLatin1String("put")) if (a == QLatin1String("put"))
...@@ -229,6 +242,16 @@ CodaClientApplication::ParseArgsResult CodaClientApplication::parseArguments(QSt ...@@ -229,6 +242,16 @@ CodaClientApplication::ParseArgsResult CodaClientApplication::parseArguments(QSt
return ParseInitError; return ParseInitError;
} }
break; 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: case Install:
if (m_address.isEmpty() || m_installSisFile.isEmpty()) { if (m_address.isEmpty() || m_installSisFile.isEmpty()) {
*errorMessage = QString::fromLatin1("Not enough parameters for install."); *errorMessage = QString::fromLatin1("Not enough parameters for install.");
...@@ -257,6 +280,8 @@ bool CodaClientApplication::start() ...@@ -257,6 +280,8 @@ bool CodaClientApplication::start()
{ {
m_startTime.start(); m_startTime.start();
switch (m_mode) { switch (m_mode) {
case Ping:
break;
case Launch: { case Launch: {
const QString args = m_launchArgs.join(QString(QLatin1Char(' '))); const QString args = m_launchArgs.join(QString(QLatin1Char(' ')));
std::printf("Launching 0x%x '%s '%s' (debug: %d)\n", std::printf("Launching 0x%x '%s '%s' (debug: %d)\n",
...@@ -288,9 +313,9 @@ bool CodaClientApplication::start() ...@@ -288,9 +313,9 @@ bool CodaClientApplication::start()
this, SLOT(slotTrkLogMessage(QString))); this, SLOT(slotTrkLogMessage(QString)));
connect(m_trkDevice.data(), SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)), connect(m_trkDevice.data(), SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)),
this, SLOT(slotTcftrkEvent(tcftrk::TcfTrkEvent))); this, SLOT(slotTcftrkEvent(tcftrk::TcfTrkEvent)));
if (m_address.startsWith(QLatin1String("/dev")) connect(m_trkDevice.data(), SIGNAL(serialPong(QString)),
|| m_address.startsWith(QLatin1String("com"), Qt::CaseInsensitive) this, SLOT(slotSerialPong(QString)));
|| m_address.startsWith(QLatin1Char('\\'))) { if (isSerialPort(m_address)) {
#ifdef HAS_SERIALPORT #ifdef HAS_SERIALPORT
// Serial // Serial
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
...@@ -317,7 +342,7 @@ bool CodaClientApplication::start() ...@@ -317,7 +342,7 @@ bool CodaClientApplication::start()
return false; return false;
} }
// Initiate communication // Initiate communication
m_trkDevice->sendSerialPing(); m_trkDevice->sendSerialPing(m_mode == Ping);
serialPort->flush(); serialPort->flush();
#else #else
std::fprintf(stderr, "Not implemented\n"); std::fprintf(stderr, "Not implemented\n");
...@@ -341,6 +366,7 @@ void CodaClientApplication::slotError(const QString &e) ...@@ -341,6 +366,7 @@ void CodaClientApplication::slotError(const QString &e)
void CodaClientApplication::slotTrkLogMessage(const QString &m) void CodaClientApplication::slotTrkLogMessage(const QString &m)
{ {
printTimeStamp();
std::printf("%s\n", qPrintable(m)); std::printf("%s\n", qPrintable(m));
} }
...@@ -348,6 +374,7 @@ void CodaClientApplication::handleCreateProcess(const tcftrk::TcfTrkCommandResul ...@@ -348,6 +374,7 @@ void CodaClientApplication::handleCreateProcess(const tcftrk::TcfTrkCommandResul
{ {
const bool ok = result.type == tcftrk::TcfTrkCommandResult::SuccessReply; const bool ok = result.type == tcftrk::TcfTrkCommandResult::SuccessReply;
if (ok) { if (ok) {
printTimeStamp();
std::printf("Launch succeeded: %s\n", qPrintable(result.toString())); std::printf("Launch succeeded: %s\n", qPrintable(result.toString()));
if (!m_launchDebug) if (!m_launchDebug)
doExit(0); doExit(0);
...@@ -398,6 +425,7 @@ void CodaClientApplication::putSendNextChunk() ...@@ -398,6 +425,7 @@ void CodaClientApplication::putSendNextChunk()
closeRemoteFile(); closeRemoteFile();
} else { } else {
m_putLastChunkSize = data.size(); m_putLastChunkSize = data.size();
printTimeStamp();
std::printf("Writing %llu bytes to remote file '%s' at %llu\n", std::printf("Writing %llu bytes to remote file '%s' at %llu\n",
m_putLastChunkSize, m_putLastChunkSize,
m_remoteFileHandle.constData(), pos); m_remoteFileHandle.constData(), pos);
...@@ -431,6 +459,7 @@ void CodaClientApplication::handleFileSystemFStat(const tcftrk::TcfTrkCommandRes ...@@ -431,6 +459,7 @@ void CodaClientApplication::handleFileSystemFStat(const tcftrk::TcfTrkCommandRes
// Close remote file even if copy fails // Close remote file even if copy fails
if (m_statFstatOk) { if (m_statFstatOk) {
const tcftrk::TcfTrkStatResponse statr = tcftrk::TcfTrkDevice::parseStat(result); const tcftrk::TcfTrkStatResponse statr = tcftrk::TcfTrkDevice::parseStat(result);
printTimeStamp();
std::printf("File: %s\nSize: %llu bytes\nAccessed: %s\nModified: %s\n", std::printf("File: %s\nSize: %llu bytes\nAccessed: %s\nModified: %s\n",
qPrintable(m_statRemoteFile), statr.size, qPrintable(m_statRemoteFile), statr.size,
qPrintable(statr.accessTime.toString(Qt::LocalDate)), qPrintable(statr.accessTime.toString(Qt::LocalDate)),
...@@ -444,6 +473,7 @@ void CodaClientApplication::handleFileSystemFStat(const tcftrk::TcfTrkCommandRes ...@@ -444,6 +473,7 @@ void CodaClientApplication::handleFileSystemFStat(const tcftrk::TcfTrkCommandRes
void CodaClientApplication::handleFileSystemClose(const tcftrk::TcfTrkCommandResult &result) void CodaClientApplication::handleFileSystemClose(const tcftrk::TcfTrkCommandResult &result)
{ {
if (result.type == tcftrk::TcfTrkCommandResult::SuccessReply) { if (result.type == tcftrk::TcfTrkCommandResult::SuccessReply) {
printTimeStamp();
std::printf("File closed.\n"); std::printf("File closed.\n");
const bool ok = m_mode == Put ? m_putWriteOk : m_statFstatOk; const bool ok = m_mode == Put ? m_putWriteOk : m_statFstatOk;
doExit(ok ? 0 : -1); doExit(ok ? 0 : -1);
...@@ -456,6 +486,7 @@ void CodaClientApplication::handleFileSystemClose(const tcftrk::TcfTrkCommandRes ...@@ -456,6 +486,7 @@ void CodaClientApplication::handleFileSystemClose(const tcftrk::TcfTrkCommandRes
void CodaClientApplication::handleSymbianInstall(const tcftrk::TcfTrkCommandResult &result) void CodaClientApplication::handleSymbianInstall(const tcftrk::TcfTrkCommandResult &result)
{ {
if (result.type == tcftrk::TcfTrkCommandResult::SuccessReply) { if (result.type == tcftrk::TcfTrkCommandResult::SuccessReply) {
printTimeStamp();
std::printf("Installation succeeded\n."); std::printf("Installation succeeded\n.");
doExit(0); doExit(0);
} else { } else {
...@@ -466,10 +497,13 @@ void CodaClientApplication::handleSymbianInstall(const tcftrk::TcfTrkCommandResu ...@@ -466,10 +497,13 @@ void CodaClientApplication::handleSymbianInstall(const tcftrk::TcfTrkCommandResu
void CodaClientApplication::slotTcftrkEvent (const tcftrk::TcfTrkEvent &ev) void CodaClientApplication::slotTcftrkEvent (const tcftrk::TcfTrkEvent &ev)
{ {
printTimeStamp();
std::printf("Event: %s\n", qPrintable(ev.toString())); std::printf("Event: %s\n", qPrintable(ev.toString()));
switch (ev.type()) { switch (ev.type()) {
case tcftrk::TcfTrkEvent::LocatorHello: // Commands accepted now case tcftrk::TcfTrkEvent::LocatorHello: // Commands accepted now
switch (m_mode) { switch (m_mode) {
case Ping:
break;
case Launch: case Launch:
m_trkDevice->sendProcessStartCommand(tcftrk::TcfTrkCallback(this, &CodaClientApplication::handleCreateProcess), m_trkDevice->sendProcessStartCommand(tcftrk::TcfTrkCallback(this, &CodaClientApplication::handleCreateProcess),
m_launchBinary, m_launchUID, m_launchArgs, QString(), m_launchDebug); m_launchBinary, m_launchUID, m_launchArgs, QString(), m_launchDebug);
...@@ -509,6 +543,7 @@ void CodaClientApplication::slotTcftrkEvent (const tcftrk::TcfTrkEvent &ev) ...@@ -509,6 +543,7 @@ void CodaClientApplication::slotTcftrkEvent (const tcftrk::TcfTrkEvent &ev)
const tcftrk::TcfTrkRunControlModuleLoadContextSuspendedEvent &me = const tcftrk::TcfTrkRunControlModuleLoadContextSuspendedEvent &me =
static_cast<const tcftrk::TcfTrkRunControlModuleLoadContextSuspendedEvent &>(ev); static_cast<const tcftrk::TcfTrkRunControlModuleLoadContextSuspendedEvent &>(ev);
if (me.info().requireResume) { if (me.info().requireResume) {
printTimeStamp();
std::printf("Continuing...\n"); std::printf("Continuing...\n");
m_trkDevice->sendRunControlResumeCommand(tcftrk::TcfTrkCallback(), me.id()); m_trkDevice->sendRunControlResumeCommand(tcftrk::TcfTrkCallback(), me.id());
} }
...@@ -522,10 +557,16 @@ void CodaClientApplication::slotTcftrkEvent (const tcftrk::TcfTrkEvent &ev) ...@@ -522,10 +557,16 @@ void CodaClientApplication::slotTcftrkEvent (const tcftrk::TcfTrkEvent &ev)
} }
} }
void CodaClientApplication::doExit(int ex) void CodaClientApplication::slotSerialPong(const QString &v)
{ {
std::printf("Operation took %4.2f second(s)\n", m_startTime.elapsed()/1000.); printTimeStamp();
std::printf("Pong from '%s'\n", qPrintable(v));
if (m_mode == Ping)
doExit(0);
}
void CodaClientApplication::doExit(int ex)
{
if (!m_trkDevice.isNull()) { if (!m_trkDevice.isNull()) {
const QSharedPointer<QIODevice> dev = m_trkDevice->device(); const QSharedPointer<QIODevice> dev = m_trkDevice->device();
if (!dev.isNull()) { if (!dev.isNull()) {
...@@ -538,6 +579,15 @@ void CodaClientApplication::doExit(int ex) ...@@ -538,6 +579,15 @@ void CodaClientApplication::doExit(int ex)
} }
} }
} }
printTimeStamp();
std::printf("Exiting (%d)\n", ex); std::printf("Exiting (%d)\n", ex);
exit(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);
}
...@@ -47,7 +47,7 @@ class CodaClientApplication : public QCoreApplication ...@@ -47,7 +47,7 @@ class CodaClientApplication : public QCoreApplication
{ {
Q_OBJECT Q_OBJECT
public: public:
enum Mode { Invalid, Launch, Put, Stat, Install }; enum Mode { Invalid, Ping, Launch, Put, Stat, Install };
explicit CodaClientApplication(int &argc, char **argv); explicit CodaClientApplication(int &argc, char **argv);
~CodaClientApplication(); ~CodaClientApplication();
...@@ -63,8 +63,10 @@ private slots: ...@@ -63,8 +63,10 @@ private slots:
void slotError(const QString &);