CanTrace.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
  3. This file is part of cangaroo.
  4. cangaroo is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 2 of the License, or
  7. (at your option) any later version.
  8. cangaroo is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with cangaroo. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "CanTrace.h"
  16. #include <QMutexLocker>
  17. #include <QFile>
  18. #include <QTextStream>
  19. #include <core/Backend.h>
  20. #include <core/CanMessage.h>
  21. #include <core/CanDbMessage.h>
  22. #include <core/CanDbSignal.h>
  23. #include <driver/CanInterface.h>
  24. CanTrace::CanTrace(Backend &backend, QObject *parent, int flushInterval)
  25. : QObject(parent),
  26. _backend(backend),
  27. _isTimerRunning(false),
  28. _mutex(QMutex::Recursive),
  29. _timerMutex(),
  30. _flushTimer(this)
  31. {
  32. clear();
  33. _flushTimer.setSingleShot(true);
  34. _flushTimer.setInterval(flushInterval);
  35. connect(&_flushTimer, SIGNAL(timeout()), this, SLOT(flushQueue()));
  36. }
  37. unsigned long CanTrace::size()
  38. {
  39. QMutexLocker locker(&_mutex);
  40. return _dataRowsUsed;
  41. }
  42. void CanTrace::clear()
  43. {
  44. QMutexLocker locker(&_mutex);
  45. emit beforeClear();
  46. _data.resize(pool_chunk_size);
  47. _dataRowsUsed = 0;
  48. _newRows = 0;
  49. emit afterClear();
  50. }
  51. const CanMessage *CanTrace::getMessage(int idx)
  52. {
  53. QMutexLocker locker(&_mutex);
  54. if (idx >= (_dataRowsUsed + _newRows)) {
  55. return 0;
  56. } else {
  57. return &_data[idx];
  58. }
  59. }
  60. void CanTrace::enqueueMessage(const CanMessage &msg, bool more_to_follow)
  61. {
  62. QMutexLocker locker(&_mutex);
  63. int idx = size() + _newRows;
  64. if (idx>=_data.size()) {
  65. _data.resize(_data.size() + pool_chunk_size);
  66. }
  67. _data[idx].cloneFrom(msg);
  68. _newRows++;
  69. if (!more_to_follow) {
  70. startTimer();
  71. }
  72. emit messageEnqueued(idx);
  73. }
  74. void CanTrace::flushQueue()
  75. {
  76. {
  77. QMutexLocker locker(&_timerMutex);
  78. _isTimerRunning = false;
  79. }
  80. QMutexLocker locker(&_mutex);
  81. if (_newRows) {
  82. emit beforeAppend(_newRows);
  83. // see if we have muxed messages. cache muxed values, if any.
  84. MeasurementSetup &setup = _backend.getSetup();
  85. for (int i=_dataRowsUsed; i<_dataRowsUsed + _newRows; i++) {
  86. CanMessage &msg = _data[i];
  87. CanDbMessage *dbmsg = setup.findDbMessage(msg);
  88. if (dbmsg && dbmsg->getMuxer()) {
  89. foreach (CanDbSignal *signal, dbmsg->getSignals()) {
  90. if (signal->isMuxed() && signal->isPresentInMessage(msg)) {
  91. _muxCache[signal] = signal->extractRawDataFromMessage(msg);
  92. }
  93. }
  94. }
  95. }
  96. _dataRowsUsed += _newRows;
  97. _newRows = 0;
  98. emit afterAppend();
  99. }
  100. }
  101. void CanTrace::startTimer()
  102. {
  103. QMutexLocker locker(&_timerMutex);
  104. if (!_isTimerRunning) {
  105. _isTimerRunning = true;
  106. QMetaObject::invokeMethod(&_flushTimer, "start", Qt::QueuedConnection);
  107. }
  108. }
  109. void CanTrace::saveCanDump(QFile &file)
  110. {
  111. QMutexLocker locker(&_mutex);
  112. QTextStream stream(&file);
  113. for (unsigned int i=0; i<size(); i++) {
  114. CanMessage *msg = &_data[i];
  115. QString line;
  116. line.append(QString().sprintf("(%.6f) ", msg->getFloatTimestamp()));
  117. line.append(_backend.getInterfaceName(msg->getInterfaceId()));
  118. if (msg->isExtended()) {
  119. line.append(QString().sprintf(" %08X#", msg->getId()));
  120. } else {
  121. line.append(QString().sprintf(" %03X#", msg->getId()));
  122. }
  123. for (int i=0; i<msg->getLength(); i++) {
  124. line.append(QString().sprintf("%02X", msg->getByte(i)));
  125. }
  126. stream << line << endl;
  127. }
  128. }
  129. void CanTrace::saveVectorAsc(QFile &file)
  130. {
  131. QMutexLocker locker(&_mutex);
  132. QTextStream stream(&file);
  133. if (_data.length()<1) {
  134. return;
  135. }
  136. auto firstMessage = _data.first();
  137. double t_start = firstMessage.getFloatTimestamp();
  138. QLocale locale_c(QLocale::C);
  139. QString dt_start = locale_c.toString(firstMessage.getDateTime(), "ddd MMM dd hh:mm:ss.zzz ap yyyy");
  140. stream << "date " << dt_start << endl;
  141. stream << "base hex timestamps absolute" << endl;
  142. stream << "internal events logged" << endl;
  143. stream << "// version 8.5.0" << endl;
  144. stream << "Begin Triggerblock " << dt_start << endl;
  145. stream << " 0.000000 Start of measurement" << endl;
  146. for (unsigned int i=0; i<size(); i++) {
  147. CanMessage &msg = _data[i];
  148. double t_current = msg.getFloatTimestamp();
  149. QString id_hex_str = QString().sprintf("%x", msg.getId());
  150. QString id_dec_str = QString().sprintf("%d", msg.getId());
  151. if (msg.isExtended()) {
  152. id_hex_str.append("x");
  153. id_dec_str.append("x");
  154. }
  155. // TODO how to handle RTR flag?
  156. QString line = QString().sprintf(
  157. "%11.6lf 1 %-15s %s d %d %s Length = %d BitCount = %d ID = %s",
  158. t_current-t_start,
  159. id_hex_str.toStdString().c_str(),
  160. "Rx", // TODO handle Rx/Tx
  161. msg.getLength(),
  162. msg.getDataHexString().toStdString().c_str(),
  163. 0, // TODO Length (transfer time in ns)
  164. 0, // TODO BitCount (overall frame length, including stuff bits)
  165. id_dec_str.toStdString().c_str()
  166. );
  167. stream << line << endl;
  168. }
  169. stream << "End TriggerBlock" << endl;
  170. }
  171. bool CanTrace::getMuxedSignalFromCache(const CanDbSignal *signal, uint64_t *raw_value)
  172. {
  173. if (_muxCache.contains(signal)) {
  174. *raw_value = _muxCache[signal];
  175. return true;
  176. } else {
  177. return false;
  178. }
  179. }