source: trunk/tools/runonphone/trk/trkutils.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 14.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "trkutils.h"
43#include <ctype.h>
44
45#include <QtCore/QCoreApplication>
46#include <QtCore/QDebug>
47#include <QtCore/QDate>
48#include <QtCore/QDateTime>
49#include <QtCore/QTime>
50
51#define logMessage(s) do { qDebug() << "TRKCLIENT: " << s; } while (0)
52
53namespace trk {
54
55TrkAppVersion::TrkAppVersion()
56{
57 reset();
58}
59
60void TrkAppVersion::reset()
61{
62 trkMajor = trkMinor= protocolMajor = protocolMinor = 0;
63}
64
65Session::Session()
66{
67 reset();
68}
69
70void Session::reset()
71{
72 cpuMajor = 0;
73 cpuMinor = 0;
74 bigEndian = 0;
75 defaultTypeSize = 0;
76 fpTypeSize = 0;
77 extended1TypeSize = 0;
78 extended2TypeSize = 0;
79 pid = 0;
80 tid = 0;
81 codeseg = 0;
82 dataseg = 0;
83
84 currentThread = 0;
85 libraries.clear();
86 trkAppVersion.reset();
87}
88
89QString formatCpu(int major, int minor)
90{
91 //: CPU description of an S60 device
92 //: %1 major verison, %2 minor version
93 //: %3 real name of major verison, %4 real name of minor version
94 const QString str = QCoreApplication::translate("trk::Session", "CPU: v%1.%2%3%4");
95 QString majorStr;
96 QString minorStr;
97 switch (major) {
98 case 0x04:
99 majorStr = " ARM";
100 break;
101 }
102 switch (minor) {
103 case 0x00:
104 minorStr = " 920T";
105 break;
106 }
107 return str.arg(major).arg(minor).arg(majorStr).arg(minorStr);
108 }
109
110QString formatTrkVersion(const TrkAppVersion &version)
111{
112 QString str = QCoreApplication::translate("trk::Session",
113 "App TRK: v%1.%2 TRK protocol: v%3.%4");
114 str = str.arg(version.trkMajor).arg(version.trkMinor);
115 return str.arg(version.protocolMajor).arg(version.protocolMinor);
116}
117
118QString Session::deviceDescription(unsigned verbose) const
119{
120 if (!cpuMajor)
121 return QString();
122
123 //: s60description
124 //: description of an S60 device
125 //: %1 CPU description, %2 endianness
126 //: %3 default type size (if any), %4 float size (if any)
127 //: %5 TRK version
128 QString msg = QCoreApplication::translate("trk::Session", "%1, %2%3%4, %5");
129 QString endianness = bigEndian
130 ? QCoreApplication::translate("trk::Session", "big endian")
131 : QCoreApplication::translate("trk::Session", "little endian");
132 msg = msg.arg(formatCpu(cpuMajor, cpuMinor)).arg(endianness);
133 //: The separator in a list of strings
134 QString defaultTypeSizeStr;
135 QString fpTypeSizeStr;
136 if (verbose && defaultTypeSize)
137 //: will be inserted into s60description
138 defaultTypeSizeStr = QCoreApplication::translate("trk::Session", ", type size: %1").arg(defaultTypeSize);
139 if (verbose && fpTypeSize)
140 //: will be inserted into s60description
141 fpTypeSizeStr = QCoreApplication::translate("trk::Session", ", float size: %1").arg(fpTypeSize);
142 msg = msg.arg(defaultTypeSizeStr).arg(fpTypeSizeStr);
143 return msg.arg(formatTrkVersion(trkAppVersion));
144}
145
146
147// FIXME: Use the QByteArray based version below?
148QString stringFromByte(byte c)
149{
150 return QString("%1 ").arg(c, 2, 16, QChar('0'));
151}
152
153QString stringFromArray(const QByteArray &ba, int maxLen)
154{
155 QString str;
156 QString ascii;
157 const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen);
158 for (int i = 0; i < size; ++i) {
159 //if (i == 5 || i == ba.size() - 2)
160 // str += " ";
161 int c = byte(ba.at(i));
162 str += QString("%1 ").arg(c, 2, 16, QChar('0'));
163 if (i >= 8 && i < ba.size() - 2)
164 ascii += QChar(c).isPrint() ? QChar(c) : QChar('.');
165 }
166 if (size != ba.size()) {
167 str += "...";
168 ascii += "...";
169 }
170 return str + " " + ascii;
171}
172
173QByteArray hexNumber(uint n, int digits)
174{
175 QByteArray ba = QByteArray::number(n, 16);
176 if (digits == 0 || ba.size() == digits)
177 return ba;
178 return QByteArray(digits - ba.size(), '0') + ba;
179}
180
181QByteArray hexxNumber(uint n, int digits)
182{
183 return "0x" + hexNumber(n, digits);
184}
185
186TrkResult::TrkResult() :
187 code(0),
188 token(0),
189 isDebugOutput(false)
190{
191}
192
193void TrkResult::clear()
194{
195 code = token= 0;
196 isDebugOutput = false;
197 data.clear();
198 cookie = QVariant();
199}
200
201QString TrkResult::toString() const
202{
203 QString res = stringFromByte(code) + "[" + stringFromByte(token);
204 res.chop(1);
205 return res + "] " + stringFromArray(data);
206}
207
208QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame)
209{
210 byte s = command + token;
211 for (int i = 0; i != data.size(); ++i)
212 s += data.at(i);
213 byte checksum = 255 - (s & 0xff);
214 //int x = s + ~s;
215 //logMessage("check: " << s << checksum << x;
216
217 QByteArray response;
218 response.reserve(data.size() + 3);
219 response.append(char(command));
220 response.append(char(token));
221 response.append(data);
222 response.append(char(checksum));
223
224 QByteArray encodedData = encode7d(response);
225
226 QByteArray ba;
227 ba.reserve(encodedData.size() + 6);
228 if (serialFrame) {
229 ba.append(char(0x01));
230 ba.append(char(0x90));
231 const ushort encodedSize = encodedData.size() + 2; // 2 x 0x7e
232 appendShort(&ba, encodedSize, BigEndian);
233 }
234 ba.append(char(0x7e));
235 ba.append(encodedData);
236 ba.append(char(0x7e));
237
238 return ba;
239}
240
241/* returns 0 if array doesn't represent a result,
242otherwise returns the length of the result data */
243ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame)
244{
245 if (serialFrame) {
246 // Serial protocol with length info
247 if (buffer.length() < 4)
248 return 0;
249 if (buffer.at(0) != 0x01 || byte(buffer.at(1)) != 0x90)
250 return 0;
251 const ushort len = extractShort(buffer.data() + 2);
252 return (buffer.size() >= len + 4) ? len : ushort(0);
253 }
254 // Frameless protocol without length info
255 const char delimiter = char(0x7e);
256 const int firstDelimiterPos = buffer.indexOf(delimiter);
257 // Regular message delimited by 0x7e..0x7e
258 if (firstDelimiterPos == 0) {
259 const int endPos = buffer.indexOf(delimiter, firstDelimiterPos + 1);
260 return endPos != -1 ? endPos + 1 - firstDelimiterPos : 0;
261 }
262 // Some ASCII log message up to first delimiter or all
263 return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size();
264}
265
266bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData)
267{
268 result->clear();
269 if(rawData)
270 rawData->clear();
271 const ushort len = isValidTrkResult(*buffer, serialFrame);
272 if (!len)
273 return false;
274 // handle receiving application output, which is not a regular command
275 const int delimiterPos = serialFrame ? 4 : 0;
276 if (buffer->at(delimiterPos) != 0x7e) {
277 result->isDebugOutput = true;
278 result->data = buffer->mid(delimiterPos, len);
279 result->data.replace("\r\n", "\n");
280 *buffer->remove(0, delimiterPos + len);
281 return true;
282 }
283 // FIXME: what happens if the length contains 0xfe?
284 // Assume for now that it passes unencoded!
285 const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2));
286 if(rawData)
287 *rawData = data;
288 *buffer->remove(0, delimiterPos + len);
289
290 byte sum = 0;
291 for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum
292 sum += byte(data.at(i));
293 if (sum != 0xff)
294 logMessage("*** CHECKSUM ERROR: " << byte(sum));
295
296 result->code = data.at(0);
297 result->token = data.at(1);
298 result->data = data.mid(2, data.size() - 3);
299 //logMessage(" REST BUF: " << stringFromArray(*buffer));
300 //logMessage(" CURR DATA: " << stringFromArray(data));
301 //QByteArray prefix = "READ BUF: ";
302 //logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data());
303 return true;
304}
305
306ushort extractShort(const char *data)
307{
308 return byte(data[0]) * 256 + byte(data[1]);
309}
310
311uint extractInt(const char *data)
312{
313 uint res = byte(data[0]);
314 res *= 256; res += byte(data[1]);
315 res *= 256; res += byte(data[2]);
316 res *= 256; res += byte(data[3]);
317 return res;
318}
319
320QString quoteUnprintableLatin1(const QByteArray &ba)
321{
322 QString res;
323 char buf[10];
324 for (int i = 0, n = ba.size(); i != n; ++i) {
325 const byte c = ba.at(i);
326 if (isprint(c)) {
327 res += c;
328 } else {
329 qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c));
330 res += buf;
331 }
332 }
333 return res;
334}
335
336QByteArray decode7d(const QByteArray &ba)
337{
338 QByteArray res;
339 res.reserve(ba.size());
340 for (int i = 0; i < ba.size(); ++i) {
341 byte c = byte(ba.at(i));
342 if (c == 0x7d) {
343 ++i;
344 c = 0x20 ^ byte(ba.at(i));
345 }
346 res.append(c);
347 }
348 //if (res != ba)
349 // logMessage("DECODED: " << stringFromArray(ba)
350 // << " -> " << stringFromArray(res));
351 return res;
352}
353
354QByteArray encode7d(const QByteArray &ba)
355{
356 QByteArray res;
357 res.reserve(ba.size() + 2);
358 for (int i = 0; i < ba.size(); ++i) {
359 byte c = byte(ba.at(i));
360 if (c == 0x7e || c == 0x7d) {
361 res.append(0x7d);
362 res.append(0x20 ^ c);
363 } else {
364 res.append(c);
365 }
366 }
367 //if (res != ba)
368 // logMessage("ENCODED: " << stringFromArray(ba)
369 // << " -> " << stringFromArray(res));
370 return res;
371}
372
373void appendByte(QByteArray *ba, byte b)
374{
375 ba->append(b);
376}
377
378void appendShort(QByteArray *ba, ushort s, Endianness endian)
379{
380 if (endian == BigEndian) {
381 ba->append(s / 256);
382 ba->append(s % 256);
383 } else {
384 ba->append(s % 256);
385 ba->append(s / 256);
386 }
387}
388
389void appendInt(QByteArray *ba, uint i, Endianness endian)
390{
391 const uchar b3 = i % 256; i /= 256;
392 const uchar b2 = i % 256; i /= 256;
393 const uchar b1 = i % 256; i /= 256;
394 const uchar b0 = i;
395 ba->reserve(ba->size() + 4);
396 if (endian == BigEndian) {
397 ba->append(b0);
398 ba->append(b1);
399 ba->append(b2);
400 ba->append(b3);
401 } else {
402 ba->append(b3);
403 ba->append(b2);
404 ba->append(b1);
405 ba->append(b0);
406 }
407}
408
409void appendString(QByteArray *ba, const QByteArray &str, Endianness endian, bool appendNullTerminator)
410{
411 const int fullSize = str.size() + (appendNullTerminator ? 1 : 0);
412 appendShort(ba, fullSize, endian); // count the terminating \0
413 ba->append(str);
414 if (appendNullTerminator)
415 ba->append('\0');
416}
417
418void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness endian)
419{
420 // convert the QDateTime to UTC and append its representation to QByteArray
421 // format is the same as in FAT file system
422 dateTime = dateTime.toUTC();
423 const QTime utcTime = dateTime.time();
424 const QDate utcDate = dateTime.date();
425 uint fatDateTime = (utcTime.hour() << 11 | utcTime.minute() << 5 | utcTime.second()/2) << 16;
426 fatDateTime |= (utcDate.year()-1980) << 9 | utcDate.month() << 5 | utcDate.day();
427 appendInt(ba, fatDateTime, endian);
428}
429
430QByteArray errorMessage(byte code)
431{
432 switch (code) {
433 case 0x00: return "No error";
434 case 0x01: return "Generic error in CWDS message";
435 case 0x02: return "Unexpected packet size in send msg";
436 case 0x03: return "Internal error occurred in CWDS";
437 case 0x04: return "Escape followed by frame flag";
438 case 0x05: return "Bad FCS in packet";
439 case 0x06: return "Packet too long";
440 case 0x07: return "Sequence ID not expected (gap in sequence)";
441
442 case 0x10: return "Command not supported";
443 case 0x11: return "Command param out of range";
444 case 0x12: return "An option was not supported";
445 case 0x13: return "Read/write to invalid memory";
446 case 0x14: return "Read/write invalid registers";
447 case 0x15: return "Exception occurred in CWDS";
448 case 0x16: return "Targeted system or thread is running";
449 case 0x17: return "Breakpoint resources (HW or SW) exhausted";
450 case 0x18: return "Requested breakpoint conflicts with existing one";
451
452 case 0x20: return "General OS-related error";
453 case 0x21: return "Request specified invalid process";
454 case 0x22: return "Request specified invalid thread";
455 }
456 return "Unknown error";
457}
458
459uint swapEndian(uint in)
460{
461 return (in>>24) | ((in<<8) & 0x00FF0000) | ((in>>8) & 0x0000FF00) | (in<<24);
462}
463
464int TrkResult::errorCode() const
465{
466 // NAK means always error, else data sized 1 with a non-null element
467 const bool isNAK = code == 0xff;
468 if (data.size() != 1 && !isNAK)
469 return 0;
470 if (const int errorCode = data.at(0))
471 return errorCode;
472 return isNAK ? 0xff : 0;
473}
474
475QString TrkResult::errorString() const
476{
477 // NAK means always error, else data sized 1 with a non-null element
478 if (code == 0xff)
479 return "NAK";
480 if (data.size() < 1)
481 return "Unknown error packet";
482 return errorMessage(data.at(0));
483}
484
485} // namespace trk
486
Note: See TracBrowser for help on using the repository browser.