Merge pull request #166 from collin80/WIP

Merge WIP changes into Master
This commit is contained in:
Collin Kidder
2019-02-21 20:52:03 -05:00
committed by GitHub
59 changed files with 1815 additions and 660 deletions
+6 -5
View File
@@ -1,12 +1,12 @@
# SavvyCAN
Qt based cross platform canbus tool
(C) 2015-2017 EVTV and Collin Kidder
(C) 2015-2018 EVTV and Collin Kidder
A Qt5 based cross platform tool which can be used to load, save, and capture canbus frames.
This tool is designed to help with visualization, reverse engineering, debugging, and
capturing of canbus frames.
Really requires at a resolution of at least 1024x768. Fully multi-monitor capable.
Really requires at a resolution of at least 1024x768. Fully multi-monitor capable. Works on 4K monitors as well.
You are highly recommended to use the
[CANDue board from EVTV](http://store.evtv.me/proddetail.php?prod=ArduinoDueCANBUS&cat=23).
@@ -14,8 +14,8 @@ You are highly recommended to use the
The CANDue board must be running the GVRET firmware which can also be found
within the collin80 repos.
It is now possible to use any SocketCAN compatible device
under LINUX. There may, however, be some loss of some functionality as
It is now possible to use any QT SerialBus driver (socketcan, Vector, PeakCAN, TinyCAN).
There may, however, be some loss of some functionality as
some functions of SavvyCAN are designed for use directly with the
EVTVDue and CANDue 2.0 boards.
@@ -46,7 +46,8 @@ http://www.qcustomplot.com/
However, this source code is integrated into the source for SavvyCAN and one isn't required
to download it separately.
This project requires 5.8.0 or higher because of a dependency on QSerialBus.
This project requires 5.8.0 or higher because of a dependency on QSerialBus. However, you will get
even more SerialBus goodness if you use QT 5.11 or 5.12
## Instructions for compiling:
+4 -2
View File
@@ -65,7 +65,8 @@ SOURCES += main.cpp\
jsedit.cpp \
frameplaybackobject.cpp \
helpwindow.cpp \
blfhandler.cpp
blfhandler.cpp \
re/sniffer/SnifferDelegate.cpp
HEADERS += mainwindow.h \
can_structs.h \
@@ -121,7 +122,8 @@ HEADERS += mainwindow.h \
jsedit.h \
frameplaybackobject.h \
helpwindow.h \
blfhandler.h
blfhandler.h \
re/sniffer/SnifferDelegate.h
FORMS += ui/candatagrid.ui \
ui/connectionwindow.ui \
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+4 -4
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<QHelpCollectionProject version="1.0">
<assistant>
<title>SavvyCAN 181 documentation</title>
<homePage>qthelp://org.sphinx.savvycan.181/doc/index.html</homePage>
<startPage>qthelp://org.sphinx.savvycan.181/doc/index.html</startPage>
<title>SavvyCAN 189 documentation</title>
<homePage>qthelp://org.sphinx.savvycan.189/doc/index.html</homePage>
<startPage>qthelp://org.sphinx.savvycan.189/doc/index.html</startPage>
</assistant>
<docFiles>
<generate>
@@ -16,4 +16,4 @@
<file>SavvyCAN.qch</file>
</register>
</docFiles>
</QHelpCollectionProject>
</QHelpCollectionProject>
+59 -52
View File
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<QtHelpProject version="1.0">
<namespace>org.sphinx.savvycan.181</namespace>
<namespace>org.sphinx.savvycan.189</namespace>
<virtualFolder>doc</virtualFolder>
<customFilter name="SavvyCAN 181">
<customFilter name="SavvyCAN 189">
<filterAttribute>SavvyCAN</filterAttribute>
<filterAttribute>181</filterAttribute>
<filterAttribute>189</filterAttribute>
</customFilter>
<filterSection>
<filterAttribute>SavvyCAN</filterAttribute>
<filterAttribute>181</filterAttribute>
<filterAttribute>189</filterAttribute>
<toc>
<section title="SavvyCAN 181 documentation" ref="index.html">
<section title="SavvyCAN 189 documentation" ref="index.html">
<section title="Main / Start Up Screen" ref="mainscreen.html"/>
<section title="The Main Frame List" ref="mainscreen.html#the-main-frame-list"/>
<section title="The Bottom Statusbar" ref="mainscreen.html#the-bottom-statusbar"/>
@@ -58,6 +58,11 @@
<section title="Sniffer Window" ref="sniffer.html"/>
<section title="Using the Sniffer Window" ref="sniffer.html#using-the-sniffer-window"/>
<section title="Notching and Unnotching" ref="sniffer.html#notching-and-unnotching"/>
<section title="Advanced Options" ref="sniffer.html#advanced-options"/>
<section title="Never Expire IDs" ref="sniffer.html#never-expire-ids"/>
<section title="Mute notched bits" ref="sniffer.html#mute-notched-bits"/>
<section title="Fade inactive bytes" ref="sniffer.html#fade-inactive-bytes"/>
<section title="View Bits" ref="sniffer.html#view-bits"/>
<section title="Frame Details Window" ref="framedetails.html"/>
<section title="The Purpose of Frame Details Window" ref="framedetails.html#the-purpose-of-frame-details-window"/>
<section title="File Comparison Window" ref="filecomparison.html"/>
@@ -101,63 +106,65 @@
</keywords>
<files>
<file>flowview.html</file>
<file>dbc_manager.html</file>
<file>graphwindow.html</file>
<file>framedetails.html</file>
<file>rangestate.html</file>
<file>filecomparison.html</file>
<file>connectionwindow.html</file>
<file>fuzzingwindow.html</file>
<file>mainscreen.html</file>
<file>signaleditor.html</file>
<file>uds_scanner.html</file>
<file>customsender.html</file>
<file>graphsetup.html</file>
<file>playbackwindow.html</file>
<file>index.html</file>
<file>scriptingwindow.html</file>
<file>bisector.html</file>
<file>firmwareuploader.html</file>
<file>genindex.html</file>
<file>sniffer.html</file>
<file>isotp_decoder.html</file>
<file>preferences.html</file>
<file>connectionwindow.html</file>
<file>customsender.html</file>
<file>dbc_editor.html</file>
<file>_static/file.png</file>
<file>_static/down.png</file>
<file>dbc_manager.html</file>
<file>filecomparison.html</file>
<file>firmwareuploader.html</file>
<file>flowview.html</file>
<file>framedetails.html</file>
<file>fuzzingwindow.html</file>
<file>genindex.html</file>
<file>graphsetup.html</file>
<file>graphwindow.html</file>
<file>index.html</file>
<file>isotp_decoder.html</file>
<file>mainscreen.html</file>
<file>playbackwindow.html</file>
<file>preferences.html</file>
<file>rangestate.html</file>
<file>scriptingwindow.html</file>
<file>search.html</file>
<file>signaleditor.html</file>
<file>sniffer.html</file>
<file>uds_scanner.html</file>
<file>_static/ajax-loader.gif</file>
<file>_static/comment-close.png</file>
<file>_static/minus.png</file>
<file>_static/comment-bright.png</file>
<file>_static/up-pressed.png</file>
<file>_static/pygments.css</file>
<file>_static/plus.png</file>
<file>_static/nonav.css</file>
<file>_static/alabaster.css</file>
<file>_static/basic.css</file>
<file>_static/down-pressed.png</file>
<file>_static/up.png</file>
<file>_static/comment-bright.png</file>
<file>_static/comment-close.png</file>
<file>_static/comment.png</file>
<file>_images/SignalEditor.png</file>
<file>_images/FrameInfoWindow.png</file>
<file>_images/DBCEditor.png</file>
<file>_images/UDS_Scanner.png</file>
<file>_images/Sniffer.png</file>
<file>_static/down-pressed.png</file>
<file>_static/down.png</file>
<file>_static/file.png</file>
<file>_static/minus.png</file>
<file>_static/nonav.css</file>
<file>_static/plus.png</file>
<file>_static/pygments.css</file>
<file>_static/up-pressed.png</file>
<file>_static/up.png</file>
<file>_images/Bisector.png</file>
<file>_images/FuzzingWindow.png</file>
<file>_images/GraphingView.png</file>
<file>_images/ScriptingWindow.png</file>
<file>_images/DBCManager.png</file>
<file>_images/GraphSetup.png</file>
<file>_images/RangeState.png</file>
<file>_images/Preferences.png</file>
<file>_images/ConnectionWindow.png</file>
<file>_images/CustomSender.png</file>
<file>_images/DBCEditor.png</file>
<file>_images/DBCManager.png</file>
<file>_images/FileComparator.png</file>
<file>_images/FlowView.png</file>
<file>_images/FrameInfoWindow.png</file>
<file>_images/FuzzingWindow.png</file>
<file>_images/GraphSetup.png</file>
<file>_images/GraphingView.png</file>
<file>_images/ISOTPDecoder.png</file>
<file>_images/MainScreen.png</file>
<file>_images/FlowView.png</file>
<file>_images/CustomSender.png</file>
<file>_images/Playback.png</file>
<file>_images/Preferences.png</file>
<file>_images/RangeState.png</file>
<file>_images/ScriptingWindow.png</file>
<file>_images/SignalEditor.png</file>
<file>_images/Sniffer.png</file>
<file>_images/UDS_Scanner.png</file>
</files>
</filterSection>
</QtHelpProject>
</QtHelpProject>
+24 -23
View File
@@ -160,6 +160,7 @@ void CANFrameModel::setOverwriteMode(bool mode)
{
beginResetModel();
overwriteDups = mode;
recalcOverwrite();
endResetModel();
}
@@ -191,26 +192,20 @@ void CANFrameModel::recalcOverwrite()
mutex.lock();
beginResetModel();
for (int i = 1; i < frames.count(); i++)
{
found = false;
for (int j = 0; j <= lastUnique; j++)
{
if (frames[i].ID == frames[j].ID)
{
frames.replace(j, frames[i]);
found = true;
break;
}
}
if (!found)
{
lastUnique++;
frames.replace(lastUnique, frames[i]);
}
}
while (frames.count() > lastUnique) frames.removeLast();
//Look at the current list of frames and turn it into just a list of unique IDs
QHash<int, CANFrame> overWriteFrames;
foreach(CANFrame frame, frames)
{
if (!overWriteFrames.contains(frame.ID))
{
overWriteFrames.insert(frame.ID, frame);
}
else overWriteFrames[frame.ID] = frame;
}
//Then replace the old list of frames with just the unique list
frames.clear();
frames.append(overWriteFrames.values().toVector());
filteredFrames.clear();
filteredFrames.reserve(preallocSize);
@@ -255,6 +250,11 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
return QColor(Qt::white);
}
if (role == Qt::TextAlignmentRole)
{
return Qt::AlignLeft;
}
if (role == Qt::TextColorRole)
{
if (dbcHandler != NULL && interpretFrames)
@@ -300,7 +300,8 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
for (int i = 0; i < dLen; i++)
{
quint8 byt = thisFrame.data[i];
if (byt < 0x20) byt = 0x2E; //A dot
//0x20 through 0x7E are printable characters. Outside of that range they aren't. So use dots instead
if (byt < 0x20) byt = 0x2E; //dot character
if (byt > 0x7E) byt = 0x2E;
tempString.append(QString::fromUtf8((char *)&byt, 1));
}
@@ -326,7 +327,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
if (msg != NULL)
{
tempString.append("\n");
tempString.append(" <Interpreted>\n");
tempString.append(msg->name + "\n" + msg->comment + "\n");
for (int j = 0; j < msg->sigHandler->getCount(); j++)
{
@@ -410,7 +411,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
frames.append(tempFrame);
if (filters[tempFrame.ID])
{
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
filteredFrames.append(tempFrame);
if (autoRefresh) endInsertRows();
}
@@ -432,7 +433,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
frames.append(tempFrame);
if (filters[tempFrame.ID])
{
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
filteredFrames.append(tempFrame);
if (autoRefresh) endInsertRows();
}
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef CONFIG
#define CONFIG
#define VERSION 187
#define VERSION 190
//try to keep this in sync.
//SavvyCAN will complain if you connect a GVRET board with a revision
+1 -1
View File
@@ -16,7 +16,7 @@ namespace CANCon {
{
GVRET_SERIAL,
KVASER,
SOCKETCAN,
SERIALBUS,
REMOTE,
NONE
};
+3 -3
View File
@@ -5,11 +5,11 @@
using namespace CANCon;
CANConnection* CanConFactory::create(type pType, QString pPortName)
CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName)
{
switch(pType) {
case SOCKETCAN:
return new SerialBusConnection(pPortName);
case SERIALBUS:
return new SerialBusConnection(pPortName, pDriverName);
case GVRET_SERIAL:
return new GVRetSerial(pPortName, false);
case REMOTE:
+1 -1
View File
@@ -7,7 +7,7 @@
class CanConFactory
{
public:
static CANConnection* create(CANCon::type, QString pPortName);
static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName);
};
#endif // CANCONFACTORY_H
+6
View File
@@ -3,6 +3,7 @@
#include "canconnection.h"
CANConnection::CANConnection(QString pPort,
QString pDriver,
CANCon::type pType,
int pNumBuses,
int pQueueLen,
@@ -10,6 +11,7 @@ CANConnection::CANConnection(QString pPort,
mQueue(),
mNumBuses(pNumBuses),
mPort(pPort),
mDriver(pDriver),
mType(pType),
mIsCapSuspended(false),
mStatus(CANCon::NOT_CONNECTED),
@@ -227,6 +229,10 @@ QString CANConnection::getPort() {
return mPort;
}
QString CANConnection::getDriver()
{
return mDriver;
}
LFQueue<CANFrame>& CANConnection::getQueue() {
return mQueue;
+11 -1
View File
@@ -19,13 +19,15 @@ protected:
/**
* @brief CANConnection constructor
* @param pPort: string containing port name
* @param pDriver: string containing driver name - Really only used for SerialBus connections
* @param pType: the type of connection @ref CANCon::type
* @param pNumBuses: the number of buses the device has
* @param pQueueLen: the length of the lock free queue to use
* @param pUseThread: if set to true, object will be execute in a dedicated thread
*/
CANConnection(QString pPort,
CANCon::type pType,
QString pDriver,
CANCon::type pType,
int pNumBuses,
int pQueueLen,
bool pUseThread);
@@ -50,6 +52,13 @@ public:
*/
QString getPort();
/**
* @brief getDriver
* @return returns the name of the driver used for this device
*/
QString getDriver();
/**
* @brief getQueue
* @return the lock free queue of the device
@@ -294,6 +303,7 @@ protected:
private:
LFQueue<CANFrame> mQueue;
const QString mPort;
const QString mDriver;
const CANCon::type mType;
bool mIsCapSuspended;
QAtomicInt mStatus;
+7 -6
View File
@@ -87,10 +87,11 @@ Qt::ItemFlags CANConnectionModel::flags(const QModelIndex &index) const
CANConnection *conn_p = getAtIdx(index.row(), busId);
if (!conn_p) return Qt::ItemFlag::NoItemFlags;
//you can't set speed, single wire, or listen only on socketcan devices so
//detect if we're using GVRET where you can and turn that functionality on
bool editParams = false;
if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true;
//socketcan is limited for what you can set but the other serialbus
//devices should be able to set the stuff. For now let anyone try
//and the underlying drivers can do with them as they will
bool editParams = true;
//if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true;
switch (Column(index.column()))
{
@@ -152,7 +153,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
bool ret;
if (!conn_p) return QVariant();
ret = conn_p->getBusSettings(busId, bus);
bool isSocketCAN = (conn_p->getType() == CANCon::SOCKETCAN) ? true: false;
bool isSocketCAN = (conn_p->getType() == CANCon::SERIALBUS) ? true: false;
//qDebug() << "ConnP: " << conn_p << " ret " << ret;
@@ -167,7 +168,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
if (conn_p)
switch (conn_p->getType()) {
case CANCon::KVASER: return "KVASER";
case CANCon::SOCKETCAN: return "SocketCAN";
case CANCon::SERIALBUS: return "SerialBus";
case CANCon::GVRET_SERIAL: return "GVRET";
default: {}
}
+71 -38
View File
@@ -44,16 +44,13 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
/* load connection configuration */
loadConnections();
ui->rbSocketCAN->setEnabled(isSocketCanAvailable());
#ifdef Q_OS_WIN
ui->rbKvaser->setEnabled(true);
#endif
ui->rbSocketCAN->setEnabled(isSerialBusAvailable());
connect(ui->btnOK, &QAbstractButton::clicked, this, &ConnectionWindow::handleOKButton);
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->rbRemote, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->cbDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConnectionWindow::handleDeviceTypeChanged);
connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged);
connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll);
connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll);
@@ -63,6 +60,9 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
connect(ui->btnSendHex, &QPushButton::clicked, this, &ConnectionWindow::handleSendHex);
connect(ui->btnSendText, &QPushButton::clicked, this, &ConnectionWindow::handleSendText);
connect(ui->ckEnableConsole, &QCheckBox::toggled, this, &ConnectionWindow::consoleEnableChanged);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
}
ConnectionWindow::~ConnectionWindow()
@@ -118,7 +118,7 @@ bool ConnectionWindow::eventFilter(QObject *obj, QEvent *event)
// standard event processing
return QObject::eventFilter(obj, event);
}
return false;
//return false;
}
void ConnectionWindow::readSettings()
@@ -200,7 +200,7 @@ void ConnectionWindow::consoleEnableChanged(bool checked) {
connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray)));
}
else { //turn it off
disconnect(conn_p, SIGNAL(debugOutput(QString)), 0, 0);
disconnect(conn_p, SIGNAL(debugOutput(QString)), nullptr, nullptr);
disconnect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray)));
}
}
@@ -226,11 +226,18 @@ void ConnectionWindow::handleDisableAll()
void ConnectionWindow::handleConnTypeChanged()
{
if (ui->rbGVRET->isChecked()) selectSerial();
if (ui->rbKvaser->isChecked()) selectKvaser();
if (ui->rbSocketCAN->isChecked()) selectSocketCan();
if (ui->rbRemote->isChecked()) selectRemote();
}
void ConnectionWindow::handleDeviceTypeChanged()
{
ui->cbPort->clear();
canDevices = QCanBus::instance()->availableDevices(ui->cbDeviceType->currentText());
for (int i = 0; i < canDevices.count(); i++)
ui->cbPort->addItem(canDevices[i].name());
}
/* status */
void ConnectionWindow::connectionStatus(CANConStatus pStatus)
@@ -244,12 +251,12 @@ void ConnectionWindow::connectionStatus(CANConStatus pStatus)
void ConnectionWindow::handleOKButton()
{
CANConnection* conn_p = NULL;
CANConnection* conn_p = nullptr;
if( ! CANConManager::getInstance()->getByName(getPortName()) )
{
/* create connection */
conn_p = create(getConnectionType(), getPortName());
conn_p = create(getConnectionType(), getPortName(), getDriverName());
if(!conn_p)
return;
/* add connection to model */
@@ -281,7 +288,7 @@ return;
ui->btnOK->setText(tr("Create New Connection"));
ui->rbGVRET->setChecked(true);
setSpeed(0);
setPortName(CANCon::GVRET_SERIAL, "");
setPortName(CANCon::GVRET_SERIAL, "", "");
}
else
{
@@ -300,7 +307,7 @@ return;
ui->btnOK->setText(tr("Update Connection Settings"));
setSpeed(bus.getSpeed());
setPortName(conn_p->getType(), conn_p->getPort());
setPortName(conn_p->getType(), conn_p->getPort(), conn_p->getDriver());
}
}
@@ -333,6 +340,8 @@ void ConnectionWindow::selectSerial()
ui->lPort->setText("Port:");
/* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts();
@@ -341,41 +350,42 @@ void ConnectionWindow::selectSerial()
ui->cbPort->addItem(ports[i].portName());
}
void ConnectionWindow::selectKvaser()
{
ui->lPort->setText("Port:");
/* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage);
}
void ConnectionWindow::selectSocketCan()
{
ui->lPort->setText("Port:");
/* set edit text page visible */
ui->stPort->setCurrentWidget(ui->etPage);
ui->stPort->setCurrentWidget(ui->cbPage);
ui->lblDeviceType->setHidden(false);
ui->cbDeviceType->setHidden(false);
ui->cbDeviceType->clear();
QStringList plugins;
plugins = QCanBus::instance()->plugins();
for (int i = 0; i < plugins.count(); i++)
ui->cbDeviceType->addItem(plugins[i]);
}
void ConnectionWindow::selectRemote()
{
ui->lPort->setText("IP Address:");
ui->stPort->setCurrentWidget(ui->etPage);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
}
void ConnectionWindow::setSpeed(int speed0)
{
Q_UNUSED(speed0);
}
void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName, QString pDriver)
{
switch(pType)
{
case CANCon::GVRET_SERIAL:
ui->rbGVRET->setChecked(true);
break;
case CANCon::KVASER:
ui->rbKvaser->setChecked(true);
break;
case CANCon::SOCKETCAN:
case CANCon::SERIALBUS:
ui->rbSocketCAN->setChecked(true);
//you can't configure any of the below three with socketcan so dim them out
break;
@@ -394,7 +404,16 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
ui->cbPort->setCurrentIndex(idx);
break;
}
case CANCon::SOCKETCAN:
case CANCon::SERIALBUS:
{
int idx = ui->cbDeviceType->findText(pDriver);
if (idx < 0) idx = 0;
ui->cbDeviceType->setCurrentIndex(idx);
idx = ui->cbPort->findText(pPortName);
if( idx < 0 ) idx = 0;
ui->cbPort->setCurrentIndex(idx);
break;
}
case CANCon::REMOTE:
{
ui->lePort->setText(pPortName);
@@ -415,9 +434,8 @@ QString ConnectionWindow::getPortName()
{
switch( getConnectionType() ) {
case CANCon::GVRET_SERIAL:
case CANCon::KVASER:
case CANCon::SERIALBUS:
return ui->cbPort->currentText();
case CANCon::SOCKETCAN:
case CANCon::REMOTE:
return ui->lePort->text();
default:
@@ -427,11 +445,20 @@ QString ConnectionWindow::getPortName()
return "";
}
QString ConnectionWindow::getDriverName()
{
if (getConnectionType() == CANCon::SERIALBUS)
{
return ui->cbDeviceType->currentText();
}
return "";
}
CANCon::type ConnectionWindow::getConnectionType()
{
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
if (ui->rbKvaser->isChecked()) return CANCon::KVASER;
if (ui->rbSocketCAN->isChecked()) return CANCon::SOCKETCAN;
if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS;
if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
qDebug() << "getConnectionType: error";
return CANCon::NONE;
@@ -440,6 +467,7 @@ CANCon::type ConnectionWindow::getConnectionType()
void ConnectionWindow::setSWMode(bool mode)
{
Q_UNUSED(mode);
}
bool ConnectionWindow::getSWMode()
@@ -475,21 +503,19 @@ void ConnectionWindow::handleRevert()
}
bool ConnectionWindow::isSocketCanAvailable()
bool ConnectionWindow::isSerialBusAvailable()
{
#ifdef Q_OS_LINUX
if (QCanBus::instance()->plugins().contains(QStringLiteral("socketcan"))) return true;
#endif
if (QCanBus::instance()->plugins().count() > 0) return true;
return false;
}
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName)
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver)
{
CANConnection* conn_p;
/* create connection */
conn_p = CanConFactory::create(pTye, pPortName);
conn_p = CanConFactory::create(pTye, pPortName, pDriver);
if(conn_p)
{
/* connect signal */
@@ -512,11 +538,15 @@ void ConnectionWindow::loadConnections()
/* fill connection list */
QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>();
QVector<QString> driverNames = settings.value("connections/driverNames").value<QVector<QString>>();
QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>();
for(int i=0 ; i<portNames.count() ; i++)
//don't load the connections if the three setting arrays above aren't all the same size.
if (portNames.count() != driverNames.count() || devTypes.count() != driverNames.count()) return;
for(int i = 0 ; i < portNames.count() ; i++)
{
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i]);
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i]);
/* add connection to model */
connModel->add(conn_p);
}
@@ -533,14 +563,17 @@ void ConnectionWindow::saveConnections()
QSettings settings;
QVector<QString> portNames;
QVector<int> devTypes;
QVector<QString> driverNames;
/* save connections */
foreach(CANConnection* conn_p, conns)
{
portNames.append(conn_p->getPort());
devTypes.append(conn_p->getType());
driverNames.append(conn_p->getDriver());
}
settings.setValue("connections/portNames", QVariant::fromValue(portNames));
settings.setValue("connections/types", QVariant::fromValue(devTypes));
settings.setValue("connections/driverNames", QVariant::fromValue(driverNames));
}
+7 -3
View File
@@ -9,6 +9,7 @@
#include <QSettings>
#include <QTimer>
#include <QItemSelection>
#include <QCanBusDeviceInfo>
#include "canconnectionmodel.h"
#include "connections/canconnection.h"
@@ -47,6 +48,7 @@ public slots:
private slots:
void handleOKButton();
void handleConnTypeChanged();
void handleDeviceTypeChanged();
void currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void consoleEnableChanged(bool checked);
void handleRemoveConn();
@@ -63,6 +65,7 @@ private slots:
private:
Ui::ConnectionWindow *ui;
QList<QSerialPortInfo> ports;
QList<QCanBusDeviceInfo> canDevices;
QSettings *settings;
CANConnectionModel *connModel;
@@ -70,13 +73,14 @@ private:
void selectKvaser();
void selectSocketCan();
void selectRemote();
bool isSocketCanAvailable();
bool isSerialBusAvailable();
int getSpeed();
QString getPortName();
void setPortName(CANCon::type pType, QString pPortName);
QString getDriverName();
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
void setActiveAll(bool pActive);
CANConnection* create(CANCon::type pTye, QString pPortName);
CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver);
void loadConnections();
void saveConnections();
void showEvent(QShowEvent *);
+138 -68
View File
@@ -9,19 +9,20 @@
#include "gvretserial.h"
GVRetSerial::GVRetSerial(QString portName, bool useTcp) :
CANConnection(portName, CANCon::GVRET_SERIAL, 3, 4000, true),
CANConnection(portName, "gvret", CANCon::GVRET_SERIAL, 3, 4000, true),
useTcp(useTcp),
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{
qDebug() << "GVRetSerial()";
debugOutput("GVRetSerial()");
sendDebug("GVRetSerial()");
serial = NULL;
tcpClient = NULL;
udpClient = NULL;
rx_state = IDLE;
rx_step = 0;
gotValidated = true;
validationCounter = 10; //how many times we can miss validation before we die
isAutoRestart = false;
espSerialMode = true;
timeBasis = 0;
lastSystemTimeBasis = 0;
@@ -34,27 +35,38 @@ GVRetSerial::GVRetSerial(QString portName, bool useTcp) :
GVRetSerial::~GVRetSerial()
{
stop();
qDebug() << "~GVRetSerial()";
debugOutput("~GVRetSerial()");
sendDebug("~GVRetSerial()");
}
void GVRetSerial::sendDebug(const QString debugText)
{
qDebug() << debugText;
debugOutput(debugText);
}
void GVRetSerial::sendToSerial(const QByteArray &bytes)
{
if (serial == NULL && tcpClient == NULL)
if (serial == NULL && tcpClient == NULL && udpClient == NULL)
{
debugOutput("Attempt to write to serial port when it has not been initialized!");
sendDebug("Attempt to write to serial port when it has not been initialized!");
return;
}
if (serial && !serial->isOpen())
{
debugOutput("Attempt to write to serial port when it is not open!");
sendDebug("Attempt to write to serial port when it is not open!");
return;
}
if (tcpClient && !tcpClient->isOpen())
{
debugOutput("Attempt to write to TCP/IP port when it is not open!");
sendDebug("Attempt to write to TCP/IP port when it is not open!");
return;
}
if (udpClient && !udpClient->isOpen())
{
sendDebug("Attempt to write to UDP Socket when it is not open!");
return;
}
@@ -64,10 +76,11 @@ void GVRetSerial::sendToSerial(const QByteArray &bytes)
byt = (unsigned char)byt;
buildDebug = buildDebug % QString::number(byt, 16) % " ";
}
debugOutput(buildDebug);
sendDebug(buildDebug);
if (serial) serial->write(bytes);
if (tcpClient) tcpClient->write(bytes);
if (udpClient) udpClient->write(bytes);
}
void GVRetSerial::piStarted()
@@ -176,8 +189,7 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
if (pBusIdx < 2) {
/* update baud rates */
QByteArray buffer;
qDebug() << "Got signal to update bauds. 1: " << (can0Baud & 0xFFFFFFF) <<" 2: " << (can1Baud & 0xFFFFFFF);
debugOutput("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
sendDebug("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
buffer[0] = (char)0xF1; //start of a command over serial
buffer[1] = 5; //setup canbus
buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first
@@ -195,8 +207,7 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
{
/* update baud rates */
QByteArray buffer;
qDebug() << "Got signal to update extended bus speeds SWCAN: " << swcanBaud <<" LIN1: " << lin1Baud << " LIN2: " << lin2Baud;
debugOutput("Got signal to update extended bus speeds SWCAN: " + QString::number(swcanBaud) + " LIN1: " + QString::number(lin1Baud) + " LIN2: " + QString::number(lin2Baud));
sendDebug("Got signal to update extended bus speeds SWCAN: " + QString::number(swcanBaud) + " LIN1: " + QString::number(lin1Baud) + " LIN2: " + QString::number(lin2Baud));
buffer[0] = (char)0xF1; //start of a command over serial
buffer[1] = 14; //setup extended buses
buffer[2] = (unsigned char)(swcanBaud & 0xFF); //four bytes of ID LSB first
@@ -227,8 +238,10 @@ bool GVRetSerial::piSendFrame(const CANFrame& frame)
framesRapid++;
if (serial == NULL) return false;
if (!serial->isOpen()) return false;
if (serial == NULL && tcpClient == NULL && udpClient == NULL) return false;
if (serial && !serial->isOpen()) return false;
if (tcpClient && !tcpClient->isOpen()) return false;
if (udpClient && !udpClient->isOpen()) return false;
//if (!isConnected) return false;
// Doesn't make sense to send an error frame
@@ -283,55 +296,84 @@ void GVRetSerial::connectDevice()
disconnectDevice();
if(tcpClient)
disconnectDevice();
if (udpClient)
disconnectDevice();
/* open new device */
// this does the wrong thing if the serial port has a '.' in the name
// if (getPort().contains('.')) //TCP/IP mode then since it looks like an IP address
if (useTcp)
{
qDebug() << "TCP Connection to a GVRET device";
// /*
sendDebug("TCP Connection to a GVRET device");
tcpClient = new QTcpSocket();
tcpClient->connectToHost(getPort(), 23);
connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readSerialData()));
connect(tcpClient, SIGNAL(connected()), this, SLOT(tcpConnected()));
connect(tcpClient, SIGNAL(connected()), this, SLOT(deviceConnected()));
sendDebug("Created TCP Socket");
// */
/*
qDebug() << "UDP Connection to a GVRET device";
udpClient = new QUdpSocket();
udpClient->connectToHost(getPort(), 17222);
connect(udpClient, SIGNAL(readyRead()), this, SLOT(readSerialData()));
//connect(udpClient, SIGNAL(connected()), this, SLOT(tcpConnected()));
debugOutput("Created UDP Socket");
tcpConnected();
*/
}
else {
qDebug() << "Serial connection to a GVRET device";
sendDebug("Serial connection to a GVRET device");
serial = new QSerialPort(QSerialPortInfo(getPort()));
if(!serial) {
qDebug() << "can't open serial port " << getPort();
debugOutput("can't open serial port " + getPort());
sendDebug("can't open serial port " + getPort());
return;
}
debugOutput("Created Serial Port Object");
sendDebug("Created Serial Port Object");
/* configure */
serial->setDataBits(serial->Data8);
serial->setFlowControl(serial->HardwareControl); //this is important though
//serial->setFlowControl(serial->NoFlowControl);
serial->setBaudRate(1000000);
if (!serial->open(QIODevice::ReadWrite))
{
qDebug() << serial->errorString();
}
//serial->setDataTerminalReady(false); //you do need to set these or the fan gets dirty
//serial->setRequestToSend(false);
serial->setDataTerminalReady(true); //you do need to set these or the fan gets dirty
serial->setRequestToSend(true);
debugOutput("Opened Serial Port");
/* connect reading event */
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialError(QSerialPort::SerialPortError)));
}
if (serial) tcpConnected(); //well, not a proper function name I guess...
/* configure */
serial->setBaudRate(1000000); //most GVRET devices ignore baud, ESP32 needs it set explicitly to the proper value
serial->setDataBits(serial->Data8);
if (espSerialMode)
{
sendDebug("Trying ESP32 Serial Mode");
serial->setFlowControl(serial->NoFlowControl);
if (!serial->open(QIODevice::ReadWrite))
{
//sendDebug("Error returned during port opening: " + serial->errorString());
}
else
{
serial->setDataTerminalReady(false); //ESP32 uses these for bootloader selection and reset so turn them off
serial->setRequestToSend(false);
QTimer::singleShot(3000, this, SLOT(deviceConnected())); //give ESP32 some time as it could have rebooted
}
}
else
{
sendDebug("Trying Standard Serial Mode");
serial->setFlowControl(serial->HardwareControl); //Most GVRET style devices use hardware flow control
if (!serial->open(QIODevice::ReadWrite))
{
//sendDebug("Error returned during port opening: " + serial->errorString());
}
else
{
//serial->setDataTerminalReady(true); //Seemingly these two lines used to be needed
//serial->setRequestToSend(true); //But, really both ends should automatically handle these
deviceConnected();
}
}
}
}
void GVRetSerial::tcpConnected()
void GVRetSerial::deviceConnected()
{
qDebug() << "Connected to GVRET Device!";
sendDebug("Connecting to GVRET Device!");
QByteArray output;
output.append((unsigned char)0xE7); //this puts the device into binary comm mode
output.append((unsigned char)0xE7);
@@ -367,14 +409,8 @@ void GVRetSerial::tcpConnected()
sendToSerial(output);
/* start timer */
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
mTimer.setInterval(250); //tick four times per second
mTimer.setSingleShot(false); //keep ticking
mTimer.start();
if(doValidation) {
QTimer::singleShot(1000, this, SLOT(connectionTimeout()));
QTimer::singleShot(5000, this, SLOT(connectionTimeout()));
}
else {
setStatus(CANCon::CONNECTED);
@@ -390,7 +426,7 @@ void GVRetSerial::disconnectDevice() {
{
if (serial->isOpen())
{
serial->clear();
//serial->clear();
serial->close();
}
@@ -408,6 +444,17 @@ void GVRetSerial::disconnectDevice() {
delete tcpClient;
tcpClient = NULL;
}
if (udpClient != NULL)
{
if (udpClient->isOpen())
{
udpClient->close();
}
udpClient->disconnect();
delete udpClient;
udpClient = NULL;
}
setStatus(CANCon::NOT_CONNECTED);
CANConStatus stats;
stats.conStatus = getStatus();
@@ -426,14 +473,17 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
case QSerialPort::DeviceNotFoundError:
errMessage = "Device not found error on serial";
killConnection = true;
piStop();
break;
case QSerialPort::PermissionError:
errMessage = "Permission error on serial port";
killConnection = true;
piStop();
break;
case QSerialPort::OpenError:
errMessage = "Open error on serial port";
killConnection = true;
piStop();
break;
case QSerialPort::ParityError:
errMessage = "Parity error on serial port";
@@ -446,13 +496,16 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
break;
case QSerialPort::WriteError:
errMessage = "Write error on serial port";
piStop();
break;
case QSerialPort::ReadError:
errMessage = "Read error on serial port";
piStop();
break;
case QSerialPort::ResourceError:
errMessage = "Serial port seems to have disappeared.";
killConnection = true;
piStop();
break;
case QSerialPort::UnsupportedOperationError:
errMessage = "Unsupported operation on serial port";
@@ -461,23 +514,28 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
case QSerialPort::UnknownError:
errMessage = "Beats me what happened to the serial port.";
killConnection = true;
piStop();
break;
case QSerialPort::TimeoutError:
errMessage = "Timeout error on serial port";
killConnection = true;
break;
case QSerialPort::NotOpenError:
errMessage = "The serial port isn't open dummy";
errMessage = "The serial port isn't open";
killConnection = true;
piStop();
break;
}
serial->clearError();
serial->flush();
serial->close();
/*
if (serial)
{
serial->clearError();
serial->flush();
serial->close();
}*/
if (errMessage.length() > 1)
{
qDebug() << errMessage;
debugOutput(errMessage);
sendDebug(errMessage);
}
if (killConnection)
{
@@ -490,13 +548,23 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
void GVRetSerial::connectionTimeout()
{
//one second after trying to connect are we actually connected?
//if (CANCon::NOT_CONNECTED==getStatus()) //no?
if (!gotValidated)
if (CANCon::NOT_CONNECTED==getStatus()) //no?
{
//then emit the the failure signal and see if anyone cares
qDebug() << "Failed to connect to GVRET at that com port";
sendDebug("Failed to connect to GVRET at that com port");
//toggle the serial mode and try again
espSerialMode = !espSerialMode;
disconnectDevice();
connectDevice();
}
else
{
/* start timer */
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
mTimer.setInterval(250); //tick four times per second
mTimer.setSingleShot(false); //keep ticking
mTimer.start();
}
}
@@ -509,9 +577,9 @@ void GVRetSerial::readSerialData()
if (serial) data = serial->readAll();
if (tcpClient) data = tcpClient->readAll();
if (udpClient) data = udpClient->readAll();
debugOutput("Got data from serial. Len = " % QString::number(data.length()));
//qDebug() << (tr("Got data from serial. Len = %0").arg(data.length()));
sendDebug("Got data from serial. Len = " % QString::number(data.length()));
for (int i = 0; i < data.length(); i++)
{
c = data.at(i);
@@ -571,7 +639,7 @@ void GVRetSerial::procRXChar(unsigned char c)
rx_step = 0;
break;
case 9:
gotValidated = true;
validationCounter = 10;
//qDebug() << "Got validated";
rx_state = IDLE;
break;
@@ -932,12 +1000,14 @@ void GVRetSerial::handleTick()
if( CANCon::CONNECTED == getStatus() )
{
if (!gotValidated && doValidation)
if (doValidation) validationCounter--;
//qDebug() << validationCounter;
if (validationCounter == 0 && doValidation)
{
if (serial == NULL && tcpClient == NULL) return;
if ( (serial && serial->isOpen()) || (tcpClient && tcpClient->isOpen())) //if it's still false we have a problem...
if ( (serial && serial->isOpen()) || (tcpClient && tcpClient->isOpen()) || (udpClient && udpClient->isOpen())) //if it's still false we have a problem...
{
qDebug() << "Comm validation failed. ";
sendDebug("Comm validation failed.");
setStatus(CANCon::NOT_CONNECTED);
//emit status(getStatus());
@@ -952,6 +1022,7 @@ void GVRetSerial::handleTick()
}
if (doValidation && serial && serial->isOpen()) sendCommValidation();
if (doValidation && tcpClient && tcpClient->isOpen()) sendCommValidation();
if (doValidation && udpClient && udpClient->isOpen()) sendCommValidation();
}
@@ -959,7 +1030,6 @@ void GVRetSerial::sendCommValidation()
{
QByteArray output;
gotValidated = false;
output.append((unsigned char)0xF1); //another command to the GVRET
output.append((unsigned char)0x09); //request a reply to get validation
+6 -2
View File
@@ -6,6 +6,7 @@
#include <QThread>
#include <QTimer>
#include <QTcpSocket>
#include <QUdpSocket>
/*************/
#include <QDateTime>
@@ -64,7 +65,7 @@ private slots:
void connectionTimeout();
void readSerialData();
void serialError(QSerialPort::SerialPortError err);
void tcpConnected();
void deviceConnected();
void handleTick();
private:
@@ -73,18 +74,21 @@ private:
void sendCommValidation();
void rebuildLocalTimeBasis();
void sendToSerial(const QByteArray &bytes);
void sendDebug(const QString debugText);
protected:
QTimer mTimer;
QThread mThread;
bool doValidation;
bool gotValidated;
int validationCounter;
bool isAutoRestart;
bool continuousTimeSync;
bool useTcp;
bool espSerialMode; //special serial mode for ESP32 based boards - no flow control and much slower serial baud speed
QSerialPort *serial;
QTcpSocket *tcpClient;
QUdpSocket *udpClient;
int framesRapid;
STATE rx_state;
uint32_t rx_step;
+33 -36
View File
@@ -11,8 +11,8 @@
/**** class definition ****/
/***********************************/
SerialBusConnection::SerialBusConnection(QString portName) :
CANConnection(portName, CANCon::SOCKETCAN, 1, 4000, true),
SerialBusConnection::SerialBusConnection(QString portName, QString driverName) :
CANConnection(portName, driverName, CANCon::SERIALBUS, 1, 4000, true),
mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */
{
}
@@ -26,6 +26,22 @@ SerialBusConnection::~SerialBusConnection()
void SerialBusConnection::piStarted()
{
qDebug() << "piStarted()";
/* create device */
QString errorString;
qDebug() << "Creating device instance";
mDev_p = QCanBus::instance()->createDevice(getDriver(), getPort(), &errorString);
if (!mDev_p) {
disconnectDevice();
qDebug() << "Error: createDevice(" << getType() << getDriver() << getPort() << "):" << errorString;
return;
}
/* connect slots */
connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SerialBusConnection::errorReceived);
connect(mDev_p, &QCanBusDevice::framesWritten, this, &SerialBusConnection::framesWritten);
connect(mDev_p, &QCanBusDevice::framesReceived, this, &SerialBusConnection::framesReceived);
connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection()));
mTimer.setInterval(1000);
mTimer.setSingleShot(false); //keep ticking
@@ -47,6 +63,7 @@ void SerialBusConnection::piSuspend(bool pSuspend)
void SerialBusConnection::piStop() {
qDebug() << "piStop()";
mTimer.stop();
disconnectDevice();
}
@@ -65,6 +82,8 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
if(0 != pBusIdx)
return;
if (!mDev_p) return;
/* disconnect device if we have one connected */
disconnectDevice();
@@ -75,20 +94,6 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
if(!bus.active)
return;
/* create device */
QString errorString;
mDev_p = QCanBus::instance()->createDevice("socketcan", getPort(), &errorString);
if (!mDev_p) {
disconnectDevice();
qDebug() << "Error: createDevice(" << getType() << getPort() << "):" << errorString;
return;
}
/* connect slots */
connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SerialBusConnection::errorReceived);
connect(mDev_p, &QCanBusDevice::framesWritten, this, &SerialBusConnection::framesWritten);
connect(mDev_p, &QCanBusDevice::framesReceived, this, &SerialBusConnection::framesReceived);
/* set configuration */
/*if (p.useConfigurationEnabled) {
foreach (const SettingsDialog::ConfigurationItem &item, p.configurations)
@@ -96,7 +101,8 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
}*/
//You cannot set the speed of a socketcan interface, it has to be set with console commands.
//mDev_p->setConfigurationParameter(QCanBusDevice::BitRateKey, bus.speed);
//But, you can probabaly set the speed of many of the other serialbus devices so go ahead and try
mDev_p->setConfigurationParameter(QCanBusDevice::BitRateKey, bus.speed);
/* connect device */
if (!mDev_p->connectDevice()) {
@@ -115,8 +121,8 @@ bool SerialBusConnection::piSendFrame(const CANFrame& pFrame)
/* fill frame */
QCanBusFrame frame;
frame.setFrameId(pFrame.ID);
frame.setExtendedFrameFormat(pFrame.extended);
frame.setFrameId(pFrame.ID);
if (pFrame.remote) {
frame.setFrameType(QCanBusFrame::FrameType::RemoteRequestFrame);
} else {
@@ -137,8 +143,6 @@ bool SerialBusConnection::piSendFrame(const CANFrame& pFrame)
void SerialBusConnection::disconnectDevice() {
if(mDev_p) {
mDev_p->disconnectDevice();
delete mDev_p;
mDev_p = nullptr;
}
}
@@ -255,13 +259,12 @@ void SerialBusConnection::framesReceived()
void SerialBusConnection::testConnection() {
QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort());
CANConStatus stats;
switch(getStatus())
{
case CANCon::CONNECTED:
if (!dev_p || !dev_p->connectDevice()) {
if (!mDev_p || mDev_p->state() == QCanBusDevice::UnconnectedState) {
/* we have lost connectivity */
disconnectDevice();
@@ -269,21 +272,18 @@ void SerialBusConnection::testConnection() {
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
piStop();
}
break;
case CANCon::NOT_CONNECTED:
if (dev_p && dev_p->connectDevice()) {
if(!mDev_p) {
/* try to reconnect */
CANBus bus;
if(getBusConfig(0, bus))
{
bus.setEnabled(true);
setBusSettings(0, bus);
}
if (mDev_p && mDev_p->state() == QCanBusDevice::UnconnectedState) {
/* try to reconnect */
CANBus bus;
if(getBusConfig(0, bus))
{
bus.setEnabled(true);
setBusSettings(0, bus);
}
/* disconnect test instance */
dev_p->disconnectDevice();
setStatus(CANCon::CONNECTED);
stats.conStatus = getStatus();
@@ -293,7 +293,4 @@ void SerialBusConnection::testConnection() {
break;
default: {}
}
if(dev_p)
delete dev_p;
}
+1 -1
View File
@@ -12,7 +12,7 @@ class SerialBusConnection : public CANConnection
Q_OBJECT
public:
SerialBusConnection(QString portName);
SerialBusConnection(QString portName, QString driverName);
virtual ~SerialBusConnection();
protected:
+71 -44
View File
@@ -8,21 +8,22 @@
#include <QApplication>
#include <QPalette>
#include "utility.h"
#include "connections/canconmanager.h"
DBCHandler* DBCHandler::instance = NULL;
DBCHandler* DBCHandler::instance = nullptr;
DBC_SIGNAL* DBCSignalHandler::findSignalByIdx(int idx)
{
if (sigs.count() == 0) return NULL;
if (idx < 0) return NULL;
if (idx >= sigs.count()) return NULL;
if (sigs.count() == 0) return nullptr;
if (idx < 0) return nullptr;
if (idx >= sigs.count()) return nullptr;
return &sigs[idx];
}
DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name)
{
if (sigs.count() == 0) return NULL;
if (sigs.count() == 0) return nullptr;
for (int i = 0; i < sigs.count(); i++)
{
if (sigs[i].name.compare(name, Qt::CaseInsensitive) == 0)
@@ -30,7 +31,7 @@ DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name)
return &sigs[i];
}
}
return NULL;
return nullptr;
}
bool DBCSignalHandler::addSignal(DBC_SIGNAL &sig)
@@ -82,7 +83,7 @@ int DBCSignalHandler::getCount()
DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id)
{
if (messages.count() == 0) return NULL;
if (messages.count() == 0) return nullptr;
for (int i = 0; i < messages.count(); i++)
{
if (isJ1939Handler)
@@ -115,20 +116,20 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id)
}
}
}
return NULL;
return nullptr;
}
DBC_MESSAGE* DBCMessageHandler::findMsgByIdx(int idx)
{
if (messages.count() == 0) return NULL;
if (idx < 0) return NULL;
if (idx >= messages.count()) return NULL;
if (messages.count() == 0) return nullptr;
if (idx < 0) return nullptr;
if (idx >= messages.count()) return nullptr;
return &messages[idx];
}
DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name)
{
if (messages.count() == 0) return NULL;
if (messages.count() == 0) return nullptr;
for (int i = 0; i < messages.count(); i++)
{
if (messages[i].name.compare(name, Qt::CaseInsensitive) == 0)
@@ -136,7 +137,7 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name)
return &messages[i];
}
}
return NULL;
return nullptr;
}
bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg)
@@ -251,14 +252,14 @@ DBCFile& DBCFile::operator=(const DBCFile& cpy)
DBC_NODE* DBCFile::findNodeByIdx(int idx)
{
if (idx < 0) return NULL;
if (idx >= dbc_nodes.count()) return NULL;
if (idx < 0) return nullptr;
if (idx >= dbc_nodes.count()) return nullptr;
return &dbc_nodes[idx];
}
DBC_NODE* DBCFile::findNodeByName(QString name)
{
if (dbc_nodes.length() == 0) return NULL;
if (dbc_nodes.length() == 0) return nullptr;
for (int i = 0; i < dbc_nodes.length(); i++)
{
if (dbc_nodes[i].name.compare(name, Qt::CaseInsensitive) == 0)
@@ -266,7 +267,7 @@ DBC_NODE* DBCFile::findNodeByName(QString name)
return &dbc_nodes[i];
}
}
return NULL;
return nullptr;
}
QString DBCFile::getFullFilename()
@@ -291,14 +292,15 @@ int DBCFile::getAssocBus()
void DBCFile::setAssocBus(int bus)
{
int numBuses = CANConManager::getInstance()->getNumBuses();
if (bus < -1) return;
if (bus > 1) return;
if (bus >= numBuses) return;
assocBuses = bus;
}
DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name)
{
if (dbc_attributes.length() == 0) return NULL;
if (dbc_attributes.length() == 0) return nullptr;
for (int i = 0; i < dbc_attributes.length(); i++)
{
if (dbc_attributes[i].name.compare(name, Qt::CaseInsensitive) == 0)
@@ -306,13 +308,13 @@ DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name)
return &dbc_attributes[i];
}
}
return NULL;
return nullptr;
}
DBC_ATTRIBUTE *DBCFile::findAttributeByIdx(int idx)
{
if (idx < 0) return NULL;
if (idx >= dbc_attributes.count()) return NULL;
if (idx < 0) return nullptr;
if (idx >= dbc_attributes.count()) return nullptr;
return &dbc_attributes[idx];
}
@@ -345,8 +347,9 @@ DBC_MESSAGE* DBCFile::parseMessageLine(QString line)
DBC_MESSAGE msg;
msg.ID = match.captured(1).toULong() & 0x7FFFFFFFul; //the ID is always stored in decimal format
msg.name = match.captured(2);
msg.len = match.captured(3).toInt();
msg.len = match.captured(3).toUInt();
msg.sender = findNodeByName(match.captured(4));
if (!msg.sender) msg.sender = findNodeByIdx(0);
messageHandler->addMessage(msg);
msgPtr = messageHandler->findMsgByID(msg.ID);
}
@@ -450,9 +453,12 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg)
if (match.captured(11 + offset).contains(','))
{
QString tmp = match.captured(11 + offset).split(',')[0];
sig.receiver = findNodeByName(tmp);
sig.receiver = findNodeByName(tmp);
}
else sig.receiver = findNodeByName(match.captured(11 + offset));
if (!sig.receiver) sig.receiver = findNodeByIdx(0); //apply default if there was no match
sig.parentMessage = msg;
msg->sigHandler->addSignal(sig);
if (isMultiplexor) msg->multiplexorSignal = msg->sigHandler->findSignalByName(sig.name);
@@ -476,11 +482,11 @@ bool DBCFile::parseValueLine(QString line)
if (match.hasMatch())
{
//qDebug() << "Data was: " << match.captured(3);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
if (msg != NULL)
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
if (msg != nullptr)
{
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
if (sig != NULL)
if (sig != nullptr)
{
QString tokenString = match.captured(3);
DBC_VAL_ENUM_ENTRY val;
@@ -525,7 +531,7 @@ bool DBCFile::parseAttributeLine(QString line)
if (foundAttr)
{
qDebug() << "That attribute does exist";
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toInt());
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toUInt());
if (foundMsg)
{
qDebug() << "It references a valid, registered message";
@@ -557,7 +563,7 @@ bool DBCFile::parseAttributeLine(QString line)
if (foundAttr)
{
qDebug() << "That attribute does exist";
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toInt());
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toUInt());
if (foundMsg)
{
qDebug() << "It references a valid, registered message";
@@ -662,7 +668,7 @@ void DBCFile::loadFile(QString fileName)
QString line, rawLine;
QRegularExpression regex;
QRegularExpressionMatch match;
DBC_MESSAGE *currentMessage = NULL;
DBC_MESSAGE *currentMessage = nullptr;
DBC_ATTRIBUTE attr;
int numSigFaults = 0, numMsgFaults = 0;
@@ -746,11 +752,11 @@ void DBCFile::loadFile(QString fileName)
if (match.hasMatch())
{
//qDebug() << "Comment was: " << match.captured(3);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
if (msg != NULL)
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
if (msg != nullptr)
{
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
if (sig != NULL)
if (sig != nullptr)
{
sig->comment = match.captured(3);
}
@@ -767,8 +773,8 @@ void DBCFile::loadFile(QString fileName)
if (match.hasMatch())
{
//qDebug() << "Comment was: " << match.captured(2);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
if (msg != NULL)
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
if (msg != nullptr)
{
msg->comment = match.captured(2);
}
@@ -785,7 +791,7 @@ void DBCFile::loadFile(QString fileName)
{
//qDebug() << "Comment was: " << match.captured(2);
DBC_NODE *node = findNodeByName(match.captured(1));
if (node != NULL)
if (node != nullptr)
{
node->comment = match.captured(2);
}
@@ -1036,6 +1042,9 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr)
void DBCFile::saveFile(QString fileName)
{
int nodeNumber = 1;
int msgNumber = 1;
int sigNumber = 1;
QFile *outFile = new QFile(fileName);
QString nodesOutput, msgOutput, commentsOutput, valuesOutput;
QString defaultsOutput, attrValOutput;
@@ -1089,6 +1098,11 @@ void DBCFile::saveFile(QString fileName)
DBC_NODE node = dbc_nodes[x];
if (node.name.compare("Vector__XXX", Qt::CaseInsensitive) != 0)
{
if (node.name.length() < 1) //detect an empty string and fill it out with something
{
node.name = "NODE" + QString::number(nodeNumber);
nodeNumber++;
}
nodesOutput.append(node.name + " ");
if (node.comment.length() > 0)
{
@@ -1119,6 +1133,12 @@ void DBCFile::saveFile(QString fileName)
{
DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x);
if (msg->name.length() < 1) //detect an empty string and fill it out with something
{
msg->name = "MSG" + QString::number(msgNumber);
msgNumber++;
}
msgOutput.append("BO_ " + QString::number(msg->ID) + " " + msg->name + ": " + QString::number(msg->len) +
" " + msg->sender->name + "\n");
if (msg->comment.length() > 0)
@@ -1146,6 +1166,13 @@ void DBCFile::saveFile(QString fileName)
for (int s = 0; s < msg->sigHandler->getCount(); s++)
{
DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(s);
if (sig->name.length() < 1) //detect an empty string and fill it out with something
{
sig->name = "SIG" + QString::number(sigNumber);
sigNumber++;
}
msgOutput.append(" SG_ " + sig->name);
if (sig->isMultiplexor) msgOutput.append(" M");
@@ -1399,7 +1426,7 @@ DBCFile* DBCHandler::loadDBCFile(int idx)
return &loadedFiles.last();
}
return NULL;
return nullptr;
}
void DBCHandler::removeDBCFile(int idx)
@@ -1439,10 +1466,10 @@ DBC_MESSAGE* DBCHandler::findMessage(const CANFrame &frame)
if (loadedFiles[i].getAssocBus() == -1 || frame.bus == (unsigned int)loadedFiles[i].getAssocBus())
{
DBC_MESSAGE* msg = loadedFiles[i].messageHandler->findMsgByID(frame.ID);
if (msg != NULL) return msg;
if (msg != nullptr) return msg;
}
}
return NULL;
return nullptr;
}
int DBCHandler::getFileCount()
@@ -1452,15 +1479,15 @@ int DBCHandler::getFileCount()
DBCFile* DBCHandler::getFileByIdx(int idx)
{
if (loadedFiles.count() == 0) return NULL;
if (idx < 0) return NULL;
if (idx >= loadedFiles.count()) return NULL;
if (loadedFiles.count() == 0) return nullptr;
if (idx < 0) return nullptr;
if (idx >= loadedFiles.count()) return nullptr;
return &loadedFiles[idx];
}
DBCFile* DBCHandler::getFileByName(QString name)
{
if (loadedFiles.count() == 0) return NULL;
if (loadedFiles.count() == 0) return nullptr;
for (int i = 0; i < loadedFiles.count(); i++)
{
if (loadedFiles[i].getFilename().compare(name, Qt::CaseInsensitive) == 0)
@@ -1468,7 +1495,7 @@ DBCFile* DBCHandler::getFileByName(QString name)
return &loadedFiles[i];
}
}
return NULL;
return nullptr;
}
DBCHandler::DBCHandler()
+22 -3
View File
@@ -2,6 +2,7 @@
#include "ui_dbcloadsavewindow.h"
#include <QCheckBox>
#include "helpwindow.h"
#include "connections/canconmanager.h"
DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
@@ -34,6 +35,7 @@ DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *p
connect(ui->tableFiles, &QTableWidget::cellDoubleClicked, this, &DBCLoadSaveWindow::cellDoubleClicked);
editorWindow = new DBCMainEditor(frames);
currentlyEditingFile = nullptr;
installEventFilter(this);
}
@@ -108,10 +110,25 @@ void DBCLoadSaveWindow::saveFile()
void DBCLoadSaveWindow::removeFile()
{
bool bContinue = true;
int idx = ui->tableFiles->currentRow();
if (idx < 0) return;
dbcHandler->removeDBCFile(idx);
ui->tableFiles->removeRow(idx);
if (currentlyEditingFile == dbcHandler->getFileByIdx(idx))
{
bContinue = false;
QMessageBox::StandardButton confirmDialog;
confirmDialog = QMessageBox::question(this, "Confirm Deletion", "This DBC is currently open for editing.\nMake sure you've saved any changes!\nAre you sure you want to remove this DBC?",
QMessageBox::Yes|QMessageBox::No);
if (confirmDialog == QMessageBox::Yes) bContinue = true;
}
if (bContinue)
{
editorWindow->close();
dbcHandler->removeDBCFile(idx);
ui->tableFiles->removeRow(idx);
}
}
void DBCLoadSaveWindow::moveUp()
@@ -146,7 +163,8 @@ void DBCLoadSaveWindow::cellChanged(int row, int col)
{
DBCFile *file = dbcHandler->getFileByIdx(row);
int bus = ui->tableFiles->item(row, col)->text().toInt();
if (bus > -2 && bus < 2)
int numBuses = CANConManager::getInstance()->getNumBuses();
if (bus > -2 && bus < numBuses)
{
file->setAssocBus(bus);
}
@@ -185,6 +203,7 @@ void DBCLoadSaveWindow::cellChanged(int row, int col)
void DBCLoadSaveWindow::cellDoubleClicked(int row, int col)
{
Q_UNUSED(col)
currentlyEditingFile = dbcHandler->getFileByIdx(row);
editorWindow->setFileIdx(row);
editorWindow->show();
}
+1
View File
@@ -32,6 +32,7 @@ private slots:
private:
Ui::DBCLoadSaveWindow *ui;
DBCHandler *dbcHandler;
DBCFile *currentlyEditingFile;
const QVector<CANFrame> *referenceFrames;
DBCMainEditor *editorWindow;
+6 -2
View File
@@ -103,6 +103,7 @@ void DBCMainEditor::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
writeSettings();
sigEditor->close();
}
void DBCMainEditor::readSettings()
@@ -153,7 +154,7 @@ void DBCMainEditor::deleteCurrentNode()
int thisRow = ui->NodesTable->currentRow();
QString nodeName = ui->NodesTable->item(thisRow, 0)->text();
if (nodeName.length() > 0 && nodeName.compare("Vector__XXX", Qt::CaseInsensitive) != 0)
{
{
ui->NodesTable->removeRow(thisRow);
dbcFile->dbc_nodes.removeAt(thisRow);
inhibitCellChanged = true;
@@ -283,6 +284,9 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
newMsg.name = "";
newMsg.sender = node;
newMsg.len = 0;
newMsg.fgColor = ui->MessagesTable->item(row, 4)->backgroundColor();
newMsg.bgColor = ui->MessagesTable->item(row, 5)->backgroundColor();
for (int i = 0; i < referenceFrames->length(); i++)
{
if ((uint) referenceFrames->at(i).ID == msgID)
@@ -547,7 +551,7 @@ void DBCMainEditor::insertBlankRow()
{
QTableWidgetItem *item = new QTableWidgetItem("");
if (i == 4) item->setBackgroundColor(QApplication::palette().color(QPalette::WindowText)); //foreground color
//if (i == 5) item->setBackgroundColor(ui->MessagesTable->palette().color(ui->MessagesTable->backgroundRole())); //background color
if (i == 5) item->setBackgroundColor(QApplication::palette().color(QPalette::Base));
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
ui->MessagesTable->setItem(rowIdx, i, item);
}
+5 -4
View File
@@ -156,7 +156,8 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
[=]()
{
if (currentSignal == NULL) return;
currentSignal->name = ui->txtName->text().simplified().replace(' ', '_');
QString tempNameStr = ui->txtName->text().simplified().replace(' ', '_');
if (tempNameStr.length() > 0) currentSignal->name = tempNameStr;
//need to update the list too.
ui->signalsList->currentItem()->setText(currentSignal->name);
});
@@ -256,7 +257,7 @@ void DBCSignalEditor::readSettings()
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("DBCSignalEditor/WindowSize", QSize(800, 572)).toSize());
resize(settings.value("DBCSignalEditor/WindowSize", QSize(1000, 600)).toSize());
move(settings.value("DBCSignalEditor/WindowPos", QPoint(100, 100)).toPoint());
}
}
@@ -371,8 +372,8 @@ void DBCSignalEditor::deleteCurrentSignal()
{
int currIdx = ui->signalsList->currentRow();
if(currIdx==ui->signalsList->count()-1)
return;
//if(currIdx==ui->signalsList->count()-1)
//return;
if (currIdx > -1)
{
+2 -2
View File
@@ -1,4 +1,4 @@
make qthelp
~/Qt/5.9.1/gcc_64/bin/qcollectiongenerator build/qthelp/SavvyCAN.qhcp
~/Qt/5.9.1/gcc_64/bin/assistant -collectionFile build/qthelp/SavvyCAN.qhc
~/Qt/5.12.1/gcc_64/bin/qcollectiongenerator build/qthelp/SavvyCAN.qhcp
~/Qt/5.12.1/gcc_64/bin/assistant -collectionFile build/qthelp/SavvyCAN.qhc
+3 -3
View File
@@ -47,7 +47,7 @@ master_doc = 'index'
# General information about the project.
project = u'SavvyCAN'
copyright = u'2017, EVTV'
copyright = u'2018, EVTV'
author = u'Collin Kidder'
# The version info for the project you're documenting, acts as replacement for
@@ -55,9 +55,9 @@ author = u'Collin Kidder'
# built documents.
#
# The short X.Y version.
version = '181'
version = '189'
# The full version, including alpha/beta/rc tags.
release = '181'
release = '189'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+47 -19
View File
@@ -5,32 +5,60 @@ Connection Window
.. image:: ./images/ConnectionWindow.png
The connection window is used to add, remove, and modify connections. At the moment it is possible to use any SocketCAN compatible device (in LINUX) and any GVRET compatible device in any of the supported operating systems.
At this time GVRET compatible devices are: EVTVDue, EVTV CANDue (1.3/2/2.1/2.2), Teensy 3.1-3.6, Macchina M2.
The connection window is used to add, remove, and modify connections. At the moment it is possible
to use any QT SerialBus compatible device and any GVRET compatible device in any of the supported
operating systems. SerialBus supports socketcan on linux, passthrough on Linux and Windows 32
bit, and Vector, PeakCAN, and TinyCAN on supported OS's.
At this time GVRET compatible devices are: EVTVDue, EVTV CANDue (1.3/2/2.1/2.2),
Teensy 3.1-3.6, Macchina M2, EVTV ESP32 Due.
Connecting To A Dongle
==============================
SavvyCAN is able to connect to GVRET compatible devices to capture new traffic. These devices will present as serial ports on the connected PC.
To connect to a dongle select the proper serial port and click "Create New Connection". If a valid device is found on that serial port the first
statusbar section will update and the currently set canbus speeds will show in the table at the left of the window. These speeds can then
be changed by clicking on the speed (or otherwise selecting the cell in the table) and typing in a new value. Leaving the cell will update the speed to the new value. GVRET devices also support
setting "listen only" on each bus. This mode causes the device to not acknowledge any traffic or try to modify the bus at all. It is as it says, a mode where you can only listen to whatever traffic
is found on the bus. Some older GVRET devices supported a mode where you could change the second bus between single wire CAN and normal CAN. This is deprecated. However, newer GVRET devices have
dedicated single wire CAN buses and the relevant bus will show the checkbox.
SavvyCAN is able to connect to GVRET compatible devices to capture new traffic. These
devices will present as serial ports on the connected PC.
To connect to a dongle select the proper serial port and click "Create New Connection".
If a valid device is found on that serial port the first statusbar section will update
and the currently set canbus speeds will show in the table at the left of the window.
These speeds can then be changed by clicking on the speed (or otherwise selecting the cell
in the table) and typing in a new value. Leaving the cell will update the speed to the new
value. GVRET devices also support setting "listen only" on each bus. This mode causes the
device to not acknowledge any traffic or try to modify the bus at all. It is as it says,
a mode where you can only listen to whatever traffic is found on the bus. Some older GVRET
devices supported a mode where you could change the second bus between single wire CAN
and normal CAN. This is deprecated. However, newer GVRET devices have dedicated single
wire CAN buses and the relevant bus will show the checkbox.
SavvyCAN can also connect to SocketCAN devices in LINUX. Select "SocketCAN" as the connection type and then type in the device name. This should be just the same as you would provide to the can-utils
programs. That is, do not enter /dev/can0 but rather can0. Then push "Create New Connection" and you should see the new connection in the table on the left of the window. Note that SocketCAN devices don't
support changing the baud rate within a program. You must do this when you set up the connection via console commands. This is outside the scope of this documentation. Consult the SocketCAN documentation
for details on configuring such devices.
SavvyCAN can also connect to a wide variety of CAN hardware through the built-in QT
SerialBus drivers. These drivers vary by operating system but support socketcan on LINUX
and Vector tools on both LINUX and Windows. When you select "QT SerialBus Devices" you will
get a list of device types supported. Select a device type and for most devices you should see
the Port list fill out with all registered and valid ports for that driver. Socketcan devices, for
instance, are automatically detected now. Then push "Create New Connection" and you should
see the new connection in the table on the left of the window. Note that SocketCAN devices
don't support changing the baud rate within a program. You must do this when you set up
the connection via console commands. This is outside the scope of this documentation.
Consult the SocketCAN documentation for details on configuring such devices.
The last connection option is "Remote Host." If you select this option then Port will change
to a textbox. Enter the IP address of the remote (but still local to your LAN) IP address. Currently
this works with EVTV ESP32 boards and M2 boards.
Debugging Connection Problems
==============================
GVRET devices present as serial ports and have significant configuration options. However, the ability to configure so many things and the ability to compile the firmware yourself both come as a
double edged sword. They present many opportunities for things to go wrong. Because of this there is a debugging console present on the connection window. Click a bus in the table then click "Enable Console"
to cause it to start logging serial traffic. From this console you can see what is going on. It shows what SavvyCAN is sending and what it is getting back. It has extended status messages that might help to narrow down
what is going wrong. Additionally, if you're feeling adventurous you can send traffic to the serial device from the Send line. "Send Hex" accepts a set of hex values separated by spaces. "Send Text" will send the raw
text you type on the line. GVRET traffic is ordinarily binary so "Send Text" won't work very well for that. But, there is also a text console possible on GVRET devices. If you connect to them with a serial program you can
configure things via a text console. Type ? and follow it up with some form of line ending (Cr, Lf, CrLf, any will work).
GVRET devices present as serial ports and have significant configuration options.
However, the ability to configure so many things and the ability to compile the firmware
yourself both come as a double edged sword. They present many opportunities for things
to go wrong. Because of this there is a debugging console present on the connection window.
Click a bus in the table then click "Enable Console" to cause it to start logging serial
traffic. From this console you can see what is going on. It shows what SavvyCAN is sending
and what it is getting back. It has extended status messages that might help to narrow down
what is going wrong. Additionally, if you're feeling adventurous you can send traffic to
the serial device from the Send line. "Send Hex" accepts a set of hex values separated
by spaces. "Send Text" will send the raw text you type on the line. GVRET traffic is
ordinarily binary so "Send Text" won't work very well for that. But, there is also a
text console possible on GVRET devices. If you connect to them with a serial program you can
configure things via a text console. Type ? and follow it up with some form of line
ending (Cr, Lf, CrLf, any will work).
+9 -1
View File
@@ -8,4 +8,12 @@ Frame Details Window
The Purpose of Frame Details Window
===================================
This window is used to get detailed statistics about frames. It provides information about a given frame ID across all frames with that ID. You can get such information as the number of frames, the number of data bytes that frame ID has, the average interval between frames with that ID, and the minimum and maximum interval. Also listed are detailed statistics for each data byte in that frame. Each byte has listed which bits changed, the range of values found, and a histogram both graphically (at the bottom of the window) and textually. The textual representation shows the number of times a specific value occurred. Also listed at the bottom is a histogram of each bit and how many times it was set. The graph is a histogram of all the bits and the number of times each bit was set. This can be used to quickly visually see where data has changed. All information can be saved to a text file for later analysis.
This window is used to get detailed statistics about frames.
It provides information about a given frame ID across all frames with that ID. You can get such information as the number of frames, the number of data bytes that frame ID has, the average interval between frames with that ID, and the minimum and maximum interval.
Also listed are detailed statistics for each data byte in that frame. Each byte has listed which bits changed, the range of values found, and a histogram both graphically (at the righthand side of the window) and textually. The textual representation shows the number of times a specific value occurred.
The top right graph is a histogram of all the bits and the number of times each bit was set. This can be used to quickly visually see where data has changed.
The bottom right graph is of each individual byte as its value varies over time. All textual information can be saved to a text file for later analysis.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 135 KiB

+1 -1
View File
@@ -1,5 +1,5 @@
Welcome to SavvyCAN V181 documentation!
Welcome to SavvyCAN V189 documentation!
=========================================
Contents:
+55 -2
View File
@@ -8,11 +8,64 @@ Sniffer Window
Using the Sniffer Window
=========================
This window is essentially a graphical version of the linux can_utils. The general idea here is to display a list of frames such that you only see frames that are actively updating. If a given ID has not been seen in 4 seconds the ID portion will turn RED and then disappear from the list. In this way only frames that are updating are in the list. They are ordered by last update time. Bytes that have deincremented will be red and bytes that have incremented will be green. You can use the "Filters" area to mask away some IDs so that they never show up. This can help to declutter the list.
This window is essentially a turbo charged graphical version of the linux
can_utils program "cansniffer". The general idea here is to display a list
of frames such that you only see frames that are actively updating. If a given
ID has not been seen in 5 seconds the ID portion will turn RED and then disappear
from the list. In this way only frames that are updating are in the list. They are
ordered by ID. Bytes that have deincremented will be red and bytes that have incremented
will be green. You can use the "Filters" area to mask away some IDs so that they never
show up. This can help to declutter the list.
This window updates with a 200ms interval.
Notching and Unnotching
========================
Honestly, I don't know. It seems that notching means to store the current value of the data bytes for each frame and then use that notch data for the comparison for increment / deincrement to color the bytes. Unnotching would then be clearing that out so that it uses the previous value from the last time the frame ID was seen. But, don't quote me on that. This should be figured out definitively and corrected.
While the window is running it keeps a running list each 200ms cycle of all the bits that
changed in that timespan. Each 200ms this list is backed up and reset. If you push the
notch button the system will remember all the bits that were set in the last 200ms window
and will not color the output if those bits are toggled in the future. They will thus somewhat
be ignored except that you can visually still see them updating. If you click the Notch
button repeatedly it will add any new changed bits to the old changed bits. In this way you
can build up a set of bits to ignore. Un-notching causes all notched (ignored) bits to be
reset and thus all changes will be colored once again.
Advanced Options
==================
All of the above was valid if you do not check any of the four checkboxes. With the checkboxes
unchecked this window is very close to cansniffer on the command line. But, what fun is that?
These checkboxes modify the way the window works in a variety of ways.
Never Expire IDs
==================
This checkbox will do exactly what it says on the tin. Instead of frame ID's expiring after
5 seconds of inactivity they will stick around forever. This can be useful so that the ID you
are watching doesn't jump up and down as IDs expire and potentially come back later on or new IDs
are seen. With no expiration you will get a more consistent view of the IDs. You are still free
to filter away IDs you are not interested in.
Mute notched bits
===================
This checkbox might sound a bit strange. With this checked any bytes that you have notched will
ignore any notched bits and not even change the display to update if only notched bits were changed.
This completely hides all notched data. The view of the frames will then NOT perfectly or correctly
represent the actual most up to date data for each ID. So, use this option with caution. But, it
is handy when you are looking for a needle in a haystack and you don't want things changing if you've
already told the program to notch them away.
Fade inactive bytes
====================
This can be used with mute or without but has a similar purpose. When this is checked any bytes
that haven't updated recently will begin to fade away to white. They never quite get all the way
to disappearing but will fade to be very light. In this way only data which is actively changing will
be very visible. This drastically aids in helping you to ignore any bytes that are not changing.
View Bits
==========
This option changes the view very starkly. This is the view shown in the picture associated with this topic. When View Bits is selected the display will change to show each bit within the bytes as separate blocks that each can separately be black when set and unchanged, white when unset and unchanged, red when freshly unset, and green when freshly set. This allows for a very fine grained view. Fade inactive, and never expire still work as usual. This mode might be a bit "busy" and lowers the number of IDs you can see at once. But, the choice is yours. You give up some density in exchange for verbosity.
+19 -16
View File
@@ -555,9 +555,9 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
thisFrame.isReceived = true;
thisFrame.bus = 0;
if (line.at(28) == ' ') {
thisFrame.extended = true;
} else {
thisFrame.extended = false;
} else {
thisFrame.extended = true;
}
if (line.at(41) == 'R') {
@@ -655,25 +655,28 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
}
if (inHeader) continue;
if (line.length() > 2)
{
{
QList<QByteArray> tokens = line.simplified().split(' ');
thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0);
thisFrame.ID = tokens[2].toUInt(NULL, 16);
thisFrame.len = tokens[5].toUInt();
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[1].toUInt();
thisFrame.extended = (thisFrame.ID > 0x7FF);
thisFrame.remote = false;
for (unsigned int d = 6; d < (6 + thisFrame.len); d++)
if (tokens.length() > 4)
{
if (tokens.count() > d)
{
thisFrame.data[d - 6] = tokens[d].toInt(NULL, 16);
}
else //expected byte wasn't there to read. Set it zero and set error flag
thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0);
thisFrame.ID = tokens[2].toUInt(NULL, 16);
thisFrame.len = tokens[5].toUInt();
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[1].toUInt();
thisFrame.extended = (thisFrame.ID > 0x7FF);
thisFrame.remote = false;
for (unsigned int d = 6; d < (6 + thisFrame.len); d++)
{
if (tokens.count() > d)
{
thisFrame.data[d - 6] = tokens[d].toInt(NULL, 16);
}
else //expected byte wasn't there to read. Set it zero and set error flag
{
thisFrame.data[d - 6] = 0;
foundErrors = true;
}
}
}
frames->append(thisFrame);
+13 -1
View File
@@ -12,7 +12,8 @@ FramePlaybackObject::FramePlaybackObject()
playbackActive = false;
playbackForward = true;
useOrigTiming = false;
whichBusSend = -1;
whichBusSend = 0;
currentSeqItem = nullptr;
}
FramePlaybackObject::~FramePlaybackObject()
@@ -25,6 +26,12 @@ FramePlaybackObject::~FramePlaybackObject()
quint64 FramePlaybackObject::updatePosition(bool forward)
{
//qDebug() << "updatePosition";
if (!currentSeqItem) {
playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false;
currentPosition = 0;
return 0;
}
if (forward)
{
if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going
@@ -231,6 +238,7 @@ void FramePlaybackObject::stepPlaybackForward()
playbackActive = false;
updatePosition(true);
CANConManager::getInstance()->sendFrames(sendingBuffer);
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::stepPlaybackBackward()
@@ -248,6 +256,7 @@ void FramePlaybackObject::stepPlaybackBackward()
updatePosition(false);
CANConManager::getInstance()->sendFrames(sendingBuffer);
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::stopPlayback()
@@ -262,6 +271,7 @@ void FramePlaybackObject::stopPlayback()
playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false;
currentPosition = 0;
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::pausePlayback()
@@ -275,6 +285,7 @@ void FramePlaybackObject::pausePlayback()
playbackActive = false;
playbackTimer->stop();
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::setSequenceObject(SequenceItem *item)
@@ -289,6 +300,7 @@ void FramePlaybackObject::setUseOriginalTiming(bool state)
void FramePlaybackObject::setSendingBus(int bus)
{
qDebug() << "Setting sending bus to " << bus;
whichBusSend = bus;
}
+6 -1
View File
@@ -296,9 +296,14 @@ void FramePlaybackWindow::calculateWhichBus()
{
int idx = ui->comboCANBus->currentIndex();
int maxIdx = ui->comboCANBus->count() - 1;
if (maxIdx == 0) maxIdx = 2;
int out = idx;
qDebug() << idx << "***" << maxIdx;
if (idx == (maxIdx - 1) ) out = -1;
if (idx == maxIdx) out = -2;
if (idx < 0) out = 0;
playbackObject.setSendingBus(out);
}
@@ -534,6 +539,7 @@ void FramePlaybackWindow::btnReverseClick()
forward = false;
isPlaying = true;
playbackObject.startPlaybackBackward();
updateFrameLabel();
}
void FramePlaybackWindow::btnStopClick()
@@ -554,7 +560,6 @@ void FramePlaybackWindow::btnStopClick()
ui->tblSequence->setCurrentCell(0, 0);
refreshIDList();
}
updateFrameLabel();
}
void FramePlaybackWindow::btnPlayClick()
+5 -3
View File
@@ -820,6 +820,8 @@ void FrameSenderWindow::processCellChange(int line, int col)
sendingData[line].count = 0;
int numBuses = CANConManager::getInstance()->getNumBuses();
switch (col)
{
case 0: //Enable check box
@@ -831,9 +833,9 @@ void FrameSenderWindow::processCellChange(int line, int col)
qDebug() << "Setting enabled to " << sendingData[line].enabled;
break;
case 1: //Bus designation
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text());
if (tempVal < 0) tempVal = 0;
if (tempVal > 1) tempVal = 1;
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text());
if (tempVal < -1) tempVal = -1;
if (tempVal >= numBuses) tempVal = numBuses - 1;
sendingData[line].bus = tempVal;
qDebug() << "Setting bus to " << tempVal;
break;
+1 -1
View File
@@ -67,7 +67,7 @@ HelpWindow* HelpWindow::getRef()
void HelpWindow::showHelp(QString help)
{
if (m_helpEngine) {
QString url = "qthelp://org.sphinx.savvycan.181/doc/" + help;
QString url = "qthelp://org.sphinx.savvycan.189/doc/" + help;
qDebug() << "Searching for " << url;
QByteArray helpData = m_helpEngine->fileData(QUrl(url));
qDebug() << "Help file size: " << helpData.length();
+44 -26
View File
@@ -55,31 +55,34 @@ MainWindow::MainWindow(QWidget *parent) :
readSettings();
QHeaderView *verticalHeader = ui->canFramesView->verticalHeader();
verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
verticalHeader->setDefaultSectionSize(10);
QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader();
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
connect(HorzHdr, SIGNAL(sectionClicked(int)), this, SLOT(headerClicked(int)));
graphingWindow = NULL;
frameInfoWindow = NULL;
playbackWindow = NULL;
flowViewWindow = NULL;
frameSenderWindow = NULL;
dbcMainEditor = NULL;
comparatorWindow = NULL;
settingsDialog = NULL;
firmwareUploaderWindow = NULL;
discreteStateWindow = NULL;
connectionWindow = NULL;
scriptingWindow = NULL;
rangeWindow = NULL;
dbcFileWindow = NULL;
fuzzingWindow = NULL;
udsScanWindow = NULL;
motorctrlConfigWindow = NULL;
isoWindow = NULL;
snifferWindow = NULL;
bisectWindow = NULL;
signalViewerWindow = NULL;
graphingWindow = nullptr;
frameInfoWindow = nullptr;
playbackWindow = nullptr;
flowViewWindow = nullptr;
frameSenderWindow = nullptr;
dbcMainEditor = nullptr;
comparatorWindow = nullptr;
settingsDialog = nullptr;
firmwareUploaderWindow = nullptr;
discreteStateWindow = nullptr;
connectionWindow = nullptr;
scriptingWindow = nullptr;
rangeWindow = nullptr;
dbcFileWindow = nullptr;
fuzzingWindow = nullptr;
udsScanWindow = nullptr;
motorctrlConfigWindow = nullptr;
isoWindow = nullptr;
snifferWindow = nullptr;
bisectWindow = nullptr;
signalViewerWindow = nullptr;
dbcHandler = DBCHandler::getReference();
bDirty = false;
inhibitFilterUpdate = false;
@@ -160,6 +163,10 @@ MainWindow::MainWindow(QWidget *parent) :
temp.bus = 0;
temp.ID = 0x100;
temp.len = 0;
temp.extended = false;
temp.isReceived = true;
temp.remote = false;
temp.timestamp = 100000000;
model->addFrame(temp, true);
qApp->processEvents();
tickGUIUpdate(); //force a GUI refresh so that the row exists to measure
@@ -180,7 +187,7 @@ MainWindow::MainWindow(QWidget *parent) :
ui->actionFirmware_Update->setVisible(false);
ui->actionMotorControlConfig->setVisible(false);
ui->actionSignal_Viewer->setVisible(false);
//ui->actionSingle_Multi_State_2->setVisible(false);
ui->actionSingle_Multi_State_2->setVisible(false);
installEventFilter(this);
}
@@ -293,7 +300,7 @@ void MainWindow::readSettings()
ui->canFramesView->setColumnWidth(5, settings.value("Main/BusColumn", 40).toUInt()); //bus
ui->canFramesView->setColumnWidth(6, settings.value("Main/LengthColumn", 40).toUInt()); //length
ui->canFramesView->setColumnWidth(7, settings.value("Main/AsciiColumn", 50).toUInt()); //ascii
ui->canFramesView->setColumnWidth(8, settings.value("Main/DataColumn", 225).toUInt()); //data
//ui->canFramesView->setColumnWidth(8, settings.value("Main/DataColumn", 225).toUInt()); //data
}
if (settings.value("Main/AutoScroll", false).toBool())
{
@@ -338,7 +345,7 @@ void MainWindow::writeSettings()
settings.setValue("Main/BusColumn", ui->canFramesView->columnWidth(5));
settings.setValue("Main/LengthColumn", ui->canFramesView->columnWidth(6));
settings.setValue("Main/AsciiColumn", ui->canFramesView->columnWidth(7));
settings.setValue("Main/DataColumn", ui->canFramesView->columnWidth(8));
//settings.setValue("Main/DataColumn", ui->canFramesView->columnWidth(8));
}
}
@@ -387,11 +394,22 @@ void MainWindow::gridDoubleClicked(QModelIndex idx)
void MainWindow::interpretToggled(bool state)
{
model->setInterpetMode(state);
//ui->canFramesView->resizeRowsToContents(); //a VERY costly operation!
}
void MainWindow::overwriteToggled(bool state)
{
model->setOverwriteMode(state);
if (state)
{
QMessageBox::StandardButton confirmDialog;
confirmDialog = QMessageBox::question(this, "Danger Will Robinson", "Enabling Overwrite mode will\ndelete your captured frames\nand replace them with one\nframe per ID.\n\nAre you ready to do that?",
QMessageBox::Yes|QMessageBox::No);
if (confirmDialog == QMessageBox::Yes)
{
model->setOverwriteMode(state);
}
else ui->cbOverwrite->setCheckState(Qt::Unchecked);
}
}
void MainWindow::updateFilterList()
@@ -466,7 +484,7 @@ void MainWindow::tickGUIUpdate()
framesPerSec = 0;
ui->lbNumFrames->setText(QString::number(model->rowCount()));
if (allowCapture && ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
if (rxFrames > 0 && /*allowCapture && */ ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
ui->lbFPS->setText(QString::number(framesPerSec));
if (rxFrames > 0)
{
+50 -7
View File
@@ -4,6 +4,10 @@
#include "helpwindow.h"
#include <QtDebug>
const QColor FrameInfoWindow::byteGraphColors[8] = {Qt::blue, Qt::green, Qt::black, Qt::red, //0 1 2 3
Qt::gray, Qt::yellow, Qt::cyan, Qt::darkMagenta}; //4 5 6 7
QPen FrameInfoWindow::bytePens[8];
FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
ui(new Ui::FrameInfoWindow)
@@ -32,19 +36,40 @@ FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *paren
ui->graphHistogram->legend->setVisible(false);
ui->graphBytes->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes |
QCP::iSelectLegend | QCP::iSelectPlottables);
ui->graphBytes->xAxis->setRange(0, 63);
ui->graphBytes->yAxis->setRange(0, 265);
ui->graphBytes->axisRect()->setupFullAxesBox();
ui->graphBytes->xAxis->setLabel("Time");
ui->graphBytes->yAxis->setLabel("Value");
ui->graphBytes->legend->setVisible(false);
if (useOpenGL)
{
ui->graphHistogram->setAntialiasedElements(QCP::aeAll);
//ui->graphingView->setNoAntialiasingOnDrag(true);
ui->graphHistogram->setOpenGl(true);
ui->graphBytes->setAntialiasedElements(QCP::aeAll);
ui->graphBytes->setOpenGl(true);
}
else
{
ui->graphHistogram->setOpenGl(false);
ui->graphHistogram->setAntialiasedElements(QCP::aeNone);
ui->graphBytes->setOpenGl(false);
ui->graphBytes->setAntialiasedElements(QCP::aeNone);
}
installEventFilter(this);
for (int i = 0; i < 8; i++)
{
bytePens[i].setColor(byteGraphColors[i]);
bytePens[i].setWidth(1);
}
}
void FrameInfoWindow::showEvent(QShowEvent* event)
@@ -94,7 +119,7 @@ void FrameInfoWindow::readSettings()
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("FrameInfo/WindowSize", QSize(794, 494)).toSize());
resize(settings.value("FrameInfo/WindowSize", QSize(794, 694)).toSize());
move(settings.value("FrameInfo/WindowPos", QPoint(50, 50)).toPoint());
}
useOpenGL = settings.value("Main/UseOpenGL", false).toBool();
@@ -188,7 +213,8 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
int maxData[8];
int dataHistogram[256][8];
int bitfieldHistogram[64];
QVector<double> graphX, graphY;
QVector<double> histGraphX, histGraphY;
QVector<double> byteGraphX, byteGraphY[8];
double maxY = -1000.0;
uint8_t changedBits[8];
uint8_t referenceBits[8];
@@ -248,7 +274,7 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
baseNode->addChild(tempItem);
tempItem = new QTreeWidgetItem();
tempItem->setText(0, tr("PGN: ") + Utility::formatNumber(jid.pgn));
tempItem->setText(0, tr("PGN: ") + Utility::formatNumber(jid.pgn) + "(" + QString::number(jid.pgn) + ")");
baseNode->addChild(tempItem);
tempItem = new QTreeWidgetItem();
@@ -287,6 +313,12 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
//then find all data points
for (int j = 0; j < frameCache.count(); j++)
{
byteGraphX.append(j);
for (int bytcnt = 0; bytcnt < frameCache[j].len; bytcnt++)
{
byteGraphY[bytcnt].append(frameCache[j].data[bytcnt]);
}
if (j != 0)
{
thisInterval = (frameCache[j].timestamp - frameCache[j-1].timestamp);
@@ -381,16 +413,17 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
+ QString::number(c % 8) + ") :" + QString::number(bitfieldHistogram[c]));
dataBase->addChild(tempItem);
graphX.append(c);
graphY.append(bitfieldHistogram[c]);
histGraphX.append(c);
histGraphY.append(bitfieldHistogram[c]);
if (bitfieldHistogram[c] > maxY) maxY = bitfieldHistogram[c];
}
baseNode->addChild(dataBase);
ui->treeDetails->insertTopLevelItem(0, baseNode);
ui->graphHistogram->clearGraphs();
ui->graphHistogram->addGraph();
ui->graphHistogram->graph()->setData(graphX, graphY);
ui->graphHistogram->graph()->setData(histGraphX, histGraphY);
ui->graphHistogram->graph()->setLineStyle(QCPGraph::lsStepLeft); //connect points with lines
QBrush graphBrush;
graphBrush.setColor(Qt::red);
@@ -400,6 +433,16 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
ui->graphHistogram->yAxis->setRange(0, maxY * 1.02);
ui->graphHistogram->axisRect()->setupFullAxesBox();
ui->graphHistogram->replot();
ui->graphBytes->clearGraphs();
for (int graphs = 0; graphs < 8; graphs++)
{
ui->graphBytes->addGraph();
ui->graphBytes->graph()->setData(byteGraphX, byteGraphY[graphs]);
ui->graphBytes->graph()->setPen(bytePens[graphs]);
}
ui->graphBytes->xAxis->setRange(0, byteGraphX.count());
ui->graphBytes->replot();
}
else
{
+2
View File
@@ -33,6 +33,8 @@ private:
QList<CANFrame> frameCache;
const QVector<CANFrame> *modelFrames;
bool useOpenGL;
static const QColor byteGraphColors[8];
static QPen bytePens[8];
void refreshIDList();
void closeEvent(QCloseEvent *event);
+17 -12
View File
@@ -696,7 +696,7 @@ void GraphingWindow::saveSpreadsheet()
*/
QList<GraphParams>::iterator iter;
double xMin = 1000000000, xMax=-1000000000;
double xMin = 10000000000000, xMax=-10000000000000;
int maxCount = 0;
int numGraphs = 0;
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
@@ -732,6 +732,7 @@ void GraphingWindow::saveSpreadsheet()
for (int j = 1; j < (maxCount - 1); j++)
{
currentX = xMin + (j * sliceSize);
qDebug() << "X: " << currentX;
outFile->write(QString::number(currentX).toUtf8());
for (int k = 0; k < graphParams.count(); k++)
{
@@ -764,9 +765,10 @@ void GraphingWindow::saveSpreadsheet()
double span = graphParams[k].x[indices[k] + 1] - graphParams[k].x[indices[k]];
double progress = (currentX - graphParams[k].x[indices[k]]) / span;
value = Utility::Lerp(graphParams[k].y[indices[k]], graphParams[k].y[indices[k] + 1], progress);
qDebug() << "Span: " << span << " Prog: " << progress << " Value: " << value;
}
if (currentX >= graphParams[k].x[indices[k] + 1]) indices[k]++;
if (currentX >= graphParams[k].x[indices[k]]) indices[k]++;
outFile->putChar(',');
outFile->write(QString::number(value).toUtf8());
@@ -845,7 +847,7 @@ void GraphingWindow::loadDefinitions()
QStringList filters;
filters.append(QString(tr("Graph definition (*.gdf)")));
if (dbcHandler == NULL) return;
if (dbcHandler == nullptr) return;
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
dialog.setFileMode(QFileDialog::ExistingFile);
@@ -871,11 +873,14 @@ void GraphingWindow::loadDefinitions()
if (tokens[0] == "X") //newest format based around signals
{
gp.ID = tokens[1].toInt(NULL, 16);
gp.mask = tokens[2].toULongLong(NULL, 16);
gp.ID = tokens[1].toUInt(nullptr, 16);
gp.mask = tokens[2].toULongLong(nullptr, 16);
gp.startBit = tokens[3].toInt();
if (gp.startBit < 0) gp.intelFormat = false;
else gp.intelFormat = true;
if (gp.startBit < 0) {
gp.intelFormat = false;
gp.startBit *= -1;
}
else gp.intelFormat = true;
gp.numBits = tokens[4].toInt();
if (tokens[5] == "Y") gp.isSigned = true;
else gp.isSigned = false;
@@ -894,18 +899,18 @@ void GraphingWindow::loadDefinitions()
}
else //one of the two older formats then
{
gp.ID = tokens[0].toInt(NULL, 16);
gp.ID = tokens[0].toUInt(nullptr, 16);
if (tokens[1] == "S") //old signal based graph definition
{
//tokens[2] is the signal name. Need to use the message ID and this name to look it up
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(gp.ID);
if (msg != NULL)
if (msg != nullptr)
{
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]);
if (sig)
{
gp.mask = 0xFFFFFFFF;
gp.bias = sig->bias;
gp.bias = (float)sig->bias;
gp.color.setRed(tokens[3].toInt());
gp.color.setGreen(tokens[4].toInt());
gp.color.setBlue(tokens[5].toInt());
@@ -914,7 +919,7 @@ void GraphingWindow::loadDefinitions()
if (sig->valType == SIGNED_INT) gp.isSigned = true;
else gp.isSigned = false;
gp.numBits = sig->signalSize;
gp.scale = sig->factor;
gp.scale = (float)sig->factor;
gp.startBit = sig->startBit;
gp.stride = 1;
createGraph(gp, true);
@@ -926,7 +931,7 @@ void GraphingWindow::loadDefinitions()
//hard part - this all changed drastically
//the difference between intel and motorola format is whether
//start is larger than end byte or not.
uint64_t oldMask = tokens[1].toULongLong(NULL, 16);
uint64_t oldMask = tokens[1].toULongLong(nullptr, 16);
int oldStart = tokens[2].toInt();
int oldEnd = tokens[3].toInt();
+6 -1
View File
@@ -179,6 +179,7 @@ void ISOTP_InterpreterWindow::updatedFrames(int numFrames)
void ISOTP_InterpreterWindow::headerClicked(int logicalIndex)
{
ui->tableIsoFrames->setSortingEnabled(false);
ui->tableIsoFrames->sortByColumn(logicalIndex);
}
@@ -261,9 +262,13 @@ void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE msg)
messages.append(msg);
rowNum = ui->tableIsoFrames->rowCount();
ui->tableIsoFrames->insertRow(rowNum);
ui->tableIsoFrames->setItem(rowNum, 0, new QTableWidgetItem(Utility::formatTimestamp(msg.timestamp)));
QTableWidgetItem *item = new QTableWidgetItem;
item->setData(Qt::EditRole, Utility::formatTimestamp(msg.timestamp));
//ui->tableIsoFrames->setItem(rowNum, 0, (double)msg.timestamp, Utility::formatTimestamp(msg.timestamp)));
ui->tableIsoFrames->setItem(rowNum, 0, item);
ui->tableIsoFrames->setItem(rowNum, 1, new QTableWidgetItem(QString::number(msg.ID, 16)));
ui->tableIsoFrames->setItem(rowNum, 2, new QTableWidgetItem(QString::number(msg.bus)));
if (msg.isReceived) ui->tableIsoFrames->setItem(rowNum, 3, new QTableWidgetItem("Rx"));
+116
View File
@@ -0,0 +1,116 @@
#include "SnifferDelegate.h"
#include <QPainter>
#include <QDebug>
#include "utility.h"
#include "re/sniffer/snifferitem.h"
SnifferDelegate::SnifferDelegate(QWidget *parent) : QItemDelegate(parent)
{
blackBrush = QBrush(Qt::black);
whiteBrush = QBrush(Qt::white);
redBrush = QBrush(Qt::red);
greenBrush = QBrush(Qt::green);
grayBrush = QBrush(QColor(230,230,230));
mainFont.setPointSize(10);
mainFontInfo = new QFontInfo(mainFont);
mFadeInactive = false;
}
bool SnifferDelegate::getFadeInactive()
{
return mFadeInactive;
}
void SnifferDelegate::setFadeInactive(bool val)
{
mFadeInactive = val;
}
void SnifferDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
//qDebug() << "SnifferDelegate Paint Event";
if (index.column() < 2) //allow default handling of the first two columns
{
QItemDelegate::paint(painter, option, index);
return;
}
if (index.column() > 9) return;
int x, y;
SnifferItem *item = static_cast<SnifferItem*>(index.internalPointer());
int idx = index.column() - 2;
int val = item->getData(idx);
int prevVal = item->getLastData(idx);
int notchPattern = item->getNotchPattern(idx);
int maskPattern;
if (val < 0) return;
QRect viewport = option.rect;
int xSpan = viewport.right() - viewport.left();
int ySpan = viewport.bottom() - viewport.top();
int yOffset = (ySpan - (xSpan / 4)) / 2;
if (yOffset < 0) yOffset = 0;
//qDebug() << "XSpan" << xSpan << " YSpan " << ySpan;
int xSector = xSpan / 8;
int v = item->getSeqInterval(index.column() - 2) * 10;
if (v > 225) v = 225;
if (v < 0) v = 0;
for (x = 0; x < 8; x++)
{
maskPattern = 1 << (7-x);
//We look to see if each bit has changed since the last update or not. If not we
//straight draw it black if set or white if unset. If it changed then draw it green if it is newly set
//and red if newly unset
//But also, if a bit is notched we just plain draw it gray no matter what it's doing
if (notchPattern & maskPattern)
{
painter->setBrush(grayBrush);
}
else if ( (val & maskPattern) == (prevVal & maskPattern) ) //wasn't notched so has it changed? No? Then...
{
if (val & maskPattern)
{
painter->setBrush(blackBrush);
}
else
{
painter->setBrush(whiteBrush);
}
}
else //wasn't notched and did change since last time.
{
if (val & maskPattern)
{
painter->setBrush(greenBrush);
}
else
{
painter->setBrush(redBrush);
}
}
if (mFadeInactive) painter->setOpacity((255 - v) / 255.0);
else painter->setOpacity(1.0);
painter->drawRect(viewport.left() + x * xSector, viewport.top() + yOffset, xSector, xSector);
}
//painter->setPen(QPen(QColor(v,v,v,255)));
painter->setOpacity(1.0);
painter->setPen(Qt::black);
painter->setFont(mainFont);
painter->drawText(QRect(viewport.left(), viewport.top() + xSector + yOffset, xSpan, mainFontInfo->pixelSize()), Qt::AlignCenter, Utility::formatNumber(val));
}
QSize SnifferDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize origSize = QItemDelegate::sizeHint(option, index);
origSize.setHeight(origSize.height() * 2.0);
return origSize;
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef SNIFFERDELEGATE_H
#define SNIFFERDELEGATE_H
#include <QItemDelegate>
class SnifferDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit SnifferDelegate(QWidget *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
bool getFadeInactive();
void setFadeInactive(bool val);
signals:
public slots:
private:
QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush;
QFont mainFont;
QFontInfo* mainFontInfo;
bool mFadeInactive;
};
#endif
+90 -17
View File
@@ -3,15 +3,21 @@
#include "snifferitem.h"
SnifferItem::SnifferItem(const CANFrame& pFrame):
mNotch(0),
SnifferItem::SnifferItem(const CANFrame& pFrame, quint32 seq):
mID(pFrame.ID)
{
mMarker = {0,0};
mLastMarker = {0,0};
for (int i = 0; i < 8; i++) {
mNotch[i] =0;
mMarker.data[i] = 0;
mMarker.dataTimestamp[i] = 0;
mCurrent.data[i] = pFrame.data[i];
mCurrent.dataTimestamp[i] = seq;
}
mLastMarker = mMarker;
mCurrent.len = pFrame.len;
/* that's dirty */
update(pFrame);
update(pFrame);
update(pFrame, seq, false);
update(pFrame, seq, false);
}
@@ -30,57 +36,124 @@ float SnifferItem::getDelta() const
return ((float)(mCurrentTime-mLastTime))/1000000;
}
//Get a data byte by index 0-7 (but not more than the length of the actual frame)
int SnifferItem::getData(uchar i) const
{
return (i>=mCurrent.len) ? -1 : ((uchar*) &mCurrent.data)[i];
return (i >= mCurrent.len) ? -1 : mCurrent.data[i];
}
quint8 SnifferItem::getNotchPattern(uchar i) const
{
return (i >= mCurrent.len) ? -1 : mNotch[i];
}
quint8 SnifferItem::getLastData(uchar i) const
{
return (i >= mLast.len) ? -1 : mLast.data[i];
}
quint32 SnifferItem::getDataTimestamp(uchar i) const
{
return (i >= mCurrent.len) ? 0 : mCurrent.dataTimestamp[i];
}
quint32 SnifferItem::getSeqInterval(uchar i) const
{
return mCurrSeqVal - getDataTimestamp(i);
}
//Return whether a given data byte (by index 0-7) has incremented, deincremented, or stayed the same
//since the last message
//The If checks first that we aren't past the actual data length
// then checks whether lastMarker shows that some bits have changed in the previous 200ms cycle
// then we check if the byte in mNotch has bits set and if it does we say nothing changed (notched out)
dc SnifferItem::dataChange(uchar i) const
{
if( i<mCurrent.len &&
((uchar*) &mLastMarker.data)[i] &&
!((uchar*) &mNotch)[i] )
if (i >= mCurrent.len) return dc::NO;
uchar notch = mNotch[i];
uchar byt = mCurrent.data[i];
uchar last = mLast.data[i];
uchar lastMark = mLastMarker.data[i];
if( lastMark )
{
return ((uchar*) &mCurrent.data)[i] >= ((uchar*) &mLast.data)[i] ? dc::INC : dc::DEINC;
if (!notch) //if no notching is set
return (byt >= last ? dc::INC : dc::DEINC);
else //mNotch contained a bit pattern so use masks and do things more complicated
{
byt &= ~notch; //mask off bits that were notched
if (byt == 0) return dc::NO; //and if result is null then nothing changed (other than maybe notched bits and they don't count)
last &= ~notch; //need to mask last too
if (last == byt) return dc::NO;
return (byt >= last ? dc::INC : dc::DEINC); //then compare the masked copies to see which way the bit(s) went
}
}
return dc::NO;
}
int SnifferItem::elapsed() const
{
return mTime.elapsed();
}
void SnifferItem::update(const CANFrame& pFrame)
//called when a new frame comes in that matches our same ID
//timeSeq is stored so we can figure out the last time a specific byte was updated
//mute is used to specify whether to mask the byte against the notching filter
//in order to hide any updates of the notched bits. This is toggleable
void SnifferItem::update(const CANFrame& pFrame, quint32 timeSeq, bool mute)
{
unsigned char maskedCurr, maskedData;
//qDebug() << "update with ts: " << timeSeq;
/* copy current to last */
mLast = mCurrent;
mLastTime = mCurrentTime;
mCurrSeqVal = timeSeq;
/* copy new value */
memcpy(&mCurrent.data, pFrame.data, 8);
for (int i = 0; i < 8; i++)
{
maskedData = pFrame.data[i];
if (mute) maskedData &= ~mNotch[i];
maskedCurr = mCurrent.data[i];
if (mute) maskedCurr &= ~mNotch[i];
if (maskedCurr != maskedData)
{
mCurrent.data[i] = pFrame.data[i];
mCurrent.dataTimestamp[i] = timeSeq;
}
}
mCurrent.len = pFrame.len;
mCurrentTime = pFrame.timestamp;
/* update marker */
mMarker.data |= mLast.data ^ mCurrent.data;
//We "OR" our stored marker with the changed bits.
//this accumulates changed bits into the marker
for (int i = 0 ; i < 8; i++) mMarker.data[i] |= mLast.data[i] ^ mCurrent.data[i]; //XOR causes only changed bits to be 1's
mMarker.len |= mLast.len ^ mCurrent.len;
/* restart timeout */
mTime.restart();
}
//Called in refresh from the model. Interval about 200ms currently.
//So, this means the marker only accumulates for 200ms then resets
void SnifferItem::updateMarker()
{
mLastMarker = mMarker;
mMarker = {0, 0};
for (int i = 0; i < 8; i++) mMarker.data[i] = 0;
}
//Notch or un-notch this snifferitem / frame
void SnifferItem::notch(bool pNotch)
{
if(pNotch)
mNotch |= mLastMarker.data;
{
for (int i = 0; i < 8; i++) mNotch[i] |= mLastMarker.data[i]; //add changed bits to notch value
}
else
mNotch = 0;
for (int i = 0; i < 8; i++) mNotch[i] = 0;
}
+12 -5
View File
@@ -7,7 +7,8 @@
struct fstCan
{
quint64 data;
quint8 data[8];
quint32 dataTimestamp[8];
int len;
};
@@ -22,26 +23,32 @@ enum dc
class SnifferItem
{
public:
explicit SnifferItem(const CANFrame& pFrame);
explicit SnifferItem(const CANFrame& pFrame, quint32 seq);
virtual ~SnifferItem();
quint64 getId() const;
float getDelta() const;
int getData(uchar i) const;
quint8 getNotchPattern(uchar i) const;
quint8 getLastData(uchar i) const;
quint32 getDataTimestamp(uchar i) const;
quint32 getSeqInterval(uchar i) const;
dc dataChange(uchar) const;
int elapsed() const;
void update(const CANFrame& pFrame);
void update(const CANFrame& pFrame, quint32 timeSeq, bool mute);
void updateMarker();
void notch(bool);
private:
quint64 mID;
quint32 mID;
struct fstCan mLast;
struct fstCan mCurrent;
struct fstCan mLastMarker;
struct fstCan mMarker;
quint64 mNotch;
quint8 mNotch[8];
quint64 mLastTime;
quint64 mCurrentTime;
quint64 mCurrSeqVal;
QTime mTime;
};
+57 -8
View File
@@ -1,11 +1,15 @@
#include <QDebug>
#include "sniffermodel.h"
#include "snifferwindow.h"
#include "SnifferDelegate.h"
SnifferModel::SnifferModel(QObject *parent)
: QAbstractItemModel(parent),
mFilter(false)
mFilter(false),
mNeverExpire(false),
mFadeInactive(false),
mMuteNotched(false),
mTimeSequence(0)
{
}
@@ -56,16 +60,29 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const
if(tc::DATA_0<=col && col <=tc::DATA_7)
{
int data = item->getData(col-tc::DATA_0);
if(data>=0)
if(data >= 0)
{
return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper();
}
}
break;
}
case Qt::ForegroundRole:
{
if (!mFadeInactive || col < 2) return QBrush(Qt::black);
int v = item->getSeqInterval(col - 2) * 10;
//qDebug() << "mTS: " << mTimeSequence << " gDT(" << (col - 2) << ") " << item->getDataTimestamp(col - 2);
if (v > 225) v = 225;
if (v < 0) v = 0;
return QBrush(QColor(v,v,v,255));
break;
}
case Qt::BackgroundRole:
{
if(tc::ID==col)
{
if(item->elapsed()>4000)
if(item->elapsed() > 4000)
return QBrush(Qt::red);
}
else if(tc::DATA_0<=col && col<=tc::DATA_7)
@@ -143,6 +160,35 @@ QModelIndex SnifferModel::parent(const QModelIndex &) const
return QModelIndex();
}
bool SnifferModel::getNeverExpire()
{
return mNeverExpire;
}
bool SnifferModel::getFadeInactive()
{
return mFadeInactive;
}
bool SnifferModel::getMuteNotched()
{
return mMuteNotched;
}
void SnifferModel::setNeverExpire(bool val)
{
mNeverExpire = val;
}
void SnifferModel::setFadeInactive(bool val)
{
mFadeInactive = val;
}
void SnifferModel::setMuteNotched(bool val)
{
mMuteNotched = val;
}
void SnifferModel::clear()
{
@@ -154,20 +200,22 @@ void SnifferModel::clear()
endResetModel();
}
//Called from window with a timer (currently 200ms)
void SnifferModel::refresh()
{
QMap<quint32, SnifferItem*>::iterator i;
QVector<quint32> toRemove;
SnifferItem* item;
mTimeSequence++;
/* update markers */
for (i = mMap.begin(); i != mMap.end(); ++i)
{
i.value()->updateMarker();
if(i.value()->elapsed()>5000)
if(i.value()->elapsed()>5000 && !mNeverExpire)
toRemove.append(i.key());
}
@@ -237,14 +285,15 @@ void SnifferModel::update(CANConnection*, QVector<CANFrame>& pFrames)
int index = std::distance(mMap.begin(), mMap.lowerBound(frame.ID));
/* add the frame */
beginInsertRows(QModelIndex(), index, index);
mMap[frame.ID] = new SnifferItem(frame);
mMap[frame.ID] = new SnifferItem(frame, mTimeSequence);
mMap[frame.ID]->update(frame, mTimeSequence, mMuteNotched);
endInsertRows();
emit idChange(frame.ID, true);
}
else
//updateData
mMap[frame.ID]->update(frame);
mMap[frame.ID]->update(frame, mTimeSequence, mMuteNotched);
}
}
+11
View File
@@ -40,6 +40,13 @@ public:
void refresh();
void clear();
void filter(fltType pType, int pId=0);
bool getNeverExpire();
bool getFadeInactive();
bool getMuteNotched();
void setNeverExpire(bool val);
void setFadeInactive(bool val);
void setMuteNotched(bool val);
public slots:
void update(CANConnection*, QVector<CANFrame>&);
@@ -53,6 +60,10 @@ private:
QMap<quint32, SnifferItem*> mMap;
QMap<quint32, SnifferItem*> mFilters;
bool mFilter;
bool mNeverExpire;
bool mFadeInactive;
bool mMuteNotched;
quint32 mTimeSequence;
};
#endif // SNIFFERMODEL_H
+68 -3
View File
@@ -4,6 +4,7 @@
#include "ui_snifferwindow.h"
#include "helpwindow.h"
#include "connections/canconmanager.h"
#include "SnifferDelegate.h"
SnifferWindow::SnifferWindow(QWidget *parent) :
QDialog(parent),
@@ -16,12 +17,17 @@ SnifferWindow::SnifferWindow(QWidget *parent) :
setWindowFlags(Qt::Window);
ui->treeView->setModel(&mModel);
sniffDel = new SnifferDelegate();
defaultDel = ui->treeView->itemDelegate();
/* set column width */
ui->treeView->setColumnWidth(tc::ID, 50);
ui->treeView->setColumnWidth(tc::ID, 80);
ui->treeView->setColumnWidth(tc::LAST, 1);
for(int i=tc::DATA_0 ; i<=tc::DATA_7 ; i++)
ui->treeView->setColumnWidth(i, 30);
ui->treeView->setColumnWidth(i, 92);
ui->treeView->setUniformRowHeights(true);
ui->treeView->header()->setDefaultAlignment(Qt::AlignCenter);
//ui->treeView->setItemDelegate(new SnifferDelegate());
/* activate sorting */
ui->listWidget->setSortingEnabled(true);
@@ -38,20 +44,75 @@ SnifferWindow::SnifferWindow(QWidget *parent) :
connect(&mModel, &SnifferModel::idChange, this, &SnifferWindow::idChange);
connect(ui->listWidget, &QListWidget::itemChanged, this, &SnifferWindow::itemChanged);
connect(ui->cbFadeInactive, &QCheckBox::stateChanged, this, [this](int val){mModel.setFadeInactive(val);sniffDel->setFadeInactive(val);});
connect(ui->cbMuteNotched, &QCheckBox::stateChanged, this, [this](int val){mModel.setMuteNotched(val);});
connect(ui->cbNoExpire, &QCheckBox::stateChanged, this, [this](int val){mModel.setNeverExpire(val);});
connect(ui->cbViewBits, &QCheckBox::stateChanged, this,
[this](int val)
{
if (val) ui->treeView->setItemDelegate(sniffDel);
else
{
ui->treeView->setItemDelegate(defaultDel);
}
}
);
}
SnifferWindow::~SnifferWindow()
{
closeEvent(NULL);
delete sniffDel;
delete ui;
}
void SnifferWindow::readSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("Sniffer/WindowSize", QSize(1100, 750)).toSize());
move(settings.value("Sniffer/WindowPos", QPoint(50, 50)).toPoint());
ui->treeView->setColumnWidth(0, settings.value("Sniffer/DeltaColumn", 110).toUInt());
ui->treeView->setColumnWidth(1, settings.value("Sniffer/IDColumn", 70).toUInt());
ui->treeView->setColumnWidth(2, settings.value("Sniffer/Data0Column", 92).toUInt());
ui->treeView->setColumnWidth(3, settings.value("Sniffer/Data1Column", 92).toUInt());
ui->treeView->setColumnWidth(4, settings.value("Sniffer/Data2Column", 92).toUInt());
ui->treeView->setColumnWidth(5, settings.value("Sniffer/Data3Column", 92).toUInt());
ui->treeView->setColumnWidth(6, settings.value("Sniffer/Data4Column", 92).toUInt());
ui->treeView->setColumnWidth(7, settings.value("Sniffer/Data5Column", 92).toUInt());
ui->treeView->setColumnWidth(8, settings.value("Sniffer/Data6Column", 92).toUInt());
ui->treeView->setColumnWidth(9, settings.value("Sniffer/Data7Column", 92).toUInt());
}
}
void SnifferWindow::writeSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
settings.setValue("Sniffer/WindowSize", size());
settings.setValue("Sniffer/WindowPos", pos());
settings.setValue("Sniffer/DeltaColumn", ui->treeView->columnWidth(0));
settings.setValue("Sniffer/IDColumn", ui->treeView->columnWidth(1));
settings.setValue("Sniffer/Data0Column", ui->treeView->columnWidth(2));
settings.setValue("Sniffer/Data1Column", ui->treeView->columnWidth(3));
settings.setValue("Sniffer/Data2Column", ui->treeView->columnWidth(4));
settings.setValue("Sniffer/Data3Column", ui->treeView->columnWidth(5));
settings.setValue("Sniffer/Data4Column", ui->treeView->columnWidth(6));
settings.setValue("Sniffer/Data5Column", ui->treeView->columnWidth(7));
settings.setValue("Sniffer/Data6Column", ui->treeView->columnWidth(8));
settings.setValue("Sniffer/Data7Column", ui->treeView->columnWidth(9));
}
}
void SnifferWindow::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
connect(CANConManager::getInstance(), &CANConManager::framesReceived, &mModel, &SnifferModel::update);
mTimer.start();
readSettings();
installEventFilter(this);
qDebug() << "show";
}
@@ -64,6 +125,7 @@ void SnifferWindow::closeEvent(QCloseEvent *event)
mTimer.stop();
/* disconnect reception of frames */
disconnect(CANConManager::getInstance(), 0, this, 0);
writeSettings();
/* clear model */
mModel.clear();
/* clean list */
@@ -127,7 +189,10 @@ void SnifferWindow::idChange(int pId, bool 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);
//item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked);
//always check new IDs now. Otherwise any that expire then come back will not be selected
//and that might be a bigger issue than defaulting them unselected.
item->setCheckState(Qt::Checked);
ui->listWidget->addItem(item);
mMap[pId] = item;
}
+5
View File
@@ -4,6 +4,7 @@
#include <QDialog>
#include <QListWidgetItem>
#include "sniffermodel.h"
#include "SnifferDelegate.h"
namespace Ui {
class snifferWindow;
@@ -46,12 +47,16 @@ public slots:
private:
void filter(bool pFilter);
bool eventFilter(QObject *obj, QEvent *event);
void readSettings();
void writeSettings();
Ui::snifferWindow* ui;
SnifferModel mModel;
QTimer mTimer;
QMap<int, QListWidgetItem*> mMap;
bool mFilter;
SnifferDelegate *sniffDel;
QAbstractItemDelegate *defaultDel;
};
#endif // SNIFFER_H
+13 -13
View File
@@ -81,16 +81,6 @@
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QRadioButton" name="rbKvaser">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Kvaser</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="rbGVRET">
<property name="text">
@@ -101,17 +91,17 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QRadioButton" name="rbSocketCAN">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>SocketCAN</string>
<string>QT SerialBus Devices (SocketCAN, PeakCAN, etc)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="1" column="0">
<widget class="QRadioButton" name="rbRemote">
<property name="text">
<string>Remote Host</string>
@@ -121,6 +111,16 @@
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="lblDeviceType">
<property name="text">
<string>Device Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbDeviceType"/>
</item>
<item>
<widget class="QLabel" name="lPort">
<property name="sizePolicy">
+154 -161
View File
@@ -6,16 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>884</width>
<height>915</height>
<width>1239</width>
<height>644</height>
</rect>
</property>
<property name="windowTitle">
<string>Signal Editor</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="10,1,5">
<layout class="QVBoxLayout" name="verticalLayout" stretch="10,1,4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2,1">
<item>
<widget class="QListWidget" name="signalsList"/>
</item>
@@ -52,155 +52,159 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Bit Length:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Byte Order</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="txtBitLength"/>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="cbIntelFormat">
<property name="text">
<string>LSB First (Little Endian)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Scale:</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Bias:</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Min Value:</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Max Value:</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Receiving Node:</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Comment:</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Units Name:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="comboType"/>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="txtScale"/>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="txtBias"/>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="txtMinVal"/>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="txtMaxVal"/>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="txtUnitName"/>
</item>
<item row="10" column="1">
<widget class="QComboBox" name="comboReceiver"/>
</item>
<item row="14" column="1">
<widget class="QLineEdit" name="txtComment"/>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Multiplexing</string>
</property>
</widget>
</item>
<item row="12" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="rbNotMulti">
<property name="text">
<string>Not multiplexed</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbMultiplexed">
<property name="text">
<string>Multiplexed</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbMultiplexor">
<property name="text">
<string>Multiplexor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Multiplex Value</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="txtMultiplexValue"/>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Bit Length:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtBitLength"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Byte Order</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="cbIntelFormat">
<property name="text">
<string>LSB First (Little Endian)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboType"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Scale:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="txtScale"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Bias:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="txtBias"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Min Value:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="txtMinVal"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Max Value:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="txtMaxVal"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Units Name:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="txtUnitName"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Receiving Node:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="comboReceiver"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Multiplexing</string>
</property>
</widget>
</item>
<item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="rbNotMulti">
<property name="text">
<string>Not multiplexed</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbMultiplexed">
<property name="text">
<string>Multiplexed</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbMultiplexor">
<property name="text">
<string>Multiplexor</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Multiplex Value</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLineEdit" name="txtMultiplexValue"/>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Comment:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLineEdit" name="txtComment"/>
</item>
</layout>
</item>
</layout>
</item>
<item>
@@ -226,20 +230,9 @@
<tabstops>
<tabstop>signalsList</tabstop>
<tabstop>txtName</tabstop>
<tabstop>txtBitLength</tabstop>
<tabstop>cbIntelFormat</tabstop>
<tabstop>comboType</tabstop>
<tabstop>txtScale</tabstop>
<tabstop>txtBias</tabstop>
<tabstop>txtMinVal</tabstop>
<tabstop>txtMaxVal</tabstop>
<tabstop>txtUnitName</tabstop>
<tabstop>comboReceiver</tabstop>
<tabstop>rbNotMulti</tabstop>
<tabstop>rbMultiplexed</tabstop>
<tabstop>rbMultiplexor</tabstop>
<tabstop>txtMultiplexValue</tabstop>
<tabstop>txtComment</tabstop>
<tabstop>valuesTable</tabstop>
</tabstops>
<resources/>
+456 -51
View File
@@ -13,67 +13,473 @@
<property name="windowTitle">
<string>Detailed Frame Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="10,1,5">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
<item>
<widget class="QLabel" name="lblFrameID">
<property name="text">
<string>Frame IDs:</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="lblFrameID">
<property name="text">
<string>Frame IDs:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listFrameID">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="listFrameID">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Details:</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="treeDetails">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Details:</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="treeDetails">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Save details to file</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Save details to file</string>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="graphHistogram" native="true"/>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,1,0,1,0">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Bit Histograph</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="graphHistogram" native="true"/>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Bytes Graph</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="graphBytes" native="true"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_6">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>52</red>
<green>101</green>
<blue>164</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>52</red>
<green>101</green>
<blue>164</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>78</red>
<green>154</green>
<blue>6</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>78</red>
<green>154</green>
<blue>6</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>1</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>2</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>204</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>204</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>3</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>136</red>
<green>138</green>
<blue>133</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>136</red>
<green>138</green>
<blue>133</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>4</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>252</red>
<green>233</green>
<blue>79</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>252</red>
<green>233</green>
<blue>79</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>5</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>114</red>
<green>159</green>
<blue>207</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>114</red>
<green>159</green>
<blue>207</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>6</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>173</red>
<green>127</green>
<blue>168</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>173</red>
<green>127</green>
<blue>168</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>13</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>7</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
@@ -88,7 +494,6 @@
<tabstops>
<tabstop>listFrameID</tabstop>
<tabstop>treeDetails</tabstop>
<tabstop>btnSave</tabstop>
</tabstops>
<resources/>
<connections/>
+5 -1
View File
@@ -89,7 +89,11 @@
</widget>
</item>
<item>
<widget class="QListWidget" name="listFilter"/>
<widget class="QListWidget" name="listFilter">
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
+29 -1
View File
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>602</width>
<width>1097</width>
<height>752</height>
</rect>
</property>
@@ -82,6 +82,34 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbNoExpire">
<property name="text">
<string>Never Expire IDs</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbMuteNotched">
<property name="text">
<string>Mute notched bits</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbFadeInactive">
<property name="text">
<string>Fade inactive bytes</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbViewBits">
<property name="text">
<string>View Bits</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
+4 -4
View File
@@ -128,13 +128,13 @@ public:
return output;
}
static QString formatTimestamp(uint64_t timestamp)
static QVariant formatTimestamp(uint64_t timestamp)
{
if (!sysTimeMode) {
if (!secondsMode) return QString::number(timestamp);
else return QString::number((double)timestamp / 1000000.0, 'f', 6);
if (!secondsMode) return (unsigned long long)(timestamp);
else return (double)timestamp / 1000000.0;
}
else return QDateTime::fromMSecsSinceEpoch(timestamp / 1000).toString(timeFormat);
else return QDateTime::fromMSecsSinceEpoch(timestamp / 1000);
}
//parses the input string to grab as much of it as possible while staying alpha numeric