add sniffer

This commit is contained in:
canpadawan
2016-07-07 16:47:43 +02:00
parent e9d3b718c9
commit 314ea0769d
10 changed files with 862 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
#include <QVariant>
#include <QDebug>
#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<mCurrent.len &&
((uchar*) &mLastMarker.data)[i] &&
!((uchar*) &mNotch)[i] )
{
return ((uchar*) &mCurrent.data)[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;
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef SNIFFERITEM_H
#define SNIFFERITEM_H
#include <QVariant>
#include <QTime>
#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
+267
View File
@@ -0,0 +1,267 @@
#include <QDebug>
#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<quint32, SnifferItem*>& 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<quint32, SnifferItem*>& 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<quint32, SnifferItem*>& 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<quint32, SnifferItem*>::iterator i;
QVector<quint32> 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<int>(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<CANFrame>& 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<quint32, SnifferItem*>& map = mFilter ? mFilters : mMap;
foreach(SnifferItem* item, map)
item->notch(true);
}
void SnifferModel::unNotch()
{
QMap<quint32, SnifferItem*>& map = mFilter ? mFilters : mMap;
foreach(SnifferItem* item, map)
item->notch(false);
}
+58
View File
@@ -0,0 +1,58 @@
#ifndef SNIFFERMODEL_H
#define SNIFFERMODEL_H
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include <QTimer>
#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<CANFrame>&);
void notch();
void unNotch();
signals:
void idChange(int, bool);
private:
QMap<quint32, SnifferItem*> mMap;
QMap<quint32, SnifferItem*> mFilters;
bool mFilter;
};
#endif // SNIFFERMODEL_H
+132
View File
@@ -0,0 +1,132 @@
#include <QDebug>
#include <QListWidgetItem>
#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;
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef SNIFFER_H
#define SNIFFER_H
#include <QDialog>
#include <QListWidgetItem>
#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<int, QListWidgetItem*> mMap;
bool mFilter;
};
#endif // SNIFFER_H