From 8e23302e792e372e230d57f35dcc8cac6558e18e Mon Sep 17 00:00:00 2001 From: selabnayr Date: Fri, 8 Mar 2019 18:01:03 -0800 Subject: [PATCH 1/3] Add load/save for Cabana log files. --- framefileio.cpp | 151 ++++++++++++++++++++++++++++++++++++++++++++++-- framefileio.h | 2 + 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/framefileio.cpp b/framefileio.cpp index dd8e2a6..89163f0 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -31,6 +31,7 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector* fram 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("Candump/Kayak(*.log)"))); + filters.append(QString(tr("Cabana Log(*.csv *.CSV)"))); dialog.setFileMode(QFileDialog::AnyFile); dialog.setNameFilters(filters); @@ -100,11 +101,16 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector* fram if (!filename.contains('.')) filename += ".csv"; result = saveVehicleSpyFile(filename, frameCache); } - if (dialog.selectedNameFilter() == filters[9]) - { - if (!filename.contains('.')) filename += ".log"; - saveCanDumpFile(filename,frameCache); - } + if (dialog.selectedNameFilter() == filters[9]) + { + if (!filename.contains('.')) filename += ".log"; + saveCanDumpFile(filename,frameCache); + } + if (dialog.selectedNameFilter() == filters[10]) + { + if (!filename.contains('.')) filename += ".csv"; + result = saveCabanaFile(filename, frameCache); + } progress.cancel(); if (result) @@ -141,6 +147,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)"))); filters.append(QString(tr("CANalyzer Binary Log Files (*.blf *.BLF)"))); filters.append(QString(tr("CANHacker Trace Files (*.trc *.TRC)"))); + filters.append(QString(tr("Cabana Log (*.csv *.CSV)"))); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setNameFilters(filters); @@ -176,6 +183,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache if (dialog.selectedNameFilter() == filters[13]) result = loadCanalyzerASC(filename, frameCache); if (dialog.selectedNameFilter() == filters[14]) result = loadCanalyzerBLF(filename, frameCache); if (dialog.selectedNameFilter() == filters[15]) result = loadCANHackerFile(filename, frameCache); + if (dialog.selectedNameFilter() == filters[16]) result = loadCabanaFile(filename, frameCache); progress.cancel(); @@ -1957,3 +1965,136 @@ bool FrameFileIO::loadKvaserFile(QString filename, QVector *frames, bo delete inFile; return !foundErrors; } + +//Cabana uses a CSV file with four columns +//time,addr,bus,data +//time is in seconds, with quite a bit of resolution after the decimal point. Does not start at 0, probably time-since-boot? +//addr is the arbitrarion ID in decimal, not hex +//bus is which CAN bus this was captured on +//data is the data in hex +//There also may or may not be some blank lines in between the csv column headers and the beginning of data. +bool FrameFileIO::loadCabanaFile(QString filename, QVector* frames) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + QByteArray line; + int fileVersion = 1; + long long timeStamp = Utility::GetTimeMS(); + int lineCounter = 0; + bool foundErrors = false; + thisFrame.remote = false; + + if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) + { + delete inFile; + return false; + } + + line = inFile->readLine().toUpper(); //read out the header first and discard it. + + while (!inFile->atEnd()) { + lineCounter++; + if (lineCounter > 100) + { + qApp->processEvents(); + lineCounter = 0; + } + + line = inFile->readLine().simplified(); + if (line.length() > 2) + { + QList tokens = line.split(','); + if (tokens.length() >= 3) + { + if (tokens[0].length() > 3) + { + long long temp = tokens[0].toLongLong(); + thisFrame.timestamp = temp; + } + else + { + timeStamp += 5; + thisFrame.timestamp = timeStamp; + } + + thisFrame.ID = tokens[1].toInt(); + if (thisFrame.ID > 0x7ff) thisFrame.extended = 1; + else thisFrame.extended = 0; + + thisFrame.remote = false; + + thisFrame.isReceived = true; + thisFrame.bus = tokens[2].toInt(); + thisFrame.len = 8; + + { + unsigned long long int tempData = tokens[3].toLongLong(NULL, 16); + thisFrame.data[0] = ((tempData >> 56) & 0xFF); + thisFrame.data[1] = ((tempData >> 48) & 0xFF); + thisFrame.data[2] = ((tempData >> 40) & 0xFF); + thisFrame.data[3] = ((tempData >> 32) & 0xFF); + thisFrame.data[4] = ((tempData >> 24) & 0xFF); + thisFrame.data[5] = ((tempData >> 16) & 0xFF); + thisFrame.data[6] = ((tempData >> 8) & 0xFF); + thisFrame.data[7] = (tempData & 0xFF); + } + + frames->append(thisFrame); + } + else foundErrors = true; + } + } + inFile->close(); + delete inFile; + return !foundErrors; +} + +bool FrameFileIO::saveCabanaFile(QString filename, const QVector* frames) +{ + QFile *outFile = new QFile(filename); + int lineCounter = 0; + + if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) + { + delete outFile; + return false; + } + + outFile->write("time,addr,bus,data"); + //outFile->write("Time Stamp,ID,Extended,Dir,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8"); + outFile->write("\n"); + + for (int c = 0; c < frames->count(); c++) + { + lineCounter++; + if (lineCounter > 100) + { + qApp->processEvents(); + lineCounter = 0; + } + + outFile->write(QString::number(frames->at(c).timestamp).toUtf8()); + outFile->putChar(44); + + outFile->write(QString::number(frames->at(c).ID, 10).toUpper().rightJustified(8, '0').toUtf8()); + outFile->putChar(44); + + outFile->write(QString::number(frames->at(c).bus).toUtf8()); + outFile->putChar(44); + + for (unsigned int temp = 0; temp < 8; temp++) + { + if (temp < frames->at(c).len) + outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); + else + outFile->write("00"); + } + outFile->putChar(44); + + outFile->write("\n"); + + } + outFile->close(); + delete outFile; + return true; +} diff --git a/framefileio.h b/framefileio.h index 69d4ef1..ed7e8ef 100644 --- a/framefileio.h +++ b/framefileio.h @@ -45,6 +45,7 @@ public: static bool loadCanalyzerASC(QString, QVector*); static bool loadCanalyzerBLF(QString, QVector*); static bool loadCANHackerFile(QString filename, QVector* frames); + static bool loadCabanaFile(QSting filename, QVector* frames); static bool saveCRTDFile(QString, const QVector*); static bool saveNativeCSVFile(QString, const QVector*); static bool saveGenericCSVFile(QString, const QVector*); @@ -55,6 +56,7 @@ public: static bool saveCANDOFile(QString, const QVector*); static bool saveVehicleSpyFile(QString, const QVector*); static bool saveCanDumpFile(QString filename, const QVector * frames); + static bool saveCabanaFile(QSting filename, const QVector* frames); static bool openContinuousNative(); static bool closeContinuousNative(); static bool writeContinuousNative(const QVector*, int); From a03a9d6d09b6e500fe04f1d297851e827572669f Mon Sep 17 00:00:00 2001 From: Izzy Date: Fri, 8 Mar 2019 23:43:34 -0800 Subject: [PATCH 2/3] Fix a few typos, and fix import/export of timestamps. Normalizes to microseconds, and makes the first sample happen at 0. Exported version is now indistinguishable from the imported version, other than the timestamps starting at 0. --- framefileio.cpp | 39 +++++++++++++++++++++++++++++---------- framefileio.h | 4 ++-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/framefileio.cpp b/framefileio.cpp index 89163f0..3971c5b 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -1978,8 +1978,9 @@ bool FrameFileIO::loadCabanaFile(QString filename, QVector* frames) QFile *inFile = new QFile(filename); CANFrame thisFrame; QByteArray line; - int fileVersion = 1; - long long timeStamp = Utility::GetTimeMS(); + bool timeStampBaseSet = false; + uint64_t timeStampBase = 0; + uint64_t lastTimeStamp = 0; int lineCounter = 0; bool foundErrors = false; thisFrame.remote = false; @@ -2006,15 +2007,30 @@ bool FrameFileIO::loadCabanaFile(QString filename, QVector* frames) QList tokens = line.split(','); if (tokens.length() >= 3) { - if (tokens[0].length() > 3) + if (tokens[0].length() > 1) { - long long temp = tokens[0].toLongLong(); - thisFrame.timestamp = temp; + double temp = tokens[0].toDouble(); + temp = temp * 1000000; + + if(!timeStampBaseSet) + { + timeStampBase = (uint64_t)(temp); + timeStampBaseSet = true; + } + + if(timeStampBaseSet) { + thisFrame.timestamp = ((uint64_t)(temp) - timeStampBase); + lastTimeStamp = thisFrame.timestamp; + } else { + thisFrame.timestamp = (lastTimeStamp + 1); + lastTimeStamp = thisFrame.timestamp; + } + } else { - timeStamp += 5; - thisFrame.timestamp = timeStamp; + thisFrame.timestamp = (lastTimeStamp + 1); + lastTimeStamp = thisFrame.timestamp; } thisFrame.ID = tokens[1].toInt(); @@ -2073,10 +2089,14 @@ bool FrameFileIO::saveCabanaFile(QString filename, const QVector* fram lineCounter = 0; } - outFile->write(QString::number(frames->at(c).timestamp).toUtf8()); + double tempTimeStamp = frames->at(c).timestamp; + tempTimeStamp /= 1000000; + + outFile->write(QString::number(tempTimeStamp, 'f').toUtf8()); + outFile->write(".0"); outFile->putChar(44); - outFile->write(QString::number(frames->at(c).ID, 10).toUpper().rightJustified(8, '0').toUtf8()); + outFile->write(QString::number(frames->at(c).ID, 10).toUpper().toUtf8()); outFile->putChar(44); outFile->write(QString::number(frames->at(c).bus).toUtf8()); @@ -2089,7 +2109,6 @@ bool FrameFileIO::saveCabanaFile(QString filename, const QVector* fram else outFile->write("00"); } - outFile->putChar(44); outFile->write("\n"); diff --git a/framefileio.h b/framefileio.h index ed7e8ef..c60e1c7 100644 --- a/framefileio.h +++ b/framefileio.h @@ -45,7 +45,7 @@ public: static bool loadCanalyzerASC(QString, QVector*); static bool loadCanalyzerBLF(QString, QVector*); static bool loadCANHackerFile(QString filename, QVector* frames); - static bool loadCabanaFile(QSting filename, QVector* frames); + static bool loadCabanaFile(QString filename, QVector* frames); static bool saveCRTDFile(QString, const QVector*); static bool saveNativeCSVFile(QString, const QVector*); static bool saveGenericCSVFile(QString, const QVector*); @@ -56,7 +56,7 @@ public: static bool saveCANDOFile(QString, const QVector*); static bool saveVehicleSpyFile(QString, const QVector*); static bool saveCanDumpFile(QString filename, const QVector * frames); - static bool saveCabanaFile(QSting filename, const QVector* frames); + static bool saveCabanaFile(QString filename, const QVector* frames); static bool openContinuousNative(); static bool closeContinuousNative(); static bool writeContinuousNative(const QVector*, int); From 79a684e74ac667484714930a9a5aadcd3bb34c3e Mon Sep 17 00:00:00 2001 From: Izzy Date: Sat, 9 Mar 2019 19:50:58 -0800 Subject: [PATCH 3/3] Fix loading for values >0x7F in the first byte. --- framefileio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framefileio.cpp b/framefileio.cpp index 3971c5b..713aecd 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -2044,7 +2044,7 @@ bool FrameFileIO::loadCabanaFile(QString filename, QVector* frames) thisFrame.len = 8; { - unsigned long long int tempData = tokens[3].toLongLong(NULL, 16); + unsigned long long int tempData = tokens[3].toULongLong(NULL, 16); thisFrame.data[0] = ((tempData >> 56) & 0xFF); thisFrame.data[1] = ((tempData >> 48) & 0xFF); thisFrame.data[2] = ((tempData >> 40) & 0xFF);