diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 8cda711..30f73b1 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -27,7 +27,8 @@ SOURCES += main.cpp\ framesenderwindow.cpp \ dbchandler.cpp \ dbcmaineditor.cpp \ - dbcsignaleditor.cpp + dbcsignaleditor.cpp \ + framefileio.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -46,7 +47,9 @@ HEADERS += mainwindow.h \ dbc_classes.h \ dbchandler.h \ dbcmaineditor.h \ - dbcsignaleditor.h + dbcsignaleditor.h \ + framefileio.h \ + config.h FORMS += mainwindow.ui \ graphingwindow.ui \ diff --git a/config.h b/config.h new file mode 100644 index 0000000..e3ac21a --- /dev/null +++ b/config.h @@ -0,0 +1,7 @@ +#ifndef CONFIG +#define CONFIG + +#define VERSION 111 + +#endif // CONFIG + diff --git a/framefileio.cpp b/framefileio.cpp new file mode 100644 index 0000000..357e840 --- /dev/null +++ b/framefileio.cpp @@ -0,0 +1,372 @@ +#include "framefileio.h" + +FrameFileIO::FrameFileIO() +{ + +} + +//CRTD format from Mark Webb-Johnson / OVMS project +/* +Sample data in CRTD format +1320745424.000 CXX OVMS Tesla Roadster cando2crtd converted log +1320745424.000 CXX OVMS Tesla roadster log: charge.20111108.csv +1320745424.002 R11 402 FA 01 C3 A0 96 00 07 01 +1320745424.015 R11 400 02 9E 01 80 AB 80 55 00 +1320745424.066 R11 400 01 01 00 00 00 00 4C 1D +1320745424.105 R11 100 A4 53 46 5A 52 45 38 42 +1320745424.106 R11 100 A5 31 35 42 33 30 30 30 +1320745424.106 R11 100 A6 35 36 39 +1320745424.106 CEV Open charge port door +1320745424.106 R11 100 9B 97 A6 31 03 15 05 06 +1320745424.107 R11 100 07 64 + +tokens: +0 = timestamp +1 = line type +2 = ID +3-x = The data bytes +*/ + +bool FrameFileIO::loadCRTDFile(QString filename, QVector* frames) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + QByteArray line; + + if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + line = inFile->readLine(); //read out the header first and discard it. + + while (!inFile->atEnd()) { + line = inFile->readLine().simplified(); + if (line.length() > 2) + { + QList tokens = line.split(' '); + int multiplier; + int idxOfDecimal = tokens[0].indexOf('.'); + if (idxOfDecimal > -1) { + int decimalPlaces = tokens[0].length() - tokens[0].indexOf('.') - 1; + //the result of the above is the # of digits after the decimal. + //This program deals in microsecond so turn the value into microseconds + multiplier = 1000000; //turn the decimal into full microseconds + } + else + { + multiplier = 1; //special case. Assume no decimal means microseconds + } + //qDebug() << "decimal places " << decimalPlaces; + thisFrame.timestamp = (int64_t)(tokens[0].toDouble() * multiplier); + if (tokens[1] == "R11" || tokens[1] == "R29") + { + thisFrame.ID = tokens[2].toInt(NULL, 16); + if (tokens[1] == "R29") thisFrame.extended = true; + else thisFrame.extended = false; + thisFrame.bus = 0; + thisFrame.len = tokens.length() - 3; + for (int d = 0; d < thisFrame.len; d++) + { + if (tokens[d + 3] != "") + { + thisFrame.data[d] = tokens[d + 3].toInt(NULL, 16); + } + else thisFrame.data[d] = 0; + } + frames->append(thisFrame); + } + } + } + inFile->close(); + return true; +} + +bool FrameFileIO::saveCRTDFile(QString filename, QVector* frames) +{ + QFile *outFile = new QFile(filename); + + if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) + return false; + + //write in float format with 6 digits after the decimal point + outFile->write(QString::number(frames->at(0).timestamp / 1000000.0, 'f', 6).toUtf8() + tr(" CXX GVRET-PC Reverse Engineering Tool Output V").toUtf8() + QString::number(VERSION).toUtf8()); + outFile->write("\n"); + + for (int c = 0; c < frames->count(); c++) + { + outFile->write(QString::number(frames->at(c).timestamp / 1000000.0, 'f', 6).toUtf8()); + outFile->putChar(' '); + if (frames->at(c).extended) + { + outFile->write("R29 "); + } + else outFile->write("R11 "); + outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); + outFile->putChar(' '); + + for (int temp = 0; temp < frames->at(c).len; temp++) + { + outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); + outFile->putChar(' '); + } + + outFile->write("\n"); + } + outFile->close(); + + return true; +} + +//The "native" file format for this program +bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + QByteArray line; + long long timeStamp = Utility::GetTimeMS(); + + if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + line = inFile->readLine(); //read out the header first and discard it. + + while (!inFile->atEnd()) { + line = inFile->readLine(); + if (line.length() > 2) + { + QList tokens = line.split(','); + if (tokens[0].length() > 3) + { + long long temp = tokens[0].right(10).toLongLong(); + thisFrame.timestamp = temp; + } + else + { + timeStamp += 5; + thisFrame.timestamp = timeStamp; + } + + thisFrame.ID = tokens[1].toInt(NULL, 16); + if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1; + else thisFrame.extended = 0; + thisFrame.bus = tokens[3].toInt(); + thisFrame.len = tokens[4].toInt(); + for (int c = 0; c < 8; c++) thisFrame.data[c] = 0; + for (int d = 0; d < thisFrame.len; d++) + thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16); + frames->append(thisFrame); + } + } + inFile->close(); + return true; +} + +bool FrameFileIO::saveNativeCSVFile(QString filename, QVector* frames) +{ + QFile *outFile = new QFile(filename); + + if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) + return false; + + outFile->write("Time Stamp,ID,Extended,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8"); + outFile->write("\n"); + + for (int c = 0; c < frames->count(); c++) + { + outFile->write(QString::number(frames->at(c).timestamp).toUtf8()); + outFile->putChar(44); + + outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8()); + outFile->putChar(44); + + if (frames->at(c).extended) outFile->write("true,"); + else outFile->write("false,"); + + outFile->write(QString::number(frames->at(c).bus).toUtf8()); + outFile->putChar(44); + + outFile->write(QString::number(frames->at(c).len).toUtf8()); + outFile->putChar(44); + + for (int temp = 0; temp < 8; temp++) + { + outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8()); + outFile->putChar(44); + } + + outFile->write("\n"); + + } + outFile->close(); + return true; +} + +bool FrameFileIO::loadGenericCSVFile(QString filename, QVector* frames) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + QByteArray line; + long long timeStamp = Utility::GetTimeMS(); + + if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + line = inFile->readLine(); //read out the header first and discard it. + + while (!inFile->atEnd()) { + line = inFile->readLine(); + if (line.length() > 2) + { + QList tokens = line.split(','); + + timeStamp += 5; + thisFrame.timestamp = timeStamp; + thisFrame.ID = tokens[0].toInt(NULL, 16); + if (thisFrame.ID > 0x7FF) thisFrame.extended = true; + else thisFrame.extended = false; + thisFrame.bus = 0; + QList dataTok = tokens[1].split(' '); + thisFrame.len = dataTok.length(); + if (thisFrame.len > 8) thisFrame.len = 8; + for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataTok[d].toInt(NULL, 16); + + frames->append(thisFrame); + } + } + inFile->close(); + return true; +} + +bool FrameFileIO::saveGenericCSVFile(QString filename, QVector* frames) +{ + return false; +} + +//busmaster log file +/* +tokens: +0 = timestamp +1 = Transmission direction +2 = Channel +3 = ID +4 = Type (s = standard, I believe x = extended) +5 = Data byte length +6-x = The data bytes + +Sample chunk of a busmaster log: +***BUSMASTER Ver 2.4.0*** +***PROTOCOL CAN*** +***NOTE: PLEASE DO NOT EDIT THIS DOCUMENT*** +***[START LOGGING SESSION]*** +***START DATE AND TIME 8:8:2014 11:49:7:965*** +***HEX*** +***SYSTEM MODE*** +***START CHANNEL BAUD RATE*** +***CHANNEL 1 - Kvaser - Kvaser Leaf Light HS #0 (Channel 0), Serial Number- 0, Firmware- 0x00000037 0x00020000 - 500000 bps*** +***END CHANNEL BAUD RATE*** +***START DATABASE FILES (DBF/DBC)*** +***END OF DATABASE FILES (DBF/DBC)*** +***