| 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 |  | 
|---|
| 53 | namespace trk { | 
|---|
| 54 |  | 
|---|
| 55 | TrkAppVersion::TrkAppVersion() | 
|---|
| 56 | { | 
|---|
| 57 | reset(); | 
|---|
| 58 | } | 
|---|
| 59 |  | 
|---|
| 60 | void TrkAppVersion::reset() | 
|---|
| 61 | { | 
|---|
| 62 | trkMajor = trkMinor= protocolMajor = protocolMinor = 0; | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | Session::Session() | 
|---|
| 66 | { | 
|---|
| 67 | reset(); | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | void 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 |  | 
|---|
| 89 | QString 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 |  | 
|---|
| 110 | QString 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 |  | 
|---|
| 118 | QString 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? | 
|---|
| 148 | QString stringFromByte(byte c) | 
|---|
| 149 | { | 
|---|
| 150 | return QString("%1 ").arg(c, 2, 16, QChar('0')); | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | QString 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 |  | 
|---|
| 173 | QByteArray 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 |  | 
|---|
| 181 | QByteArray hexxNumber(uint n, int digits) | 
|---|
| 182 | { | 
|---|
| 183 | return "0x" + hexNumber(n, digits); | 
|---|
| 184 | } | 
|---|
| 185 |  | 
|---|
| 186 | TrkResult::TrkResult() : | 
|---|
| 187 | code(0), | 
|---|
| 188 | token(0), | 
|---|
| 189 | isDebugOutput(false) | 
|---|
| 190 | { | 
|---|
| 191 | } | 
|---|
| 192 |  | 
|---|
| 193 | void TrkResult::clear() | 
|---|
| 194 | { | 
|---|
| 195 | code = token= 0; | 
|---|
| 196 | isDebugOutput = false; | 
|---|
| 197 | data.clear(); | 
|---|
| 198 | cookie = QVariant(); | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | QString TrkResult::toString() const | 
|---|
| 202 | { | 
|---|
| 203 | QString res = stringFromByte(code) + "[" + stringFromByte(token); | 
|---|
| 204 | res.chop(1); | 
|---|
| 205 | return res + "] " + stringFromArray(data); | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | QByteArray 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, | 
|---|
| 242 | otherwise returns the length of the result data */ | 
|---|
| 243 | ushort 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 |  | 
|---|
| 266 | bool 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 |  | 
|---|
| 306 | ushort extractShort(const char *data) | 
|---|
| 307 | { | 
|---|
| 308 | return byte(data[0]) * 256 + byte(data[1]); | 
|---|
| 309 | } | 
|---|
| 310 |  | 
|---|
| 311 | uint 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 |  | 
|---|
| 320 | QString 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 |  | 
|---|
| 336 | QByteArray 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 |  | 
|---|
| 354 | QByteArray 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 |  | 
|---|
| 373 | void appendByte(QByteArray *ba, byte b) | 
|---|
| 374 | { | 
|---|
| 375 | ba->append(b); | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | void 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 |  | 
|---|
| 389 | void 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 |  | 
|---|
| 409 | void 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 |  | 
|---|
| 418 | void 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 |  | 
|---|
| 430 | QByteArray 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 |  | 
|---|
| 459 | uint swapEndian(uint in) | 
|---|
| 460 | { | 
|---|
| 461 | return (in>>24) | ((in<<8) & 0x00FF0000) | ((in>>8) & 0x0000FF00) | (in<<24); | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | int 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 |  | 
|---|
| 475 | QString 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 |  | 
|---|