Files
Chm30Utility/CanDriver/core/CanTrace.cpp
2025-03-17 19:12:22 +09:00

216 lines
5.9 KiB
C++

/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
This file is part of cangaroo.
cangaroo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
cangaroo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cangaroo. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CanTrace.h"
#include <QMutexLocker>
#include <QFile>
#include <QTextStream>
#include <core/Backend.h>
#include <core/CanMessage.h>
#include <core/CanDbMessage.h>
#include <core/CanDbSignal.h>
#include <driver/CanInterface.h>
CanTrace::CanTrace(Backend &backend, QObject *parent, int flushInterval)
: QObject(parent),
_backend(backend),
_isTimerRunning(false),
_mutex(QMutex::Recursive),
_timerMutex(),
_flushTimer(this)
{
clear();
_flushTimer.setSingleShot(true);
_flushTimer.setInterval(flushInterval);
connect(&_flushTimer, SIGNAL(timeout()), this, SLOT(flushQueue()));
}
unsigned long CanTrace::size()
{
QMutexLocker locker(&_mutex);
return _dataRowsUsed;
}
void CanTrace::clear()
{
QMutexLocker locker(&_mutex);
emit beforeClear();
_data.resize(pool_chunk_size);
_dataRowsUsed = 0;
_newRows = 0;
emit afterClear();
}
const CanMessage *CanTrace::getMessage(int idx)
{
QMutexLocker locker(&_mutex);
if (idx >= (_dataRowsUsed + _newRows)) {
return 0;
} else {
return &_data[idx];
}
}
void CanTrace::enqueueMessage(const CanMessage &msg, bool more_to_follow)
{
QMutexLocker locker(&_mutex);
int idx = size() + _newRows;
if (idx>=_data.size()) {
_data.resize(_data.size() + pool_chunk_size);
}
_data[idx].cloneFrom(msg);
_newRows++;
if (!more_to_follow) {
startTimer();
}
emit messageEnqueued(idx);
}
void CanTrace::flushQueue()
{
{
QMutexLocker locker(&_timerMutex);
_isTimerRunning = false;
}
QMutexLocker locker(&_mutex);
if (_newRows) {
emit beforeAppend(_newRows);
// see if we have muxed messages. cache muxed values, if any.
MeasurementSetup &setup = _backend.getSetup();
for (int i=_dataRowsUsed; i<_dataRowsUsed + _newRows; i++) {
CanMessage &msg = _data[i];
CanDbMessage *dbmsg = setup.findDbMessage(msg);
if (dbmsg && dbmsg->getMuxer()) {
foreach (CanDbSignal *signal, dbmsg->getSignals()) {
if (signal->isMuxed() && signal->isPresentInMessage(msg)) {
_muxCache[signal] = signal->extractRawDataFromMessage(msg);
}
}
}
}
_dataRowsUsed += _newRows;
_newRows = 0;
emit afterAppend();
}
}
void CanTrace::startTimer()
{
QMutexLocker locker(&_timerMutex);
if (!_isTimerRunning) {
_isTimerRunning = true;
QMetaObject::invokeMethod(&_flushTimer, "start", Qt::QueuedConnection);
}
}
void CanTrace::saveCanDump(QFile &file)
{
QMutexLocker locker(&_mutex);
QTextStream stream(&file);
for (unsigned int i=0; i<size(); i++) {
CanMessage *msg = &_data[i];
QString line;
line.append(QString().sprintf("(%.6f) ", msg->getFloatTimestamp()));
line.append(_backend.getInterfaceName(msg->getInterfaceId()));
if (msg->isExtended()) {
line.append(QString().sprintf(" %08X#", msg->getId()));
} else {
line.append(QString().sprintf(" %03X#", msg->getId()));
}
for (int i=0; i<msg->getLength(); i++) {
line.append(QString().sprintf("%02X", msg->getByte(i)));
}
stream << line << endl;
}
}
void CanTrace::saveVectorAsc(QFile &file)
{
QMutexLocker locker(&_mutex);
QTextStream stream(&file);
if (_data.length()<1) {
return;
}
auto firstMessage = _data.first();
double t_start = firstMessage.getFloatTimestamp();
QLocale locale_c(QLocale::C);
QString dt_start = locale_c.toString(firstMessage.getDateTime(), "ddd MMM dd hh:mm:ss.zzz ap yyyy");
stream << "date " << dt_start << endl;
stream << "base hex timestamps absolute" << endl;
stream << "internal events logged" << endl;
stream << "// version 8.5.0" << endl;
stream << "Begin Triggerblock " << dt_start << endl;
stream << " 0.000000 Start of measurement" << endl;
for (unsigned int i=0; i<size(); i++) {
CanMessage &msg = _data[i];
double t_current = msg.getFloatTimestamp();
QString id_hex_str = QString().sprintf("%x", msg.getId());
QString id_dec_str = QString().sprintf("%d", msg.getId());
if (msg.isExtended()) {
id_hex_str.append("x");
id_dec_str.append("x");
}
// TODO how to handle RTR flag?
QString line = QString().sprintf(
"%11.6lf 1 %-15s %s d %d %s Length = %d BitCount = %d ID = %s",
t_current-t_start,
id_hex_str.toStdString().c_str(),
"Rx", // TODO handle Rx/Tx
msg.getLength(),
msg.getDataHexString().toStdString().c_str(),
0, // TODO Length (transfer time in ns)
0, // TODO BitCount (overall frame length, including stuff bits)
id_dec_str.toStdString().c_str()
);
stream << line << endl;
}
stream << "End TriggerBlock" << endl;
}
bool CanTrace::getMuxedSignalFromCache(const CanDbSignal *signal, uint64_t *raw_value)
{
if (_muxCache.contains(signal)) {
*raw_value = _muxCache[signal];
return true;
} else {
return false;
}
}