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 @@
+
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+