diff --git a/framefileio.cpp b/framefileio.cpp index 20e7fb0..84b563b 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -13,6 +13,17 @@ QFile FrameFileIO::continuousFile; +struct TeslaAPCANRecord +{ + int64_t sec; + int32_t nano; + int32_t padding1; + uint16_t id; + uint8_t ctr; + uint8_t data[8]; + uint8_t padding2; +} __attribute__((packed)); + FrameFileIO::FrameFileIO() { } @@ -172,6 +183,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache filters.append(QString(tr("Generic ID/Data CSV (*.csv *.CSV)"))); filters.append(QString(tr("Cabana Log (*.csv *.CSV)"))); filters.append(QString(tr("CANOpen Magic (*.csv *.CSV)"))); + filters.append(QString(tr("Tesla Autopilot Snapshot (*.CAN *.can)"))); dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString()); dialog.setFileMode(QFileDialog::ExistingFile); @@ -214,6 +226,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache if (selectedNameFilter == filters[18]) result = loadGenericCSVFile(filename, frameCache); if (selectedNameFilter == filters[19]) result = loadCabanaFile(filename, frameCache); if (selectedNameFilter == filters[20]) result = loadCANOpenFile(filename, frameCache); + if (selectedNameFilter == filters[21]) result = loadTeslaAPFile(filename, frameCache); progress.cancel(); @@ -264,6 +277,16 @@ bool FrameFileIO::autoDetectLoadFile(QString filename, QVector* frames } } + qDebug() << "Attempting Tesla AP Snapshot"; + if (isTeslaAPFile(filename)) + { + if (loadTeslaAPFile(filename, frames)) + { + qDebug() << "Loaded as Tesla AP Snapshot successfully!"; + return true; + } + } + qDebug() << "Attempting canalyzer ASC"; if (isCanalyzerASC(filename)) { @@ -3915,3 +3938,84 @@ bool FrameFileIO::saveCabanaFile(QString filename, const QVector* fram delete outFile; return true; } + +bool FrameFileIO::isTeslaAPFile(QString filename) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + QByteArray data; + bool isValidFile = true; + TeslaAPCANRecord record; + + if (!inFile->open(QIODevice::ReadOnly)) + { + delete inFile; + return false; + } + + while (!inFile->atEnd()) + { + inFile->read((char *)&record, sizeof(TeslaAPCANRecord)); + if (record.id > 0x7FF) isValidFile = false; + if ((record.ctr >> 4) > 8) isValidFile = false; + if ((record.ctr & 0xF) > 6) isValidFile = false; + } + + inFile->close(); + delete inFile; + return isValidFile; +} + +bool FrameFileIO::loadTeslaAPFile(QString filename, QVector* frames) +{ + QFile *inFile = new QFile(filename); + CANFrame thisFrame; + int lineCounter = 0; + QByteArray data; + int timeOffset = 0; + int64_t lastTimeStamp = 0; + bool foundErrors = false; + thisFrame.setFrameType(QCanBusFrame::DataFrame); + TeslaAPCANRecord record; + + if (!inFile->open(QIODevice::ReadOnly)) + { + delete inFile; + return false; + } + + while (!inFile->atEnd()) + { + lineCounter++; + if (lineCounter > 100) + { + qApp->processEvents(); + lineCounter = 0; + } + + inFile->read((char *)&record, sizeof(TeslaAPCANRecord)); + + thisFrame.isReceived = true; + thisFrame.setExtendedFrameFormat(false); //format is incapable of extended frames + thisFrame.setFrameType(QCanBusFrame::DataFrame); + qint64 tempStamp; + tempStamp = record.sec * 1000000 + (record.nano/1000); + thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, tempStamp)); + thisFrame.setFrameId(record.id); + int numBytes = (record.ctr >> 4); + thisFrame.bus = (record.ctr & 0xF); + QByteArray bytes(numBytes, 0); + + if (numBytes <= 8) + { + for (int d = 0; d < numBytes; d++) bytes[d] = record.data[d]; + thisFrame.setPayload(bytes); + frames->append(thisFrame); + } + else foundErrors = true; + } + + inFile->close(); + delete inFile; + return !foundErrors; +} diff --git a/framefileio.h b/framefileio.h index fad147d..2e24b38 100644 --- a/framefileio.h +++ b/framefileio.h @@ -50,6 +50,7 @@ public: static bool loadCANHackerFile(QString filename, QVector* frames); static bool loadCabanaFile(QString filename, QVector* frames); static bool loadCANOpenFile(QString filename, QVector* frames); + static bool loadTeslaAPFile(QString filename, QVector* frames); //functions that pre-scan a file to try to figure out if they could read it. Used to automatically determine //file type and load it. @@ -72,6 +73,7 @@ public: static bool isCANHackerFile(QString filename); static bool isCabanaFile(QString filename); static bool isCANOpenFile(QString filename); + static bool isTeslaAPFile(QString filename); static bool saveCRTDFile(QString, const QVector*); static bool saveNativeCSVFile(QString, const QVector*);