From 314ea0769d445d24ee3d4c6cb425420311bc6f63 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 7 Jul 2016 16:47:43 +0200 Subject: [PATCH 01/10] add sniffer --- mainwindow.cpp | 17 +++ mainwindow.h | 3 + mainwindow.ui | 6 + re/sniffer/snifferitem.cpp | 86 +++++++++++ re/sniffer/snifferitem.h | 49 +++++++ re/sniffer/sniffermodel.cpp | 267 +++++++++++++++++++++++++++++++++++ re/sniffer/sniffermodel.h | 58 ++++++++ re/sniffer/snifferwindow.cpp | 132 +++++++++++++++++ re/sniffer/snifferwindow.h | 56 ++++++++ snifferwindow.ui | 188 ++++++++++++++++++++++++ 10 files changed, 862 insertions(+) create mode 100644 re/sniffer/snifferitem.cpp create mode 100644 re/sniffer/snifferitem.h create mode 100644 re/sniffer/sniffermodel.cpp create mode 100644 re/sniffer/sniffermodel.h create mode 100644 re/sniffer/snifferwindow.cpp create mode 100644 re/sniffer/snifferwindow.h create mode 100644 snifferwindow.ui diff --git a/mainwindow.cpp b/mainwindow.cpp index 59a8d84..d5826c0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -80,6 +80,7 @@ MainWindow::MainWindow(QWidget *parent) : fuzzingWindow = NULL; udsScanWindow = NULL; isoWindow = NULL; + snifferWindow = NULL; dbcHandler = new DBCHandler; bDirty = false; inhibitFilterUpdate = false; @@ -123,6 +124,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow); connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow); connect(ui->actionISO_TP_Decoder, &QAction::triggered, this, &MainWindow::showISOInterpreterWindow); + connect(ui->actionSniffer, &QAction::triggered, this, &MainWindow::showSnifferWindow); connect(CANConManager::getInstance(), &CANConManager::framesReceived, model, &CANFrameModel::addFrames); @@ -264,6 +266,12 @@ MainWindow::~MainWindow() isoWindow->close(); delete isoWindow; } + if (snifferWindow) + { + snifferWindow->close(); + delete snifferWindow; + snifferWindow = NULL; + } delete elapsedTime; @@ -291,6 +299,7 @@ void MainWindow::exitApp() if (fuzzingWindow) fuzzingWindow->close(); if (udsScanWindow) udsScanWindow->close(); if (isoWindow) isoWindow->close(); + if (snifferWindow) snifferWindow->close(); this->close(); } @@ -839,6 +848,14 @@ void MainWindow::showISOInterpreterWindow() isoWindow->show(); } +void MainWindow::showSnifferWindow() +{ + if (!snifferWindow) + snifferWindow = new SnifferWindow(this); + snifferWindow->show(); +} + + void MainWindow::showFrameSenderWindow() { if (!frameSenderWindow) diff --git a/mainwindow.h b/mainwindow.h index 191008a..a2925f5 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -25,6 +25,7 @@ #include "dbcloadsavewindow.h" #include "fuzzingwindow.h" #include "udsscanwindow.h" +#include "re/sniffer/snifferwindow.h" #include "isotp_interpreterwindow.h" class ConnectionWindow; @@ -67,6 +68,7 @@ private slots: void showFuzzingWindow(); void showUDSScanWindow(); void showISOInterpreterWindow(); + void showSnifferWindow(); void exitApp(); void handleSaveDecoded(); void connectionFailed(); @@ -137,6 +139,7 @@ private: FuzzingWindow *fuzzingWindow; UDSScanWindow *udsScanWindow; ISOTP_InterpreterWindow *isoWindow; + SnifferWindow* snifferWindow; //various private storage QLabel lbStatusConnected; diff --git a/mainwindow.ui b/mainwindow.ui index a4850ac..1c6437c 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -214,6 +214,7 @@ + @@ -395,6 +396,11 @@ ISO-TP Decoder + + + Sniffer + + diff --git a/re/sniffer/snifferitem.cpp b/re/sniffer/snifferitem.cpp new file mode 100644 index 0000000..0fe870b --- /dev/null +++ b/re/sniffer/snifferitem.cpp @@ -0,0 +1,86 @@ +#include +#include +#include "snifferitem.h" + + +SnifferItem::SnifferItem(const CANFrame& pFrame): + mNotch(0) +{ + mID = pFrame.ID; + mMarker = {0,0}; + mLastMarker = {0,0}; + /* that's dirty */ + update(pFrame); + update(pFrame); +} + + +SnifferItem::~SnifferItem() +{ + +} + +quint64 SnifferItem::getId() const +{ + return mID; +} + +float SnifferItem::getDelta() const +{ + return ((float)(mCurrentTime-mLastTime))/1000000; +} + +int SnifferItem::getData(uchar i) const +{ + return (i>=mCurrent.len) ? -1 : ((uchar*) &mCurrent.data)[i]; +} + +dc SnifferItem::dataChange(uchar i) const +{ + if( i= ((uchar*) &mLast.data)[i] ? dc::INC : dc::DEC; + } + + return dc::NO; +} + +int SnifferItem::elapsed() const +{ + return mTime.elapsed(); +} + +void SnifferItem::update(const CANFrame& pFrame) +{ + /* copy current to last */ + mLast = mCurrent; + mLastTime = mCurrentTime; + + /* copy new value */ + memcpy(&mCurrent.data, pFrame.data, 8); + mCurrent.len = pFrame.len; + mCurrentTime = pFrame.timestamp; + + /* update marker */ + mMarker.data |= mLast.data ^ mCurrent.data; + mMarker.len |= mLast.len ^ mCurrent.data; + + /* restart timeout */ + mTime.restart(); +} + +void SnifferItem::updateMarker() +{ + mLastMarker = mMarker; + mMarker = {0, 0}; +} + +void SnifferItem::notch(bool pNotch) +{ + if(pNotch) + mNotch |= mLastMarker.data; + else + mNotch = 0; +} diff --git a/re/sniffer/snifferitem.h b/re/sniffer/snifferitem.h new file mode 100644 index 0000000..cc06c3a --- /dev/null +++ b/re/sniffer/snifferitem.h @@ -0,0 +1,49 @@ +#ifndef SNIFFERITEM_H +#define SNIFFERITEM_H + +#include +#include +#include "can_structs.h" + +struct fstCan +{ + quint64 data; + int len; +}; + +enum dc +{ + NO, + INC, + DEC +}; + + +class SnifferItem +{ +public: + explicit SnifferItem(const CANFrame& pFrame); + virtual ~SnifferItem(); + + quint64 getId() const; + float getDelta() const; + int getData(uchar i) const; + dc dataChange(uchar) const; + int elapsed() const; + void update(const CANFrame& pFrame); + void updateMarker(); + void notch(bool); +private: + quint64 mID; + struct fstCan mLast; + struct fstCan mCurrent; + struct fstCan mLastMarker; + struct fstCan mMarker; + quint64 mNotch; + quint64 mLastTime; + quint64 mCurrentTime; + + QTime mTime; +}; + +#endif // SNIFFERITEM_H diff --git a/re/sniffer/sniffermodel.cpp b/re/sniffer/sniffermodel.cpp new file mode 100644 index 0000000..a762346 --- /dev/null +++ b/re/sniffer/sniffermodel.cpp @@ -0,0 +1,267 @@ +#include +#include "sniffermodel.h" +#include "snifferwindow.h" + + +SnifferModel::SnifferModel(QObject *parent) + : QAbstractItemModel(parent), + mFilter(false) +{ +} + +SnifferModel::~SnifferModel() +{ + clear(); +} + + +int SnifferModel::columnCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : tc::LAST+1; +} + + +int SnifferModel::rowCount(const QModelIndex &parent) const +{ + const QMap& map = mFilter ? mFilters : mMap; + return parent.isValid() ? 0 : map.size(); +} + + +QVariant SnifferModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + const QMap& map = mFilter ? mFilters : mMap; + + if(index.row()<=map.size()) + { + quint64 key = map.keys()[index.row()]; + SnifferItem* item = map[key]; + + int col = index.column(); + + switch(role) + { + case Qt::DisplayRole: + { + switch(col) + { + case tc::DELTA: + return QString::number(item->getDelta(), 'f'); + case tc::ID: + return QString("%1").arg(item->getId(), 5, 16, QLatin1Char(' ')).toUpper(); + default: + break; + } + if(tc::DATA_0<=col && col <=tc::DATA_7) + { + int data = item->getData(col-tc::DATA_0); + if(data>=0) + return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper(); + } + break; + } + case Qt::BackgroundRole: + { + if(tc::ID==col) + { + if(item->elapsed()>4000) + return QBrush(Qt::red); + } + else if(tc::DATA_0<=col && col<=tc::DATA_7) + { + dc change = item->dataChange(col-tc::DATA_0); + switch(change) + { + case dc::INC: + return QBrush(Qt::green); + case dc::DEC: + return QBrush(Qt::red); + default: + break; + } + } + break; + } + } + } + + return QVariant(); +} + + +Qt::ItemFlags SnifferModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + + +QVariant SnifferModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + switch(section) + { + case tc::DELTA: + return QString("Delta"); + case tc::ID: + return QString("ID"); + default: + break; + } + if(tc::DATA_0<=section && section <=tc::DATA_7) + return QString::number(section-tc::DATA_0); + } + + return QVariant(); +} + + +QModelIndex SnifferModel::index(int row, int column, const QModelIndex &parent) + const +{ + if (parent.isValid()) + return QModelIndex(); + + const QMap& map = mFilter ? mFilters : mMap; + + if(column>tc::LAST || row>=map.size()) + return QModelIndex(); + + return createIndex(row, column); +} + + +QModelIndex SnifferModel::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + + +void SnifferModel::clear() +{ + beginResetModel(); + qDeleteAll(mMap); + mMap.clear(); + mFilters.clear(); + endResetModel(); + + mFilter = false; +} + + +void SnifferModel::refresh() +{ + QMap::iterator i; + QVector toRemove; + SnifferItem* item; + + /* update markers */ + + + for (i = mMap.begin(); i != mMap.end(); ++i) + { + i.value()->updateMarker(); + if(i.value()->elapsed()>5000) + toRemove.append(i.key()); + } + + if(toRemove.size()) + { + beginResetModel(); + foreach(quint32 id, toRemove) + { + /* remove element */ + item = mMap.take(id); + mFilters.remove(id); + delete item; + /* send notification */ + emit idChange(id, false); + } + endResetModel(); + } + else + /* refresh data */ + dataChanged(createIndex(0, 0), + createIndex(rowCount()-1, columnCount()-1), QVector(Qt::DisplayRole)); +} + + +void SnifferModel::filter(fltType pType, int pId) +{ + beginResetModel(); + switch(pType) + { + case fltType::NONE: + /* erase everything */ + mFilter = true; + mFilters.clear(); + break; + case fltType::ADD: + /* add filter to list */ + mFilter = true; + mFilters[pId] = mMap[pId]; + break; + case fltType::REMOVE: + /* remove filter */ + if(!mFilter) + mFilters = mMap; + mFilter = true; + mFilters.remove(pId); + break; + case fltType::ALL: + /* stop filtering */ + mFilter = false; + mFilters.clear(); + break; + } + endResetModel(); +} + + +/***********************************************/ +/********** slots ****************/ +/***********************************************/ + +void SnifferModel::update(CANConnection*, QVector& pFrames) +{ + foreach(const CANFrame& frame, pFrames) + { + if(!mMap.contains(frame.ID)) + { + int index = std::distance(mMap.begin(), mMap.lowerBound(frame.ID)); + /* add the frame */ + beginInsertRows(QModelIndex(), index, index); + mMap[frame.ID] = new SnifferItem(frame); + endInsertRows(); + + emit idChange(frame.ID, true); + } + else + //updateData + mMap[frame.ID]->update(frame); + } +} + +void SnifferModel::notch() +{ + QMap& map = mFilter ? mFilters : mMap; + + foreach(SnifferItem* item, map) + item->notch(true); +} + +void SnifferModel::unNotch() +{ + QMap& map = mFilter ? mFilters : mMap; + + foreach(SnifferItem* item, map) + item->notch(false); +} + + diff --git a/re/sniffer/sniffermodel.h b/re/sniffer/sniffermodel.h new file mode 100644 index 0000000..7c3fc19 --- /dev/null +++ b/re/sniffer/sniffermodel.h @@ -0,0 +1,58 @@ +#ifndef SNIFFERMODEL_H +#define SNIFFERMODEL_H + +#include +#include +#include +#include + +#include "can_structs.h" +#include "connections/canconnection.h" +#include "snifferitem.h" + + +enum fltType +{ + ALL, + ADD, + REMOVE, + NONE +}; + +class SnifferModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit SnifferModel(QObject *parent = 0); + virtual ~SnifferModel(); + + /* from QAbstractItemModel */ + QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + void refresh(); + void clear(); + void filter(fltType pType, int pId=0); + +public slots: + void update(CANConnection*, QVector&); + void notch(); + void unNotch(); + +signals: + void idChange(int, bool); + +private: + QMap mMap; + QMap mFilters; + bool mFilter; +}; + +#endif // SNIFFERMODEL_H diff --git a/re/sniffer/snifferwindow.cpp b/re/sniffer/snifferwindow.cpp new file mode 100644 index 0000000..cab2a88 --- /dev/null +++ b/re/sniffer/snifferwindow.cpp @@ -0,0 +1,132 @@ +#include +#include +#include "snifferwindow.h" +#include "ui_snifferwindow.h" +#include "connections/canconmanager.h" + +SnifferWindow::SnifferWindow(QWidget *parent) : + QDialog(parent), + ui(new Ui::snifferWindow), + mModel(this), + mTimer(this), + mFilter(false) +{ + ui->setupUi(this); + ui->treeView->setModel(&mModel); + + /* set column width */ + ui->treeView->setColumnWidth(tc::ID, 50); + ui->treeView->setColumnWidth(tc::LAST, 1); + for(int i=tc::DATA_0 ; i<=tc::DATA_7 ; i++) + ui->treeView->setColumnWidth(i, 30); + ui->treeView->header()->setDefaultAlignment(Qt::AlignCenter); + + /* activate sorting */ + ui->listWidget->setSortingEnabled(true); + + /* connect timer */ + connect(&mTimer, &QTimer::timeout, this, &SnifferWindow::update); + mTimer.setInterval(200); + + /* connect buttons */ + connect(ui->btNotch, &QPushButton::clicked, &mModel, &SnifferModel::notch); + connect(ui->btUnNotch, &QPushButton::clicked, &mModel, &SnifferModel::unNotch); + connect(ui->btAll, &QPushButton::clicked, this, &SnifferWindow::fltAll); + connect(ui->btNone, &QPushButton::clicked, this, &SnifferWindow::fltNone); + connect(&mModel, &SnifferModel::idChange, this, &SnifferWindow::idChange); + connect(ui->listWidget, &QListWidget::itemChanged, this, &SnifferWindow::itemChanged); + +} + +SnifferWindow::~SnifferWindow() +{ + closeEvent(NULL); + delete ui; +} + + +void SnifferWindow::showEvent(QShowEvent* event) +{ + QDialog::showEvent(event); + connect(CANConManager::getInstance(), &CANConManager::framesReceived, &mModel, &SnifferModel::update); + mTimer.start(); + + qDebug() << "show"; +} + + +void SnifferWindow::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event); + /* stop timer */ + mTimer.stop(); + /* disconnect reception of frames */ + disconnect(CANConManager::getInstance(), 0, this, 0); + /* clear model */ + mModel.clear(); + /* clean list */ + qDeleteAll(mMap); + mMap.clear(); + /* reset filtering */ + mFilter = false; +} + + +void SnifferWindow::update() +{ + mModel.refresh(); +} + + +void SnifferWindow::fltAll() +{ + filter(false); +} + + +void SnifferWindow::fltNone() +{ + filter(true); +} + +void SnifferWindow::filter(bool pFilter) +{ + mFilter = pFilter; + mModel.filter(mFilter ? fltType::NONE : fltType::ALL); + + foreach(QListWidgetItem* item, mMap) + item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked); +} + +void SnifferWindow::idChange(int pId, bool pAdd) +{ + QListWidgetItem* item; + + if(pAdd) + { + QString text = QString("0x") + QString("%1").arg(pId, 3, 16, QLatin1Char('0')).toUpper(); + item = new QListWidgetItem(text); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked); + ui->listWidget->addItem(item); + mMap[pId] = item; + } + else + { + item = mMap.take(pId); + ui->listWidget->removeItemWidget(item); + delete item; + } +} + + +void SnifferWindow::itemChanged(QListWidgetItem * item) +{ + bool checked = (Qt::Checked == item->checkState()); + + if( !mFilter && checked ) + return; + + mModel.filter(checked ? fltType::ADD : fltType::REMOVE, mMap.key(item)); + mFilter = true; +} diff --git a/re/sniffer/snifferwindow.h b/re/sniffer/snifferwindow.h new file mode 100644 index 0000000..2d2cb1d --- /dev/null +++ b/re/sniffer/snifferwindow.h @@ -0,0 +1,56 @@ +#ifndef SNIFFER_H +#define SNIFFER_H + +#include +#include +#include "sniffermodel.h" + +namespace Ui { +class snifferWindow; +} + +enum tc +{ + DELTA = 0, + ID, + DATA_0, + DATA_1, + DATA_2, + DATA_3, + DATA_4, + DATA_5, + DATA_6, + DATA_7, + LAST +}; + + +class SnifferWindow : public QDialog +{ + Q_OBJECT + +public: + explicit SnifferWindow(QWidget *parent = 0); + ~SnifferWindow(); + + void showEvent(QShowEvent*); + void closeEvent(QCloseEvent*); + +public slots: + void update(); + void idChange(int, bool); + void fltAll(); + void fltNone(); + void itemChanged(QListWidgetItem*); + +private: + void filter(bool pFilter); + + Ui::snifferWindow* ui; + SnifferModel mModel; + QTimer mTimer; + QMap mMap; + bool mFilter; +}; + +#endif // SNIFFER_H diff --git a/snifferwindow.ui b/snifferwindow.ui new file mode 100644 index 0000000..44d36a0 --- /dev/null +++ b/snifferwindow.ui @@ -0,0 +1,188 @@ + + + snifferWindow + + + + 0 + 0 + 602 + 752 + + + + Sniffer + + + + QLayout::SetDefaultConstraint + + + + + QAbstractItemView::NoSelection + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Notch + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Unnotch + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Filters: + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 75 + 16777215 + + + + All + + + + + + + + 75 + 16777215 + + + + None + + + + + + + + + + + + + + + + + From 92955101687b7cf97776c9a7b99932304c3be3a1 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 7 Jul 2016 16:48:14 +0200 Subject: [PATCH 02/10] change refresh rate to 250ms --- connections/canconmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index b0b5a37..5f645d1 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -15,7 +15,7 @@ CANConManager* CANConManager::getInstance() CANConManager::CANConManager(QObject *parent): QObject(parent) { connect(&mTimer, SIGNAL(timeout()), this, SLOT(refreshCanList())); - mTimer.setInterval(500); /*tick twice a second */ + mTimer.setInterval(250); /*tick 4 times a second */ mTimer.setSingleShot(false); mTimer.start(); } From 6cd79c7f710532c41801cb4e92bb11873338e813 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Thu, 7 Jul 2016 16:50:24 +0200 Subject: [PATCH 03/10] add sniffer files to project --- SavvyCAN.pro | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/SavvyCAN.pro b/SavvyCAN.pro index b1369e2..ed7f854 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -55,7 +55,10 @@ SOURCES += main.cpp\ connections/socketcan.cpp \ connections/canconfactory.cpp \ connections/gvretserial.cpp \ - connections/canconmanager.cpp + connections/canconmanager.cpp \ + re/sniffer/snifferitem.cpp \ + re/sniffer/sniffermodel.cpp \ + re/sniffer/snifferwindow.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -99,7 +102,10 @@ HEADERS += mainwindow.h \ connections/canconconst.h \ connections/canconfactory.h \ connections/gvretserial.h \ - connections/canconmanager.h + connections/canconmanager.h \ + re/sniffer/snifferitem.h \ + re/sniffer/sniffermodel.h \ + re/sniffer/snifferwindow.h FORMS += mainwindow.ui \ graphingwindow.ui \ @@ -121,7 +127,8 @@ FORMS += mainwindow.ui \ dbcloadsavewindow.ui \ fuzzingwindow.ui \ udsscanwindow.ui \ - isotp_interpreterwindow.ui + isotp_interpreterwindow.ui \ + snifferwindow.ui DISTFILES += From 5162769712f3b69895f26154e64a0ebefd08704b Mon Sep 17 00:00:00 2001 From: canpadawan Date: Fri, 8 Jul 2016 11:01:53 +0200 Subject: [PATCH 04/10] bug fix: use after free --- canframemodel.cpp | 9 +++++++++ canframemodel.h | 1 + mainwindow.cpp | 7 +++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index e1cb200..799ae10 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -3,6 +3,15 @@ #include #include "utility.h" + +CANFrameModel::~CANFrameModel() +{ + frames.clear(); + filteredFrames.clear(); + filters.clear(); +} + + int CANFrameModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); diff --git a/canframemodel.h b/canframemodel.h index 57e6e6a..f69858a 100644 --- a/canframemodel.h +++ b/canframemodel.h @@ -16,6 +16,7 @@ class CANFrameModel: public QAbstractTableModel public: CANFrameModel(QObject *parent = 0); + virtual ~CANFrameModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; diff --git a/mainwindow.cpp b/mainwindow.cpp index d5826c0..27546b4 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -273,12 +273,11 @@ MainWindow::~MainWindow() snifferWindow = NULL; } - delete elapsedTime; - delete ui; - delete dbcHandler; - model->clearFrames(); delete model; + delete elapsedTime; + delete dbcHandler; + delete ui; } void MainWindow::exitApp() From d36b437239f57a0c3f58a76d9482c87828a40663 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Fri, 8 Jul 2016 11:02:23 +0200 Subject: [PATCH 05/10] optimization --- re/sniffer/snifferitem.cpp | 6 +-- re/sniffer/sniffermodel.cpp | 95 +++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/re/sniffer/snifferitem.cpp b/re/sniffer/snifferitem.cpp index 0fe870b..af8bee1 100644 --- a/re/sniffer/snifferitem.cpp +++ b/re/sniffer/snifferitem.cpp @@ -4,9 +4,9 @@ SnifferItem::SnifferItem(const CANFrame& pFrame): - mNotch(0) + mNotch(0), + mID(pFrame.ID) { - mID = pFrame.ID; mMarker = {0,0}; mLastMarker = {0,0}; /* that's dirty */ @@ -65,7 +65,7 @@ void SnifferItem::update(const CANFrame& pFrame) /* update marker */ mMarker.data |= mLast.data ^ mCurrent.data; - mMarker.len |= mLast.len ^ mCurrent.data; + mMarker.len |= mLast.len ^ mCurrent.len; /* restart timeout */ mTime.restart(); diff --git a/re/sniffer/sniffermodel.cpp b/re/sniffer/sniffermodel.cpp index a762346..3bedbbc 100644 --- a/re/sniffer/sniffermodel.cpp +++ b/re/sniffer/sniffermodel.cpp @@ -11,7 +11,9 @@ SnifferModel::SnifferModel(QObject *parent) SnifferModel::~SnifferModel() { - clear(); + qDeleteAll(mMap); + mMap.clear(); + mFilters.clear(); } @@ -33,58 +35,53 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); - const QMap& map = mFilter ? mFilters : mMap; + SnifferItem *item = static_cast(index.internalPointer()); + if(!item) QVariant(); - if(index.row()<=map.size()) + int col = index.column(); + + switch(role) { - quint64 key = map.keys()[index.row()]; - SnifferItem* item = map[key]; - - int col = index.column(); - - switch(role) + case Qt::DisplayRole: { - case Qt::DisplayRole: + switch(col) { - switch(col) + case tc::DELTA: + return QString::number(item->getDelta(), 'f'); + case tc::ID: + return QString("%1").arg(item->getId(), 5, 16, QLatin1Char(' ')).toUpper(); + default: + break; + } + if(tc::DATA_0<=col && col <=tc::DATA_7) + { + int data = item->getData(col-tc::DATA_0); + if(data>=0) + return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper(); + } + break; + } + case Qt::BackgroundRole: + { + if(tc::ID==col) + { + if(item->elapsed()>4000) + return QBrush(Qt::red); + } + else if(tc::DATA_0<=col && col<=tc::DATA_7) + { + dc change = item->dataChange(col-tc::DATA_0); + switch(change) { - case tc::DELTA: - return QString::number(item->getDelta(), 'f'); - case tc::ID: - return QString("%1").arg(item->getId(), 5, 16, QLatin1Char(' ')).toUpper(); + case dc::INC: + return QBrush(Qt::green); + case dc::DEC: + return QBrush(Qt::red); default: break; } - if(tc::DATA_0<=col && col <=tc::DATA_7) - { - int data = item->getData(col-tc::DATA_0); - if(data>=0) - return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper(); - } - break; - } - case Qt::BackgroundRole: - { - if(tc::ID==col) - { - if(item->elapsed()>4000) - return QBrush(Qt::red); - } - else if(tc::DATA_0<=col && col<=tc::DATA_7) - { - dc change = item->dataChange(col-tc::DATA_0); - switch(change) - { - case dc::INC: - return QBrush(Qt::green); - case dc::DEC: - return QBrush(Qt::red); - default: - break; - } - } - break; } + break; } } @@ -122,8 +119,7 @@ QVariant SnifferModel::headerData(int section, Qt::Orientation orientation, int } -QModelIndex SnifferModel::index(int row, int column, const QModelIndex &parent) - const +QModelIndex SnifferModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid()) return QModelIndex(); @@ -133,7 +129,12 @@ QModelIndex SnifferModel::index(int row, int column, const QModelIndex &parent) if(column>tc::LAST || row>=map.size()) return QModelIndex(); - return createIndex(row, column); + /* ugly but I can't find best without creating a list to keep indexes */ + QMap::const_iterator iter; + int i; + for(iter = map.begin(), i=0 ; i Date: Fri, 8 Jul 2016 11:24:21 +0200 Subject: [PATCH 06/10] bug fix: race condition --- re/sniffer/sniffermodel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/re/sniffer/sniffermodel.cpp b/re/sniffer/sniffermodel.cpp index 3bedbbc..031b487 100644 --- a/re/sniffer/sniffermodel.cpp +++ b/re/sniffer/sniffermodel.cpp @@ -150,9 +150,8 @@ void SnifferModel::clear() qDeleteAll(mMap); mMap.clear(); mFilters.clear(); - endResetModel(); - mFilter = false; + endResetModel(); } From 1e3192fc48f9af4da1a8d985b78d35cfdaa70011 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Mon, 18 Jul 2016 17:12:14 +0200 Subject: [PATCH 07/10] removed extra "\r" --- canframemodel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index 799ae10..fa3aba7 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -227,15 +227,15 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame); if (msg != NULL) { - tempString.append("\r\n"); - tempString.append(msg->name + " " + msg->comment + "\r\n"); + tempString.append("\n"); + tempString.append(msg->name + " " + msg->comment + "\n"); for (int j = 0; j < msg->sigHandler->getCount(); j++) { QString sigString; if (msg->sigHandler->findSignalByIdx(j)->processAsText(thisFrame, sigString)) { tempString.append(sigString); - tempString.append("\r\n"); + tempString.append("\n"); } } } From 0bfdfb740321ffd02a1c2eb7d7bb0f2659b88e91 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Mon, 18 Jul 2016 17:14:14 +0200 Subject: [PATCH 08/10] bug fix when changing MsgID --- dbcmaineditor.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/dbcmaineditor.cpp b/dbcmaineditor.cpp index 596346e..118f07c 100644 --- a/dbcmaineditor.cpp +++ b/dbcmaineditor.cpp @@ -259,17 +259,16 @@ void DBCMainEditor::onCellChangedMessage(int row,int col) } } dbcFile->messageHandler->addMessage(newMsg); + + /* insert message in table */ + inhibitCellChanged = true; + replacement = new QTableWidgetItem(Utility::formatNumber(msgID)); + replacement->setFlags(replacement->flags() ^ Qt::ItemIsEditable); + ui->MessagesTable->setItem(row, col, replacement); + replacement = new QTableWidgetItem(QString::number(newMsg.len)); + ui->MessagesTable->setItem(row, 2, replacement); + inhibitCellChanged = false; } - else //editing an existing record - { - if (msg != NULL) msg->ID = msgID; - } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(Utility::formatNumber(msgID)); - ui->MessagesTable->setItem(row, col, replacement); - replacement = new QTableWidgetItem(QString::number(newMsg.len)); - ui->MessagesTable->setItem(row, 2, replacement); - inhibitCellChanged = false; break; case 1: //msg name From 72ee2148128298b21cc50b2efa08ccf50b0ae0e1 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Tue, 19 Jul 2016 10:33:53 +0200 Subject: [PATCH 09/10] simplification of messagestable management --- dbcmaineditor.cpp | 192 ++++++++++++++++++++++------------------------ dbcmaineditor.h | 1 + 2 files changed, 93 insertions(+), 100 deletions(-) diff --git a/dbcmaineditor.cpp b/dbcmaineditor.cpp index 118f07c..d51fcc1 100644 --- a/dbcmaineditor.cpp +++ b/dbcmaineditor.cpp @@ -5,6 +5,8 @@ #include #include +#define MT_COLUMN_COUNT 5 + DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector *frames, QWidget *parent) : QDialog(parent), ui(new Ui::DBCMainEditor) @@ -26,7 +28,7 @@ DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector *frame QStringList headers2; headers2 << "Msg ID" << "Msg Name" << "Data Len" << "Signals" << "Comment"; - ui->MessagesTable->setColumnCount(5); + ui->MessagesTable->setColumnCount(MT_COLUMN_COUNT); ui->MessagesTable->setColumnWidth(0, 80); ui->MessagesTable->setColumnWidth(1, 240); ui->MessagesTable->setColumnWidth(2, 80); @@ -210,49 +212,57 @@ void DBCMainEditor::onCellChangedNode(int row,int col) void DBCMainEditor::onCellChangedMessage(int row,int col) { + QTableWidgetItem* item = NULL; + bool ret = false; + DBC_MESSAGE *msg = NULL; + uint msgID; + if (inhibitCellChanged) return; - qDebug() << "Editing row: " << row << " col: " << col; - - QTableWidgetItem *replacement = NULL; - int msgID; - QString msgName; - int msgLen; - QString msgComment; - DBC_MESSAGE newMsg; DBC_NODE *node = dbcFile->findNodeByIdx(ui->NodesTable->currentRow()); - DBC_MESSAGE *msg; if (node == NULL) { qDebug() << "No node set?!? This is bad!"; return; - //dbcHandler->findNodeByIdx(0); } - msgID = Utility::ParseStringToNum(ui->MessagesTable->item(row, 0)->text()); - qDebug() << "Msg ID of edited: " << msgID; + item = ui->MessagesTable->item(row, 0); + if(!item) return; + + msgID = Utility::ParseStringToNum2(item->text(), &ret); msg = dbcFile->messageHandler->findMsgByID(msgID); switch(col) { - case 0: //msg id - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - if (dbcFile->messageHandler->findMsgByID(msgID) != NULL) + case 0: //msg id + { + /* sanity checks */ + if(!ret) + { + /* bad message id */ + ui->MessagesTable->item(row, 0)->setText(""); + return; + } + if (msg != NULL) { QMessageBox msg; msg.setParent(0); msg.setText("An existing msg with that ID already exists! Aborting!"); msg.exec(); + + ui->MessagesTable->item(row, 0)->setText(""); return; } + + /* insert row */ + DBC_MESSAGE newMsg; newMsg.ID = msgID; newMsg.name = ""; newMsg.sender = node; newMsg.len = 0; for (int i = 0; i < referenceFrames->length(); i++) { - if (referenceFrames->at(i).ID == msgID) + if ((uint) referenceFrames->at(i).ID == msgID) { newMsg.len = referenceFrames->at(i).len; break; @@ -262,95 +272,65 @@ void DBCMainEditor::onCellChangedMessage(int row,int col) /* insert message in table */ inhibitCellChanged = true; - replacement = new QTableWidgetItem(Utility::formatNumber(msgID)); - replacement->setFlags(replacement->flags() ^ Qt::ItemIsEditable); - ui->MessagesTable->setItem(row, col, replacement); - replacement = new QTableWidgetItem(QString::number(newMsg.len)); - ui->MessagesTable->setItem(row, 2, replacement); - inhibitCellChanged = false; - } - break; - case 1: //msg name - msgName = ui->MessagesTable->item(row, col)->text().simplified().replace(' ', '_'); - if (msgName.length() == 0) return; - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - if (dbcFile->messageHandler->findMsgByName(msgName) != NULL) + item = ui->MessagesTable->item(row, 0); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + item->setText(Utility::formatNumber(msgID)); + + for(int i=1 ; iMessagesTable->item(row, i); + item->setFlags(item->flags() | Qt::ItemIsEditable); + } + + /* set length */ + item = ui->MessagesTable->item(row, 2); + item->setText(QString::number(newMsg.len)); + + inhibitCellChanged = false; + + /* insert a new row */ + insertBlankRow(); + break; + } + case 1: //msg name + { + QString msgName = ui->MessagesTable->item(row, 1)->text().simplified().replace(' ', '_'); + if (msgName.length() == 0) return; + if( ret && (msg!=NULL) ) + msg->name = msgName; + break; + } + case 2: //data length + { + bool parseOk = false; + uint msgLen = ui->MessagesTable->item(row, col)->text().toUInt(&parseOk); + + /* sanity checks */ + if(!parseOk) + { + ui->MessagesTable->item(row, col)->setText(""); return; } - newMsg.ID = -1; - newMsg.name = msgName; - newMsg.sender = node; - dbcFile->messageHandler->addMessage(newMsg); - } - else - { - if (msg != NULL) msg->name = msgName; - } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(msgName); - ui->MessagesTable->setItem(row, col, replacement); - inhibitCellChanged = false; - break; + if (msgLen > 8) + { + msgLen = 8; + ui->MessagesTable->item(row, col)->setText(QString::number(msgLen)); + } - case 2: //data length - msgLen = ui->MessagesTable->item(row, col)->text().toInt(); - if (msgLen < 0) msgLen = 0; - if (msgLen > 8) msgLen = 8; - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - DBC_MESSAGE newMsg; - newMsg.ID = -1; - newMsg.name = ""; - newMsg.len = msgLen; - newMsg.sender = node; - dbcFile->messageHandler->addMessage(newMsg); + if( ret && (msg!=NULL) ) + msg->len = msgLen; + break; } - else //editing an existing record + case 3: //signals (number) - we don't handle anything here. User cannot directly change this value + break; + case 4: //comment { - if (msg != NULL) msg->len = msgLen; + QString msgComment = ui->MessagesTable->item(row, col)->text().simplified(); + if( ret && (msgComment!=NULL) ) + msg->comment = msgComment; + break; } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(QString::number(msgLen, 16)); - ui->MessagesTable->setItem(row, col, replacement); - inhibitCellChanged = false; - - break; - case 3: //signals (number) - we don't handle anything here. User cannot directly change this value - break; - case 4: //comment - msgComment = ui->MessagesTable->item(row, col)->text().simplified(); - if (row == ui->MessagesTable->rowCount() - 1) //new record - { - DBC_MESSAGE newMsg; - newMsg.ID = -1; - newMsg.name = ""; - newMsg.len = 0; - newMsg.comment = msgComment; - newMsg.sender = node; - dbcFile->messageHandler->addMessage(newMsg); - } - else //editing an existing record - { - if (msg != NULL) msg->comment = msgComment; - } - inhibitCellChanged = true; - replacement = new QTableWidgetItem(msgComment); - ui->MessagesTable->setItem(row, col, replacement); - inhibitCellChanged = false; - break; - - } - - if (row == ui->MessagesTable->rowCount() - 1) - { - ui->MessagesTable->insertRow(ui->MessagesTable->rowCount()); } ui->MessagesTable->setCurrentCell(row, col); @@ -465,5 +445,17 @@ void DBCMainEditor::refreshMessagesTable(const DBC_NODE *node) } //insert blank record that can be used to add new messages - ui->MessagesTable->insertRow(ui->MessagesTable->rowCount()); + insertBlankRow(); +} + +void DBCMainEditor::insertBlankRow() +{ + int rowIdx = ui->MessagesTable->rowCount(); + ui->MessagesTable->insertRow(rowIdx); + for(int i=1 ; isetFlags(item->flags() & ~Qt::ItemIsEditable); + ui->MessagesTable->setItem(rowIdx, i, item); + } } diff --git a/dbcmaineditor.h b/dbcmaineditor.h index 07e8e11..4067693 100644 --- a/dbcmaineditor.h +++ b/dbcmaineditor.h @@ -46,6 +46,7 @@ private: void closeEvent(QCloseEvent *event); void readSettings(); void writeSettings(); + void insertBlankRow(); }; From 7bede56e6892711f2dba5d085728e52eea77a327 Mon Sep 17 00:00:00 2001 From: canpadawan Date: Tue, 19 Jul 2016 10:34:43 +0200 Subject: [PATCH 10/10] add temporary ParseStringToNum2 --- utility.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/utility.h b/utility.h index d5614e8..e2792ad 100644 --- a/utility.h +++ b/utility.h @@ -23,7 +23,7 @@ public: if (input.length() < 3) temp = 0; else temp = input.right(input.size() - 2).toLongLong(NULL, 16); } - else if (input.startsWith("B")) //binary number + else if (input.startsWith("0B") || input.startsWith("B")) //binary number { input = input.right(input.size() - 1); //remove the B for (int i = 0; i < input.length(); i++) @@ -44,6 +44,17 @@ public: return ParseStringToNum(input.toUtf8()); } + static uint ParseStringToNum2(QString pInput, bool* pOk_p = NULL) + { + if(pInput.startsWith("0b")) + { + pInput.remove(0, 2); + return pInput.toUInt(pOk_p, 2); + } + + return pInput.toUInt(pOk_p, 0); + } + static long GetTimeMS() { QDateTime stamp = QDateTime::currentDateTime();