From e6058ead34896ff5bae396231bd11c67839a968e Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Tue, 20 Sep 2022 16:23:18 -0500 Subject: [PATCH 01/15] Progress! Masked error caused by saving dbc while editor is open that causes msg IDs to go crazy by making editor modal, but that affects all other windows, so might be a better fix. Added new value type of VALUE_STRING, probably better named ENUMERATED_STRING, and it uses the table in the editor to define the enum. Fixed a bug in the signal viewer load when a signal is not matched (I found it by renaming a signal and then loading) --- dbc/dbc_classes.cpp | 15 +++++++++++++-- dbc/dbc_classes.h | 3 ++- dbc/dbchandler.cpp | 6 ++++++ dbc/dbcloadsavewindow.cpp | 1 + dbc/dbcsignaleditor.cpp | 9 ++++++++- signalviewerwindow.cpp | 7 ++++--- 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index 5467b4f..2a43815 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -137,6 +137,17 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString, bool o cachedValue = outString; return true; } + else if(valType == VALUE_STRING) + { + result = Utility::processIntegerSignal(frame.payload(), startBit, signalSize, intelByteOrder, isSigned); + + if(!getValueString(result, outString)) + { + outString = "Signal string value is undefined"; + } + + return true; + } if (valType == SIGNED_INT) isSigned = true; if (valType == SIGNED_INT || valType == UNSIGNED_INT) @@ -229,7 +240,7 @@ bool DBC_SIGNAL::processAsInt(const CANFrame &frame, int32_t &outValue) int32_t result = 0; bool isSigned = false; - if (valType == STRING || valType == SP_FLOAT || valType == DP_FLOAT) + if (valType == STRING || valType == VALUE_STRING || valType == SP_FLOAT || valType == DP_FLOAT) { return false; } @@ -262,7 +273,7 @@ bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue) bool isSigned = false; double endResult; - if (valType == STRING) + if (valType == STRING || valType == VALUE_STRING) { return false; } diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index fd085c2..b093a5d 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -21,7 +21,8 @@ enum DBC_SIG_VAL_TYPE SIGNED_INT, SP_FLOAT, DP_FLOAT, - STRING + STRING, + VALUE_STRING }; enum DBC_ATTRIBUTE_VAL_TYPE diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index d60dd1b..0dd3cd4 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -576,6 +576,9 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) sig.valType = DP_FLOAT; sig.intelByteOrder = true; break; + case 7: //double point float in little endian + sig.valType = VALUE_STRING; + break; } sig.factor = match.captured(6 + offset).toDouble(); sig.bias = match.captured(7 + offset).toDouble(); @@ -1443,6 +1446,9 @@ bool DBCFile::saveFile(QString fileName) case STRING: msgOutput.append("4-"); break; + case VALUE_STRING: + msgOutput.append("7-"); + break; default: msgOutput.append("0-"); break; diff --git a/dbc/dbcloadsavewindow.cpp b/dbc/dbcloadsavewindow.cpp index 7136379..fd38dd9 100644 --- a/dbc/dbcloadsavewindow.cpp +++ b/dbc/dbcloadsavewindow.cpp @@ -285,6 +285,7 @@ void DBCLoadSaveWindow::editFile() if (idx < 0) return; editorWindow->setFileIdx(idx); + editorWindow->setModal(true); editorWindow->show(); } diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index b81c11c..606ff63 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -34,6 +34,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : ui->comboType->addItem("SINGLE PRECISION"); ui->comboType->addItem("DOUBLE PRECISION"); ui->comboType->addItem("STRING"); + ui->comboType->addItem("ENUMERATED STRING"); ui->bitfield->setMode(GridMode::SIGNAL_VIEW); @@ -84,7 +85,10 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : break; case 4: currentSignal->valType = STRING; - break; + break; + case 5: + currentSignal->valType = VALUE_STRING; + break; } dbcFile->setDirtyFlag(); fillSignalForm(currentSignal); @@ -577,6 +581,9 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) case STRING: ui->comboType->setCurrentIndex(4); break; + case VALUE_STRING: + ui->comboType->setCurrentIndex(5); + break; } for (int i = 0; i < ui->comboReceiver->count(); i++) diff --git a/signalviewerwindow.cpp b/signalviewerwindow.cpp index cb70364..6346168 100644 --- a/signalviewerwindow.cpp +++ b/signalviewerwindow.cpp @@ -286,13 +286,14 @@ void SignalViewerWindow::loadDefinitions(bool append) if (msg = dbcHandler->findMessage(msgName)) { sig = msg->sigHandler->findSignalByName(sigName); - loadedSignals.append(sig); + if(sig) + loadedSignals.append(sig); } else if(msg = dbcHandler->findMessage(msgId)) { sig = msg->sigHandler->findSignalByName(sigName); - //fix anything up about the name? - loadedSignals.append(sig); + if(sig) + loadedSignals.append(sig); } else { From da7a721494ab474abc17d7a438e470faeedbbfde Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Tue, 20 Sep 2022 16:27:53 -0500 Subject: [PATCH 02/15] Changed default signalviewer message matching to be by ID --- signalviewerwindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/signalviewerwindow.cpp b/signalviewerwindow.cpp index 6346168..2835699 100644 --- a/signalviewerwindow.cpp +++ b/signalviewerwindow.cpp @@ -283,14 +283,15 @@ void SignalViewerWindow::loadDefinitions(bool append) QString msgName = QString(tokens[2]); QString sigName = QString(tokens[3]); DBC_MESSAGE *msg;; - if (msg = dbcHandler->findMessage(msgName)) + if(msg = dbcHandler->findMessage(msgId)) { sig = msg->sigHandler->findSignalByName(sigName); if(sig) loadedSignals.append(sig); } - else if(msg = dbcHandler->findMessage(msgId)) + else if (msg = dbcHandler->findMessage(msgName)) { + //this is not a very safe way to match since messages names can be duplicated sig = msg->sigHandler->findSignalByName(sigName); if(sig) loadedSignals.append(sig); From 6accf2e9e7fa8adef80ff4294db26fa9159fdab9 Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Tue, 20 Sep 2022 16:48:11 -0500 Subject: [PATCH 03/15] Fixed bug in extended addressing check where ID was being AND'ed with 80000000 decimal instead of hex --- dbc/dbchandler.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index 0dd3cd4..3c11d33 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -453,7 +453,7 @@ DBC_MESSAGE* DBCFile::parseMessageLine(QString line) DBC_MESSAGE msg; uint32_t ID = match.captured(1).toULong(); //the ID is always stored in decimal format msg.ID = ID & 0x1FFFFFFFul; - msg.extendedID = (ID & 80000000ul) ? true : false; + msg.extendedID = (ID & 0x80000000ul) ? true : false; msg.name = match.captured(2); msg.len = match.captured(3).toUInt(); msg.sender = findNodeByName(match.captured(4)); @@ -1372,7 +1372,10 @@ bool DBCFile::saveFile(QString fileName) } uint32_t ID = msg->ID; - if (msg->ID > 0x7FF || msg->extendedID) msg->ID += 0x80000000ul; //set bit 31 if this ID is extended. + if (msg->ID > 0x7FF || msg->extendedID) + { + msg->ID += 0x80000000ul; //set bit 31 if this ID is extended. + } msgOutput.append("BO_ " + QString::number(ID) + " " + msg->name + ": " + QString::number(msg->len) + " " + msg->sender->name + "\n"); @@ -1571,7 +1574,10 @@ bool DBCFile::saveFile(QString fileName) DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x); uint32_t ID = msg->ID; - if (msg->ID > 0x7FF || msg->extendedID) msg->ID += 0x80000000ul; //set bit 31 if this ID is extended. + if (msg->ID > 0x7FF || msg->extendedID) + { + msg->ID += 0x80000000ul; //set bit 31 if this ID is extended. + } for (int s = 0; s < msg->sigHandler->getCount(); s++) { From d9e371c494bf721f3edb35c72330dbd3dd45eedc Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Tue, 20 Sep 2022 16:50:04 -0500 Subject: [PATCH 04/15] The last commit of the ext ID fix removed need for modal editor --- dbc/dbcloadsavewindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbc/dbcloadsavewindow.cpp b/dbc/dbcloadsavewindow.cpp index fd38dd9..7136379 100644 --- a/dbc/dbcloadsavewindow.cpp +++ b/dbc/dbcloadsavewindow.cpp @@ -285,7 +285,6 @@ void DBCLoadSaveWindow::editFile() if (idx < 0) return; editorWindow->setFileIdx(idx); - editorWindow->setModal(true); editorWindow->show(); } From 0ee9eacbb3e16973b0564fc9e20c1a592518b6af Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Tue, 20 Sep 2022 17:08:20 -0500 Subject: [PATCH 05/15] realized that the value list was already supported so reverted my custom code. The issue that made me go down this path is related to the little endian checkbox mysteriously and inconsistently unchecking and therefore interpreting enum values wrong...would really like to find this. --- dbc/dbc_classes.cpp | 15 ++------------- dbc/dbc_classes.h | 3 +-- dbc/dbchandler.cpp | 6 ------ dbc/dbcsignaleditor.cpp | 6 ------ 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/dbc/dbc_classes.cpp b/dbc/dbc_classes.cpp index 2a43815..5467b4f 100644 --- a/dbc/dbc_classes.cpp +++ b/dbc/dbc_classes.cpp @@ -137,17 +137,6 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString, bool o cachedValue = outString; return true; } - else if(valType == VALUE_STRING) - { - result = Utility::processIntegerSignal(frame.payload(), startBit, signalSize, intelByteOrder, isSigned); - - if(!getValueString(result, outString)) - { - outString = "Signal string value is undefined"; - } - - return true; - } if (valType == SIGNED_INT) isSigned = true; if (valType == SIGNED_INT || valType == UNSIGNED_INT) @@ -240,7 +229,7 @@ bool DBC_SIGNAL::processAsInt(const CANFrame &frame, int32_t &outValue) int32_t result = 0; bool isSigned = false; - if (valType == STRING || valType == VALUE_STRING || valType == SP_FLOAT || valType == DP_FLOAT) + if (valType == STRING || valType == SP_FLOAT || valType == DP_FLOAT) { return false; } @@ -273,7 +262,7 @@ bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue) bool isSigned = false; double endResult; - if (valType == STRING || valType == VALUE_STRING) + if (valType == STRING) { return false; } diff --git a/dbc/dbc_classes.h b/dbc/dbc_classes.h index b093a5d..fd085c2 100644 --- a/dbc/dbc_classes.h +++ b/dbc/dbc_classes.h @@ -21,8 +21,7 @@ enum DBC_SIG_VAL_TYPE SIGNED_INT, SP_FLOAT, DP_FLOAT, - STRING, - VALUE_STRING + STRING }; enum DBC_ATTRIBUTE_VAL_TYPE diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index 3c11d33..9088bda 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -576,9 +576,6 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg) sig.valType = DP_FLOAT; sig.intelByteOrder = true; break; - case 7: //double point float in little endian - sig.valType = VALUE_STRING; - break; } sig.factor = match.captured(6 + offset).toDouble(); sig.bias = match.captured(7 + offset).toDouble(); @@ -1449,9 +1446,6 @@ bool DBCFile::saveFile(QString fileName) case STRING: msgOutput.append("4-"); break; - case VALUE_STRING: - msgOutput.append("7-"); - break; default: msgOutput.append("0-"); break; diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index 606ff63..b4bd6a3 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -86,9 +86,6 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : case 4: currentSignal->valType = STRING; break; - case 5: - currentSignal->valType = VALUE_STRING; - break; } dbcFile->setDirtyFlag(); fillSignalForm(currentSignal); @@ -581,9 +578,6 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) case STRING: ui->comboType->setCurrentIndex(4); break; - case VALUE_STRING: - ui->comboType->setCurrentIndex(5); - break; } for (int i = 0; i < ui->comboReceiver->count(); i++) From 74366d1c6b07bd91dd2d3428400fc5f7e219547f Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Tue, 20 Sep 2022 17:49:04 -0500 Subject: [PATCH 06/15] context menu in place for node rebase/duplicate need to add menu for rebase options and code for both actions --- dbc/dbcmaineditor.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ dbc/dbcmaineditor.h | 5 ++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index 54a046b..d10fcc3 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -21,11 +21,14 @@ DBCMainEditor::DBCMainEditor( const QVector *frames, QWidget *parent) dbcHandler = DBCHandler::getReference(); referenceFrames = frames; + ui->treeDBC->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->btnSearch, &QAbstractButton::clicked, this, &DBCMainEditor::handleSearch); connect(ui->lineSearch, &QLineEdit::returnPressed, this, &DBCMainEditor::handleSearch); connect(ui->btnSearchNext, &QAbstractButton::clicked, this, &DBCMainEditor::handleSearchForward); connect(ui->btnSearchPrev, &QAbstractButton::clicked, this, &DBCMainEditor::handleSearchBackward); connect(ui->treeDBC, &QTreeWidget::doubleClicked, this, &DBCMainEditor::onTreeDoubleClicked); + connect(ui->treeDBC, &QTreeWidget::customContextMenuRequested, this, &DBCMainEditor::onTreeContextMenu); connect(ui->treeDBC, &QTreeWidget::currentItemChanged, this, &DBCMainEditor::currentItemChanged); connect(ui->btnDelete, &QAbstractButton::clicked, this, &DBCMainEditor::deleteCurrentTreeItem); connect(ui->btnNewNode, &QAbstractButton::clicked, this, &DBCMainEditor::newNode); @@ -298,6 +301,51 @@ void DBCMainEditor::onTreeDoubleClicked(const QModelIndex &index) } } +void DBCMainEditor::onTreeContextMenu(const QPoint & pos) +{ + QTreeWidgetItem* firstCol = ui->treeDBC->currentItem(); + bool ret = false; + DBC_MESSAGE *msg; + DBC_SIGNAL *sig; + DBC_NODE *node; + uint32_t msgID; + QString idString; + + qDebug() << firstCol->data(0, Qt::UserRole) << " - " << firstCol->text(0); + + switch (firstCol->data(0, Qt::UserRole).toInt()) + { + case 1: //a node + idString = firstCol->text(0).split(" ")[0]; + node = dbcFile->findNodeByName(idString); + + QAction *actionRebase = new QAction(QIcon(":/Resource/warning32.ico"), tr("Rebase all messages"), this); + actionRebase->setStatusTip(tr("Rebase all messages in node")); + connect(actionRebase, SIGNAL(triggered()), this, SLOT(onRebaseMessages())); + + QAction *actionDupe = new QAction(QIcon(":/Resource/warning32.ico"), tr("Duplicate node"), this); + actionDupe->setStatusTip(tr("Duplicate node and messages")); + connect(actionDupe, SIGNAL(triggered()), this, SLOT(onDuplicateNode())); + + QMenu menu(this); + menu.addAction(actionRebase); + menu.addAction(actionDupe); + + QPoint pt(pos); + menu.exec( ui->treeDBC->mapToGlobal(pos) ); + break; + } +} + +void DBCMainEditor::onRebaseMessages() +{ + qDebug() << "rebase!!"; +} + +void DBCMainEditor::onDuplicateNode() +{ + qDebug() << "dupe!!"; +} /* * Recreate the whole tree with pretty icons and custom user roles that give the rest of code an easy way to figure out whether a given tree node diff --git a/dbc/dbcmaineditor.h b/dbc/dbcmaineditor.h index bfc3acd..dc8ea7c 100644 --- a/dbc/dbcmaineditor.h +++ b/dbc/dbcmaineditor.h @@ -32,6 +32,7 @@ public slots: private slots: void onTreeDoubleClicked(const QModelIndex &index); + void onTreeContextMenu(const QPoint & pos); void currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *prev); void onCustomMenuTree(QPoint); void deleteCurrentTreeItem(); @@ -43,7 +44,9 @@ private slots: void handleSearchBackward(); void newNode(); void newMessage(); - void newSignal(); + void newSignal(); + void onRebaseMessages(); + void onDuplicateNode(); private: Ui::DBCMainEditor *ui; From 27b58552df7219ec7d27b7c88a59ebe074f509ef Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Wed, 21 Sep 2022 18:04:11 -0500 Subject: [PATCH 07/15] rebase working but definitely needs clean up for all the whatifs --- SavvyCAN.pro | 3 + canframemodel.cpp | 1 + dbc/dbchandler.cpp | 18 ++++ dbc/dbchandler.h | 1 + dbc/dbcmaineditor.cpp | 18 +++- dbc/dbcmaineditor.h | 2 + dbc/dbcnoderebaseeditor.cpp | 166 ++++++++++++++++++++++++++++++++++++ dbc/dbcnoderebaseeditor.h | 42 +++++++++ ui/dbcnoderebaseeditor.ui | 75 ++++++++++++++++ 9 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 dbc/dbcnoderebaseeditor.cpp create mode 100644 dbc/dbcnoderebaseeditor.h create mode 100644 ui/dbcnoderebaseeditor.ui diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 9df479e..0a7094b 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -67,6 +67,7 @@ SOURCES += main.cpp\ dbc/dbcmaineditor.cpp \ dbc/dbcnodeeditor.cpp \ dbc/dbcsignaleditor.cpp \ + dbc/dbcnoderebaseeditor.cpp \ re/discretestatewindow.cpp \ re/filecomparatorwindow.cpp \ re/flowviewwindow.cpp \ @@ -100,6 +101,7 @@ HEADERS += mainwindow.h \ canframemodel.h \ connections/socketcand.h \ connections/mqtt_bus.h \ + dbc/dbcnoderebaseeditor.h \ mqtt/qmqtt.h \ mqtt/qmqtt_client.h \ mqtt/qmqtt_client_p.h \ @@ -188,6 +190,7 @@ FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ ui/dbcloadsavewindow.ui \ ui/dbcmaineditor.ui \ + ui/dbcnoderebaseeditor.ui \ ui/dbcsignaleditor.ui \ ui/dbcnodeeditor.ui \ ui/discretestatewindow.ui \ diff --git a/canframemodel.cpp b/canframemodel.cpp index aef3a34..03bb5d7 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -380,6 +380,7 @@ void CANFrameModel::recalcOverwrite() //Then replace the old list of frames with just the unique list frames.clear(); frames.append(overWriteFrames.values().toVector()); + frames.reserve(preallocSize); filteredFrames.clear(); filteredFrames.reserve(preallocSize); diff --git a/dbc/dbchandler.cpp b/dbc/dbchandler.cpp index 9088bda..23523ec 100644 --- a/dbc/dbchandler.cpp +++ b/dbc/dbchandler.cpp @@ -177,6 +177,24 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByPartialName(QString name) return nullptr; } +QList DBCMessageHandler::findMsgsByNode(DBC_NODE* node) +{ + QList messagesForNode; + + if (messages.count() == 0) + return messagesForNode; + + for (int i = 0; i < messages.count(); i++) + { + if (messages[i].sender == node) + { + messagesForNode.append(&messages[i]); + } + } + + return messagesForNode; +} + bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg) { messages.append(msg); diff --git a/dbc/dbchandler.h b/dbc/dbchandler.h index 9e040cb..925bc8c 100644 --- a/dbc/dbchandler.h +++ b/dbc/dbchandler.h @@ -43,6 +43,7 @@ public: DBC_MESSAGE *findMsgByIdx(int idx); DBC_MESSAGE *findMsgByName(QString name); DBC_MESSAGE *findMsgByPartialName(QString name); + QList findMsgsByNode(DBC_NODE *node); bool addMessage(DBC_MESSAGE &msg); bool removeMessage(DBC_MESSAGE *msg); bool removeMessageByIndex(int idx); diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index d10fcc3..88e3753 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -38,11 +38,13 @@ DBCMainEditor::DBCMainEditor( const QVector *frames, QWidget *parent) sigEditor = new DBCSignalEditor(this); msgEditor = new DBCMessageEditor(this); nodeEditor = new DBCNodeEditor(this); + nodeRebaseEditor = new DBCNodeRebaseEditor(this); //all three might potentially change the data stored and force the tree to be updated connect(sigEditor, &DBCSignalEditor::updatedTreeInfo, this, &DBCMainEditor::updatedSignal); connect(msgEditor, &DBCMessageEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage); connect(nodeEditor, &DBCNodeEditor::updatedTreeInfo, this, &DBCMainEditor::updatedNode); + connect(nodeRebaseEditor, &DBCNodeRebaseEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage); nodeIcon = QIcon(":/icons/images/node.png"); messageIcon = QIcon(":/icons/images/message.png"); @@ -339,7 +341,21 @@ void DBCMainEditor::onTreeContextMenu(const QPoint & pos) void DBCMainEditor::onRebaseMessages() { - qDebug() << "rebase!!"; + QTreeWidgetItem* firstCol = ui->treeDBC->currentItem(); + bool ret = false; + DBC_MESSAGE *msg; + DBC_SIGNAL *sig; + DBC_NODE *node; + uint32_t msgID; + QString idString; + + idString = firstCol->text(0).split(" ")[0]; + node = dbcFile->findNodeByName(idString); + nodeRebaseEditor->setFileIdx(fileIdx); + nodeRebaseEditor->setNodeRef(node); + nodeRebaseEditor->refreshView(); + nodeRebaseEditor->setModal(true); + nodeRebaseEditor->show(); } void DBCMainEditor::onDuplicateNode() diff --git a/dbc/dbcmaineditor.h b/dbc/dbcmaineditor.h index dc8ea7c..62f0876 100644 --- a/dbc/dbcmaineditor.h +++ b/dbc/dbcmaineditor.h @@ -10,6 +10,7 @@ #include "dbcsignaleditor.h" #include "dbcmessageeditor.h" #include "dbcnodeeditor.h" +#include "dbcnoderebaseeditor.h" #include "utility.h" namespace Ui { @@ -55,6 +56,7 @@ private: DBCSignalEditor *sigEditor; DBCMessageEditor *msgEditor; DBCNodeEditor *nodeEditor; + DBCNodeRebaseEditor *nodeRebaseEditor; DBCFile *dbcFile; int fileIdx; QIcon nodeIcon; diff --git a/dbc/dbcnoderebaseeditor.cpp b/dbc/dbcnoderebaseeditor.cpp new file mode 100644 index 0000000..393b656 --- /dev/null +++ b/dbc/dbcnoderebaseeditor.cpp @@ -0,0 +1,166 @@ +#include "dbcnoderebaseeditor.h" +#include "ui_dbcnoderebaseeditor.h" + +#include +#include +#include +#include "helpwindow.h" +#include "utility.h" + +DBCNodeRebaseEditor::DBCNodeRebaseEditor(QWidget *parent) : + QDialog(parent), + ui(new Ui::DBCNodeRebaseEditor) +{ + ui->setupUi(this); + + readSettings(); + + dbcHandler = DBCHandler::getReference(); + dbcNode = nullptr; + + connect(ui->btnDoRebase, &QPushButton::pressed, + [=]() + { + if (dbcNode == nullptr) return; + if (lowestMsgId > 0x1FFFFFFFul) return; + + uint newBase = Utility::ParseStringToNum(ui->lineEdit->text()); + + if (newBase <= 0x1FFFFFFFul && newBase != lowestMsgId) + { + uint rebaseDiff = newBase - lowestMsgId; + + QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + if(messagesForNode.count() == 0) + { + return; + } + + for (int i=0; iID += rebaseDiff; + emit updatedTreeInfo(messagesForNode[i]); + } + + dbcFile->setDirtyFlag(); + } + + + }); + +// connect(ui->lineOriginalBaseId, &QLineEdit::editingFinished, +// [=]() +// { +// if (dbcNode == nullptr) return; +// if (dbcNode->comment != ui->lineComment->text()) dbcFile->setDirtyFlag(); +// dbcNode->comment = ui->lineComment->text(); +// emit updatedTreeInfo(dbcNode); +// }); + +// connect(ui->lineMsgName, &QLineEdit::editingFinished, +// [=]() +// { +// if (dbcNode == nullptr) return; +// if (dbcNode->name != ui->lineMsgName->text()) dbcFile->setDirtyFlag(); +// dbcNode->name = ui->lineMsgName->text(); +// emit updatedTreeInfo(dbcNode); +// }); + + installEventFilter(this); +} + +DBCNodeRebaseEditor::~DBCNodeRebaseEditor() +{ + removeEventFilter(this); + delete ui; +} + +void DBCNodeRebaseEditor::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event); + writeSettings(); +} + +bool DBCNodeRebaseEditor::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::KeyRelease) { + QKeyEvent *keyEvent = static_cast(event); + switch (keyEvent->key()) + { + case Qt::Key_F1: + HelpWindow::getRef()->showHelp("nodeeditor.md"); + break; + } + return true; + } else { + // standard event processing + return QObject::eventFilter(obj, event); + } + return false; +} + +void DBCNodeRebaseEditor::setFileIdx(int idx) +{ + if (idx < 0 || idx > dbcHandler->getFileCount() - 1) return; + dbcFile = dbcHandler->getFileByIdx(idx); +} + +void DBCNodeRebaseEditor::readSettings() +{ + QSettings settings; + if (settings.value("Main/SaveRestorePositions", false).toBool()) + { + resize(settings.value("DBCNodeRebaseEditor/WindowSize", QSize(312, 128)).toSize()); + move(Utility::constrainedWindowPos(settings.value("DBCNodeRebaseEditor/WindowPos", QPoint(100, 100)).toPoint())); + } +} + +void DBCNodeRebaseEditor::writeSettings() +{ + QSettings settings; + + if (settings.value("Main/SaveRestorePositions", false).toBool()) + { + settings.setValue("DBCNodeRebaseEditor/WindowSize", size()); + settings.setValue("DBCNodeRebaseEditor/WindowPos", pos()); + } +} + + +void DBCNodeRebaseEditor::setNodeRef(DBC_NODE *node) +{ + dbcNode = node; +} + +void DBCNodeRebaseEditor::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + + refreshView(); +} + +void DBCNodeRebaseEditor::refreshView() +{ + if(dbcNode) + { + QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + if(messagesForNode.count() == 0) + { + //?? + + } + + lowestMsgId = 0xFFFFFFFF; + + for (int i=0; iID < lowestMsgId) + lowestMsgId = messagesForNode[i]->ID; + } + + ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul)); + ui->lineMsgName->setText(dbcNode->name); + } + + //generateSampleText(); +} diff --git a/dbc/dbcnoderebaseeditor.h b/dbc/dbcnoderebaseeditor.h new file mode 100644 index 0000000..8e787f0 --- /dev/null +++ b/dbc/dbcnoderebaseeditor.h @@ -0,0 +1,42 @@ +#ifndef DBCNODEREBASEEDITOR_H +#define DBCNODEREBASEEDITOR_H + +#include +#include "dbc_classes.h" +#include "dbchandler.h" + +namespace Ui { +class DBCNodeRebaseEditor; +} + +class DBCNodeRebaseEditor : public QDialog +{ + Q_OBJECT + +public: + explicit DBCNodeRebaseEditor(QWidget *parent = nullptr); + ~DBCNodeRebaseEditor(); + void showEvent(QShowEvent*); + void setNodeRef(DBC_NODE *node); + void setFileIdx(int idx); + void refreshView(); + +signals: + void updatedTreeInfo(DBC_MESSAGE *msg); + +private: + Ui::DBCNodeRebaseEditor *ui; + + DBCHandler *dbcHandler; + DBC_NODE *dbcNode; + DBCFile *dbcFile; + + void closeEvent(QCloseEvent *event); + bool eventFilter(QObject *obj, QEvent *event); + void readSettings(); + void writeSettings(); + + uint lowestMsgId; +}; + +#endif // DBCNODEREBASEEDITOR_H diff --git a/ui/dbcnoderebaseeditor.ui b/ui/dbcnoderebaseeditor.ui new file mode 100644 index 0000000..58bc46c --- /dev/null +++ b/ui/dbcnoderebaseeditor.ui @@ -0,0 +1,75 @@ + + + DBCNodeRebaseEditor + + + + 0 + 0 + 303 + 159 + + + + Dialog + + + + + 10 + 20 + 283 + 116 + + + + + + + Node Name: + + + + + + + + + + Current Base ID: + + + + + + + + + + New Base ID: + + + + + + + + + + Rebase All Messages in Node + + + + + + + Cancel + + + + + + + + + From 47d63c6296e0bfc7f4307bee2fea6ee4993fdd43 Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Thu, 22 Sep 2022 18:04:27 -0500 Subject: [PATCH 08/15] duplicate works! multiplexed signals are not copied at this time need to learn more about them first need to do clean up and corner case handling --- SavvyCAN.pro | 4 + dbc/dbcmaineditor.cpp | 105 +++++++++++++++++++- dbc/dbcmaineditor.h | 4 + dbc/dbcnodeduplicateeditor.cpp | 171 +++++++++++++++++++++++++++++++++ dbc/dbcnodeduplicateeditor.h | 45 +++++++++ dbc/dbcnoderebaseeditor.cpp | 9 +- ui/dbcnodeduplicateeditor.ui | 75 +++++++++++++++ ui/dbcnoderebaseeditor.ui | 2 +- 8 files changed, 409 insertions(+), 6 deletions(-) create mode 100644 dbc/dbcnodeduplicateeditor.cpp create mode 100644 dbc/dbcnodeduplicateeditor.h create mode 100644 ui/dbcnodeduplicateeditor.ui diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 0a7094b..b8f445b 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -21,6 +21,7 @@ ICON = icons/SavvyIcon.icns SOURCES += main.cpp\ connections/mqtt_bus.cpp \ + dbc/dbcnodeduplicateeditor.cpp \ mqtt/qmqtt_client.cpp \ mqtt/qmqtt_client_p.cpp \ mqtt/qmqtt_frame.cpp \ @@ -101,6 +102,7 @@ HEADERS += mainwindow.h \ canframemodel.h \ connections/socketcand.h \ connections/mqtt_bus.h \ + dbc/dbcnodeduplicateeditor.h \ dbc/dbcnoderebaseeditor.h \ mqtt/qmqtt.h \ mqtt/qmqtt_client.h \ @@ -185,11 +187,13 @@ HEADERS += mainwindow.h \ pcaplite.h FORMS += ui/candatagrid.ui \ + ui/dbcnodeduplicateeditor.ui \ ui/dbccomparatorwindow.ui \ ui/dbcmessageeditor.ui \ ui/connectionwindow.ui \ ui/dbcloadsavewindow.ui \ ui/dbcmaineditor.ui \ + ui/dbcnodeduplicateeditor.ui \ ui/dbcnoderebaseeditor.ui \ ui/dbcsignaleditor.ui \ ui/dbcnodeeditor.ui \ diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index 88e3753..2415bd5 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -31,7 +31,7 @@ DBCMainEditor::DBCMainEditor( const QVector *frames, QWidget *parent) connect(ui->treeDBC, &QTreeWidget::customContextMenuRequested, this, &DBCMainEditor::onTreeContextMenu); connect(ui->treeDBC, &QTreeWidget::currentItemChanged, this, &DBCMainEditor::currentItemChanged); connect(ui->btnDelete, &QAbstractButton::clicked, this, &DBCMainEditor::deleteCurrentTreeItem); - connect(ui->btnNewNode, &QAbstractButton::clicked, this, &DBCMainEditor::newNode); + connect(ui->btnNewNode, &QAbstractButton::clicked, this, QOverload<>::of(&DBCMainEditor::newNode)); connect(ui->btnNewMessage, &QAbstractButton::clicked, this, &DBCMainEditor::newMessage); connect(ui->btnNewSignal, &QAbstractButton::clicked, this, &DBCMainEditor::newSignal); @@ -39,12 +39,17 @@ DBCMainEditor::DBCMainEditor( const QVector *frames, QWidget *parent) msgEditor = new DBCMessageEditor(this); nodeEditor = new DBCNodeEditor(this); nodeRebaseEditor = new DBCNodeRebaseEditor(this); + nodeDuplicateEditor = new DBCNodeDuplicateEditor(this); //all three might potentially change the data stored and force the tree to be updated connect(sigEditor, &DBCSignalEditor::updatedTreeInfo, this, &DBCMainEditor::updatedSignal); connect(msgEditor, &DBCMessageEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage); connect(nodeEditor, &DBCNodeEditor::updatedTreeInfo, this, &DBCMainEditor::updatedNode); connect(nodeRebaseEditor, &DBCNodeRebaseEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage); + connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage); + connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::createNode, this, QOverload::of(&DBCMainEditor::newNode)); + connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::cloneMessageToNode, this, &DBCMainEditor::copyMessageToNode); + connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::nodeAdded, this, &DBCMainEditor::refreshTree); nodeIcon = QIcon(":/icons/images/node.png"); messageIcon = QIcon(":/icons/images/message.png"); @@ -360,7 +365,21 @@ void DBCMainEditor::onRebaseMessages() void DBCMainEditor::onDuplicateNode() { - qDebug() << "dupe!!"; + QTreeWidgetItem* firstCol = ui->treeDBC->currentItem(); + bool ret = false; + DBC_MESSAGE *msg; + DBC_SIGNAL *sig; + DBC_NODE *node; + uint32_t msgID; + QString idString; + + idString = firstCol->text(0).split(" ")[0]; + node = dbcFile->findNodeByName(idString); + nodeDuplicateEditor->setFileIdx(fileIdx); + nodeDuplicateEditor->setNodeRef(node); + nodeDuplicateEditor->refreshView(); + nodeDuplicateEditor->setModal(true); + nodeDuplicateEditor->show(); } /* @@ -545,11 +564,18 @@ void DBCMainEditor::updatedSignal(DBC_SIGNAL *sig) else qDebug() << "That signal doesn't exist. That's a bug dude."; } -void DBCMainEditor::newNode() +void DBCMainEditor::newNode(QString nodeName) { DBC_NODE node; DBC_NODE *nodePtr; - node.name = "Unnamed" + QString::number(randGen.bounded(50000)); + if(nodeName.isEmpty()) + { + node.name = "Unnamed" + QString::number(randGen.bounded(50000)); + } + else + { + node.name = nodeName; + } dbcFile->dbc_nodes.append(node); nodePtr = dbcFile->findNodeByName(node.name); QTreeWidgetItem *nodeItem = new QTreeWidgetItem(); @@ -563,6 +589,77 @@ void DBCMainEditor::newNode() dbcFile->setDirtyFlag(); } +void DBCMainEditor::newNode() +{ + newNode(QString()); +} + +void DBCMainEditor::copyMessageToNode(DBC_NODE *parentNode, DBC_MESSAGE *source, uint newMsgId) +{ + DBC_NODE *node = parentNode; + if (!node) node = dbcFile->findNodeByIdx(0); + QTreeWidgetItem *nodeItem = nullptr; + DBC_MESSAGE msg; + DBC_MESSAGE *msgPtr; + + nodeItem = ui->treeDBC->currentItem(); + + msg.name = source->name; + msg.ID = newMsgId; + msg.len = source->len; + msg.bgColor = source->bgColor; + msg.fgColor = source->fgColor; + msg.comment = source->comment; + msg.sender = node; + + DBC_SIGNAL *sigSource; + int sigCount = source->sigHandler->getCount(); + + for(int i=0; isigHandler->findSignalByIdx(i); + + DBC_SIGNAL sig; + + //Does not properly handle multiplexed signals, for now + sig.name = sigSource->name; + sig.bias = sigSource->bias; + sig.isMultiplexed = false; //sigSource->isMultiplexed; + sig.isMultiplexor = false; //sigSource->isMultiplexor; + sig.max = sigSource->max; + sig.min = sigSource->min; + sig.multiplexLowValue = sigSource->multiplexLowValue; + sig.multiplexHighValue = sigSource->multiplexHighValue; + sig.factor = sigSource->factor; + sig.intelByteOrder = sigSource->intelByteOrder; + sig.parentMessage = &msg; + sig.multiplexParent = nullptr; //need to learn about multiplexed signals and track them when copying + sig.receiver = node; + sig.signalSize = sigSource->signalSize; + sig.startBit = sigSource->startBit; + sig.valType = sigSource->valType; + + + sig.parentMessage = &msg; + msg.sigHandler->addSignal(sig); + } + + msg.sigHandler->sort(); + + dbcFile->messageHandler->addMessage(msg); + msgPtr = dbcFile->messageHandler->findMsgByIdx(dbcFile->messageHandler->getCount() - 1); + QTreeWidgetItem *newMsgItem = new QTreeWidgetItem(); + QString msgInfo = Utility::formatCANID(msg.ID) + " " + msg.name; + if (msg.comment.count() > 0) msgInfo.append(" - ").append(msg.comment); + newMsgItem->setText(0, msgInfo); + newMsgItem->setIcon(0, messageIcon); + newMsgItem->setData(0, Qt::UserRole, 2); + messageToItem.insert(msgPtr, newMsgItem); + itemToMessage.insert(newMsgItem, msgPtr); + nodeItem->addChild(newMsgItem); + //ui->treeDBC->setCurrentItem(newMsgItem); + dbcFile->setDirtyFlag(); +} //create a new message with it's parent being the node we're currently within void DBCMainEditor::newMessage() diff --git a/dbc/dbcmaineditor.h b/dbc/dbcmaineditor.h index 62f0876..5977f82 100644 --- a/dbc/dbcmaineditor.h +++ b/dbc/dbcmaineditor.h @@ -11,6 +11,7 @@ #include "dbcmessageeditor.h" #include "dbcnodeeditor.h" #include "dbcnoderebaseeditor.h" +#include "dbcnodeduplicateeditor.h" #include "utility.h" namespace Ui { @@ -43,7 +44,9 @@ private slots: void handleSearch(); void handleSearchForward(); void handleSearchBackward(); + void newNode(QString nodeName); void newNode(); + void copyMessageToNode(DBC_NODE *node, DBC_MESSAGE *source, uint newMsgId); void newMessage(); void newSignal(); void onRebaseMessages(); @@ -57,6 +60,7 @@ private: DBCMessageEditor *msgEditor; DBCNodeEditor *nodeEditor; DBCNodeRebaseEditor *nodeRebaseEditor; + DBCNodeDuplicateEditor *nodeDuplicateEditor; DBCFile *dbcFile; int fileIdx; QIcon nodeIcon; diff --git a/dbc/dbcnodeduplicateeditor.cpp b/dbc/dbcnodeduplicateeditor.cpp new file mode 100644 index 0000000..c2a3164 --- /dev/null +++ b/dbc/dbcnodeduplicateeditor.cpp @@ -0,0 +1,171 @@ +#include "dbcnodeduplicateeditor.h" +#include "ui_dbcnodeduplicateeditor.h" + +#include +#include +#include +#include "helpwindow.h" +#include "utility.h" + +DBCNodeDuplicateEditor::DBCNodeDuplicateEditor(QWidget *parent) : + QDialog(parent), + ui(new Ui::DBCNodeDuplicateEditor) +{ + ui->setupUi(this); + + readSettings(); + + dbcHandler = DBCHandler::getReference(); + dbcNode = nullptr; + + connect(ui->btnDuplicate, &QPushButton::pressed, + [=]() + { + if (dbcNode == nullptr) return; + if (lowestMsgId > 0x1FFFFFFFul) return; + + uint newBase = Utility::ParseStringToNum(ui->lineNewBaseId->text()); + + if (newBase <= 0x1FFFFFFFul && newBase != lowestMsgId) + { + uint rebaseDiff = newBase - lowestMsgId; + + QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + if(messagesForNode.count() == 0) + { + return; + } + + if(ui->lineNodeName->text().isEmpty()) + { + //tell! + return; + } + + QString newNodeName = ui->lineNodeName->text(); + emit createNode(newNodeName); + + DBC_NODE *nodePtr = dbcFile->findNodeByName(newNodeName); + + if(nodePtr == nullptr) + { + //uhoh + return; + } + + for (int i=0; iID + rebaseDiff; + emit cloneMessageToNode(nodePtr, messagesForNode[i], newMsgId); + } + + dbcFile->setDirtyFlag(); + emit nodeAdded(); + } + }); + + connect(ui->btnCancel, &QPushButton::pressed, + [=]() + { + + + }); + + installEventFilter(this); +} + +DBCNodeDuplicateEditor::~DBCNodeDuplicateEditor() +{ + removeEventFilter(this); + delete ui; +} + +void DBCNodeDuplicateEditor::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event); + writeSettings(); +} + +bool DBCNodeDuplicateEditor::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::KeyRelease) { + QKeyEvent *keyEvent = static_cast(event); + switch (keyEvent->key()) + { + case Qt::Key_F1: + HelpWindow::getRef()->showHelp("nodeeditor.md"); + break; + } + return true; + } else { + // standard event processing + return QObject::eventFilter(obj, event); + } + return false; +} + +void DBCNodeDuplicateEditor::setFileIdx(int idx) +{ + if (idx < 0 || idx > dbcHandler->getFileCount() - 1) return; + dbcFile = dbcHandler->getFileByIdx(idx); +} + +void DBCNodeDuplicateEditor::readSettings() +{ + QSettings settings; + if (settings.value("Main/SaveRestorePositions", false).toBool()) + { + resize(settings.value("DBCNodeDuplicateEditor/WindowSize", QSize(312, 128)).toSize()); + move(Utility::constrainedWindowPos(settings.value("DBCNodeDuplicateEditor/WindowPos", QPoint(100, 100)).toPoint())); + } +} + +void DBCNodeDuplicateEditor::writeSettings() +{ + QSettings settings; + + if (settings.value("Main/SaveRestorePositions", false).toBool()) + { + settings.setValue("DBCNodeDuplicateEditor/WindowSize", size()); + settings.setValue("DBCNodeDuplicateEditor/WindowPos", pos()); + } +} + + +void DBCNodeDuplicateEditor::setNodeRef(DBC_NODE *node) +{ + dbcNode = node; +} + +void DBCNodeDuplicateEditor::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + + refreshView(); +} + +void DBCNodeDuplicateEditor::refreshView() +{ + if(dbcNode) + { + QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + if(messagesForNode.count() == 0) + { + //?? + + } + + lowestMsgId = 0xFFFFFFFF; + + for (int i=0; iID < lowestMsgId) + lowestMsgId = messagesForNode[i]->ID; + } + + ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul)); + ui->lineNodeName->setText(dbcNode->name + QString("_Copy")); + } + + //generateSampleText(); +} diff --git a/dbc/dbcnodeduplicateeditor.h b/dbc/dbcnodeduplicateeditor.h new file mode 100644 index 0000000..9a29a93 --- /dev/null +++ b/dbc/dbcnodeduplicateeditor.h @@ -0,0 +1,45 @@ +#ifndef DBCNODEDUPLICATEEDITOR_H +#define DBCNODEDUPLICATEEDITOR_H + +#include +#include "dbc_classes.h" +#include "dbchandler.h" + +namespace Ui { +class DBCNodeDuplicateEditor; +} + +class DBCNodeDuplicateEditor : public QDialog +{ + Q_OBJECT + +public: + explicit DBCNodeDuplicateEditor(QWidget *parent = nullptr); + ~DBCNodeDuplicateEditor(); + void showEvent(QShowEvent*); + void setNodeRef(DBC_NODE *node); + void setFileIdx(int idx); + void refreshView(); + +signals: + void updatedTreeInfo(DBC_MESSAGE *msg); + void createNode(QString nodeName); + void cloneMessageToNode(DBC_NODE *parentNode, DBC_MESSAGE *source, uint newMsgId); + void nodeAdded(); + +private: + Ui::DBCNodeDuplicateEditor *ui; + + DBCHandler *dbcHandler; + DBC_NODE *dbcNode; + DBCFile *dbcFile; + + void closeEvent(QCloseEvent *event); + bool eventFilter(QObject *obj, QEvent *event); + void readSettings(); + void writeSettings(); + + uint lowestMsgId; +}; + +#endif // DBCNODEDUPLICATEEDITOR_H diff --git a/dbc/dbcnoderebaseeditor.cpp b/dbc/dbcnoderebaseeditor.cpp index 393b656..5a8f6bb 100644 --- a/dbc/dbcnoderebaseeditor.cpp +++ b/dbc/dbcnoderebaseeditor.cpp @@ -46,6 +46,13 @@ DBCNodeRebaseEditor::DBCNodeRebaseEditor(QWidget *parent) : } + }); + + connect(ui->btnCancel, &QPushButton::pressed, + [=]() + { + + }); // connect(ui->lineOriginalBaseId, &QLineEdit::editingFinished, @@ -159,7 +166,7 @@ void DBCNodeRebaseEditor::refreshView() } ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul)); - ui->lineMsgName->setText(dbcNode->name); + ui->lineNodeName->setText(dbcNode->name); } //generateSampleText(); diff --git a/ui/dbcnodeduplicateeditor.ui b/ui/dbcnodeduplicateeditor.ui new file mode 100644 index 0000000..a07c435 --- /dev/null +++ b/ui/dbcnodeduplicateeditor.ui @@ -0,0 +1,75 @@ + + + DBCNodeDuplicateEditor + + + + 0 + 0 + 314 + 193 + + + + Dialog + + + + + 10 + 10 + 290 + 116 + + + + + + + New Node Name: + + + + + + + + + + Current Base ID: + + + + + + + + + + New Base ID: + + + + + + + + + + Duplicate Node + + + + + + + Cancel + + + + + + + + + diff --git a/ui/dbcnoderebaseeditor.ui b/ui/dbcnoderebaseeditor.ui index 58bc46c..ddcfbe1 100644 --- a/ui/dbcnoderebaseeditor.ui +++ b/ui/dbcnoderebaseeditor.ui @@ -31,7 +31,7 @@ - + From 9ebbaca66886d6d72f037c55049759ea8dce5884 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Tue, 4 Oct 2022 19:48:11 -0400 Subject: [PATCH 09/15] Add a new connection type - Lawicel. It works for some devices, not all. More development needed but this is a start. Also added ability to set serial speed and bus speed in the device setup which may be useful for other connection devices too. --- SavvyCAN.pro | 2 + connections/canconconst.h | 1 + connections/canconfactory.cpp | 5 +- connections/canconfactory.h | 2 +- connections/canconnection.cpp | 5 + connections/canconnection.h | 7 +- connections/canconnectionmodel.cpp | 1 + connections/connectionwindow.cpp | 20 +- connections/connectionwindow.h | 2 +- connections/gvretserial.cpp | 2 +- connections/lawicel_serial.cpp | 496 ++++++++++++++++++++++++++++ connections/lawicel_serial.h | 66 ++++ connections/mqtt_bus.cpp | 2 +- connections/newconnectiondialog.cpp | 96 ++++++ connections/newconnectiondialog.h | 3 + connections/serialbusconnection.cpp | 2 +- connections/socketcand.cpp | 2 +- ui/newconnectiondialog.ui | 84 +++-- 18 files changed, 763 insertions(+), 35 deletions(-) create mode 100644 connections/lawicel_serial.cpp create mode 100644 connections/lawicel_serial.h diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 9df479e..34c629a 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -20,6 +20,7 @@ QMAKE_INFO_PLIST = Info.plist.template ICON = icons/SavvyIcon.icns SOURCES += main.cpp\ + connections/lawicel_serial.cpp \ connections/mqtt_bus.cpp \ mqtt/qmqtt_client.cpp \ mqtt/qmqtt_client_p.cpp \ @@ -98,6 +99,7 @@ SOURCES += main.cpp\ HEADERS += mainwindow.h \ can_structs.h \ canframemodel.h \ + connections/lawicel_serial.h \ connections/socketcand.h \ connections/mqtt_bus.h \ mqtt/qmqtt.h \ diff --git a/connections/canconconst.h b/connections/canconconst.h index 7f479c1..2cf53cc 100644 --- a/connections/canconconst.h +++ b/connections/canconconst.h @@ -20,6 +20,7 @@ namespace CANCon { REMOTE, KAYAK, MQTT, + LAWICEL, NONE }; } diff --git a/connections/canconfactory.cpp b/connections/canconfactory.cpp index 1fc461c..77daf09 100644 --- a/connections/canconfactory.cpp +++ b/connections/canconfactory.cpp @@ -4,10 +4,11 @@ #include "gvretserial.h" #include "mqtt_bus.h" #include "socketcand.h" +#include "lawicel_serial.h" using namespace CANCon; -CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName) +CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName, int pSerialSpeed, int pBusSpeed) { switch(pType) { case SERIALBUS: @@ -16,6 +17,8 @@ CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDri return new GVRetSerial(pPortName, false); case REMOTE: return new GVRetSerial(pPortName, true); //it's a special case of GVRET connected over TCP/IP so it uses the same class + case LAWICEL: + return new LAWICELSerial(pPortName, pSerialSpeed, pBusSpeed); case KAYAK: return new SocketCANd(pPortName); case MQTT: diff --git a/connections/canconfactory.h b/connections/canconfactory.h index 668568e..c23ce8b 100644 --- a/connections/canconfactory.h +++ b/connections/canconfactory.h @@ -7,7 +7,7 @@ class CanConFactory { public: - static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName); + static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName, int pSerialSpeed, int pBusSpeed); }; #endif // CANCONFACTORY_H diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index 8f0e231..dca0490 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -5,6 +5,8 @@ CANConnection::CANConnection(QString pPort, QString pDriver, CANCon::type pType, + int pSerialSpeed, + int pBusSpeed, int pNumBuses, int pQueueLen, bool pUseThread) : @@ -13,6 +15,7 @@ CANConnection::CANConnection(QString pPort, mPort(pPort), mDriver(pDriver), mType(pType), + mSerialSpeed(pSerialSpeed), mIsCapSuspended(false), mStatus(CANCon::NOT_CONNECTED), mStarted(false), @@ -34,6 +37,8 @@ CANConnection::CANConnection(QString pPort, mBusData[i].mConfigured = false; } + if (pBusSpeed > 0) mBusData[0].mBus.setSpeed(pBusSpeed); + /* if needed, create a thread and move ourself into it */ if(pUseThread) { mThread_p = new QThread(); diff --git a/connections/canconnection.h b/connections/canconnection.h index 38d1160..ab53fc8 100644 --- a/connections/canconnection.h +++ b/connections/canconnection.h @@ -21,13 +21,17 @@ protected: * @param pPort: string containing port name * @param pDriver: string containing driver name - Really only used for SerialBus connections * @param pType: the type of connection @ref CANCon::type + * @param pSerialSpeed: for devices with variable serial speed this is that speed. + * @param pBusSpeed: set an initial speed when opening this connection * @param pNumBuses: the number of buses the device has * @param pQueueLen: the length of the lock free queue to use * @param pUseThread: if set to true, object will be execute in a dedicated thread */ CANConnection(QString pPort, QString pDriver, - CANCon::type pType, + CANCon::type pType, + int pSerialSpeed, + int pBusSpeed, int pNumBuses, int pQueueLen, bool pUseThread); @@ -201,6 +205,7 @@ protected: int mNumBuses; //protected to allow connected device to figure out how many buses are available QVector mBusData; bool mConsoleOutput; //send debugging info to the console? + int mSerialSpeed; //determine if the passed frame is part of a filter or not. void checkTargettedFrame(CANFrame &frame); diff --git a/connections/canconnectionmodel.cpp b/connections/canconnectionmodel.cpp index aba9c7c..32a277f 100644 --- a/connections/canconnectionmodel.cpp +++ b/connections/canconnectionmodel.cpp @@ -86,6 +86,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const case CANCon::SERIALBUS: return "SerialBus"; case CANCon::GVRET_SERIAL: return "GVRET"; case CANCon::KAYAK: return "socketcand"; + case CANCon::LAWICEL: return "LAWICEL"; default: {} } else qDebug() << "Tried to show connection type but connection was nullptr"; diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index a446078..043bda8 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -250,6 +250,8 @@ void ConnectionWindow::handleNewConn() CANCon::type newType; QString newPort; QString newDriver; + int newSerialSpeed; + int newBusSpeed; CANConnection *conn; if (thisDialog->exec() == QDialog::Accepted) @@ -257,7 +259,9 @@ void ConnectionWindow::handleNewConn() newType = thisDialog->getConnectionType(); newPort = thisDialog->getPortName(); newDriver = thisDialog->getDriverName(); - conn = create(newType, newPort, newDriver); + newSerialSpeed = thisDialog->getSerialSpeed(); + newBusSpeed = thisDialog->getBusSpeed(); + conn = create(newType, newPort, newDriver, newSerialSpeed, newBusSpeed); if (conn) { connModel->add(conn); @@ -292,6 +296,7 @@ void ConnectionWindow::handleResetConn() { QString port, driver; CANCon::type type; + int serSpeed, busSpeed; int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); if (selIdx <0) return; @@ -304,13 +309,15 @@ void ConnectionWindow::handleResetConn() type = conn_p->getType(); port = conn_p->getPort(); driver = conn_p->getDriver(); + serSpeed = 0; //TODO: implement these + busSpeed = 0; /* stop and delete connection */ conn_p->stop(); conn_p = nullptr; - conn_p = create(type, port, driver); + conn_p = create(type, port, driver, serSpeed, busSpeed); if (conn_p) connModel->replace(selIdx, conn_p); } @@ -476,12 +483,12 @@ void ConnectionWindow::handleSendText() { emit sendDebugData(bytes); } -CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver) +CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver, int pSerialSpeed, int pBusSpeed) { CANConnection* conn_p; /* create connection */ - conn_p = CanConFactory::create(pTye, pPortName, pDriver); + conn_p = CanConFactory::create(pTye, pPortName, pDriver, pSerialSpeed, pBusSpeed); if(conn_p) { /* connect signal */ @@ -516,7 +523,8 @@ void ConnectionWindow::loadConnections() for(int i = 0 ; i < portNames.count() ; i++) { - CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i]); + //TODO: add serial speed and bus speed to this properly. + CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i], 0, 0); /* add connection to model */ connModel->add(conn_p); } @@ -534,6 +542,8 @@ void ConnectionWindow::saveConnections() QVector portNames; QVector devTypes; QVector driverNames; + QVector serialSpeeds; + QVector busSpeeds; /* save connections */ foreach(CANConnection* conn_p, conns) diff --git a/connections/connectionwindow.h b/connections/connectionwindow.h index b13f31f..9bc3076 100644 --- a/connections/connectionwindow.h +++ b/connections/connectionwindow.h @@ -65,7 +65,7 @@ private: QVector remoteDeviceIPGVRET; QVector remoteDeviceKayak; - CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver); + CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver, int pSerialSpeed, int pBusSpeed); void populateBusDetails(int offset); void loadConnections(); void saveConnections(); diff --git a/connections/gvretserial.cpp b/connections/gvretserial.cpp index c307b44..c7d340f 100644 --- a/connections/gvretserial.cpp +++ b/connections/gvretserial.cpp @@ -9,7 +9,7 @@ #include "gvretserial.h" GVRetSerial::GVRetSerial(QString portName, bool useTcp) : - CANConnection(portName, "gvret", CANCon::GVRET_SERIAL, 3, 4000, true), + CANConnection(portName, "gvret", CANCon::GVRET_SERIAL, 0, 0, 3, 4000, true), mTimer(this), /*NB: set this as parent of timer to manage it from working thread */ useTcp(useTcp) { diff --git a/connections/lawicel_serial.cpp b/connections/lawicel_serial.cpp new file mode 100644 index 0000000..b312bf7 --- /dev/null +++ b/connections/lawicel_serial.cpp @@ -0,0 +1,496 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lawicel_serial.h" +#include "utility.h" + +LAWICELSerial::LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed) : + CANConnection(portName, "LAWICEL", CANCon::LAWICEL,serialSpeed, lawicelSpeed, 3, 4000, true), + mTimer(this) /*NB: set this as parent of timer to manage it from working thread */ +{ + sendDebug("LAWICELSerial()"); + + serial = nullptr; + isAutoRestart = false; + + readSettings(); +} + + +LAWICELSerial::~LAWICELSerial() +{ + stop(); + sendDebug("~LAWICELSerial()"); +} + +void LAWICELSerial::sendDebug(const QString debugText) +{ + qDebug() << debugText; + debugOutput(debugText); +} + +void LAWICELSerial::sendToSerial(const QByteArray &bytes) +{ + if (serial == nullptr) + { + sendDebug("Attempt to write to serial port when it has not been initialized!"); + return; + } + + if (serial && !serial->isOpen()) + { + sendDebug("Attempt to write to serial port when it is not open!"); + return; + } + + QString buildDebug; + buildDebug = "Write to serial -> "; + foreach (int byt, bytes) { + byt = (unsigned char)byt; + buildDebug = buildDebug % QString::number(byt, 16) % " "; + } + sendDebug(buildDebug); + + if (serial) serial->write(bytes); +} + +void LAWICELSerial::piStarted() +{ + connectDevice(); +} + + +void LAWICELSerial::piSuspend(bool pSuspend) +{ + /* update capSuspended */ + setCapSuspended(pSuspend); + + /* flush queue if we are suspended */ + if(isCapSuspended()) + getQueue().flush(); +} + + +void LAWICELSerial::piStop() +{ + mTimer.stop(); + disconnectDevice(); +} + + +bool LAWICELSerial::piGetBusSettings(int pBusIdx, CANBus& pBus) +{ + return getBusConfig(pBusIdx, pBus); +} + + +void LAWICELSerial::piSetBusSettings(int pBusIdx, CANBus bus) +{ + /* sanity checks */ + if( (pBusIdx < 0) || pBusIdx >= getNumBuses()) + return; + + /* copy bus config */ + setBusConfig(pBusIdx, bus); +/* + qDebug() << "About to update bus " << pBusIdx << " on GVRET"; + if (pBusIdx == 0) + { + can0Baud = bus.getSpeed(); + can0Baud |= 0x80000000; + if (bus.isActive()) + { + can0Baud |= 0x40000000; + can0Enabled = true; + } + else can0Enabled = false; + + if (bus.isListenOnly()) + { + can0Baud |= 0x20000000; + can0ListenOnly = true; + } + else can0ListenOnly = false; + } +*/ + if (pBusIdx < 2) { + /* update baud rates */ + QByteArray buffer; + //sendDebug("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF))); + buffer[0] = (char)0xF1; //start of a command over serial + //sendToSerial(buffer); + } + +} + + +bool LAWICELSerial::piSendFrame(const CANFrame& frame) +{ + QByteArray buffer; + int c; + quint32 ID; + + //qDebug() << "Sending out lawicel frame with id " << frame.ID << " on bus " << frame.bus; + + framesRapid++; + + if (serial == nullptr) return false; + if (serial && !serial->isOpen()) return false; + //if (!isConnected) return false; + + // Doesn't make sense to send an error frame + // to an adapter + if (frame.frameId() & 0x20000000) { + return true; + } + + ID = frame.frameId(); + if (frame.hasExtendedFrameFormat()) ID |= 1u << 31; + + int idx = 0; + QString buildStr; + if (frame.hasExtendedFrameFormat()) + { + buildStr = QString::asprintf("T%08X%u", ID, frame.payload().length()); + } + else + { + buildStr = QString::asprintf("t%03X%u", ID, frame.payload().length()); + } + foreach (QChar chr, buildStr) + { + buffer[idx] = chr.toLatin1(); + idx++; + } + + for (c = 0; c < frame.payload().length(); c++) + { + QString byt = Utility::formatByteAsHex(frame.payload()[c]); + buffer[idx + (c * 2)] = byt[0].toLatin1(); + buffer[idx + (c * 2) + 1] = byt[1].toLatin1(); + } + buffer[idx + (frame.payload().length() * 2)] = 13; //CR + + sendToSerial(buffer); + + return true; +} + + + +/****************************************************************/ + +void LAWICELSerial::readSettings() +{ + QSettings settings; +} + + +void LAWICELSerial::connectDevice() +{ + QSettings settings; + + /* disconnect device */ + if(serial) + disconnectDevice(); + + /* open new device */ + + qDebug() << "Serial port: " << getPort(); + + serial = new QSerialPort(QSerialPortInfo(getPort())); + if(!serial) { + sendDebug("can't open serial port " + getPort()); + return; + } + sendDebug("Created Serial Port Object"); + + /* connect reading event */ + connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData())); + connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialError(QSerialPort::SerialPortError))); + + /* configure */ + serial->setBaudRate(mSerialSpeed); + serial->setDataBits(serial->Data8); + + serial->setFlowControl(serial->HardwareControl); + //serial->setFlowControl(serial->NoFlowControl); + if (!serial->open(QIODevice::ReadWrite)) + { + //sendDebug("Error returned during port opening: " + serial->errorString()); + } + else + { + //serial->setDataTerminalReady(true); //Seemingly these two lines used to be needed + //serial->setRequestToSend(true); //But, really both ends should automatically handle these + deviceConnected(); + } +} + +void LAWICELSerial::deviceConnected() +{ + sendDebug("Connecting to LAWICEL Device!"); + + QByteArray output; + + output.clear(); + output.append('C'); //close the bus in case it was already up + output.append(13); + sendToSerial(output); + + output.clear(); + output.append('S'); //configure speed of bus + switch (this->mBusData[0].mBus.getSpeed()) + { + case 10000: + output.append('0'); + break; + case 20000: + output.append('1'); + break; + case 50000: + output.append('2'); + break; + case 100000: + output.append('3'); + break; + case 125000: + output.append('4'); + break; + case 250000: + output.append('5'); + break; + case 500000: + output.append('6'); + break; + case 800000: + output.append('7'); + break; + case 1000000: + output.append('8'); + break; + default: + output.append('6'); + break; + } + output.append('\x0D'); + + sendToSerial(output); + + output.clear(); + output.append('O'); //open bus now that we set the speed + output.append(13); + + sendToSerial(output); + + mNumBuses = 1; + setStatus(CANCon::CONNECTED); + CANConStatus stats; + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + mBusData[0].mConfigured = true; + mBusData[0].mBus.setActive(true); + //mBusData[0].mBus.setSpeed(); + emit status(stats); +} + +void LAWICELSerial::disconnectDevice() { + if (serial != nullptr) + { + if (serial->isOpen()) + { + //serial->clear(); + serial->close(); + + } + serial->disconnect(); //disconnect all signals + delete serial; + serial = nullptr; + } + + setStatus(CANCon::NOT_CONNECTED); + CANConStatus stats; + stats.conStatus = getStatus(); + stats.numHardwareBuses = mNumBuses; + emit status(stats); +} + +void LAWICELSerial::serialError(QSerialPort::SerialPortError err) +{ + QString errMessage; + bool killConnection = false; + switch (err) + { + case QSerialPort::NoError: + return; + case QSerialPort::DeviceNotFoundError: + errMessage = "Device not found error on serial"; + killConnection = true; + piStop(); + break; + case QSerialPort::PermissionError: + errMessage = "Permission error on serial port"; + killConnection = true; + piStop(); + break; + case QSerialPort::OpenError: + errMessage = "Open error on serial port"; + killConnection = true; + piStop(); + break; + case QSerialPort::ParityError: + errMessage = "Parity error on serial port"; + break; + case QSerialPort::FramingError: + errMessage = "Framing error on serial port"; + break; + case QSerialPort::BreakConditionError: + errMessage = "Break error on serial port"; + break; + case QSerialPort::WriteError: + errMessage = "Write error on serial port"; + piStop(); + break; + case QSerialPort::ReadError: + errMessage = "Read error on serial port"; + piStop(); + break; + case QSerialPort::ResourceError: + errMessage = "Serial port seems to have disappeared."; + killConnection = true; + piStop(); + break; + case QSerialPort::UnsupportedOperationError: + errMessage = "Unsupported operation on serial port"; + killConnection = true; + break; + case QSerialPort::UnknownError: + errMessage = "Beats me what happened to the serial port."; + killConnection = true; + piStop(); + break; + case QSerialPort::TimeoutError: + errMessage = "Timeout error on serial port"; + killConnection = true; + break; + case QSerialPort::NotOpenError: + errMessage = "The serial port isn't open"; + killConnection = true; + piStop(); + break; + } + /* + if (serial) + { + serial->clearError(); + serial->flush(); + serial->close(); + }*/ + if (errMessage.length() > 1) + { + sendDebug(errMessage); + } + if (killConnection) + { + qDebug() << "Shooting the serial object in the head. It deserves it."; + disconnectDevice(); + } +} + + +void LAWICELSerial::connectionTimeout() +{ + //one second after trying to connect are we actually connected? + if (CANCon::NOT_CONNECTED==getStatus()) //no? + { + //then emit the the failure signal and see if anyone cares + sendDebug("Failed to connect to LAWICEL at that com port"); + + disconnectDevice(); + connectDevice(); + } + else + { + /* start timer */ + connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick())); + mTimer.setInterval(250); //tick four times per second + mTimer.setSingleShot(false); //keep ticking + mTimer.start(); + } +} + +void LAWICELSerial::readSerialData() +{ + QByteArray data; + unsigned char c; + QString debugBuild; + CANFrame buildFrame; + QByteArray buildData; + + if (serial) data = serial->readAll(); + + sendDebug("Got data from serial. Len = " % QString::number(data.length())); + for (int i = 0; i < data.length(); i++) + { + c = data.at(i); + //qDebug() << c << " " << QString::number(c, 16) << " " << QString(c); + debugBuild = debugBuild % QString::number(c, 16).rightJustified(2,'0') % " "; + //procRXChar(c); + mBuildLine.append(c); + if (c == 13) //all lawicel commands end in CR + { + qDebug() << "Got CR!"; + switch (mBuildLine[0].toLatin1()) + { + case 't': //standard frame + //tIIILDD + buildFrame.setFrameId(mBuildLine.mid(1, 3).toInt(nullptr, 16)); + buildFrame.isReceived = true; + buildFrame.setFrameType(QCanBusFrame::FrameType::DataFrame); + buildData.resize(mBuildLine.mid(4, 1).toInt()); + for (int c = 0; c < buildData.size(); c++) + { + buildData[c] = mBuildLine.mid(5 + (c*2), 2).toInt(nullptr, 16); + } + buildFrame.setPayload(buildData); + if (!isCapSuspended()) + { + /* get frame from queue */ + CANFrame* frame_p = getQueue().get(); + if(frame_p) { + //qDebug() << "Lawicel got frame on bus " << frame_p->bus; + /* copy frame */ + *frame_p = buildFrame; + checkTargettedFrame(buildFrame); + /* enqueue frame */ + getQueue().queue(); + } + else + qDebug() << "can't get a frame, ERROR"; + } + break; + case 'T': //extended frame + break; + } + mBuildLine.clear(); + } + } + debugOutput(debugBuild); + //qDebug() << debugBuild; +} + +//Debugging data sent from connection window. Inject it into Comm traffic. +void LAWICELSerial::debugInput(QByteArray bytes) { + sendToSerial(bytes); +} + +void LAWICELSerial::handleTick() +{ + //qDebug() << "Tick!"; +} + diff --git a/connections/lawicel_serial.h b/connections/lawicel_serial.h new file mode 100644 index 0000000..555d089 --- /dev/null +++ b/connections/lawicel_serial.h @@ -0,0 +1,66 @@ +#ifndef LAWICELSERIAL_H +#define LAWICELSERIAL_H + +#include +#include +#include +#include + +/*************/ +#include +/*************/ + +#include "canframemodel.h" +#include "canconnection.h" +#include "canconmanager.h" + +class LAWICELSerial : public CANConnection +{ + Q_OBJECT + +public: + LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed); + virtual ~LAWICELSerial(); + +protected: + + virtual void piStarted(); + virtual void piStop(); + virtual void piSetBusSettings(int pBusIdx, CANBus pBus); + virtual bool piGetBusSettings(int pBusIdx, CANBus& pBus); + virtual void piSuspend(bool pSuspend); + virtual bool piSendFrame(const CANFrame&) ; + + void disconnectDevice(); + +public slots: + void debugInput(QByteArray bytes); + +private slots: + void connectDevice(); + void connectionTimeout(); + void readSerialData(); + void serialError(QSerialPort::SerialPortError err); + void deviceConnected(); + void handleTick(); + +private: + void readSettings(); + void rebuildLocalTimeBasis(); + void sendToSerial(const QByteArray &bytes); + void sendDebug(const QString debugText); + +protected: + QTimer mTimer; + QThread mThread; + QString mBuildLine; + + bool isAutoRestart; + QSerialPort *serial; + int framesRapid; + CANFrame buildFrame; + bool can0Enabled; + bool can0ListenOnly; +}; + +#endif // LAWICELSERIAL_H diff --git a/connections/mqtt_bus.cpp b/connections/mqtt_bus.cpp index 6b05be5..bfaa04b 100644 --- a/connections/mqtt_bus.cpp +++ b/connections/mqtt_bus.cpp @@ -9,7 +9,7 @@ #include "mqtt_bus.h" MQTT_BUS::MQTT_BUS(QString topicName) : - CANConnection(topicName, "mqtt_client", CANCon::MQTT, 1, 4000, true), + CANConnection(topicName, "mqtt_client", CANCon::MQTT, 0, 0, 1, 4000, true), mTimer(this) /*NB: set this as parent of timer to manage it from working thread */ { diff --git a/connections/newconnectiondialog.cpp b/connections/newconnectiondialog.cpp index db4a721..88383b0 100644 --- a/connections/newconnectiondialog.cpp +++ b/connections/newconnectiondialog.cpp @@ -27,12 +27,17 @@ NewConnectionDialog::NewConnectionDialog(QVector* gvretips, QVectorrbRemote, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); connect(ui->rbKayak, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); connect(ui->rbMQTT, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); + connect(ui->rbLawicel, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); connect(ui->cbDeviceType, QOverload::of(&QComboBox::currentIndexChanged), this, &NewConnectionDialog::handleDeviceTypeChanged); connect(ui->btnOK, &QPushButton::clicked, this, &NewConnectionDialog::handleCreateButton); ui->lblDeviceType->setHidden(true); ui->cbDeviceType->setHidden(true); + ui->cbCANSpeed->setHidden(true); + ui->cbSerialSpeed->setHidden(true); + ui->lblCANSpeed->setHidden(true); + ui->lblSerialSpeed->setHidden(true); selectSerial(); qDebug() << "Was passed " << remoteDeviceIPGVRET->count() << " remote GVRET IPs"; @@ -53,6 +58,7 @@ void NewConnectionDialog::handleConnTypeChanged() { if (ui->rbGVRET->isChecked()) selectSerial(); if (ui->rbSocketCAN->isChecked()) selectSocketCan(); + if (ui->rbLawicel->isChecked()) selectLawicel(); if (ui->rbRemote->isChecked()) selectRemote(); if (ui->rbKayak->isChecked()) selectKayak(); if (ui->rbMQTT->isChecked()) selectMQTT(); @@ -68,12 +74,57 @@ void NewConnectionDialog::handleDeviceTypeChanged() ui->cbPort->addItem(canDevices[i].name()); } +void NewConnectionDialog::selectLawicel() +{ + ui->lPort->setText("Serial Port:"); + + ui->lblDeviceType->setHidden(true); + ui->cbDeviceType->setHidden(true); + + ui->cbCANSpeed->setHidden(false); + ui->cbSerialSpeed->setHidden(false); + ui->lblCANSpeed->setHidden(false); + ui->lblSerialSpeed->setHidden(false); + + ui->cbPort->clear(); + ports = QSerialPortInfo::availablePorts(); + + for (int i = 0; i < ports.count(); i++) + ui->cbPort->addItem(ports[i].portName()); + + if (ui->cbCANSpeed->count() == 0) + { + ui->cbCANSpeed->addItem("10000"); + ui->cbCANSpeed->addItem("20000"); + ui->cbCANSpeed->addItem("50000"); + ui->cbCANSpeed->addItem("100000"); + ui->cbCANSpeed->addItem("125000"); + ui->cbCANSpeed->addItem("250000"); + ui->cbCANSpeed->addItem("500000"); + ui->cbCANSpeed->addItem("1000000"); + } + if (ui->cbSerialSpeed->count() == 0) + { + ui->cbSerialSpeed->addItem("115200"); + ui->cbSerialSpeed->addItem("150000"); + ui->cbSerialSpeed->addItem("250000"); + ui->cbSerialSpeed->addItem("500000"); + ui->cbSerialSpeed->addItem("1000000"); + ui->cbSerialSpeed->addItem("2000000"); + } + +} + void NewConnectionDialog::selectSerial() { ui->lPort->setText("Serial Port:"); ui->lblDeviceType->setHidden(true); ui->cbDeviceType->setHidden(true); + ui->cbCANSpeed->setHidden(true); + ui->cbSerialSpeed->setHidden(true); + ui->lblCANSpeed->setHidden(true); + ui->lblSerialSpeed->setHidden(true); ui->cbPort->clear(); ports = QSerialPortInfo::availablePorts(); @@ -87,6 +138,10 @@ void NewConnectionDialog::selectSocketCan() ui->lPort->setText("Port:"); ui->lblDeviceType->setHidden(false); ui->cbDeviceType->setHidden(false); + ui->cbCANSpeed->setHidden(true); + ui->cbSerialSpeed->setHidden(true); + ui->lblCANSpeed->setHidden(true); + ui->lblSerialSpeed->setHidden(true); ui->cbDeviceType->clear(); QStringList plugins; @@ -99,8 +154,14 @@ void NewConnectionDialog::selectSocketCan() void NewConnectionDialog::selectRemote() { ui->lPort->setText("IP Address:"); + ui->lblDeviceType->setHidden(true); ui->cbDeviceType->setHidden(true); + ui->cbCANSpeed->setHidden(true); + ui->cbSerialSpeed->setHidden(true); + ui->lblCANSpeed->setHidden(true); + ui->lblSerialSpeed->setHidden(true); + ui->cbPort->clear(); foreach(QString pName, *remoteDeviceIPGVRET) { @@ -111,8 +172,14 @@ void NewConnectionDialog::selectRemote() void NewConnectionDialog::selectKayak() { ui->lPort->setText("Available Bus(ses):"); + ui->lblDeviceType->setHidden(true); ui->cbDeviceType->setHidden(true); + ui->cbCANSpeed->setHidden(true); + ui->cbSerialSpeed->setHidden(true); + ui->lblCANSpeed->setHidden(true); + ui->lblSerialSpeed->setHidden(true); + ui->cbPort->clear(); foreach(QString pName, *remoteBusKayak) { @@ -123,8 +190,14 @@ void NewConnectionDialog::selectKayak() void NewConnectionDialog::selectMQTT() { ui->lPort->setText("Topic Name:"); + ui->lblDeviceType->setHidden(true); ui->cbDeviceType->setHidden(true); + ui->cbCANSpeed->setHidden(true); + ui->cbSerialSpeed->setHidden(true); + ui->lblCANSpeed->setHidden(true); + ui->lblSerialSpeed->setHidden(true); + ui->cbPort->clear(); } @@ -148,6 +221,8 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt case CANCon::MQTT: ui->rbMQTT->setChecked(true); break; + case CANCon::LAWICEL: + ui->rbLawicel->setChecked(true); default: {} } @@ -157,6 +232,7 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt switch(pType) { case CANCon::GVRET_SERIAL: + case CANCon::LAWICEL: { int idx = ui->cbPort->findText(pPortName); if( idx<0 ) idx=0; @@ -201,6 +277,7 @@ QString NewConnectionDialog::getPortName() case CANCon::SERIALBUS: case CANCon::REMOTE: case CANCon::MQTT: + case CANCon::LAWICEL: return ui->cbPort->currentText(); case CANCon::KAYAK: return ui->cbPort->currentText(); @@ -220,6 +297,24 @@ QString NewConnectionDialog::getDriverName() return "N/A"; } +int NewConnectionDialog::getSerialSpeed() +{ + if (getConnectionType() == CANCon::LAWICEL) + { + return ui->cbSerialSpeed->currentText().toInt(); + } + else return 0; +} + +int NewConnectionDialog::getBusSpeed() +{ + if (getConnectionType() == CANCon::LAWICEL) + { + return ui->cbCANSpeed->currentText().toInt(); + } + else return 0; +} + CANCon::type NewConnectionDialog::getConnectionType() { if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL; @@ -227,6 +322,7 @@ CANCon::type NewConnectionDialog::getConnectionType() if (ui->rbRemote->isChecked()) return CANCon::REMOTE; if (ui->rbKayak->isChecked()) return CANCon::KAYAK; if (ui->rbMQTT->isChecked()) return CANCon::MQTT; + if (ui->rbLawicel->isChecked()) return CANCon::LAWICEL; qDebug() << "getConnectionType: error"; return CANCon::NONE; diff --git a/connections/newconnectiondialog.h b/connections/newconnectiondialog.h index 1410b42..938d2d2 100644 --- a/connections/newconnectiondialog.h +++ b/connections/newconnectiondialog.h @@ -24,6 +24,8 @@ public: CANCon::type getConnectionType(); QString getPortName(); QString getDriverName(); + int getSerialSpeed(); + int getBusSpeed(); public slots: void handleConnTypeChanged(); @@ -43,6 +45,7 @@ private: void selectRemote(); void selectKayak(); void selectMQTT(); + void selectLawicel(); bool isSerialBusAvailable(); void setPortName(CANCon::type pType, QString pPortName, QString pDriver); }; diff --git a/connections/serialbusconnection.cpp b/connections/serialbusconnection.cpp index 6ea71c3..b1a2f6e 100644 --- a/connections/serialbusconnection.cpp +++ b/connections/serialbusconnection.cpp @@ -12,7 +12,7 @@ /***********************************/ SerialBusConnection::SerialBusConnection(QString portName, QString driverName) : - CANConnection(portName, driverName, CANCon::SERIALBUS, 1, 4000, true), + CANConnection(portName, driverName, CANCon::SERIALBUS,0 ,0 ,1, 4000, true), mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */ { } diff --git a/connections/socketcand.cpp b/connections/socketcand.cpp index 9bbddbb..6fbf5e4 100644 --- a/connections/socketcand.cpp +++ b/connections/socketcand.cpp @@ -10,7 +10,7 @@ #include "socketcand.h" SocketCANd::SocketCANd(QString portName) : - CANConnection(portName, "kayak", CANCon::KAYAK, 1, 4000, true), + CANConnection(portName, "kayak", CANCon::KAYAK, 0, 0, 1, 4000, true), mTimer(this) /*NB: set this as parent of timer to manage it from working thread */ { diff --git a/ui/newconnectiondialog.ui b/ui/newconnectiondialog.ui index faa847a..a257907 100644 --- a/ui/newconnectiondialog.ui +++ b/ui/newconnectiondialog.ui @@ -6,8 +6,8 @@ 0 0 - 356 - 282 + 426 + 540 @@ -23,6 +23,30 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + socketcand (SocketCAN over Ethernet) + + + + + + + false + + + QT SerialBus Devices (SocketCAN, PeakCAN, etc) + + + + + + + MQTT Connection + + + @@ -40,27 +64,10 @@ - - - - false - + + - QT SerialBus Devices (SocketCAN, PeakCAN, etc) - - - - - - - socketcand (SocketCAN over Ethernet) - - - - - - - MQTT Connection + LAWICEL / SLCAN Serial @@ -109,6 +116,39 @@ + + + + Serial Port Speed: + + + + + + + + + + CAN Bus Speed: + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + From 61b49c9126bc69c73d904bbd0f47e920a59a784a Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Tue, 4 Oct 2022 19:54:55 -0400 Subject: [PATCH 10/15] Changed the UDS Scan window quite a bit. Now there are more options for scan types and the ability to create a list of scans to run. --- re/udsscanwindow.cpp | 691 +++++++++++++++++++++++++++++++--------- re/udsscanwindow.h | 61 +++- ui/udsscanwindow.ui | 733 ++++++++++++++++++++++++------------------- 3 files changed, 1010 insertions(+), 475 deletions(-) diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 630ccab..69d6d51 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -6,6 +6,23 @@ #include "utility.h" #include "helpwindow.h" + +static QVector SCANTYPE_NAMES = { + QString("Tester Present"), + QString("Session Control"), + QString("Communication Control"), + QString("ECU Reset"), + QString("Clear DTCs"), + QString("Read DTCs"), + QString("Security Access"), + QString("Read By ID"), + QString("Read By Address"), + QString("Read Scaling Data By ID"), + QString("IO Control"), + QString("Routine Control"), + QString("Custom UDS"), +}; + UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : QDialog(parent), ui(new Ui::UDSScanWindow) @@ -21,15 +38,23 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : waitTimer->setInterval(100); udsHandler = new UDS_HANDLER; + inhibitUpdates = false; + + for (int i = 0; i < 13; i++) ui->cbScanType->addItem(SCANTYPE_NAMES[i]); + + ui->cbSessType->addItem("No Change"); + ui->cbSessType->addItem("Default"); + ui->cbSessType->addItem("Programming"); + ui->cbSessType->addItem("Extended Diag"); + ui->cbSessType->addItem("Safety Sys Diag"); connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); connect(udsHandler, &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply); - connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); + connect(ui->btnScanAll, &QPushButton::clicked, this, &UDSScanWindow::scanAll); + connect(ui->btnScanSelected, &QPushButton::clicked, this, &UDSScanWindow::scanSelected); connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults); - connect(ui->ckWildcard, &QCheckBox::toggled, this, &UDSScanWindow::wildcardToggled); - connect(ui->ckReadByAddr, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled); - connect(ui->ckReadByID, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled); + connect(ui->cbScanType, &QComboBox::currentTextChanged, this, &UDSScanWindow::changedScanType); connect(ui->cbAllowAdaptiveOffset, &QCheckBox::toggled, this, &UDSScanWindow::adaptiveToggled); connect(ui->spinNumBytes, SIGNAL(valueChanged(int)), this, SLOT(numBytesChanged())); connect(ui->spinLowerService, SIGNAL(valueChanged(int)), this, SLOT(checkServiceRange())); @@ -38,10 +63,23 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : connect(ui->spinUpperSubfunc, SIGNAL(valueChanged(int)), this, SLOT(checkSubFuncRange())); connect(ui->spinStartID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange())); connect(ui->spinEndID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange())); + connect(ui->btnAdd, &QPushButton::clicked, this, &UDSScanWindow::addNewScan); + connect(ui->btnDelete, &QPushButton::clicked, this, &UDSScanWindow::deleteSelectedScan); + connect(ui->btnSave, &QPushButton::clicked, this, &UDSScanWindow::saveScans); + connect(ui->btnLoad, &QPushButton::clicked, this, &UDSScanWindow::loadScans); + connect(ui->listScansToRun, &QListWidget::currentRowChanged, this, &UDSScanWindow::displayScanEntry); + connect(ui->ckShowNoReply, &QCheckBox::toggled, this, &UDSScanWindow::setNoReplyVal); + connect(ui->spinDelay, SIGNAL(valueChanged(int)), this, SLOT(setMaxDelayVal())); + connect(ui->spinIncrement, SIGNAL(valueChanged(int)), this, SLOT(setIncrementVal())); + connect(ui->spinReplyOffset, SIGNAL(valueChanged(int)), this, SLOT(setReplyOffset())); + connect(ui->cbSessType, &QComboBox::currentTextChanged, this, &UDSScanWindow::setSessType); +//not handling show no reply, max reply delay, reply offset, increment int numBuses = CANConManager::getInstance()->getNumBuses(); for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); installEventFilter(this); + + addNewScan(); } UDSScanWindow::~UDSScanWindow() @@ -71,74 +109,368 @@ bool UDSScanWindow::eventFilter(QObject *obj, QEvent *event) return false; } +void UDSScanWindow::displayScanEntry(int idx) +{ + if (inhibitUpdates) return; + if (idx == -1) return; + currEditEntry = &scanEntries.data()[idx]; + ui->spinStartID->setValue(currEditEntry->startID); + ui->spinEndID->setValue(currEditEntry->endID); + ui->spinReplyOffset->setValue(currEditEntry->idOffset); + ui->cbAllowAdaptiveOffset->setChecked(currEditEntry->bAdaptiveOffset); + ui->ckShowNoReply->setChecked(currEditEntry->bShowNoReplies); + ui->cbBuses->setCurrentIndex(currEditEntry->busToScan); + ui->spinDelay->setValue(currEditEntry->maxWaitTime); + ui->cbScanType->setCurrentIndex((int)currEditEntry->scanType); + ui->cbSessType->setCurrentIndex(currEditEntry->sessType); + ui->spinNumBytes->setValue(currEditEntry->subfunctLen); + ui->spinLowerService->setValue(currEditEntry->serviceLower); + ui->spinUpperService->setValue(currEditEntry->serviceUpper); + ui->spinLowerSubfunc->setValue(currEditEntry->subfunctLower); + ui->spinUpperSubfunc->setValue(currEditEntry->subfunctUpper); + ui->spinIncrement->setValue(currEditEntry->subfunctIncrement); +} + +void UDSScanWindow::deleteSelectedScan() +{ + int idx = ui->listScansToRun->currentRow(); + if (idx == -1) return; + scanEntries.removeAt(idx); + + QListWidgetItem *item = ui->listScansToRun->takeItem(idx); + delete item; + int rows = ui->listScansToRun->count(); + ui->listScansToRun->setCurrentRow(rows - 1); + + for (int i = 0; i < rows; i++) + { + QListWidgetItem *item = ui->listScansToRun->item(i); + item->setText(generateListDesc(i)); + } +} + +void UDSScanWindow::addNewScan() +{ + ScanEntry newEntry; + newEntry.busToScan = 0; + newEntry.scanType = SCAN_TYPE::ST_TESTER_PRESENT; + newEntry.sessType = 0; + newEntry.bAdaptiveOffset = false; + newEntry.bShowNoReplies = false; + newEntry.idOffset = 8; + newEntry.startID = 0x7E0; + newEntry.endID = 0x7E7; + newEntry.maxWaitTime = 100; + newEntry.subfunctLen = 1; + newEntry.subfunctIncrement = 1; + newEntry.subfunctLower = 0; + newEntry.subfunctUpper = 0; + newEntry.serviceLower = 1; + newEntry.serviceUpper = 1; + scanEntries.append(newEntry); + displayScanEntry(scanEntries.length() - 1); + ui->listScansToRun->addItem(generateListDesc(scanEntries.length() - 1)); + ui->listScansToRun->setCurrentRow(ui->listScansToRun->count() - 1); +} + +void UDSScanWindow::loadScans() +{ + QString filename; + QFileDialog dialog(qApp->activeWindow()); + QSettings settings; + bool result = false; + + QStringList filters; + filters.append(QString(tr("UDS Test Specification (*.uds *.UDS)"))); + + dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString()); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.setViewMode(QFileDialog::Detail); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + + if (dialog.exec() == QDialog::Accepted) + { + filename = dialog.selectedFiles()[0]; + QFile inFile(filename); + inFile.open(QIODevice::ReadOnly); + QDataStream load(&inFile); + int fileVersion; + load >> fileVersion; + if (fileVersion != 1) + { + QMessageBox::warning(this, "Cannot Load File", "File is not a supported version.\nCannot load it!"); + return; + } + inhibitUpdates = true;; + scanEntries.clear(); + ui->listScansToRun->clear(); + int numEntries; + load >> numEntries; + for (int i = 0; i < numEntries; i++) + { + ScanEntry entry; + load >> entry.startID >> entry.endID; + load >> entry.idOffset >> entry.bAdaptiveOffset >> entry.bShowNoReplies; + load >> entry.busToScan >> entry.maxWaitTime >> entry.scanType; + load >> entry.sessType >> entry.subfunctLen >> entry.subfunctLower; + load >> entry.subfunctUpper >> entry.subfunctIncrement; + load >> entry.serviceLower >> entry.serviceUpper; + scanEntries.append(entry); + ui->listScansToRun->addItem(generateListDesc(scanEntries.length() - 1)); + } + inFile.close(); + inhibitUpdates = false; + ui->listScansToRun->setCurrentRow(ui->listScansToRun->count() - 1); + displayScanEntry(scanEntries.length() - 1); + } +} + +void UDSScanWindow::saveScans() +{ + QString filename; + QFileDialog dialog(qApp->activeWindow()); + QSettings settings; + bool result = false; + + QStringList filters; + filters.append(QString(tr("UDS Test Specification (*.uds *.UDS)"))); + + dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString()); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.setViewMode(QFileDialog::Detail); + dialog.setAcceptMode(QFileDialog::AcceptSave); + + if (dialog.exec() == QDialog::Accepted) + { + filename = dialog.selectedFiles()[0]; + QFile outFile(filename); + outFile.open(QIODevice::WriteOnly); + QDataStream save(&outFile); + save << 1; //file version + save << scanEntries.count(); + for (int i = 0; i < scanEntries.count(); i++) + { + save << scanEntries[i].startID; + save << scanEntries[i].endID; + save << scanEntries[i].idOffset; + save << scanEntries[i].bAdaptiveOffset; + save << scanEntries[i].bShowNoReplies; + save << scanEntries[i].busToScan; + save << scanEntries[i].maxWaitTime; + save << scanEntries[i].scanType; + save << scanEntries[i].sessType; + save << scanEntries[i].subfunctLen; + save << scanEntries[i].subfunctLower; + save << scanEntries[i].subfunctUpper; + save << scanEntries[i].subfunctIncrement; + save << scanEntries[i].serviceLower; + save << scanEntries[i].serviceUpper; + } + outFile.close(); + } +} + +QString UDSScanWindow::generateListDesc(int idx) +{ + QString builder; + ScanEntry entry = scanEntries[idx]; + builder = "(0x" + QString::number(entry.startID, 16) + " - 0x" + QString::number(entry.endID, 16) + ") "; + switch (entry.scanType) + { + case ST_TESTER_PRESENT: + builder += "TP"; + break; + case ST_SESS_CTRL: + builder += "SESS"; + break; + case ST_COMM_CTRL: + builder += "COMM"; + break; + case ST_ECU_RESET: + builder += "ECU"; + break; + case ST_CLEAR_DTC: + builder += "CDTC"; + break; + case ST_READ_DTC: + builder += "RDTC"; + break; + case ST_SEC_ACCESS: + builder += "SECU"; + break; + case ST_READ_ID: + builder += "RID"; + break; + case ST_READ_ADDR: + builder += "RADD"; + break; + case ST_READ_SCALING: + builder += "RSCAL"; + break; + case ST_IO_CTRL: + builder += "IO"; + break; + case ST_ROUTINE_CTRL: + builder += "ROUT"; + break; + case ST_CUSTOM: + builder += "CUST"; + break; + } + return builder; +} + void UDSScanWindow::adaptiveToggled() { + if (inhibitUpdates) return; if (ui->cbAllowAdaptiveOffset->isChecked()) ui->spinReplyOffset->setEnabled(false); else ui->spinReplyOffset->setEnabled(true); + if (currEditEntry) currEditEntry->bAdaptiveOffset = ui->cbAllowAdaptiveOffset->isChecked(); } -void UDSScanWindow::wildcardToggled() +void UDSScanWindow::setSessType() { - bool state = false; - if (ui->ckWildcard->isChecked()) state = false; - else state = true; - - ui->ckReset->setEnabled(state); - ui->ckSecurity->setEnabled(state); - ui->ckSession->setEnabled(state); - ui->ckTester->setEnabled(state); - ui->ckReadByAddr->setEnabled(state); - ui->ckReadByID->setEnabled(state); - ui->ckReset->setChecked(false); - ui->ckSecurity->setChecked(false); - ui->ckSession->setChecked(false); - ui->ckTester->setChecked(false); - ui->ckReadByAddr->setChecked(false); - ui->ckReadByID->setChecked(false); - - ui->spinLowerService->setEnabled(!state); - ui->spinLowerSubfunc->setEnabled(!state); - ui->spinNumBytes->setEnabled(!state); - ui->spinUpperService->setEnabled(!state); - ui->spinUpperSubfunc->setEnabled(!state); + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->sessType = ui->cbSessType->currentIndex(); } -void UDSScanWindow::readByToggled() +void UDSScanWindow::setNoReplyVal() { - bool state = false; - if (ui->ckReadByAddr->isChecked() || ui->ckReadByID->isChecked()) state = true; - else state = false; + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->bShowNoReplies = ui->ckShowNoReply->isChecked(); +} - ui->spinLowerService->setEnabled(false); - ui->spinLowerSubfunc->setEnabled(state); - ui->spinNumBytes->setEnabled(state); - ui->spinUpperService->setEnabled(false); - ui->spinUpperSubfunc->setEnabled(state); +void UDSScanWindow::setMaxDelayVal() +{ + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->maxWaitTime = ui->spinDelay->value(); +} + +void UDSScanWindow::setIncrementVal() +{ + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->subfunctIncrement = ui->spinIncrement->value(); +} + +void UDSScanWindow::setReplyOffset() +{ + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->idOffset = ui->spinReplyOffset->value(); +} + +void UDSScanWindow::changedScanType() +{ + if (inhibitUpdates) return; + int idx = ui->cbScanType->currentIndex(); + if (idx == -1) + { + ui->cbScanType->setCurrentIndex(0); + idx = 0; + } + + if (currEditEntry) currEditEntry->scanType = (SCAN_TYPE)idx; + + QListWidgetItem* item = ui->listScansToRun->currentItem(); + item->setText(generateListDesc(ui->listScansToRun->currentRow())); + + switch (idx) + { + case ST_TESTER_PRESENT: + case ST_SESS_CTRL: + ui->cbSessType->setEnabled(false); + ui->spinLowerService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinUpperSubfunc->setEnabled(false); + ui->spinNumBytes->setEnabled(false); + ui->spinIncrement->setEnabled(false); + ui->cbSessType->setCurrentIndex(0); + break; + case ST_COMM_CTRL: + case ST_ECU_RESET: + case ST_CLEAR_DTC: + case ST_SEC_ACCESS: + case ST_READ_DTC: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(false); + ui->spinUpperSubfunc->setEnabled(false); + ui->spinNumBytes->setEnabled(false); + ui->spinIncrement->setEnabled(false); + break; + case ST_IO_CTRL: + case ST_ROUTINE_CTRL: + case ST_READ_SCALING: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(true); + ui->spinUpperSubfunc->setEnabled(true); + ui->spinNumBytes->setEnabled(false); + ui->spinNumBytes->setValue(2); + ui->spinIncrement->setEnabled(true); + break; + case ST_READ_ID: + case ST_READ_ADDR: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(true); + ui->spinUpperSubfunc->setEnabled(true); + ui->spinNumBytes->setEnabled(true); + ui->spinIncrement->setEnabled(true); + break; + case ST_CUSTOM: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(true); + ui->spinUpperService->setEnabled(true); + ui->spinLowerSubfunc->setEnabled(true); + ui->spinUpperSubfunc->setEnabled(true); + ui->spinNumBytes->setEnabled(true); + ui->spinIncrement->setEnabled(true); + break; + } } void UDSScanWindow::numBytesChanged() { + if (inhibitUpdates) return; uint64_t upperBound = (1ull << (8ull * ui->spinNumBytes->value())) - 1; if (upperBound > 0x7FFFFFFF) upperBound = 0x7FFFFFFF; ui->spinUpperSubfunc->setMaximum(upperBound); + if (currEditEntry) currEditEntry->subfunctLen = ui->spinNumBytes->value(); } void UDSScanWindow::checkIDRange() { + if (inhibitUpdates) return; ui->spinStartID->setMaximum(ui->spinEndID->value()); ui->spinEndID->setMinimum(ui->spinStartID->value()); + if (currEditEntry) currEditEntry->startID = ui->spinStartID->value(); + if (currEditEntry) currEditEntry->endID = ui->spinEndID->value(); + QListWidgetItem* item = ui->listScansToRun->currentItem(); + item->setText(generateListDesc(ui->listScansToRun->currentRow())); } void UDSScanWindow::checkServiceRange() { + if (inhibitUpdates) return; ui->spinLowerService->setMaximum(ui->spinUpperService->value()); ui->spinUpperService->setMinimum(ui->spinLowerService->value()); + if (currEditEntry) currEditEntry->serviceLower = ui->spinLowerService->value(); + if (currEditEntry) currEditEntry->serviceUpper = ui->spinUpperService->value(); } void UDSScanWindow::checkSubFuncRange() { + if (inhibitUpdates) return; ui->spinLowerSubfunc->setMaximum(ui->spinUpperSubfunc->value()); ui->spinUpperSubfunc->setMinimum(ui->spinLowerSubfunc->value()); + if (currEditEntry) currEditEntry->subfunctLower = ui->spinLowerSubfunc->value(); + if (currEditEntry) currEditEntry->subfunctUpper = ui->spinUpperSubfunc->value(); } void UDSScanWindow::saveResults() @@ -196,20 +528,27 @@ void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses) sendingFrames.append(test); } -void UDSScanWindow::scanUDS() +void UDSScanWindow::scanAll() { - if (currentlyRunning) + sendingFrames.clear(); + for (int i = 0; i < scanEntries.count(); i++) { - waitTimer->stop(); - sendingFrames.clear(); - udsHandler->setReception(false); - udsHandler->setProcessAllIDs(false); - udsHandler->setFlowCtrl(false); - currentlyRunning = false; - ui->btnScan->setText("Start Scan"); - return; + setupScan(i); } + startScan(); +} +void UDSScanWindow::scanSelected() +{ + sendingFrames.clear(); + int idx = ui->listScansToRun->currentRow(); + if (idx < 0) return; + setupScan(idx); + startScan(); +} + +void UDSScanWindow::startScan() +{ udsHandler->setReception(true); udsHandler->setProcessAllIDs(true); udsHandler->setFlowCtrl(true); @@ -217,121 +556,173 @@ void UDSScanWindow::scanUDS() waitTimer->setInterval(ui->spinDelay->value()); ui->treeResults->clear(); - sendingFrames.clear(); nodeService = nullptr; nodeID = nullptr; nodeSubFunc = nullptr; - UDS_MESSAGE test; - int typ, id; - int startID, endID; - startID = ui->spinStartID->value(); - endID = ui->spinEndID->value(); - if (endID < startID) { - int temp = startID; - startID = endID; - endID = temp; - } - - int buses = ui->cbBuses->currentIndex(); - - for (id = startID; id <= endID; id++) - { - test.setFrameId( id ); - test.payload().clear(); - - if (ui->ckTester->isChecked()) - { - test.service = UDS_SERVICES::TESTER_PRESENT; - test.subFunc = 0; - sendOnBuses(test, buses); - } - - if (ui->ckSession->isChecked()) - { - for (typ = 1; typ < 4; typ++) //try each type of session access - { - test.service = UDS_SERVICES::DIAG_CONTROL; - test.subFunc = typ; - sendOnBuses(test, buses); - } - } - - if (ui->ckReset->isChecked()) //try to command a reset of the ECU. You're likely to know if it works. ;) - { - for (typ = 1; typ < 4; typ++) //try each type of session access - { - test.service = UDS_SERVICES::ECU_RESET; - test.subFunc = typ; - sendOnBuses(test, buses); - } - } - - if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists. - { - for (typ = 1; typ < 0x42; typ = typ + 2) //try each type of session access. In practice only the first 1-3 are likely to work - { - test.service = UDS_SERVICES::SECURITY_ACCESS; - test.subFunc = typ; - sendOnBuses(test, buses); - } - } - - if (ui->ckReadByAddr->isChecked()) - { - test.subFuncLen = ui->spinNumBytes->value(); - test.service = UDS_SERVICES::READ_BY_ADDR; - for (int subf = ui->spinLowerSubfunc->value(); subf <= ui->spinUpperSubfunc->value(); subf++) - { - test.subFunc = subf; - sendOnBuses(test, buses); - } - } - - if (ui->ckReadByID->isChecked()) - { - test.subFuncLen = ui->spinNumBytes->value(); - test.service = UDS_SERVICES::READ_BY_ID; - for (int subf = ui->spinLowerSubfunc->value(); subf <= ui->spinUpperSubfunc->value(); subf++) - { - test.subFunc = subf; - sendOnBuses(test, buses); - } - } - - if (ui->ckWildcard->isChecked()) - { - //preallocate the whole buffer so we don't have to keep updating the size and moving as we go. - //TODO: this shows a downside to the current method - it might potentially need to create a huge - //number of frames here. Of course, the rest of the system will do the same so I guess it's a bad idea - //any way you go to generate a 1 billion frame test. - int size = (endID - startID) * (ui->spinUpperService->value() - ui->spinLowerService->value()); - size *= (ui->spinUpperSubfunc->value() - ui->spinLowerSubfunc->value()); - sendingFrames.reserve(size); - - test.subFuncLen = ui->spinNumBytes->value(); - - for (typ = ui->spinLowerService->value(); typ <= ui->spinUpperService->value(); typ++) - { - test.service = typ; - for (int subTyp = ui->spinLowerSubfunc->value(); subTyp <= ui->spinUpperSubfunc->value(); subTyp++) - { - test.subFunc = subTyp; - sendOnBuses(test, buses); - } - } - } - } - waitTimer->start(); currIdx = -1; currentlyRunning = true; - ui->btnScan->setText("Abort Scan"); + //ui->btnScan->setText("Abort Scan"); ui->progressBar->setValue(0); ui->progressBar->setMaximum(sendingFrames.length()); + qDebug() << "Number of operations: " << sendingFrames.length(); sendNextMsg(); } +void UDSScanWindow::stopScan() +{ + waitTimer->stop(); + sendingFrames.clear(); + udsHandler->setReception(false); + udsHandler->setProcessAllIDs(false); + udsHandler->setFlowCtrl(false); + currentlyRunning = false; + //ui->btnScan->setText("Start Scan"); +} + +void UDSScanWindow::setupScan(int idx) +{ + UDS_MESSAGE test; + + qDebug() << "Generating scan id: " << idx; + + for (uint32_t id = scanEntries[idx].startID; id <= scanEntries[idx].endID; id++) + { + test.setFrameId( id ); + + if (scanEntries[idx].sessType > 0) + { + test.payload().clear(); + test.service = UDS_SERVICES::DIAG_CONTROL; + test.subFuncLen = 1; + test.subFunc = scanEntries[ idx].sessType; + sendOnBuses(test, scanEntries[idx].busToScan); + } + + test.payload().clear(); + + qDebug() << "Generating scan on ID " << QString::number(id, 16) << " of type " << scanEntries[idx].scanType; + + switch (scanEntries[idx].scanType) + { + case ST_TESTER_PRESENT: + test.service = UDS_SERVICES::TESTER_PRESENT; + test.subFuncLen = 1; + test.subFunc = 0; + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_SESS_CTRL: + for (int typ = 1; typ < 4; typ++) //try each type of session access + { + test.service = UDS_SERVICES::DIAG_CONTROL; + test.subFuncLen = 1; + test.subFunc = typ; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_COMM_CTRL: + test.service = UDS_SERVICES::COMM_CTRL; + test.subFuncLen = 2; //need two bytes for this one + test.subFunc = 0x100; //00 01 on the bus = enable Rx/Tx + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_ECU_RESET: + for (int typ = 1; typ < 4; typ++) //try each type of session access + { + test.service = UDS_SERVICES::ECU_RESET; + test.subFuncLen = 1; + test.subFunc = typ; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_CLEAR_DTC: + test.service = UDS_SERVICES::CLEAR_DIAG; + test.subFuncLen = 3; //DTC groups are sent as 3 bytes + test.subFunc = 0xFFFFFF; //clear everything! + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_READ_DTC: + test.service = UDS_SERVICES::READ_DTC; + test.subFuncLen = 2; + test.subFunc = 0x8702; //get DTCs by mask (87 is the mask) + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_SEC_ACCESS: + for (int typ = 1; typ < 0x42; typ = typ + 2) //try each type of session access. In practice only the first 1-3 are likely to work + { + test.service = UDS_SERVICES::SECURITY_ACCESS; + test.subFuncLen = 1; + test.subFunc = typ; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_READ_ID: + test.subFuncLen = scanEntries[idx].subfunctLen; + test.service = UDS_SERVICES::READ_BY_ID; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_READ_ADDR: + test.subFuncLen = scanEntries[idx].subfunctLen; + test.service = UDS_SERVICES::READ_BY_ADDR; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_READ_SCALING: + //sub function should always be a length of 2 though. Should conform to this in the GUI + test.subFuncLen = 2; + test.service = UDS_SERVICES::READ_SCALING_ID; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_IO_CTRL: + test.subFuncLen = 3; + test.service = UDS_SERVICES::IO_CTRL; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; //the upper byte will be 0 which is what we want. 0 = Return control to ECU + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_ROUTINE_CTRL: + test.subFuncLen = 3; + test.service = UDS_SERVICES::ROUTINE_CTRL; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + //request results of routine for all the addresses we're testing. This is the safest thing to do. + //starting or stopping arbitrary routines is super dangerous. Don't do that unless you really know + //what the hell you're doing or something really crazy might happen. + test.subFunc = (subf << 8) + 3; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_CUSTOM: + test.subFuncLen = scanEntries[idx].subfunctLen; + + for (uint32_t typ = scanEntries[idx].serviceLower; typ <= scanEntries[idx].serviceUpper; typ++) + { + test.service = typ; + for (int subTyp = scanEntries[idx].subfunctLower; subTyp <= scanEntries[idx].subfunctUpper; subTyp += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subTyp; + sendOnBuses(test, scanEntries[idx].busToScan); + } + } + break; + } + } +} + //Updates here are sent about every 1/4 second. That's fine for most windows but not this one. void UDSScanWindow::updatedFrames(int numFrames) { @@ -491,7 +882,7 @@ void UDSScanWindow::sendNextMsg() udsHandler->setReception(false); udsHandler->setProcessAllIDs(false); udsHandler->setFlowCtrl(false); - ui->btnScan->setText("Start Scan"); + //ui->btnScan->setText("Start Scan"); currentlyRunning = false; } ui->progressBar->setValue(currIdx); diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 9ec8745..ed50e01 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -9,6 +9,44 @@ #include #include + +enum SCAN_TYPE +{ + ST_TESTER_PRESENT, + ST_SESS_CTRL, + ST_COMM_CTRL, + ST_ECU_RESET, + ST_CLEAR_DTC, + ST_READ_DTC, + ST_SEC_ACCESS, + ST_READ_ID, + ST_READ_ADDR, + ST_READ_SCALING, + ST_IO_CTRL, + ST_ROUTINE_CTRL, + ST_CUSTOM, +}; + +//stores the parameters for one scan +class ScanEntry +{ +public: + uint32_t startID, endID; + int32_t idOffset; + bool bAdaptiveOffset; + bool bShowNoReplies; + uint32_t busToScan; + uint32_t maxWaitTime; //in milliseconds + SCAN_TYPE scanType; + uint32_t sessType; + uint32_t subfunctLen; + qint64 subfunctLower; + qint64 subfunctUpper; + uint32_t subfunctIncrement; + uint32_t serviceLower; + uint32_t serviceUpper; +}; + namespace Ui { class UDSScanWindow; } @@ -24,16 +62,25 @@ public: private slots: void updatedFrames(int numFrames); void gotUDSReply(UDS_MESSAGE msg); - void scanUDS(); + void scanAll(); + void scanSelected(); void saveResults(); void timeOut(); void adaptiveToggled(); - void wildcardToggled(); - void readByToggled(); + void changedScanType(); void numBytesChanged(); void checkIDRange(); void checkServiceRange(); void checkSubFuncRange(); + void deleteSelectedScan(); + void addNewScan(); + void loadScans(); + void saveScans(); + void setNoReplyVal(); + void setMaxDelayVal(); + void setIncrementVal(); + void setReplyOffset(); + void setSessType(); private: Ui::UDSScanWindow *ui; @@ -44,9 +91,17 @@ private: QTreeWidgetItem *nodeID; QTreeWidgetItem *nodeService; QTreeWidgetItem *nodeSubFunc; + QVector scanEntries; + ScanEntry *currEditEntry; int currIdx = 0; bool currentlyRunning; + bool inhibitUpdates; + void displayScanEntry(int idx); + QString generateListDesc(int idx); + void setupScan(int idx); + void startScan(); + void stopScan(); void sendNextMsg(); void sendOnBuses(UDS_MESSAGE frame, int buses); void setupNodes(uint32_t replyID); diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index cae150e..b9ad262 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -6,61 +6,346 @@ 0 0 - 742 - 628 + 1053 + 624 UDS Scanner - + - - - Results - - - - - - - false - - - - 1 - - - - - - - - Save Scan Results - - - - - + - + + + Scans To Run + + + + + + + + - + - Starting ID + Add - + + + Delete + + + + + + + + + + + Load + + + + + + + Save + + + + + + + + + + + + + + + + + Starting ID + + + + + + + 0x + + + 536870911 + + + 2016 + + + 16 + + + + + + + + + + + Ending ID + + + + + + + 0x + + + 536870911 + + + 2023 + + + 16 + + + + + + + + + + + Show "No Reply" + + + true + + + + + + + Allow adaptive reply offset + + + true + + + + + + + + + + + + + Bus to scan + + + + + + + + + + Maximum reply delay (ms) + + + + + + + 50 + + + 10000 + + + 10 + + + 100 + + + + + + + Reply Offset: + + + + + + + false + + + -128 + + + 128 + + + 8 + + + + + + + + + + + + 0 + 0 + + + + Scan Type: + + + + + + + + 0 + 0 + + + + + + + + Run test in session type: + + + + + + + false + + + + + + + + + + + + + + Subfunct Len: + + + + + + + false + + + 1 + + + 4 + + + 1 + + + + + + + Lower Bound: + + + + + + + false + 0x - 536870911 + 255 + + + 16 + + + + + + + Upper Bound: + + + + + + + false + + + 0x + + + 255 - 2016 + 255 + + + 16 + + + + + + + Increment + + + + + + + false + + + 0x + + + 1024 + + + 8 16 @@ -70,24 +355,50 @@ - + - + - Ending ID + Lower Service: - + + + false + 0x - 536870911 + 255 + + + 16 + + + + + + + Upper Service: + + + + + + + false + + + 0x + + + 255 - 2023 + 255 16 @@ -97,323 +408,101 @@ - - - Show Tests with no Replies + + + + 0 + 20 + - - true + + QFrame::Plain - - - - - - - - - - Reply Offset: - - - - - - - false - - - -128 - - - 128 - - - 8 - - - - - - - Allow adaptive reply offset - - - true - - - - - - - - - - - Bus to scan - - - - - - - - - - Maximum reply delay (ms) - - - - - - - 50 - - - 10000 - - - 10 - - - 100 - - - - - - - - - - - Scan Types: - - - - - - - Tester Present - - - - - - - Session Ctrl - - - - - - - ECU Reset - - - - - - - Security Access - - - - - - - - - - - Read By ID - - - - - - - Read By Addr - - - - - - - Wildcard - - - - - - - - - - - Lower Service: - - - - - - - false - - - 0x - - - 255 - - - 16 - - - - - - - Upper Service: - - - - - - - false - - - 0x - - - 255 - - - 255 - - - 16 - - - - - - - - - - - Subfunction Bytes: - - - - - - - false - - - 1 - - + 4 - - 1 + + Qt::Horizontal - + - Lower Bound: + Results + + + Qt::AlignCenter - + + + false + + + + 1 + + + + + + false - - 0x + + 0 - - 255 + + true - - 16 - - - - - - - Upper Bound: - - - - - - + false - - 0x - - - 255 - - - 255 - - - 16 + + + + + + + + Run All Scans + + + + + + + Run Selected Scan + + + + + + + + + Save Scan Results - - - - 0 - - - - - - - Start Scan - - - spinStartID spinEndID - ckShowNoReply - spinReplyOffset - cbAllowAdaptiveOffset cbBuses spinDelay - ckTester - ckSession - ckReset - ckSecurity - ckReadByID - ckReadByAddr - ckWildcard spinLowerService spinUpperService spinNumBytes spinLowerSubfunc spinUpperSubfunc - btnScan - treeResults - btnSaveResults From c6cb0d0bf513f569e84ed75c9cb5b4b1ce200539 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 6 Oct 2022 21:52:05 -0400 Subject: [PATCH 11/15] Reworked Canalyzer ASC import to support more formats --- framefileio.cpp | 186 +++++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 83 deletions(-) diff --git a/framefileio.cpp b/framefileio.cpp index e350671..0c11672 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -1599,10 +1599,13 @@ bool FrameFileIO::isCanalyzerASC(QString filename) //47.971842 2 248 Rx d 8 FF FF FF FF FF FF FF FF //version 8.1 //47244640.194244 CANFD 1 Rx 122 0 0 6 6 00 00 18 12 D2 00 0 0 200000 0 0 0 0 0 +//Version 9.0 +//0.001371 CANFD 1 Rx 171 A0066_Unknown 0 0 8 8 00 00 07 76 23 00 00 00 230199 119 220000 62e7 46500250 460a0250 20011736 20010205 //Version 16.0.0 //0.008600 1 358 Rx d 8 04 03 50 01 F0 40 54 2C Length = 233910 BitCount = 121 ID = 856 //Time bus id dir ? len databytes (Ver 8.0) //Time type bus dir ID ? ? length length bytes then many values of unknown type (ver 8.1) +//Time type bus dir ID SignalName ? ? length length bytes then many values of unknown type (ver 9.0) //Time bus id dir ? len databytes additional crap (ver 16.0) //So it seems the file format is not entirely different based on version but rather on some other //settings... Fun! @@ -1660,104 +1663,74 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector* frames) { tokens = line.simplified().split(' '); + if (tokens[0].contains("Begin")) continue; //probably begin triggerblock but we're ignoring that. + //try to do some investigating to see if this line is a CAN frame or not. The file format has many other potential line types it seems... if (tokens.length() > 5) { - if (tokens[5].at(0) >= '0' && tokens[5].at(0) <= '9') + if (tokens[3].toUpper().startsWith("RX") || tokens[3].toUpper().startsWith("TX")) { - if (tokens[3].toUpper().startsWith("RX") || tokens[3].toUpper().startsWith("TX")) + thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast(tokens[0].toDouble() * 1000000.0))); + if (tokens[1].contains("CAN")) //the different format I haven't seen a whole lot of, seems to support CANFD in this format { - int payloadLen = tokens[5].toInt(); - thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast(tokens[0].toDouble() * 1000000.0))); - - //Time bus id dir ? len databytes (Ver 8.0) - //Time type bus dir ID ? ? length length bytes then many values of unknown type (ver 8.1) - if (tokens[1].contains("CAN")) //the different format I haven't seen a whole lot of, seems to support CANFD in this format + if (tokens[4].endsWith('x')) { - thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast(tokens[0].toDouble() * 1000000.0))); - if (tokens[4].endsWith('x')) - { - QByteArray copied_id = tokens[4]; - copied_id.chop(1); - thisFrame.setFrameId(copied_id.toUInt(nullptr, 16)); - thisFrame.setExtendedFrameFormat(true); - } - else - { - thisFrame.setFrameId(tokens[4].toUInt(nullptr, 16)); - thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x' - } - - int payloadLen = tokens[8].toInt(); - QByteArray bytes(payloadLen, 0); - - if (payloadLen > 8) - { - qDebug() << "Payload length too long. Original line: " << line; - return false; - } - if (payloadLen < 0) - { - qDebug() << "Payload length negative! Original line: " << line; - return false; - } - thisFrame.isReceived = tokens[3].toUpper().contains("RX"); - thisFrame.bus = tokens[2].toInt(); - if (tokens[5] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame); - for (int d = 9; d < (9 + payloadLen); d++) - { - if (tokens.count() > d) - { - bytes[d - 9] = static_cast(tokens[d].toInt(nullptr, 16)); - } - else //expected byte wasn't there to read. Set it zero and set error flag - { - bytes[d - 9] = 0; - foundErrors = true; - qDebug() << "D:" << d << " Count:" << tokens.count(); - qDebug() << "Expected byte missing! Original line: " << line; - } - } - thisFrame.setPayload(bytes); + QByteArray copied_id = tokens[4]; + copied_id.chop(1); + thisFrame.setFrameId(copied_id.toUInt(nullptr, 16)); + thisFrame.setExtendedFrameFormat(true); } else { - if (tokens[2].endsWith('x')) - { - QByteArray copied_id = tokens[2]; - copied_id.chop(1); - thisFrame.setFrameId(copied_id.toUInt(nullptr, 16)); - thisFrame.setExtendedFrameFormat(true); - } - else - { - thisFrame.setFrameId(tokens[2].toUInt(nullptr, 16)); - thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x' - } - QByteArray bytes(payloadLen, 0); + thisFrame.setFrameId(tokens[4].toUInt(nullptr, 16)); + thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x' + } - if (payloadLen > 8) - { - qDebug() << "Payload length too long. Original line: " << line; - return false; - } - if (payloadLen < 0) - { - qDebug() << "Payload length negative! Original line: " << line; - return false; - } - thisFrame.isReceived = tokens[3].toUpper().contains("RX"); - thisFrame.bus = tokens[1].toInt(); - if (tokens[4] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame); - for (int d = 6; d < (6 + payloadLen); d++) + int payloadLen = tokens[8].toInt(); + qDebug() << "PayloadLen: " << payloadLen << " Tokens: " << tokens; + QByteArray bytes(payloadLen, 0); + if (payloadLen > 8) + { + qDebug() << "Payload length too long. Original line: " << line; + return false; + } + if (payloadLen < 0) + { + qDebug() << "Payload length negative! Original line: " << line; + return false; + } + thisFrame.isReceived = tokens[3].toUpper().contains("RX"); + thisFrame.bus = tokens[2].toInt(); + + if (tokens[5].at(0) >= '0' && tokens[5].at(0) <= '9') + { + for (int d = 9; d < (9 + payloadLen); d++) { if (tokens.count() > d) { - bytes[d - 6] = static_cast(tokens[d].toInt(nullptr, 16)); + bytes[d - 9] = static_cast(tokens[d].toInt(nullptr, 16)); } else //expected byte wasn't there to read. Set it zero and set error flag { - bytes[d - 6] = 0; + bytes[d - 9] = 0; + foundErrors = true; + qDebug() << "D:" << d << " Count:" << tokens.count(); + qDebug() << "Expected byte missing! Original line: " << line; + } + } + thisFrame.setPayload(bytes); + } + else + { + for (int d = 10; d < (10 + payloadLen); d++) + { + if (tokens.count() > d) + { + bytes[d - 10] = static_cast(tokens[d].toInt(nullptr, 16)); + } + else //expected byte wasn't there to read. Set it zero and set error flag + { + bytes[d - 10] = 0; foundErrors = true; qDebug() << "D:" << d << " Count:" << tokens.count(); qDebug() << "Expected byte missing! Original line: " << line; @@ -1765,8 +1738,55 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector* frames) } thisFrame.setPayload(bytes); } - frames->append(thisFrame); } + else + { + int payloadLen = tokens[5].toInt(); + thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast(tokens[0].toDouble() * 1000000.0))); + if (tokens[2].endsWith('x')) + { + QByteArray copied_id = tokens[2]; + copied_id.chop(1); + thisFrame.setFrameId(copied_id.toUInt(nullptr, 16)); + thisFrame.setExtendedFrameFormat(true); + } + else + { + thisFrame.setFrameId(tokens[2].toUInt(nullptr, 16)); + thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x' + } + QByteArray bytes(payloadLen, 0); + + if (payloadLen > 8) + { + qDebug() << "Payload length too long. Original line: " << line; + return false; + } + if (payloadLen < 0) + { + qDebug() << "Payload length negative! Original line: " << line; + return false; + } + thisFrame.isReceived = tokens[3].toUpper().contains("RX"); + thisFrame.bus = tokens[1].toInt(); + if (tokens[4] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame); + for (int d = 6; d < (6 + payloadLen); d++) + { + if (tokens.count() > d) + { + bytes[d - 6] = static_cast(tokens[d].toInt(nullptr, 16)); + } + else //expected byte wasn't there to read. Set it zero and set error flag + { + bytes[d - 6] = 0; + foundErrors = true; + qDebug() << "D:" << d << " Count:" << tokens.count(); + qDebug() << "Expected byte missing! Original line: " << line; + } + } + thisFrame.setPayload(bytes); + } + frames->append(thisFrame); } } } From e9a364c4cce7213850acb96bea6ce2bc01eb31e6 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 6 Oct 2022 21:58:11 -0400 Subject: [PATCH 12/15] Added a function used by lawicel comm code. --- utility.h | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/utility.h b/utility.h index 0f31ca3..47a6e96 100644 --- a/utility.h +++ b/utility.h @@ -146,6 +146,11 @@ public: return output; } + static QString formatByteAsHex(uint8_t value) + { + return QString::number(value, 16).toUpper().rightJustified(2,'0'); + } + static QVariant formatTimestamp(uint64_t timestamp) { if (!sysTimeMode) { @@ -200,17 +205,44 @@ public: return (value1 * (1.0 - samplePoint)) + (value2 * samplePoint); } + /* A unified function that can extract a signal from the (up to) 64 bits of data bytes in a CAN frame + * handles both little and big endian signals (and floats too but that's untested). + */ static int64_t processIntegerSignal(const QByteArray data, int startBit, int sigSize, bool littleEndian, bool isSigned) { - int64_t result = 0; - int bit; + uint64_t result = 0; + int bit = 0; int maxBytes = (startBit + sigSize) / 8; - if (data.size() < maxBytes) return 0; + if (data.size() < maxBytes) return 0; //if signal extends past the end of data then abort if (littleEndian) { +/* + int currByte = (startBit) / 8; + int currOffset = startBit - (currByte * 8); + int remainingBits = qMax(0, (sigSize - (8 - currOffset)) ); + int prevBits = qMin((8 - currOffset), sigSize); + result = data[currByte] >> currOffset; + result &= ( (1 << sigSize) - 1); //doesn't hurt to do this even if sigSize is way larger than the # of bits we've got so far + + while (remainingBits > 0) + { + currByte++; + if (remainingBits >= 8) //use this entire byte, its easy + { + result += data[currByte] << prevBits; + remainingBits -= 8; + prevBits += 8; + } + else //use only part of this byte. We're going to need to mask it + { + result += ((data[currByte] & ((1 << remainingBits) - 1) ) << prevBits); + remainingBits = 0; + } + }*/ + bit = startBit; for (int bitpos = 0; bitpos < sigSize; bitpos++) { @@ -222,6 +254,7 @@ public: } bit++; } + } else //motorola / big endian mode { @@ -266,6 +299,7 @@ public: */ uint64_t signedMask = ~((1ULL << sigSize) - 1); result = (-1LL & signedMask) | result; + return (int64_t)(result); } } From e86cfb277a24096b7cb3f3536d2592bf672bef39 Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Sun, 9 Oct 2022 10:45:30 -0500 Subject: [PATCH 13/15] Cleaned up all the UI elements and error checking for rebase and duplicate --- connections/socketcand.cpp | 4 + dbc/dbcmaineditor.cpp | 18 +++-- dbc/dbcnodeduplicateeditor.cpp | 131 +++++++++++++++++++++------------ dbc/dbcnodeduplicateeditor.h | 2 +- dbc/dbcnoderebaseeditor.cpp | 120 ++++++++++++++++++------------ dbc/dbcnoderebaseeditor.h | 2 +- ui/dbcnodeduplicateeditor.ui | 19 ++++- ui/dbcnoderebaseeditor.ui | 30 ++++++-- 8 files changed, 211 insertions(+), 115 deletions(-) diff --git a/connections/socketcand.cpp b/connections/socketcand.cpp index 8a6e5da..3388047 100644 --- a/connections/socketcand.cpp +++ b/connections/socketcand.cpp @@ -291,6 +291,10 @@ QString SocketCANd::decodeFrames(QString data, int busNum) if(frameParsed.length() < 4) { qDebug() << "Received frame doesn't contain any data: " << data; + + //todo + //this is not totally true, ive seen frames come through that look like < frame 1F020240 1664924225.371291 > + //if we found the closing token but theres no data then remove the message from the buffer return data; } diff --git a/dbc/dbcmaineditor.cpp b/dbc/dbcmaineditor.cpp index 2415bd5..53982e3 100644 --- a/dbc/dbcmaineditor.cpp +++ b/dbc/dbcmaineditor.cpp @@ -358,9 +358,11 @@ void DBCMainEditor::onRebaseMessages() node = dbcFile->findNodeByName(idString); nodeRebaseEditor->setFileIdx(fileIdx); nodeRebaseEditor->setNodeRef(node); - nodeRebaseEditor->refreshView(); - nodeRebaseEditor->setModal(true); - nodeRebaseEditor->show(); + if(nodeRebaseEditor->refreshView()) + { + nodeRebaseEditor->setModal(true); + nodeRebaseEditor->show(); + } } void DBCMainEditor::onDuplicateNode() @@ -376,10 +378,12 @@ void DBCMainEditor::onDuplicateNode() idString = firstCol->text(0).split(" ")[0]; node = dbcFile->findNodeByName(idString); nodeDuplicateEditor->setFileIdx(fileIdx); - nodeDuplicateEditor->setNodeRef(node); - nodeDuplicateEditor->refreshView(); - nodeDuplicateEditor->setModal(true); - nodeDuplicateEditor->show(); + nodeDuplicateEditor->setNodeRef(node); + if(nodeDuplicateEditor->refreshView()) + { + nodeDuplicateEditor->setModal(true); + nodeDuplicateEditor->show(); + } } /* diff --git a/dbc/dbcnodeduplicateeditor.cpp b/dbc/dbcnodeduplicateeditor.cpp index c2a3164..0c5b546 100644 --- a/dbc/dbcnodeduplicateeditor.cpp +++ b/dbc/dbcnodeduplicateeditor.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "helpwindow.h" #include "utility.h" @@ -18,58 +19,87 @@ DBCNodeDuplicateEditor::DBCNodeDuplicateEditor(QWidget *parent) : dbcHandler = DBCHandler::getReference(); dbcNode = nullptr; - connect(ui->btnDuplicate, &QPushButton::pressed, - [=]() + connect(ui->btnDuplicate, &QPushButton::pressed, + [=]() + { + if (dbcNode == nullptr) return; + if (lowestMsgId > 0x1FFFFFFFul) return; + + uint newBase = Utility::ParseStringToNum(ui->lineNewBaseId->text()); + + if(newBase <= 0 || newBase > 0x1FFFFFFFul) { - if (dbcNode == nullptr) return; - if (lowestMsgId > 0x1FFFFFFFul) return; + QMessageBox::question(this, "Invalid Address", "The new address is outside of the valid range.", + QMessageBox::Ok); + return; + } - uint newBase = Utility::ParseStringToNum(ui->lineNewBaseId->text()); + if(newBase == lowestMsgId) + { + QMessageBox::question(this, "Invalid Address", "The new address is the same as the original.", + QMessageBox::Ok); + return; + } - if (newBase <= 0x1FFFFFFFul && newBase != lowestMsgId) + uint rebaseDiff = newBase - lowestMsgId; + + QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + if(messagesForNode.count() == 0) + { + QMessageBox::question(this, "No Messages", "The node has no messages to duplicate.", + QMessageBox::Ok); + return; + } + + if(ui->lineNodeName->text().isEmpty()) + { + QMessageBox::question(this, "No Name", "The new node needs a name before it can be created.", + QMessageBox::Ok); + return; + } + + QString newNodeName = ui->lineNodeName->text(); + emit createNode(newNodeName); + + DBC_NODE *nodePtr = dbcFile->findNodeByName(newNodeName); + + if(nodePtr == nullptr) + { + QMessageBox::question(this, "Node Invalid", "There was an problem identifying the selected node.", + QMessageBox::Ok); + return; + } + + for (int i=0; iID + rebaseDiff; + + if(newMsgId < 0 || newMsgId > 0x1FFFFFFFul) { - uint rebaseDiff = newBase - lowestMsgId; - - QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); - if(messagesForNode.count() == 0) - { - return; - } - - if(ui->lineNodeName->text().isEmpty()) - { - //tell! - return; - } - - QString newNodeName = ui->lineNodeName->text(); - emit createNode(newNodeName); - - DBC_NODE *nodePtr = dbcFile->findNodeByName(newNodeName); - - if(nodePtr == nullptr) - { - //uhoh - return; - } - - for (int i=0; iID + rebaseDiff; - emit cloneMessageToNode(nodePtr, messagesForNode[i], newMsgId); - } - - dbcFile->setDirtyFlag(); - emit nodeAdded(); + QMessageBox::question(this, "Invalid Address Range", "The new starting address would cause a message to be outside of the valid address range.", + QMessageBox::Ok); + return; } - }); + } - connect(ui->btnCancel, &QPushButton::pressed, - [=]() + for (int i=0; iID + rebaseDiff; + emit cloneMessageToNode(nodePtr, messagesForNode[i], newMsgId); + } + dbcFile->setDirtyFlag(); + emit nodeAdded(); - }); + this->close(); + + }); + + connect(ui->btnCancel, &QPushButton::pressed, + [=]() + { + this->close(); + }); installEventFilter(this); } @@ -144,19 +174,20 @@ void DBCNodeDuplicateEditor::showEvent(QShowEvent* event) refreshView(); } -void DBCNodeDuplicateEditor::refreshView() +bool DBCNodeDuplicateEditor::refreshView() { + ui->lineNewBaseId->setText(""); + if(dbcNode) { QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + lowestMsgId = 0xFFFFFFFF; + if(messagesForNode.count() == 0) { - //?? - + return false; } - lowestMsgId = 0xFFFFFFFF; - for (int i=0; iID < lowestMsgId) @@ -165,7 +196,9 @@ void DBCNodeDuplicateEditor::refreshView() ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul)); ui->lineNodeName->setText(dbcNode->name + QString("_Copy")); + + return true; } - //generateSampleText(); + return false; } diff --git a/dbc/dbcnodeduplicateeditor.h b/dbc/dbcnodeduplicateeditor.h index 9a29a93..57610bd 100644 --- a/dbc/dbcnodeduplicateeditor.h +++ b/dbc/dbcnodeduplicateeditor.h @@ -19,7 +19,7 @@ public: void showEvent(QShowEvent*); void setNodeRef(DBC_NODE *node); void setFileIdx(int idx); - void refreshView(); + bool refreshView(); signals: void updatedTreeInfo(DBC_MESSAGE *msg); diff --git a/dbc/dbcnoderebaseeditor.cpp b/dbc/dbcnoderebaseeditor.cpp index 5a8f6bb..8ce105d 100644 --- a/dbc/dbcnoderebaseeditor.cpp +++ b/dbc/dbcnoderebaseeditor.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "helpwindow.h" #include "utility.h" @@ -18,60 +19,78 @@ DBCNodeRebaseEditor::DBCNodeRebaseEditor(QWidget *parent) : dbcHandler = DBCHandler::getReference(); dbcNode = nullptr; - connect(ui->btnDoRebase, &QPushButton::pressed, - [=]() + connect(ui->btnDoRebase, &QPushButton::pressed, + [=]() + { + if (dbcNode == nullptr) { - if (dbcNode == nullptr) return; - if (lowestMsgId > 0x1FFFFFFFul) return; + QMessageBox::question(this, "Node Invalid", "There was an problem identifying the selected node.", + QMessageBox::Ok); + return; + } - uint newBase = Utility::ParseStringToNum(ui->lineEdit->text()); + if (lowestMsgId > 0x1FFFFFFFul) + { + QMessageBox::question(this, "No Valid Messages", "The node has no valid messages to change.", + QMessageBox::Ok); + return; + } - if (newBase <= 0x1FFFFFFFul && newBase != lowestMsgId) + uint newBase = Utility::ParseStringToNum(ui->lineNewBaseId->text()); + + if(newBase <= 0 || newBase > 0x1FFFFFFFul) + { + QMessageBox::question(this, "Invalid Address", "The new address is outside of the valid range.", + QMessageBox::Ok); + return; + } + + if(newBase == lowestMsgId) + { + QMessageBox::question(this, "Invalid Address", "The new address is the same as the original.", + QMessageBox::Ok); + return; + } + + uint rebaseDiff = newBase - lowestMsgId; + + QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + if(messagesForNode.count() == 0) + { + QMessageBox::question(this, "No Messages", "The node has no messages to change.", + QMessageBox::Ok); + return; + } + + for (int i=0; iID + rebaseDiff; + + if(newMsgId < 0 || newMsgId > 0x1FFFFFFFul) { - uint rebaseDiff = newBase - lowestMsgId; - - QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); - if(messagesForNode.count() == 0) - { - return; - } - - for (int i=0; iID += rebaseDiff; - emit updatedTreeInfo(messagesForNode[i]); - } - - dbcFile->setDirtyFlag(); + QMessageBox::question(this, "Invalid Address Range", "The new starting address would cause a message to be outside of the valid address range.", + QMessageBox::Ok); + return; } + } - - }); - - connect(ui->btnCancel, &QPushButton::pressed, - [=]() + for (int i=0; iID += rebaseDiff; + emit updatedTreeInfo(messagesForNode[i]); + } + dbcFile->setDirtyFlag(); - }); + this->close(); -// connect(ui->lineOriginalBaseId, &QLineEdit::editingFinished, -// [=]() -// { -// if (dbcNode == nullptr) return; -// if (dbcNode->comment != ui->lineComment->text()) dbcFile->setDirtyFlag(); -// dbcNode->comment = ui->lineComment->text(); -// emit updatedTreeInfo(dbcNode); -// }); + }); -// connect(ui->lineMsgName, &QLineEdit::editingFinished, -// [=]() -// { -// if (dbcNode == nullptr) return; -// if (dbcNode->name != ui->lineMsgName->text()) dbcFile->setDirtyFlag(); -// dbcNode->name = ui->lineMsgName->text(); -// emit updatedTreeInfo(dbcNode); -// }); + connect(ui->btnCancel, &QPushButton::pressed, + [=]() + { + this->close(); + }); installEventFilter(this); } @@ -146,19 +165,20 @@ void DBCNodeRebaseEditor::showEvent(QShowEvent* event) refreshView(); } -void DBCNodeRebaseEditor::refreshView() +bool DBCNodeRebaseEditor::refreshView() { + ui->lineNewBaseId->setText(""); + if(dbcNode) { QList messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode); + lowestMsgId = 0xFFFFFFFF; + if(messagesForNode.count() == 0) { - //?? - + return false; } - lowestMsgId = 0xFFFFFFFF; - for (int i=0; iID < lowestMsgId) @@ -167,7 +187,9 @@ void DBCNodeRebaseEditor::refreshView() ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul)); ui->lineNodeName->setText(dbcNode->name); + + return true; } - //generateSampleText(); + return false; } diff --git a/dbc/dbcnoderebaseeditor.h b/dbc/dbcnoderebaseeditor.h index 8e787f0..26f1645 100644 --- a/dbc/dbcnoderebaseeditor.h +++ b/dbc/dbcnoderebaseeditor.h @@ -19,7 +19,7 @@ public: void showEvent(QShowEvent*); void setNodeRef(DBC_NODE *node); void setFileIdx(int idx); - void refreshView(); + bool refreshView(); signals: void updatedTreeInfo(DBC_MESSAGE *msg); diff --git a/ui/dbcnodeduplicateeditor.ui b/ui/dbcnodeduplicateeditor.ui index a07c435..b236251 100644 --- a/ui/dbcnodeduplicateeditor.ui +++ b/ui/dbcnodeduplicateeditor.ui @@ -7,11 +7,17 @@ 0 0 314 - 193 + 144 + + + 0 + 0 + + - Dialog + Duplicate Node @@ -41,7 +47,14 @@ - + + + true + + + true + + diff --git a/ui/dbcnoderebaseeditor.ui b/ui/dbcnoderebaseeditor.ui index ddcfbe1..3c043cc 100644 --- a/ui/dbcnoderebaseeditor.ui +++ b/ui/dbcnoderebaseeditor.ui @@ -7,11 +7,17 @@ 0 0 303 - 159 + 148 + + + 0 + 0 + + - Dialog + Rebase All Node Messages @@ -31,7 +37,14 @@ - + + + true + + + true + + @@ -41,7 +54,14 @@ - + + + true + + + true + + @@ -51,7 +71,7 @@ - + From 04f4af1bf9f1eaa42e8a63c9c19f456c13f1b04d Mon Sep 17 00:00:00 2001 From: Andy Huska Date: Sun, 9 Oct 2022 10:57:25 -0500 Subject: [PATCH 14/15] One lingering thing removed before PR --- dbc/dbcsignaleditor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbc/dbcsignaleditor.cpp b/dbc/dbcsignaleditor.cpp index b4bd6a3..3788781 100644 --- a/dbc/dbcsignaleditor.cpp +++ b/dbc/dbcsignaleditor.cpp @@ -34,7 +34,6 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) : ui->comboType->addItem("SINGLE PRECISION"); ui->comboType->addItem("DOUBLE PRECISION"); ui->comboType->addItem("STRING"); - ui->comboType->addItem("ENUMERATED STRING"); ui->bitfield->setMode(GridMode::SIGNAL_VIEW); From 677d9ba9f8db4e3680625679c231cde38c229951 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Mon, 10 Oct 2022 20:09:51 -0400 Subject: [PATCH 15/15] Add 83.33k speed to possible CAN speed options in the connections windows. --- connections/connectionwindow.cpp | 1 + connections/newconnectiondialog.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index 210fcdd..d29ebd9 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -64,6 +64,7 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) : ui->cbBusSpeed->addItem("33333"); ui->cbBusSpeed->addItem("50000"); + ui->cbBusSpeed->addItem("83333"); ui->cbBusSpeed->addItem("100000"); ui->cbBusSpeed->addItem("125000"); ui->cbBusSpeed->addItem("250000"); diff --git a/connections/newconnectiondialog.cpp b/connections/newconnectiondialog.cpp index 88383b0..e6b1b24 100644 --- a/connections/newconnectiondialog.cpp +++ b/connections/newconnectiondialog.cpp @@ -97,6 +97,7 @@ void NewConnectionDialog::selectLawicel() ui->cbCANSpeed->addItem("10000"); ui->cbCANSpeed->addItem("20000"); ui->cbCANSpeed->addItem("50000"); + ui->cbCANSpeed->addItem("83333"); ui->cbCANSpeed->addItem("100000"); ui->cbCANSpeed->addItem("125000"); ui->cbCANSpeed->addItem("250000");