diff --git a/canframemodel.cpp b/canframemodel.cpp index 39dd246..de09091 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -311,6 +311,8 @@ void CANFrameModel::recalcOverwrite() uint64_t idAugmented; //id in lower 29 bits, bus number shifted up 29 bits foreach(CANFrame frame, frames) { + if (frame.frameType() != frame.DataFrame) continue; + idAugmented = frame.frameId(); idAugmented = idAugmented + (frame.bus << 29ull); if (!overWriteFrames.contains(idAugmented)) @@ -445,7 +447,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const tempString.append(QString::number(thisFrame.frameId() & 0x7)); return tempString; } - if (thisFrame.frameType() != QCanBusFrame::RemoteRequestFrame) { + if (thisFrame.frameType() == QCanBusFrame::DataFrame) { if (dataLen < 0) dataLen = 0; //if (dLen > 8) dLen = 8; for (int i = 0; i < dataLen; i++) @@ -457,6 +459,10 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const tempString.append(QString::fromUtf8(&byt, 1)); } } + if (thisFrame.frameType() == QCanBusFrame::ErrorFrame) + { + tempString = "ERROR"; + } return tempString; case Column::Data: if (dataLen < 0) dataLen = 0; @@ -470,8 +476,23 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const else tempString.append(QString::number(data[i], 10)); tempString.append(" "); } + if (thisFrame.frameType() == thisFrame.ErrorFrame) + { + if (thisFrame.error() & thisFrame.TransmissionTimeoutError) tempString.append("\nTX Timeout"); + if (thisFrame.error() & thisFrame.LostArbitrationError) tempString.append("\nLost Arbitration"); + if (thisFrame.error() & thisFrame.ControllerError) tempString.append("\nController Error"); + if (thisFrame.error() & thisFrame.ProtocolViolationError) tempString.append("\nProtocol Violation"); + if (thisFrame.error() & thisFrame.TransceiverError) tempString.append("\nTransceiver Error"); + if (thisFrame.error() & thisFrame.MissingAcknowledgmentError) tempString.append("\nMissing ACK"); + if (thisFrame.error() & thisFrame.BusOffError) tempString.append("\nBus OFF"); + if (thisFrame.error() & thisFrame.BusError) tempString.append("\nBus ERR"); + if (thisFrame.error() & thisFrame.ControllerRestartError) tempString.append("\nController restart err"); + if (thisFrame.error() & thisFrame.UnknownError) tempString.append("\nUnknown error type"); + } + //TODO: technically the actual returned bytes for an error frame encode some more info. Not interpreting it yet. + //now, if we're supposed to interpret the data and the DBC handler is loaded then use it - if (dbcHandler != nullptr && interpretFrames) + if ( (dbcHandler != nullptr) && interpretFrames && (thisFrame.frameType() == thisFrame.DataFrame) ) { DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame); if (msg != nullptr) diff --git a/config.h b/config.h index 3bbbd8a..0e8517d 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 200 +#define VERSION 201 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index e63e72a..26e4c70 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -150,7 +150,7 @@ void ConnectionWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("ConnWindow/WindowSize", QSize(956, 665)).toSize()); - move(settings.value("ConnWindow/WindowPos", QPoint(100, 100)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("ConnWindow/WindowPos", QPoint(100, 100)).toPoint())); } } diff --git a/connections/serialbusconnection.cpp b/connections/serialbusconnection.cpp index 5da0d19..6ea71c3 100644 --- a/connections/serialbusconnection.cpp +++ b/connections/serialbusconnection.cpp @@ -184,55 +184,22 @@ void SerialBusConnection::framesReceived() if(frame_p) { frame_p->setPayload(recFrame.payload()); frame_p->bus = 0; - - if (recFrame.frameType() == QCanBusFrame::ErrorFrame) { - // Constants defined in include/uapi/linux/can/error.h - //since the whole program uses QCanBusFrame now we can just grab errors directly out of the proper place from now on - /* - switch (recFrame.error()) { - case QCanBusFrame::TransmissionTimeoutError: - frame_p->setFrameId(0x20000001); - break; - case QCanBusFrame::LostArbitrationError: - frame_p->ID = 0x20000002; - break; - case QCanBusFrame::ControllerError: - frame_p->ID = 0x20000004; - break; - case QCanBusFrame::ProtocolViolationError: - frame_p->ID = 0x20000008; - break; - case QCanBusFrame::TransceiverError: - frame_p->ID = 0x20000010; - break; - case QCanBusFrame::MissingAcknowledgmentError: - frame_p->ID = 0x20000020; - break; - case QCanBusFrame::BusOffError: - frame_p->ID = 0x20000040; - break; - case QCanBusFrame::BusError: - frame_p->ID = 0x20000080; - break; - case QCanBusFrame::ControllerRestartError: - frame_p->ID = 0x20000100; - break; - default: - break; - } - frame_p->extended = true; - */ - frame_p->isReceived = true; - } else { + if (recFrame.frameType() == recFrame.ErrorFrame) + { + frame_p->setExtendedFrameFormat(recFrame.hasExtendedFrameFormat()); + frame_p->setFrameId(recFrame.frameId() + 0x20000000ull); + frame_p->isReceived = true; + } + else + { frame_p->setExtendedFrameFormat(recFrame.hasExtendedFrameFormat()); frame_p->setFrameId(recFrame.frameId()); - frame_p->setTimeStamp(recFrame.timeStamp()); - frame_p->setFrameType(recFrame.frameType()); - frame_p->setError(recFrame.error()); - - /* If recorded frame has a local echo, it is a Tx message, and thus should not be marked as Rx */ - frame_p->isReceived = !recFrame.hasLocalEcho(); } + frame_p->setTimeStamp(recFrame.timeStamp()); + frame_p->setFrameType(recFrame.frameType()); + frame_p->setError(recFrame.error()); + /* If recorded frame has a local echo, it is a Tx message, and thus should not be marked as Rx */ + frame_p->isReceived = !recFrame.hasLocalEcho(); if (useSystemTime) { frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ul)); diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index fb67985..904dc2e 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -6,8 +6,30 @@ DBC_MESSAGE::DBC_MESSAGE() { sigHandler = new DBCSignalHandler; + ID = 0; + len = 0; + multiplexorSignal = nullptr; + sender = nullptr; } +DBC_SIGNAL::DBC_SIGNAL() +{ + bias = 0; + isMultiplexed = false; + isMultiplexor = false; + max = 1; + min = 0; + multiplexValue = 0; + factor = 1.0; + intelByteOrder = false; + parentMessage = nullptr; + receiver = nullptr; + signalSize = 1; + startBit = 1; + valType = DBC_SIG_VAL_TYPE::UNSIGNED_INT; +} + + /* The way that the DBC file format works is kind of weird... For intel format signals you count up from the start bit to the end bit which is (startbit + signallength - 1). At each point diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index 3006737..a2eb3b9 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -106,6 +106,7 @@ public: //TODO: this is sloppy. It shouldn't all be public! QList attributes; QList valList; + DBC_SIGNAL(); bool processAsText(const CANFrame &frame, QString &outString, bool outputName = true); bool processAsInt(const CANFrame &frame, int32_t &outValue); bool processAsDouble(const CANFrame &frame, double &outValue); diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index e88a658..8332958 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -281,6 +281,7 @@ DBCFile::DBCFile() messageHandler->setMatchingCriteria(EXACT); messageHandler->setFilterLabeling(false); isDirty = false; + fileName = ""; } DBCFile::DBCFile(const DBCFile& cpy) : QObject() @@ -759,7 +760,7 @@ bool DBCFile::parseDefaultAttrLine(QString line) return false; } -void DBCFile::loadFile(QString fileName) +bool DBCFile::loadFile(QString fileName) { QFile *inFile = new QFile(fileName); QString line, rawLine; @@ -777,7 +778,8 @@ void DBCFile::loadFile(QString fileName) if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) { delete inFile; - return; + qDebug() << "Could not load the file!"; + return false; } qDebug() << "Starting DBC load"; @@ -1039,6 +1041,7 @@ void DBCFile::loadFile(QString fileName) filePath = fileName.left(fileName.length() - this->fileName.length()); assocBuses = -1; isDirty = false; + return true; } QVariant DBCFile::processAttributeVal(QString input, DBC_ATTRIBUTE_VAL_TYPE typ) @@ -1156,7 +1159,7 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr) return goodAttr; } -void DBCFile::saveFile(QString fileName) +bool DBCFile::saveFile(QString fileName) { int nodeNumber = 1; int msgNumber = 1; @@ -1168,7 +1171,7 @@ void DBCFile::saveFile(QString fileName) if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) { delete outFile; - return; + return false; } //right now it outputs a standard hard coded boilerplate @@ -1454,6 +1457,7 @@ void DBCFile::saveFile(QString fileName) QStringList fileList = fileName.split('/'); this->fileName = fileList[fileList.length() - 1]; //whoops... same name as parameter in this function. filePath = fileName.left(fileName.length() - this->fileName.length()); + return true; } void DBCHandler::saveDBCFile(int idx) @@ -1534,6 +1538,7 @@ int DBCHandler::createBlankFile() falseNode.name = "Vector__XXX"; falseNode.comment = "Default node if none specified"; newFile.dbc_nodes.append(falseNode); + newFile.setAssocBus(-1); loadedFiles.append(newFile); return loadedFiles.count(); @@ -1542,9 +1547,16 @@ int DBCHandler::createBlankFile() DBCFile* DBCHandler::loadDBCFile(QString filename) { DBCFile newFile; - newFile.loadFile(filename); - loadedFiles.append(newFile); - return &loadedFiles.last(); + if (newFile.loadFile(filename)) + { + loadedFiles.append(newFile); + } + else + { + //createBlankFile(); + } + if (loadedFiles.count()> 0) return &loadedFiles.last(); + else return nullptr; } //the only reason to even bother sending the index is to see if @@ -1587,6 +1599,7 @@ DBCFile* DBCHandler::loadJSONFile(QString filename) createBlankFile(); thisFile = &loadedFiles.last(); + QFile *inFile = new QFile(filename); if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -1843,40 +1856,44 @@ DBCHandler::DBCHandler() // Load previously saved DBC file settings QSettings settings; int filecount = settings.value("DBC/FileCount", 0).toInt(); + qDebug() << "Previously loaded DBC file count: " << filecount; for (int i=0; isetAssocBus(bus); + if (file) + { + int bus = settings.value("DBC/AssocBus_" + QString(i),0).toInt(); + file->setAssocBus(bus); - MatchingCriteria_t matchingCriteria = (MatchingCriteria_t)settings.value("DBC/MatchingCriteria_" + QString(i),0).toInt(); + MatchingCriteria_t matchingCriteria = (MatchingCriteria_t)settings.value("DBC/MatchingCriteria_" + QString(i),0).toInt(); - DBC_ATTRIBUTE attr; + DBC_ATTRIBUTE attr; - attr.attrType = MESSAGE; - attr.defaultValue = matchingCriteria; - attr.enumVals.clear(); - attr.lower = 0; - attr.upper = 0; - attr.name = "matchingcriteria"; - attr.valType = QINT; - file->dbc_attributes.append(attr); - file->messageHandler->setMatchingCriteria(matchingCriteria); + attr.attrType = MESSAGE; + attr.defaultValue = matchingCriteria; + attr.enumVals.clear(); + attr.lower = 0; + attr.upper = 0; + attr.name = "matchingcriteria"; + attr.valType = QINT; + file->dbc_attributes.append(attr); + file->messageHandler->setMatchingCriteria(matchingCriteria); - bool filterLabeling = settings.value("DBC/FilterLabeling_" + QString(i),0).toBool(); - attr.attrType = MESSAGE; - attr.defaultValue = filterLabeling; - attr.enumVals.clear(); - attr.lower = 0; - attr.upper = 0; - attr.name = "filterlabeling"; - attr.valType = QINT; - file->dbc_attributes.append(attr); - file->messageHandler->setFilterLabeling(filterLabeling); + bool filterLabeling = settings.value("DBC/FilterLabeling_" + QString(i),0).toBool(); + attr.attrType = MESSAGE; + attr.defaultValue = filterLabeling; + attr.enumVals.clear(); + attr.lower = 0; + attr.upper = 0; + attr.name = "filterlabeling"; + attr.valType = QINT; + file->dbc_attributes.append(attr); + file->messageHandler->setFilterLabeling(filterLabeling); - qInfo() << "Loaded DBC file" << filename << " (bus:" << bus - << ", Matching Criteria:" << (int)matchingCriteria << "Filter labeling: " << (filterLabeling?"enabled":"disabled") << ")"; + qInfo() << "Loaded DBC file" << filename << " (bus:" << bus + << ", Matching Criteria:" << (int)matchingCriteria << "Filter labeling: " << (filterLabeling?"enabled":"disabled") << ")"; + } } } diff --git a/dbc/dbchandler.h b/dbc/dbchandler.h index f2341eb..11bd480 100644 --- a/dbc/dbchandler.h +++ b/dbc/dbchandler.h @@ -76,8 +76,8 @@ public: DBC_ATTRIBUTE *findAttributeByName(QString name); DBC_ATTRIBUTE *findAttributeByIdx(int idx); void findAttributesByType(DBC_ATTRIBUTE_TYPE typ, QList *list); - void saveFile(QString); - void loadFile(QString); + bool saveFile(QString); + bool loadFile(QString); QString getFullFilename(); QString getFilename(); QString getPath(); diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index 2aa5825..76dd76c 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -133,7 +133,7 @@ void DBCMainEditor::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("DBCMainEditor/WindowSize", QSize(1103, 571)).toSize()); - move(settings.value("DBCMainEditor/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("DBCMainEditor/WindowPos", QPoint(50, 50)).toPoint())); } } @@ -370,8 +370,8 @@ void DBCMainEditor::updatedMessage(DBC_MESSAGE *msg) item->setText(0, msgInfo); //editor could have changed the parent Node too. Have to figure out which node //is parent in the GUI and compare that to parent in the data. - DBC_NODE *oldParent = dbcFile->findNodeByName(item->parent()->text(0)); - if (oldParent != msg->sender) + DBC_NODE *oldParent = dbcFile->findNodeByName(item->parent()->text(0).split(" - ")[0]); + if (oldParent != msg->sender && oldParent) { qDebug() << "Changed parent of message. Trying to rehome it."; QTreeWidgetItem *newParent = nullptr; @@ -448,7 +448,11 @@ void DBCMainEditor::newMessage() nodeItem = msgItem->parent(); } - DBC_NODE *node = dbcFile->findNodeByName(nodeItem->data(0, Qt::DisplayRole).toString()); + //if there was a comment this will find the location of the comment and snip it out. + QString nodeName = nodeItem->data(0, Qt::DisplayRole).toString().split(" - ")[0]; + + DBC_NODE *node = dbcFile->findNodeByName(nodeName); + if (!node) node = dbcFile->findNodeByIdx(0); DBC_MESSAGE msg; DBC_MESSAGE *msgPtr; if (msgItem) @@ -467,17 +471,17 @@ void DBCMainEditor::newMessage() } else { - msg.name = nodeItem->text(0) + "Msg" + QString::number(randGen.bounded(500)); + msg.name = nodeName + "Msg" + QString::number(randGen.bounded(500)); msg.ID = 0; msg.len = 0; } } else { - msg.name = nodeItem->text(0) + "Msg" + QString::number(randGen.bounded(500)); + msg.name = nodeName + "Msg" + QString::number(randGen.bounded(500)); msg.ID = 0; msg.len = 0; - } + } msg.sender = node; dbcFile->messageHandler->addMessage(msg); diff --git a/dbc/dbcmessageeditor.cpp b/dbc/dbcmessageeditor.cpp index 2366696..6502f44 100644 --- a/dbc/dbcmessageeditor.cpp +++ b/dbc/dbcmessageeditor.cpp @@ -187,7 +187,7 @@ void DBCMessageEditor::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("DBCMessageEditor/WindowSize", QSize(340, 400)).toSize()); - move(settings.value("DBCMessageEditor/WindowPos", QPoint(100, 100)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("DBCMessageEditor/WindowPos", QPoint(100, 100)).toPoint())); } } diff --git a/dbc/dbcnodeeditor.cpp b/dbc/dbcnodeeditor.cpp index 0f25543..7a94790 100644 --- a/dbc/dbcnodeeditor.cpp +++ b/dbc/dbcnodeeditor.cpp @@ -81,7 +81,7 @@ void DBCNodeEditor::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("DBCNodeEditor/WindowSize", QSize(312, 128)).toSize()); - move(settings.value("DBCNodeEditor/WindowPos", QPoint(100, 100)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("DBCNodeEditor/WindowPos", QPoint(100, 100)).toPoint())); } } diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index ce69871..c02fdac 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -280,7 +280,7 @@ void DBCSignalEditor::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("DBCSignalEditor/WindowSize", QSize(1000, 600)).toSize()); - move(settings.value("DBCSignalEditor/WindowPos", QPoint(100, 100)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("DBCSignalEditor/WindowPos", QPoint(100, 100)).toPoint())); } } diff --git a/firmwareuploaderwindow.cpp b/firmwareuploaderwindow.cpp index 44571d3..05028be 100644 --- a/firmwareuploaderwindow.cpp +++ b/firmwareuploaderwindow.cpp @@ -149,7 +149,7 @@ void FirmwareUploaderWindow::sendFirmwareChunk() for (int i = 0; i < 6; i++) xorByte = xorByte ^ static_cast(output->payload()[i]); output->payload()[6] = xorByte; output->setPayload(bytes); - sendCANFrame(output); + CANConManager::getInstance()->sendFrame(*output); timer->start(); } @@ -187,16 +187,18 @@ void FirmwareUploaderWindow::handleStartStopTransfer() QByteArray bytes(8,0); output->bus = bus; output->setFrameId(baseAddress); + output->setFrameType(QCanBusFrame::DataFrame); - output->payload()[0] = 0xEF; - output->payload()[1] = 0xBE; - output->payload()[2] = 0xAD; - output->payload()[3] = 0xDE; - output->payload()[4] = token & 0xFF; - output->payload()[5] = (token >> 8) & 0xFF; - output->payload()[6] = (token >> 16) & 0xFF; - output->payload()[7] = (token >> 24) & 0xFF; - sendCANFrame(output); + bytes[0] = 0xEF; + bytes[1] = 0xBE; + bytes[2] = 0xAD; + bytes[3] = 0xDE; + bytes[4] = token & 0xFF; + bytes[5] = (token >> 8) & 0xFF; + bytes[6] = (token >> 16) & 0xFF; + bytes[7] = (token >> 24) & 0xFF; + output->setPayload(bytes); + CANConManager::getInstance()->sendFrame(*output); } else //stop anything in process { diff --git a/firmwareuploaderwindow.h b/firmwareuploaderwindow.h index ec07906..5950735 100644 --- a/firmwareuploaderwindow.h +++ b/firmwareuploaderwindow.h @@ -19,9 +19,6 @@ public: explicit FirmwareUploaderWindow(const QVector *frames, QWidget *parent = 0); ~FirmwareUploaderWindow(); -signals: - void sendCANFrame(const CANFrame *); - public slots: void gotTargettedFrame(CANFrame frame); diff --git a/framefileio.cpp b/framefileio.cpp index d086013..ac09ead 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -13,6 +13,19 @@ QFile FrameFileIO::continuousFile; +struct TeslaAPCANRecord +{ + #pragma pack(push, 1) + int64_t sec; + int32_t nano; + int32_t padding1; + uint16_t id; + uint8_t ctr; + uint8_t data[8]; + uint8_t padding2; + #pragma pack(pop) +}; + FrameFileIO::FrameFileIO() { } @@ -172,6 +185,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 +228,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 +279,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 +3940,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*); diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index 85fd517..5cef16f 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -143,7 +143,7 @@ void FramePlaybackWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("Playback/WindowSize", QSize(742, 606)).toSize()); - move(settings.value("Playback/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("Playback/WindowPos", QPoint(50, 50)).toPoint())); } if (settings.value("Playback/AutoLoop", false).toBool()) { diff --git a/helpwindow.cpp b/helpwindow.cpp index 386948b..056ef32 100644 --- a/helpwindow.cpp +++ b/helpwindow.cpp @@ -1,4 +1,5 @@ #include +#include "utility.h" #include "helpwindow.h" #include "ui_helpwindow.h" @@ -32,7 +33,7 @@ void HelpWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("HelpViewer/WindowSize", QSize(600, 700)).toSize()); - move(settings.value("HelpViewer/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("HelpViewer/WindowPos", QPoint(50, 50)).toPoint())); } } diff --git a/mainwindow.cpp b/mainwindow.cpp index dc4ab13..dd5c091 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -324,7 +324,8 @@ void MainWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("Main/WindowSize", QSize(800, 750)).toSize()); - move(settings.value("Main/WindowPos", QPoint(100, 100)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("Main/WindowPos", QPoint(100, 100)).toPoint())); + ui->canFramesView->setColumnWidth(0, settings.value("Main/TimeColumn", 150).toUInt()); //time stamp ui->canFramesView->setColumnWidth(1, settings.value("Main/IDColumn", 70).toUInt()); //frame ID ui->canFramesView->setColumnWidth(2, settings.value("Main/ExtColumn", 40).toUInt()); //extended diff --git a/re/dbccomparatorwindow.cpp b/re/dbccomparatorwindow.cpp index 57d4c1e..f7b27fd 100644 --- a/re/dbccomparatorwindow.cpp +++ b/re/dbccomparatorwindow.cpp @@ -66,7 +66,7 @@ void DBCComparatorWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("DBCComparator/WindowSize", QSize(720, 631)).toSize()); - move(settings.value("DBCComparator/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("DBCComparator/WindowPos", QPoint(50, 50)).toPoint())); } } diff --git a/re/discretestatewindow.cpp b/re/discretestatewindow.cpp index a4a0ba3..0844e40 100644 --- a/re/discretestatewindow.cpp +++ b/re/discretestatewindow.cpp @@ -198,7 +198,7 @@ void DiscreteStateWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("DiscreteState/WindowSize", QSize(400, 300)).toSize()); - move(settings.value("DiscreteState/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("DiscreteState/WindowPos", QPoint(50, 50)).toPoint())); } } diff --git a/re/filecomparatorwindow.cpp b/re/filecomparatorwindow.cpp index a159146..4c93be7 100644 --- a/re/filecomparatorwindow.cpp +++ b/re/filecomparatorwindow.cpp @@ -64,7 +64,7 @@ void FileComparatorWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("FileComparator/WindowSize", QSize(720, 631)).toSize()); - move(settings.value("FileComparator/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("FileComparator/WindowPos", QPoint(50, 50)).toPoint())); } } diff --git a/re/flowviewwindow.cpp b/re/flowviewwindow.cpp index 31e4010..5c60202 100644 --- a/re/flowviewwindow.cpp +++ b/re/flowviewwindow.cpp @@ -158,7 +158,7 @@ void FlowViewWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("FlowView/WindowSize", QSize(1078, 621)).toSize()); - move(settings.value("FlowView/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("FlowView/WindowPos", QPoint(50, 50)).toPoint())); } if (settings.value("FlowView/AutoRef", false).toBool()) diff --git a/re/frameinfowindow.cpp b/re/frameinfowindow.cpp index 03ab8e6..d97b2d9 100644 --- a/re/frameinfowindow.cpp +++ b/re/frameinfowindow.cpp @@ -170,7 +170,7 @@ void FrameInfoWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("FrameInfo/WindowSize", QSize(794, 694)).toSize()); - move(settings.value("FrameInfo/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("FrameInfo/WindowPos", QPoint(50, 50)).toPoint())); } useOpenGL = settings.value("Main/UseOpenGL", false).toBool(); diff --git a/re/graphingwindow.cpp b/re/graphingwindow.cpp index 8849183..82be855 100644 --- a/re/graphingwindow.cpp +++ b/re/graphingwindow.cpp @@ -125,7 +125,7 @@ void GraphingWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("Graphing/WindowSize", QSize(800, 600)).toSize()); - move(settings.value("Graphing/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("Graphing/WindowPos", QPoint(50, 50)).toPoint())); } secondsMode = settings.value("Main/TimeSeconds", false).toBool(); useOpenGL = settings.value("Main/UseOpenGL", false).toBool(); diff --git a/re/isotp_interpreterwindow.cpp b/re/isotp_interpreterwindow.cpp index 9d5e440..9d23399 100644 --- a/re/isotp_interpreterwindow.cpp +++ b/re/isotp_interpreterwindow.cpp @@ -112,7 +112,7 @@ void ISOTP_InterpreterWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("ISODecodeWindow/WindowSize", this->size()).toSize()); - move(settings.value("ISODecodeWindow/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("ISODecodeWindow/WindowPos", QPoint(50, 50)).toPoint())); } } diff --git a/re/rangestatewindow.cpp b/re/rangestatewindow.cpp index 498ff20..9e62021 100644 --- a/re/rangestatewindow.cpp +++ b/re/rangestatewindow.cpp @@ -126,7 +126,7 @@ void RangeStateWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("RangeStateView/WindowSize", QSize(765, 615)).toSize()); - move(settings.value("RangeStateView/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("RangeStateView/WindowPos", QPoint(50, 50)).toPoint())); } } diff --git a/re/sniffer/snifferwindow.cpp b/re/sniffer/snifferwindow.cpp index 1c7a729..29faed0 100644 --- a/re/sniffer/snifferwindow.cpp +++ b/re/sniffer/snifferwindow.cpp @@ -6,6 +6,7 @@ #include "helpwindow.h" #include "connections/canconmanager.h" #include "SnifferDelegate.h" +#include "utility.h" SnifferWindow::SnifferWindow(QWidget *parent) : QDialog(parent), @@ -73,7 +74,7 @@ void SnifferWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("Sniffer/WindowSize", QSize(1100, 750)).toSize()); - move(settings.value("Sniffer/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("Sniffer/WindowPos", QPoint(50, 50)).toPoint())); ui->treeView->setColumnWidth(0, settings.value("Sniffer/DeltaColumn", 110).toUInt()); ui->treeView->setColumnWidth(1, settings.value("Sniffer/IDColumn", 70).toUInt()); ui->treeView->setColumnWidth(2, settings.value("Sniffer/Data0Column", 92).toUInt()); diff --git a/re/temporalgraphwindow.cpp b/re/temporalgraphwindow.cpp index 2b3ff4c..26319c6 100644 --- a/re/temporalgraphwindow.cpp +++ b/re/temporalgraphwindow.cpp @@ -91,7 +91,7 @@ void TemporalGraphWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("Temporal/WindowSize", QSize(800, 600)).toSize()); - move(settings.value("Temporal/WindowPos", QPoint(50, 50)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("Temporal/WindowPos", QPoint(50, 50)).toPoint())); } useOpenGL = settings.value("Main/UseOpenGL", false).toBool(); } diff --git a/scriptingwindow.cpp b/scriptingwindow.cpp index 46ffa2b..101bf6b 100644 --- a/scriptingwindow.cpp +++ b/scriptingwindow.cpp @@ -126,7 +126,7 @@ void ScriptingWindow::readSettings() if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("ScriptingWindow/WindowSize", QSize(860, 650)).toSize()); - move(settings.value("ScriptingWindow/WindowPos", QPoint(100, 100)).toPoint()); + move(Utility::constrainedWindowPos(settings.value("ScriptingWindow/WindowPos", QPoint(100, 100)).toPoint())); } } diff --git a/utility.h b/utility.h index ab2d44d..fd369e3 100644 --- a/utility.h +++ b/utility.h @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include class Utility { @@ -16,6 +19,19 @@ public: static bool sysTimeMode; static QString timeFormat; + //determines whether the window position is within any available screens. If it is not we default + //back to 0,0 which is going to be on screen. This fixes a problem where some operating systems would + //otherwise let you put windows on a second monitor, disconnect that monitor, and still put windows on it. + static QPoint constrainedWindowPos(QPoint originalPos) + { + QScreen *screen = QGuiApplication::screenAt(originalPos); + if (!screen) + { + return QPoint(0,0); + } + return originalPos; + } + static QString unQuote(QString inStr) { QStringList temp;