+10
-3
@@ -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 +=
|
||||
|
||||
|
||||
+12
-3
@@ -3,6 +3,15 @@
|
||||
#include <QFile>
|
||||
#include "utility.h"
|
||||
|
||||
|
||||
CANFrameModel::~CANFrameModel()
|
||||
{
|
||||
frames.clear();
|
||||
filteredFrames.clear();
|
||||
filters.clear();
|
||||
}
|
||||
|
||||
|
||||
int CANFrameModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
@@ -218,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+84
-93
@@ -5,6 +5,8 @@
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
|
||||
#define MT_COLUMN_COUNT 5
|
||||
|
||||
DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::DBCMainEditor)
|
||||
@@ -26,7 +28,7 @@ DBCMainEditor::DBCMainEditor(DBCHandler *handler, const QVector<CANFrame> *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,148 +212,125 @@ 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)
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
dbcFile->messageHandler->addMessage(newMsg);
|
||||
}
|
||||
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;
|
||||
|
||||
/* insert message in table */
|
||||
inhibitCellChanged = true;
|
||||
|
||||
item = ui->MessagesTable->item(row, 0);
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
item->setText(Utility::formatNumber(msgID));
|
||||
|
||||
for(int i=1 ; i<MT_COLUMN_COUNT ; i++)
|
||||
{
|
||||
item = ui->MessagesTable->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
|
||||
msgName = ui->MessagesTable->item(row, col)->text().simplified().replace(' ', '_');
|
||||
{
|
||||
QString msgName = ui->MessagesTable->item(row, 1)->text().simplified().replace(' ', '_');
|
||||
if (msgName.length() == 0) return;
|
||||
if (row == ui->MessagesTable->rowCount() - 1) //new record
|
||||
if( ret && (msg!=NULL) )
|
||||
msg->name = msgName;
|
||||
break;
|
||||
}
|
||||
case 2: //data length
|
||||
{
|
||||
if (dbcFile->messageHandler->findMsgByName(msgName) != NULL)
|
||||
bool parseOk = false;
|
||||
uint msgLen = ui->MessagesTable->item(row, col)->text().toUInt(&parseOk);
|
||||
|
||||
/* sanity checks */
|
||||
if(!parseOk)
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setParent(0);
|
||||
msg.setText("An existing msg with that name already exists! Aborting!");
|
||||
msg.exec();
|
||||
ui->MessagesTable->item(row, col)->setText("");
|
||||
return;
|
||||
}
|
||||
newMsg.ID = -1;
|
||||
newMsg.name = msgName;
|
||||
newMsg.sender = node;
|
||||
dbcFile->messageHandler->addMessage(newMsg);
|
||||
}
|
||||
else
|
||||
if (msgLen > 8)
|
||||
{
|
||||
if (msg != NULL) msg->name = msgName;
|
||||
msgLen = 8;
|
||||
ui->MessagesTable->item(row, col)->setText(QString::number(msgLen));
|
||||
}
|
||||
inhibitCellChanged = true;
|
||||
replacement = new QTableWidgetItem(msgName);
|
||||
ui->MessagesTable->setItem(row, col, replacement);
|
||||
inhibitCellChanged = false;
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
else //editing an existing record
|
||||
{
|
||||
if (msg != NULL) msg->len = msgLen;
|
||||
}
|
||||
inhibitCellChanged = true;
|
||||
replacement = new QTableWidgetItem(QString::number(msgLen, 16));
|
||||
ui->MessagesTable->setItem(row, col, replacement);
|
||||
inhibitCellChanged = false;
|
||||
|
||||
if( ret && (msg!=NULL) )
|
||||
msg->len = msgLen;
|
||||
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;
|
||||
QString msgComment = ui->MessagesTable->item(row, col)->text().simplified();
|
||||
if( ret && (msgComment!=NULL) )
|
||||
msg->comment = msgComment;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (row == ui->MessagesTable->rowCount() - 1)
|
||||
{
|
||||
ui->MessagesTable->insertRow(ui->MessagesTable->rowCount());
|
||||
}
|
||||
|
||||
ui->MessagesTable->setCurrentCell(row, col);
|
||||
@@ -466,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 ; i<MT_COLUMN_COUNT ; i++)
|
||||
{
|
||||
QTableWidgetItem *item = new QTableWidgetItem("");
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
ui->MessagesTable->setItem(rowIdx, i, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
void insertBlankRow();
|
||||
|
||||
};
|
||||
|
||||
|
||||
+20
-4
@@ -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,13 +266,18 @@ MainWindow::~MainWindow()
|
||||
isoWindow->close();
|
||||
delete isoWindow;
|
||||
}
|
||||
if (snifferWindow)
|
||||
{
|
||||
snifferWindow->close();
|
||||
delete snifferWindow;
|
||||
snifferWindow = NULL;
|
||||
}
|
||||
|
||||
delete elapsedTime;
|
||||
|
||||
delete ui;
|
||||
delete dbcHandler;
|
||||
model->clearFrames();
|
||||
delete model;
|
||||
delete elapsedTime;
|
||||
delete dbcHandler;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::exitApp()
|
||||
@@ -291,6 +298,7 @@ void MainWindow::exitApp()
|
||||
if (fuzzingWindow) fuzzingWindow->close();
|
||||
if (udsScanWindow) udsScanWindow->close();
|
||||
if (isoWindow) isoWindow->close();
|
||||
if (snifferWindow) snifferWindow->close();
|
||||
this->close();
|
||||
}
|
||||
|
||||
@@ -839,6 +847,14 @@ void MainWindow::showISOInterpreterWindow()
|
||||
isoWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showSnifferWindow()
|
||||
{
|
||||
if (!snifferWindow)
|
||||
snifferWindow = new SnifferWindow(this);
|
||||
snifferWindow->show();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::showFrameSenderWindow()
|
||||
{
|
||||
if (!frameSenderWindow)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -214,6 +214,7 @@
|
||||
<addaction name="actionRange_State_2"/>
|
||||
<addaction name="actionSingle_Multi_State_2"/>
|
||||
<addaction name="actionISO_TP_Decoder"/>
|
||||
<addaction name="actionSniffer"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSend_Frames">
|
||||
<property name="title">
|
||||
@@ -395,6 +396,11 @@
|
||||
<string>ISO-TP Decoder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSniffer">
|
||||
<property name="text">
|
||||
<string>Sniffer</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
||||
@@ -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.len;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,267 @@
|
||||
#include <QDebug>
|
||||
#include "sniffermodel.h"
|
||||
#include "snifferwindow.h"
|
||||
|
||||
|
||||
SnifferModel::SnifferModel(QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
mFilter(false)
|
||||
{
|
||||
}
|
||||
|
||||
SnifferModel::~SnifferModel()
|
||||
{
|
||||
qDeleteAll(mMap);
|
||||
mMap.clear();
|
||||
mFilters.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();
|
||||
|
||||
SnifferItem *item = static_cast<SnifferItem*>(index.internalPointer());
|
||||
if(!item) QVariant();
|
||||
|
||||
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();
|
||||
|
||||
/* ugly but I can't find best without creating a list to keep indexes */
|
||||
QMap<quint32, SnifferItem*>::const_iterator iter;
|
||||
int i;
|
||||
for(iter = map.begin(), i=0 ; i<row ; ++i, ++iter);
|
||||
|
||||
return createIndex(row, column, iter.value());
|
||||
}
|
||||
|
||||
|
||||
QModelIndex SnifferModel::parent(const QModelIndex &) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
|
||||
void SnifferModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
qDeleteAll(mMap);
|
||||
mMap.clear();
|
||||
mFilters.clear();
|
||||
mFilter = false;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,188 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>snifferWindow</class>
|
||||
<widget class="QDialog" name="snifferWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<height>752</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Sniffer</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Maximum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btNotch">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Notch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btUnNotch">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Unnotch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Maximum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Filters:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btAll">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btNone">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user