Save CARBUS Analyzer format
This commit is contained in:
+155
-17
@@ -3,6 +3,7 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QProgressDialog>
|
#include <QProgressDialog>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -33,9 +34,10 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector<CANFrame>* fram
|
|||||||
filters.append(QString(tr("IXXAT MiniLog (*.csv *.CSV)")));
|
filters.append(QString(tr("IXXAT MiniLog (*.csv *.CSV)")));
|
||||||
filters.append(QString(tr("CAN-DO Log (*.can *.avc *.evc *.qcc *.CAN *.AVC *.EVC *.QCC)")));
|
filters.append(QString(tr("CAN-DO Log (*.can *.avc *.evc *.qcc *.CAN *.AVC *.EVC *.QCC)")));
|
||||||
filters.append(QString(tr("Vehicle Spy (*.csv *.CSV)")));
|
filters.append(QString(tr("Vehicle Spy (*.csv *.CSV)")));
|
||||||
filters.append(QString(tr("Candump/Kayak(*.log)")));
|
filters.append(QString(tr("Candump/Kayak (*.log)")));
|
||||||
filters.append(QString(tr("Cabana Log(*.csv *.CSV)")));
|
filters.append(QString(tr("Cabana Log (*.csv *.CSV)")));
|
||||||
filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)")));
|
filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)")));
|
||||||
|
filters.append(QString(tr("CARBUS Analyzer (*.trc *.TRC)")));
|
||||||
|
|
||||||
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
|
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
|
||||||
dialog.setFileMode(QFileDialog::AnyFile);
|
dialog.setFileMode(QFileDialog::AnyFile);
|
||||||
@@ -121,6 +123,11 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector<CANFrame>* fram
|
|||||||
if (!filename.contains('.')) filename += ".asc";
|
if (!filename.contains('.')) filename += ".asc";
|
||||||
result = saveCanalyzerASC(filename, frameCache);
|
result = saveCanalyzerASC(filename, frameCache);
|
||||||
}
|
}
|
||||||
|
if (dialog.selectedNameFilter() == filters[12])
|
||||||
|
{
|
||||||
|
if (!filename.contains('.')) filename += ".trc";
|
||||||
|
result = saveCARBUSAnalzyer(filename, frameCache);
|
||||||
|
}
|
||||||
|
|
||||||
progress.cancel();
|
progress.cancel();
|
||||||
|
|
||||||
@@ -751,30 +758,40 @@ bool FrameFileIO::isCARBUSAnalyzerFile(QString filename)
|
|||||||
return isMatch;
|
return isMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CARBUS Analayzer trace format:
|
// CARBUS Analayzer trace format https://canhacker.ru/can-trace-format/ :
|
||||||
|
// header
|
||||||
//@ TEXT @ 2 @ 64 @ 0 @ 591 @ 38782 @ 00:00:38.782 @
|
//@ TEXT @ 2 @ 64 @ 0 @ 591 @ 38782 @ 00:00:38.782 @
|
||||||
|
// 2 - format version
|
||||||
//14,687 1 0004 4E0 8 24 00 00 00 00 00 00 00 00000000 $
|
//14,687 1 0004 4E0 8 24 00 00 00 00 00 00 00 00000000 $
|
||||||
// timestamp: sec,ms
|
// timestamp: sec,ms - for version 2
|
||||||
|
// sec,us - for version 3
|
||||||
bool FrameFileIO::loadCARBUSAnalyzerFile(QString filename, QVector<CANFrame>* frames)
|
bool FrameFileIO::loadCARBUSAnalyzerFile(QString filename, QVector<CANFrame>* frames)
|
||||||
{
|
{
|
||||||
QFile *inFile = new QFile(filename);
|
QFile *inFile = new QFile(filename);
|
||||||
CANFrame thisFrame;
|
|
||||||
QString line;
|
|
||||||
int lineCounter = 0;
|
|
||||||
bool foundErrors = false;
|
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly))
|
if (!inFile->open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CANFrame thisFrame;
|
||||||
|
QString line;
|
||||||
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
// readLine() works only with "\n" and "\r\n"
|
// readLine() works only with "\n" and "\r\n"
|
||||||
QString localReadAll = inFile->readAll().replace("\r", "\r\n");
|
QString localReadAll = inFile->readAll().replace("\r", "\r\n");
|
||||||
|
|
||||||
QTextStream txt(&localReadAll);
|
QTextStream txt(&localReadAll);
|
||||||
|
|
||||||
line = txt.readLine().toUpper(); //read out the header first and discard it.
|
line = txt.readLine().toUpper(); //read out the header
|
||||||
|
|
||||||
|
int version = 3; // current default
|
||||||
|
QRegularExpression re("@ TEXT @ (?<version>\\d) @.*");
|
||||||
|
QRegularExpressionMatch match = re.match(line);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
version = match.captured("version").toInt();
|
||||||
|
}
|
||||||
|
|
||||||
while (!txt.atEnd()) {
|
while (!txt.atEnd()) {
|
||||||
lineCounter++;
|
lineCounter++;
|
||||||
@@ -789,14 +806,18 @@ bool FrameFileIO::loadCARBUSAnalyzerFile(QString filename, QVector<CANFrame>* fr
|
|||||||
QList<QString> tokens = line.split(QRegExp("\\s+"));
|
QList<QString> tokens = line.split(QRegExp("\\s+"));
|
||||||
if (tokens.length() > 3)
|
if (tokens.length() > 3)
|
||||||
{
|
{
|
||||||
QString time = tokens[0].replace(",",".");
|
QString time = tokens[0].replace(",", "");
|
||||||
double timeStamp = time.toDouble() * 1000000.0;
|
int64_t timeStamp = time.toInt();
|
||||||
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<int64_t>(timeStamp)));
|
if (version == 2) {
|
||||||
thisFrame.setFrameId(static_cast<uint32_t>(tokens[3].toInt(nullptr, 16)));
|
timeStamp *= 1000; // ms -> us
|
||||||
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF);
|
}
|
||||||
|
|
||||||
thisFrame.isReceived = true;
|
thisFrame.isReceived = true;
|
||||||
thisFrame.setFrameType(QCanBusFrame::DataFrame);
|
thisFrame.setFrameType(QCanBusFrame::DataFrame);
|
||||||
thisFrame.bus = 0;
|
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<int64_t>(timeStamp)));
|
||||||
|
thisFrame.bus = tokens[1].toInt();
|
||||||
|
thisFrame.setFrameId(static_cast<uint32_t>(tokens[3].toInt(nullptr, 16)));
|
||||||
|
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF);
|
||||||
int numBytes = tokens[4].toInt(nullptr, 16);
|
int numBytes = tokens[4].toInt(nullptr, 16);
|
||||||
QByteArray bytes(numBytes , 0);
|
QByteArray bytes(numBytes , 0);
|
||||||
for (int d = 0; d < numBytes; d++)
|
for (int d = 0; d < numBytes; d++)
|
||||||
@@ -810,7 +831,10 @@ bool FrameFileIO::loadCARBUSAnalyzerFile(QString filename, QVector<CANFrame>* fr
|
|||||||
thisFrame.setPayload(bytes);
|
thisFrame.setPayload(bytes);
|
||||||
frames->append(thisFrame);
|
frames->append(thisFrame);
|
||||||
}
|
}
|
||||||
else foundErrors = true;
|
else
|
||||||
|
{
|
||||||
|
foundErrors = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
@@ -818,6 +842,120 @@ bool FrameFileIO::loadCARBUSAnalyzerFile(QString filename, QVector<CANFrame>* fr
|
|||||||
return !foundErrors;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString getCARBUSAnalzyerStr(uint64_t time, QString symbol) {
|
||||||
|
QString finalStr = "";
|
||||||
|
QString strTime = QString::number(time);
|
||||||
|
while (strTime.size() < 5) {
|
||||||
|
strTime = "0" + strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < strTime.size(); ++i ) {
|
||||||
|
finalStr += strTime.at(i);
|
||||||
|
if (i == 1) {
|
||||||
|
finalStr += symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrameFileIO::saveCARBUSAnalzyer(QString filename, const QVector<CANFrame>* frames)
|
||||||
|
{
|
||||||
|
QFile *outFile = new QFile(filename);
|
||||||
|
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
{
|
||||||
|
delete outFile;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QTextStream outTextStream(outFile);
|
||||||
|
|
||||||
|
int lineCounter = 0;
|
||||||
|
|
||||||
|
qint64 minTime = frames->at(0).timeStamp().microSeconds();
|
||||||
|
qint64 maxTime = minTime;
|
||||||
|
for (int c = 0; c < frames->count(); c++)
|
||||||
|
{
|
||||||
|
if (frames->at(c).timeStamp().microSeconds() < minTime) minTime = frames->at(c).timeStamp().microSeconds();
|
||||||
|
if (frames->at(c).timeStamp().microSeconds() > maxTime) maxTime = frames->at(c).timeStamp().microSeconds();
|
||||||
|
}
|
||||||
|
qint64 totalTime = maxTime - minTime;
|
||||||
|
// looks like a bug in CARBUS format for 3 version. time is in ms, while packets in us.
|
||||||
|
totalTime /= 1000;
|
||||||
|
QTime someTime(0,0,0);
|
||||||
|
someTime = someTime.addMSecs(totalTime);
|
||||||
|
|
||||||
|
// header:
|
||||||
|
// @see #loadCARBUSAnalyzer()
|
||||||
|
// 14012 = number of packets
|
||||||
|
// 15688 = max time - start time in ms
|
||||||
|
//
|
||||||
|
// "@ TEXT @ 3 @ 64 @ 0 @ 14012 @ 15688 @ 00:00:15.688 @"
|
||||||
|
// saving in version format 3 with microseconds in packets time
|
||||||
|
outTextStream << "@ TEXT @ 3 @ 64 @ 0 @ " << frames->count() << " @ " << totalTime
|
||||||
|
<<" @ " << someTime.toString("hh:mm:ss.zzz") <<" @\r";
|
||||||
|
|
||||||
|
const unsigned char *data;
|
||||||
|
for (int c = 0; c < frames->count(); c++)
|
||||||
|
{
|
||||||
|
lineCounter++;
|
||||||
|
if (lineCounter > 100)
|
||||||
|
{
|
||||||
|
qApp->processEvents();
|
||||||
|
lineCounter = 0;
|
||||||
|
}
|
||||||
|
auto frame = frames->at(c);
|
||||||
|
|
||||||
|
uint64_t timeStamp = frame.timeStamp().microSeconds();
|
||||||
|
QString canId = QString::number(frame.frameId(), 16).toUpper().rightJustified(3, '0').toUtf8();
|
||||||
|
QString canDlc = QString::number(frame.payload().length()).toUtf8();
|
||||||
|
|
||||||
|
QString ascii = "";
|
||||||
|
QString finalCanData;
|
||||||
|
|
||||||
|
data = reinterpret_cast<const unsigned char *>(frame.payload().constData());
|
||||||
|
for (int d = 0; d < frame.payload().length(); d++)
|
||||||
|
{
|
||||||
|
auto octet = data[d];
|
||||||
|
finalCanData.append(QString::number(octet, 16).toUpper().rightJustified(2, '0').toUtf8());
|
||||||
|
finalCanData.append(" ");
|
||||||
|
|
||||||
|
QString strCode = QString::number(octet, 16);
|
||||||
|
bool conv;
|
||||||
|
uint symbolCode = strCode.toInt(&conv, 16);
|
||||||
|
|
||||||
|
if ((symbolCode >= 32 && symbolCode < 126)) {
|
||||||
|
QChar localQChar = QChar(symbolCode);
|
||||||
|
if (localQChar.toLatin1() != 0) {
|
||||||
|
ascii += QString::fromLocal8Bit(QByteArray::fromHex(strCode.toLatin1()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ascii += " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finalCanData = finalCanData.trimmed().leftJustified(23, ' ');
|
||||||
|
ascii = ascii.leftJustified(8, ' ');
|
||||||
|
auto seconds = QString::number(timeStamp / 1000000);
|
||||||
|
auto uSeconds = QString::number(timeStamp % 1000000);
|
||||||
|
QString localArg = "";
|
||||||
|
localArg.append(seconds).append(",").append(uSeconds).append("\t")
|
||||||
|
.append(QString::number(frame.bus)).append("\t") // bus channel
|
||||||
|
.append("0004").append("\t") // it's CAN frame
|
||||||
|
.append(canId).append("\t")
|
||||||
|
.append(canDlc).append("\t")
|
||||||
|
.append(finalCanData).append("\t")
|
||||||
|
.append("00000000").append("\t")
|
||||||
|
.append(ascii).append("\t")
|
||||||
|
.append("\r");
|
||||||
|
|
||||||
|
qDebug() << localArg;
|
||||||
|
outTextStream << localArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile->close();
|
||||||
|
delete outFile;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool FrameFileIO::isCANHackerFile(QString filename)
|
bool FrameFileIO::isCANHackerFile(QString filename)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ public:
|
|||||||
static bool saveCanDumpFile(QString filename, const QVector<CANFrame> * frames);
|
static bool saveCanDumpFile(QString filename, const QVector<CANFrame> * frames);
|
||||||
static bool saveCabanaFile(QString filename, const QVector<CANFrame>* frames);
|
static bool saveCabanaFile(QString filename, const QVector<CANFrame>* frames);
|
||||||
static bool saveCanalyzerASC(QString filename, const QVector<CANFrame>* frames);
|
static bool saveCanalyzerASC(QString filename, const QVector<CANFrame>* frames);
|
||||||
|
static bool saveCARBUSAnalzyer(QString filename, const QVector<CANFrame>* frames);
|
||||||
|
|
||||||
static bool openContinuousNative();
|
static bool openContinuousNative();
|
||||||
static bool closeContinuousNative();
|
static bool closeContinuousNative();
|
||||||
|
|||||||
Reference in New Issue
Block a user