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 # SavvyCAN
Qt based cross platform canbus tool 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. 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 This tool is designed to help with visualization, reverse engineering, debugging, and
capturing of canbus frames. 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 You are highly recommended to use the
[CANDue board from EVTV](http://store.evtv.me/proddetail.php?prod=ArduinoDueCANBUS&cat=23). [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 The CANDue board must be running the GVRET firmware which can also be found
within the collin80 repos. within the collin80 repos.
It is now possible to use any SocketCAN compatible device It is now possible to use any QT SerialBus driver (socketcan, Vector, PeakCAN, TinyCAN).
under LINUX. There may, however, be some loss of some functionality as There may, however, be some loss of some functionality as
some functions of SavvyCAN are designed for use directly with the some functions of SavvyCAN are designed for use directly with the
EVTVDue and CANDue 2.0 boards. 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 However, this source code is integrated into the source for SavvyCAN and one isn't required
to download it separately. 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: ## Instructions for compiling:
+4 -2
View File
@@ -65,7 +65,8 @@ SOURCES += main.cpp\
jsedit.cpp \ jsedit.cpp \
frameplaybackobject.cpp \ frameplaybackobject.cpp \
helpwindow.cpp \ helpwindow.cpp \
blfhandler.cpp blfhandler.cpp \
re/sniffer/SnifferDelegate.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
can_structs.h \ can_structs.h \
@@ -121,7 +122,8 @@ HEADERS += mainwindow.h \
jsedit.h \ jsedit.h \
frameplaybackobject.h \ frameplaybackobject.h \
helpwindow.h \ helpwindow.h \
blfhandler.h blfhandler.h \
re/sniffer/SnifferDelegate.h
FORMS += ui/candatagrid.ui \ FORMS += ui/candatagrid.ui \
ui/connectionwindow.ui \ ui/connectionwindow.ui \
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+3 -3
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<QHelpCollectionProject version="1.0"> <QHelpCollectionProject version="1.0">
<assistant> <assistant>
<title>SavvyCAN 181 documentation</title> <title>SavvyCAN 189 documentation</title>
<homePage>qthelp://org.sphinx.savvycan.181/doc/index.html</homePage> <homePage>qthelp://org.sphinx.savvycan.189/doc/index.html</homePage>
<startPage>qthelp://org.sphinx.savvycan.181/doc/index.html</startPage> <startPage>qthelp://org.sphinx.savvycan.189/doc/index.html</startPage>
</assistant> </assistant>
<docFiles> <docFiles>
<generate> <generate>
+58 -51
View File
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<QtHelpProject version="1.0"> <QtHelpProject version="1.0">
<namespace>org.sphinx.savvycan.181</namespace> <namespace>org.sphinx.savvycan.189</namespace>
<virtualFolder>doc</virtualFolder> <virtualFolder>doc</virtualFolder>
<customFilter name="SavvyCAN 181"> <customFilter name="SavvyCAN 189">
<filterAttribute>SavvyCAN</filterAttribute> <filterAttribute>SavvyCAN</filterAttribute>
<filterAttribute>181</filterAttribute> <filterAttribute>189</filterAttribute>
</customFilter> </customFilter>
<filterSection> <filterSection>
<filterAttribute>SavvyCAN</filterAttribute> <filterAttribute>SavvyCAN</filterAttribute>
<filterAttribute>181</filterAttribute> <filterAttribute>189</filterAttribute>
<toc> <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="Main / Start Up Screen" ref="mainscreen.html"/>
<section title="The Main Frame List" ref="mainscreen.html#the-main-frame-list"/> <section title="The Main Frame List" ref="mainscreen.html#the-main-frame-list"/>
<section title="The Bottom Statusbar" ref="mainscreen.html#the-bottom-statusbar"/> <section title="The Bottom Statusbar" ref="mainscreen.html#the-bottom-statusbar"/>
@@ -58,6 +58,11 @@
<section title="Sniffer Window" ref="sniffer.html"/> <section title="Sniffer Window" ref="sniffer.html"/>
<section title="Using the Sniffer Window" ref="sniffer.html#using-the-sniffer-window"/> <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="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="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="The Purpose of Frame Details Window" ref="framedetails.html#the-purpose-of-frame-details-window"/>
<section title="File Comparison Window" ref="filecomparison.html"/> <section title="File Comparison Window" ref="filecomparison.html"/>
@@ -101,63 +106,65 @@
</keywords> </keywords>
<files> <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>bisector.html</file>
<file>firmwareuploader.html</file> <file>connectionwindow.html</file>
<file>genindex.html</file> <file>customsender.html</file>
<file>sniffer.html</file>
<file>isotp_decoder.html</file>
<file>preferences.html</file>
<file>dbc_editor.html</file> <file>dbc_editor.html</file>
<file>_static/file.png</file> <file>dbc_manager.html</file>
<file>_static/down.png</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/ajax-loader.gif</file>
<file>_static/comment-close.png</file> <file>_static/alabaster.css</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/basic.css</file> <file>_static/basic.css</file>
<file>_static/down-pressed.png</file> <file>_static/comment-bright.png</file>
<file>_static/up.png</file> <file>_static/comment-close.png</file>
<file>_static/comment.png</file> <file>_static/comment.png</file>
<file>_images/SignalEditor.png</file> <file>_static/down-pressed.png</file>
<file>_images/FrameInfoWindow.png</file> <file>_static/down.png</file>
<file>_images/DBCEditor.png</file> <file>_static/file.png</file>
<file>_images/UDS_Scanner.png</file> <file>_static/minus.png</file>
<file>_images/Sniffer.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/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/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/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/ISOTPDecoder.png</file>
<file>_images/MainScreen.png</file> <file>_images/MainScreen.png</file>
<file>_images/FlowView.png</file>
<file>_images/CustomSender.png</file>
<file>_images/Playback.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> </files>
</filterSection> </filterSection>
</QtHelpProject> </QtHelpProject>
+24 -23
View File
@@ -160,6 +160,7 @@ void CANFrameModel::setOverwriteMode(bool mode)
{ {
beginResetModel(); beginResetModel();
overwriteDups = mode; overwriteDups = mode;
recalcOverwrite();
endResetModel(); endResetModel();
} }
@@ -191,26 +192,20 @@ void CANFrameModel::recalcOverwrite()
mutex.lock(); mutex.lock();
beginResetModel(); 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.clear();
filteredFrames.reserve(preallocSize); filteredFrames.reserve(preallocSize);
@@ -255,6 +250,11 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
return QColor(Qt::white); return QColor(Qt::white);
} }
if (role == Qt::TextAlignmentRole)
{
return Qt::AlignLeft;
}
if (role == Qt::TextColorRole) if (role == Qt::TextColorRole)
{ {
if (dbcHandler != NULL && interpretFrames) if (dbcHandler != NULL && interpretFrames)
@@ -300,7 +300,8 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
for (int i = 0; i < dLen; i++) for (int i = 0; i < dLen; i++)
{ {
quint8 byt = thisFrame.data[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; if (byt > 0x7E) byt = 0x2E;
tempString.append(QString::fromUtf8((char *)&byt, 1)); 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); DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
if (msg != NULL) if (msg != NULL)
{ {
tempString.append("\n"); tempString.append(" <Interpreted>\n");
tempString.append(msg->name + "\n" + msg->comment + "\n"); tempString.append(msg->name + "\n" + msg->comment + "\n");
for (int j = 0; j < msg->sigHandler->getCount(); j++) 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); frames.append(tempFrame);
if (filters[tempFrame.ID]) 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); filteredFrames.append(tempFrame);
if (autoRefresh) endInsertRows(); if (autoRefresh) endInsertRows();
} }
@@ -432,7 +433,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
frames.append(tempFrame); frames.append(tempFrame);
if (filters[tempFrame.ID]) 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); filteredFrames.append(tempFrame);
if (autoRefresh) endInsertRows(); if (autoRefresh) endInsertRows();
} }
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef CONFIG #ifndef CONFIG
#define CONFIG #define CONFIG
#define VERSION 187 #define VERSION 190
//try to keep this in sync. //try to keep this in sync.
//SavvyCAN will complain if you connect a GVRET board with a revision //SavvyCAN will complain if you connect a GVRET board with a revision
+1 -1
View File
@@ -16,7 +16,7 @@ namespace CANCon {
{ {
GVRET_SERIAL, GVRET_SERIAL,
KVASER, KVASER,
SOCKETCAN, SERIALBUS,
REMOTE, REMOTE,
NONE NONE
}; };
+3 -3
View File
@@ -5,11 +5,11 @@
using namespace CANCon; using namespace CANCon;
CANConnection* CanConFactory::create(type pType, QString pPortName) CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName)
{ {
switch(pType) { switch(pType) {
case SOCKETCAN: case SERIALBUS:
return new SerialBusConnection(pPortName); return new SerialBusConnection(pPortName, pDriverName);
case GVRET_SERIAL: case GVRET_SERIAL:
return new GVRetSerial(pPortName, false); return new GVRetSerial(pPortName, false);
case REMOTE: case REMOTE:
+1 -1
View File
@@ -7,7 +7,7 @@
class CanConFactory class CanConFactory
{ {
public: public:
static CANConnection* create(CANCon::type, QString pPortName); static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName);
}; };
#endif // CANCONFACTORY_H #endif // CANCONFACTORY_H
+6
View File
@@ -3,6 +3,7 @@
#include "canconnection.h" #include "canconnection.h"
CANConnection::CANConnection(QString pPort, CANConnection::CANConnection(QString pPort,
QString pDriver,
CANCon::type pType, CANCon::type pType,
int pNumBuses, int pNumBuses,
int pQueueLen, int pQueueLen,
@@ -10,6 +11,7 @@ CANConnection::CANConnection(QString pPort,
mQueue(), mQueue(),
mNumBuses(pNumBuses), mNumBuses(pNumBuses),
mPort(pPort), mPort(pPort),
mDriver(pDriver),
mType(pType), mType(pType),
mIsCapSuspended(false), mIsCapSuspended(false),
mStatus(CANCon::NOT_CONNECTED), mStatus(CANCon::NOT_CONNECTED),
@@ -227,6 +229,10 @@ QString CANConnection::getPort() {
return mPort; return mPort;
} }
QString CANConnection::getDriver()
{
return mDriver;
}
LFQueue<CANFrame>& CANConnection::getQueue() { LFQueue<CANFrame>& CANConnection::getQueue() {
return mQueue; return mQueue;
+10
View File
@@ -19,12 +19,14 @@ protected:
/** /**
* @brief CANConnection constructor * @brief CANConnection constructor
* @param pPort: string containing port name * @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 pType: the type of connection @ref CANCon::type
* @param pNumBuses: the number of buses the device has * @param pNumBuses: the number of buses the device has
* @param pQueueLen: the length of the lock free queue to use * @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 * @param pUseThread: if set to true, object will be execute in a dedicated thread
*/ */
CANConnection(QString pPort, CANConnection(QString pPort,
QString pDriver,
CANCon::type pType, CANCon::type pType,
int pNumBuses, int pNumBuses,
int pQueueLen, int pQueueLen,
@@ -50,6 +52,13 @@ public:
*/ */
QString getPort(); QString getPort();
/**
* @brief getDriver
* @return returns the name of the driver used for this device
*/
QString getDriver();
/** /**
* @brief getQueue * @brief getQueue
* @return the lock free queue of the device * @return the lock free queue of the device
@@ -294,6 +303,7 @@ protected:
private: private:
LFQueue<CANFrame> mQueue; LFQueue<CANFrame> mQueue;
const QString mPort; const QString mPort;
const QString mDriver;
const CANCon::type mType; const CANCon::type mType;
bool mIsCapSuspended; bool mIsCapSuspended;
QAtomicInt mStatus; 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); CANConnection *conn_p = getAtIdx(index.row(), busId);
if (!conn_p) return Qt::ItemFlag::NoItemFlags; if (!conn_p) return Qt::ItemFlag::NoItemFlags;
//you can't set speed, single wire, or listen only on socketcan devices so //socketcan is limited for what you can set but the other serialbus
//detect if we're using GVRET where you can and turn that functionality on //devices should be able to set the stuff. For now let anyone try
bool editParams = false; //and the underlying drivers can do with them as they will
if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true; bool editParams = true;
//if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true;
switch (Column(index.column())) switch (Column(index.column()))
{ {
@@ -152,7 +153,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
bool ret; bool ret;
if (!conn_p) return QVariant(); if (!conn_p) return QVariant();
ret = conn_p->getBusSettings(busId, bus); 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; //qDebug() << "ConnP: " << conn_p << " ret " << ret;
@@ -167,7 +168,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
if (conn_p) if (conn_p)
switch (conn_p->getType()) { switch (conn_p->getType()) {
case CANCon::KVASER: return "KVASER"; case CANCon::KVASER: return "KVASER";
case CANCon::SOCKETCAN: return "SocketCAN"; case CANCon::SERIALBUS: return "SerialBus";
case CANCon::GVRET_SERIAL: return "GVRET"; case CANCon::GVRET_SERIAL: return "GVRET";
default: {} default: {}
} }
+70 -37
View File
@@ -44,16 +44,13 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
/* load connection configuration */ /* load connection configuration */
loadConnections(); loadConnections();
ui->rbSocketCAN->setEnabled(isSocketCanAvailable()); ui->rbSocketCAN->setEnabled(isSerialBusAvailable());
#ifdef Q_OS_WIN
ui->rbKvaser->setEnabled(true);
#endif
connect(ui->btnOK, &QAbstractButton::clicked, this, &ConnectionWindow::handleOKButton); connect(ui->btnOK, &QAbstractButton::clicked, this, &ConnectionWindow::handleOKButton);
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged); 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->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
connect(ui->rbRemote, &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->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged);
connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll); connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll);
connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll); 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->btnSendHex, &QPushButton::clicked, this, &ConnectionWindow::handleSendHex);
connect(ui->btnSendText, &QPushButton::clicked, this, &ConnectionWindow::handleSendText); connect(ui->btnSendText, &QPushButton::clicked, this, &ConnectionWindow::handleSendText);
connect(ui->ckEnableConsole, &QCheckBox::toggled, this, &ConnectionWindow::consoleEnableChanged); connect(ui->ckEnableConsole, &QCheckBox::toggled, this, &ConnectionWindow::consoleEnableChanged);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
} }
ConnectionWindow::~ConnectionWindow() ConnectionWindow::~ConnectionWindow()
@@ -118,7 +118,7 @@ bool ConnectionWindow::eventFilter(QObject *obj, QEvent *event)
// standard event processing // standard event processing
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);
} }
return false; //return false;
} }
void ConnectionWindow::readSettings() void ConnectionWindow::readSettings()
@@ -200,7 +200,7 @@ void ConnectionWindow::consoleEnableChanged(bool checked) {
connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray)));
} }
else { //turn it off 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))); disconnect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray)));
} }
} }
@@ -226,11 +226,18 @@ void ConnectionWindow::handleDisableAll()
void ConnectionWindow::handleConnTypeChanged() void ConnectionWindow::handleConnTypeChanged()
{ {
if (ui->rbGVRET->isChecked()) selectSerial(); if (ui->rbGVRET->isChecked()) selectSerial();
if (ui->rbKvaser->isChecked()) selectKvaser();
if (ui->rbSocketCAN->isChecked()) selectSocketCan(); if (ui->rbSocketCAN->isChecked()) selectSocketCan();
if (ui->rbRemote->isChecked()) selectRemote(); 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 */ /* status */
void ConnectionWindow::connectionStatus(CANConStatus pStatus) void ConnectionWindow::connectionStatus(CANConStatus pStatus)
@@ -244,12 +251,12 @@ void ConnectionWindow::connectionStatus(CANConStatus pStatus)
void ConnectionWindow::handleOKButton() void ConnectionWindow::handleOKButton()
{ {
CANConnection* conn_p = NULL; CANConnection* conn_p = nullptr;
if( ! CANConManager::getInstance()->getByName(getPortName()) ) if( ! CANConManager::getInstance()->getByName(getPortName()) )
{ {
/* create connection */ /* create connection */
conn_p = create(getConnectionType(), getPortName()); conn_p = create(getConnectionType(), getPortName(), getDriverName());
if(!conn_p) if(!conn_p)
return; return;
/* add connection to model */ /* add connection to model */
@@ -281,7 +288,7 @@ return;
ui->btnOK->setText(tr("Create New Connection")); ui->btnOK->setText(tr("Create New Connection"));
ui->rbGVRET->setChecked(true); ui->rbGVRET->setChecked(true);
setSpeed(0); setSpeed(0);
setPortName(CANCon::GVRET_SERIAL, ""); setPortName(CANCon::GVRET_SERIAL, "", "");
} }
else else
{ {
@@ -300,7 +307,7 @@ return;
ui->btnOK->setText(tr("Update Connection Settings")); ui->btnOK->setText(tr("Update Connection Settings"));
setSpeed(bus.getSpeed()); 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:"); ui->lPort->setText("Port:");
/* set combobox page visible */ /* set combobox page visible */
ui->stPort->setCurrentWidget(ui->cbPage); ui->stPort->setCurrentWidget(ui->cbPage);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbPort->clear(); ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts(); ports = QSerialPortInfo::availablePorts();
@@ -341,41 +350,42 @@ void ConnectionWindow::selectSerial()
ui->cbPort->addItem(ports[i].portName()); 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() void ConnectionWindow::selectSocketCan()
{ {
ui->lPort->setText("Port:"); ui->lPort->setText("Port:");
/* set edit text page visible */ /* 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() void ConnectionWindow::selectRemote()
{ {
ui->lPort->setText("IP Address:"); ui->lPort->setText("IP Address:");
ui->stPort->setCurrentWidget(ui->etPage); ui->stPort->setCurrentWidget(ui->etPage);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
} }
void ConnectionWindow::setSpeed(int speed0) 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) switch(pType)
{ {
case CANCon::GVRET_SERIAL: case CANCon::GVRET_SERIAL:
ui->rbGVRET->setChecked(true); ui->rbGVRET->setChecked(true);
break; break;
case CANCon::KVASER: case CANCon::SERIALBUS:
ui->rbKvaser->setChecked(true);
break;
case CANCon::SOCKETCAN:
ui->rbSocketCAN->setChecked(true); ui->rbSocketCAN->setChecked(true);
//you can't configure any of the below three with socketcan so dim them out //you can't configure any of the below three with socketcan so dim them out
break; break;
@@ -394,7 +404,16 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
ui->cbPort->setCurrentIndex(idx); ui->cbPort->setCurrentIndex(idx);
break; 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: case CANCon::REMOTE:
{ {
ui->lePort->setText(pPortName); ui->lePort->setText(pPortName);
@@ -415,9 +434,8 @@ QString ConnectionWindow::getPortName()
{ {
switch( getConnectionType() ) { switch( getConnectionType() ) {
case CANCon::GVRET_SERIAL: case CANCon::GVRET_SERIAL:
case CANCon::KVASER: case CANCon::SERIALBUS:
return ui->cbPort->currentText(); return ui->cbPort->currentText();
case CANCon::SOCKETCAN:
case CANCon::REMOTE: case CANCon::REMOTE:
return ui->lePort->text(); return ui->lePort->text();
default: default:
@@ -427,11 +445,20 @@ QString ConnectionWindow::getPortName()
return ""; return "";
} }
QString ConnectionWindow::getDriverName()
{
if (getConnectionType() == CANCon::SERIALBUS)
{
return ui->cbDeviceType->currentText();
}
return "";
}
CANCon::type ConnectionWindow::getConnectionType() CANCon::type ConnectionWindow::getConnectionType()
{ {
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL; if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
if (ui->rbKvaser->isChecked()) return CANCon::KVASER; if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS;
if (ui->rbSocketCAN->isChecked()) return CANCon::SOCKETCAN;
if (ui->rbRemote->isChecked()) return CANCon::REMOTE; if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
qDebug() << "getConnectionType: error"; qDebug() << "getConnectionType: error";
return CANCon::NONE; return CANCon::NONE;
@@ -440,6 +467,7 @@ CANCon::type ConnectionWindow::getConnectionType()
void ConnectionWindow::setSWMode(bool mode) void ConnectionWindow::setSWMode(bool mode)
{ {
Q_UNUSED(mode);
} }
bool ConnectionWindow::getSWMode() bool ConnectionWindow::getSWMode()
@@ -475,21 +503,19 @@ void ConnectionWindow::handleRevert()
} }
bool ConnectionWindow::isSocketCanAvailable() bool ConnectionWindow::isSerialBusAvailable()
{ {
#ifdef Q_OS_LINUX if (QCanBus::instance()->plugins().count() > 0) return true;
if (QCanBus::instance()->plugins().contains(QStringLiteral("socketcan"))) return true;
#endif
return false; return false;
} }
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName) CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver)
{ {
CANConnection* conn_p; CANConnection* conn_p;
/* create connection */ /* create connection */
conn_p = CanConFactory::create(pTye, pPortName); conn_p = CanConFactory::create(pTye, pPortName, pDriver);
if(conn_p) if(conn_p)
{ {
/* connect signal */ /* connect signal */
@@ -512,11 +538,15 @@ void ConnectionWindow::loadConnections()
/* fill connection list */ /* fill connection list */
QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>(); 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>>(); QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>();
//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++) 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 */ /* add connection to model */
connModel->add(conn_p); connModel->add(conn_p);
} }
@@ -533,14 +563,17 @@ void ConnectionWindow::saveConnections()
QSettings settings; QSettings settings;
QVector<QString> portNames; QVector<QString> portNames;
QVector<int> devTypes; QVector<int> devTypes;
QVector<QString> driverNames;
/* save connections */ /* save connections */
foreach(CANConnection* conn_p, conns) foreach(CANConnection* conn_p, conns)
{ {
portNames.append(conn_p->getPort()); portNames.append(conn_p->getPort());
devTypes.append(conn_p->getType()); devTypes.append(conn_p->getType());
driverNames.append(conn_p->getDriver());
} }
settings.setValue("connections/portNames", QVariant::fromValue(portNames)); settings.setValue("connections/portNames", QVariant::fromValue(portNames));
settings.setValue("connections/types", QVariant::fromValue(devTypes)); 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 <QSettings>
#include <QTimer> #include <QTimer>
#include <QItemSelection> #include <QItemSelection>
#include <QCanBusDeviceInfo>
#include "canconnectionmodel.h" #include "canconnectionmodel.h"
#include "connections/canconnection.h" #include "connections/canconnection.h"
@@ -47,6 +48,7 @@ public slots:
private slots: private slots:
void handleOKButton(); void handleOKButton();
void handleConnTypeChanged(); void handleConnTypeChanged();
void handleDeviceTypeChanged();
void currentRowChanged(const QModelIndex &current, const QModelIndex &previous); void currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void consoleEnableChanged(bool checked); void consoleEnableChanged(bool checked);
void handleRemoveConn(); void handleRemoveConn();
@@ -63,6 +65,7 @@ private slots:
private: private:
Ui::ConnectionWindow *ui; Ui::ConnectionWindow *ui;
QList<QSerialPortInfo> ports; QList<QSerialPortInfo> ports;
QList<QCanBusDeviceInfo> canDevices;
QSettings *settings; QSettings *settings;
CANConnectionModel *connModel; CANConnectionModel *connModel;
@@ -70,13 +73,14 @@ private:
void selectKvaser(); void selectKvaser();
void selectSocketCan(); void selectSocketCan();
void selectRemote(); void selectRemote();
bool isSocketCanAvailable(); bool isSerialBusAvailable();
int getSpeed(); int getSpeed();
QString getPortName(); QString getPortName();
void setPortName(CANCon::type pType, QString pPortName); QString getDriverName();
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
void setActiveAll(bool pActive); void setActiveAll(bool pActive);
CANConnection* create(CANCon::type pTye, QString pPortName); CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver);
void loadConnections(); void loadConnections();
void saveConnections(); void saveConnections();
void showEvent(QShowEvent *); void showEvent(QShowEvent *);
+136 -66
View File
@@ -9,19 +9,20 @@
#include "gvretserial.h" #include "gvretserial.h"
GVRetSerial::GVRetSerial(QString portName, bool useTcp) : 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), useTcp(useTcp),
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */ mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{ {
qDebug() << "GVRetSerial()"; sendDebug("GVRetSerial()");
debugOutput("GVRetSerial()");
serial = NULL; serial = NULL;
tcpClient = NULL; tcpClient = NULL;
udpClient = NULL;
rx_state = IDLE; rx_state = IDLE;
rx_step = 0; rx_step = 0;
gotValidated = true; validationCounter = 10; //how many times we can miss validation before we die
isAutoRestart = false; isAutoRestart = false;
espSerialMode = true;
timeBasis = 0; timeBasis = 0;
lastSystemTimeBasis = 0; lastSystemTimeBasis = 0;
@@ -34,27 +35,38 @@ GVRetSerial::GVRetSerial(QString portName, bool useTcp) :
GVRetSerial::~GVRetSerial() GVRetSerial::~GVRetSerial()
{ {
stop(); stop();
qDebug() << "~GVRetSerial()"; sendDebug("~GVRetSerial()");
debugOutput("~GVRetSerial()"); }
void GVRetSerial::sendDebug(const QString debugText)
{
qDebug() << debugText;
debugOutput(debugText);
} }
void GVRetSerial::sendToSerial(const QByteArray &bytes) 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; return;
} }
if (serial && !serial->isOpen()) 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; return;
} }
if (tcpClient && !tcpClient->isOpen()) 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; return;
} }
@@ -64,10 +76,11 @@ void GVRetSerial::sendToSerial(const QByteArray &bytes)
byt = (unsigned char)byt; byt = (unsigned char)byt;
buildDebug = buildDebug % QString::number(byt, 16) % " "; buildDebug = buildDebug % QString::number(byt, 16) % " ";
} }
debugOutput(buildDebug); sendDebug(buildDebug);
if (serial) serial->write(bytes); if (serial) serial->write(bytes);
if (tcpClient) tcpClient->write(bytes); if (tcpClient) tcpClient->write(bytes);
if (udpClient) udpClient->write(bytes);
} }
void GVRetSerial::piStarted() void GVRetSerial::piStarted()
@@ -176,8 +189,7 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
if (pBusIdx < 2) { if (pBusIdx < 2) {
/* update baud rates */ /* update baud rates */
QByteArray buffer; QByteArray buffer;
qDebug() << "Got signal to update bauds. 1: " << (can0Baud & 0xFFFFFFF) <<" 2: " << (can1Baud & 0xFFFFFFF); sendDebug("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
debugOutput("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[0] = (char)0xF1; //start of a command over serial
buffer[1] = 5; //setup canbus buffer[1] = 5; //setup canbus
buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first 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 */ /* update baud rates */
QByteArray buffer; QByteArray buffer;
qDebug() << "Got signal to update extended bus speeds SWCAN: " << swcanBaud <<" LIN1: " << lin1Baud << " LIN2: " << lin2Baud; sendDebug("Got signal to update extended bus speeds SWCAN: " + QString::number(swcanBaud) + " LIN1: " + QString::number(lin1Baud) + " LIN2: " + QString::number(lin2Baud));
debugOutput("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[0] = (char)0xF1; //start of a command over serial
buffer[1] = 14; //setup extended buses buffer[1] = 14; //setup extended buses
buffer[2] = (unsigned char)(swcanBaud & 0xFF); //four bytes of ID LSB first buffer[2] = (unsigned char)(swcanBaud & 0xFF); //four bytes of ID LSB first
@@ -227,8 +238,10 @@ bool GVRetSerial::piSendFrame(const CANFrame& frame)
framesRapid++; framesRapid++;
if (serial == NULL) return false; if (serial == NULL && tcpClient == NULL && udpClient == NULL) return false;
if (!serial->isOpen()) return false; if (serial && !serial->isOpen()) return false;
if (tcpClient && !tcpClient->isOpen()) return false;
if (udpClient && !udpClient->isOpen()) return false;
//if (!isConnected) return false; //if (!isConnected) return false;
// Doesn't make sense to send an error frame // Doesn't make sense to send an error frame
@@ -283,55 +296,84 @@ void GVRetSerial::connectDevice()
disconnectDevice(); disconnectDevice();
if(tcpClient) if(tcpClient)
disconnectDevice(); disconnectDevice();
if (udpClient)
disconnectDevice();
/* open new device */ /* 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) if (useTcp)
{ {
qDebug() << "TCP Connection to a GVRET device"; // /*
sendDebug("TCP Connection to a GVRET device");
tcpClient = new QTcpSocket(); tcpClient = new QTcpSocket();
tcpClient->connectToHost(getPort(), 23); tcpClient->connectToHost(getPort(), 23);
connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readSerialData())); 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 { else {
qDebug() << "Serial connection to a GVRET device"; sendDebug("Serial connection to a GVRET device");
serial = new QSerialPort(QSerialPortInfo(getPort())); serial = new QSerialPort(QSerialPortInfo(getPort()));
if(!serial) { if(!serial) {
qDebug() << "can't open serial port " << getPort(); sendDebug("can't open serial port " + getPort());
debugOutput("can't open serial port " + getPort());
return; 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 reading event */
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData())); connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialError(QSerialPort::SerialPortError))); 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);
void GVRetSerial::tcpConnected() if (espSerialMode)
{ {
qDebug() << "Connected to GVRET Device!"; 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::deviceConnected()
{
sendDebug("Connecting to GVRET Device!");
QByteArray output; QByteArray output;
output.append((unsigned char)0xE7); //this puts the device into binary comm mode output.append((unsigned char)0xE7); //this puts the device into binary comm mode
output.append((unsigned char)0xE7); output.append((unsigned char)0xE7);
@@ -367,14 +409,8 @@ void GVRetSerial::tcpConnected()
sendToSerial(output); 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) { if(doValidation) {
QTimer::singleShot(1000, this, SLOT(connectionTimeout())); QTimer::singleShot(5000, this, SLOT(connectionTimeout()));
} }
else { else {
setStatus(CANCon::CONNECTED); setStatus(CANCon::CONNECTED);
@@ -390,7 +426,7 @@ void GVRetSerial::disconnectDevice() {
{ {
if (serial->isOpen()) if (serial->isOpen())
{ {
serial->clear(); //serial->clear();
serial->close(); serial->close();
} }
@@ -408,6 +444,17 @@ void GVRetSerial::disconnectDevice() {
delete tcpClient; delete tcpClient;
tcpClient = NULL; tcpClient = NULL;
} }
if (udpClient != NULL)
{
if (udpClient->isOpen())
{
udpClient->close();
}
udpClient->disconnect();
delete udpClient;
udpClient = NULL;
}
setStatus(CANCon::NOT_CONNECTED); setStatus(CANCon::NOT_CONNECTED);
CANConStatus stats; CANConStatus stats;
stats.conStatus = getStatus(); stats.conStatus = getStatus();
@@ -426,14 +473,17 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
case QSerialPort::DeviceNotFoundError: case QSerialPort::DeviceNotFoundError:
errMessage = "Device not found error on serial"; errMessage = "Device not found error on serial";
killConnection = true; killConnection = true;
piStop();
break; break;
case QSerialPort::PermissionError: case QSerialPort::PermissionError:
errMessage = "Permission error on serial port"; errMessage = "Permission error on serial port";
killConnection = true; killConnection = true;
piStop();
break; break;
case QSerialPort::OpenError: case QSerialPort::OpenError:
errMessage = "Open error on serial port"; errMessage = "Open error on serial port";
killConnection = true; killConnection = true;
piStop();
break; break;
case QSerialPort::ParityError: case QSerialPort::ParityError:
errMessage = "Parity error on serial port"; errMessage = "Parity error on serial port";
@@ -446,13 +496,16 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
break; break;
case QSerialPort::WriteError: case QSerialPort::WriteError:
errMessage = "Write error on serial port"; errMessage = "Write error on serial port";
piStop();
break; break;
case QSerialPort::ReadError: case QSerialPort::ReadError:
errMessage = "Read error on serial port"; errMessage = "Read error on serial port";
piStop();
break; break;
case QSerialPort::ResourceError: case QSerialPort::ResourceError:
errMessage = "Serial port seems to have disappeared."; errMessage = "Serial port seems to have disappeared.";
killConnection = true; killConnection = true;
piStop();
break; break;
case QSerialPort::UnsupportedOperationError: case QSerialPort::UnsupportedOperationError:
errMessage = "Unsupported operation on serial port"; errMessage = "Unsupported operation on serial port";
@@ -461,23 +514,28 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
case QSerialPort::UnknownError: case QSerialPort::UnknownError:
errMessage = "Beats me what happened to the serial port."; errMessage = "Beats me what happened to the serial port.";
killConnection = true; killConnection = true;
piStop();
break; break;
case QSerialPort::TimeoutError: case QSerialPort::TimeoutError:
errMessage = "Timeout error on serial port"; errMessage = "Timeout error on serial port";
killConnection = true; killConnection = true;
break; break;
case QSerialPort::NotOpenError: case QSerialPort::NotOpenError:
errMessage = "The serial port isn't open dummy"; errMessage = "The serial port isn't open";
killConnection = true; killConnection = true;
piStop();
break; break;
} }
/*
if (serial)
{
serial->clearError(); serial->clearError();
serial->flush(); serial->flush();
serial->close(); serial->close();
}*/
if (errMessage.length() > 1) if (errMessage.length() > 1)
{ {
qDebug() << errMessage; sendDebug(errMessage);
debugOutput(errMessage);
} }
if (killConnection) if (killConnection)
{ {
@@ -490,13 +548,23 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
void GVRetSerial::connectionTimeout() void GVRetSerial::connectionTimeout()
{ {
//one second after trying to connect are we actually connected? //one second after trying to connect are we actually connected?
//if (CANCon::NOT_CONNECTED==getStatus()) //no? if (CANCon::NOT_CONNECTED==getStatus()) //no?
if (!gotValidated)
{ {
//then emit the the failure signal and see if anyone cares //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(); 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 (serial) data = serial->readAll();
if (tcpClient) data = tcpClient->readAll(); if (tcpClient) data = tcpClient->readAll();
if (udpClient) data = udpClient->readAll();
debugOutput("Got data from serial. Len = " % QString::number(data.length())); sendDebug("Got data from serial. Len = " % QString::number(data.length()));
//qDebug() << (tr("Got data from serial. Len = %0").arg(data.length()));
for (int i = 0; i < data.length(); i++) for (int i = 0; i < data.length(); i++)
{ {
c = data.at(i); c = data.at(i);
@@ -571,7 +639,7 @@ void GVRetSerial::procRXChar(unsigned char c)
rx_step = 0; rx_step = 0;
break; break;
case 9: case 9:
gotValidated = true; validationCounter = 10;
//qDebug() << "Got validated"; //qDebug() << "Got validated";
rx_state = IDLE; rx_state = IDLE;
break; break;
@@ -932,12 +1000,14 @@ void GVRetSerial::handleTick()
if( CANCon::CONNECTED == getStatus() ) if( CANCon::CONNECTED == getStatus() )
{ {
if (!gotValidated && doValidation) if (doValidation) validationCounter--;
//qDebug() << validationCounter;
if (validationCounter == 0 && doValidation)
{ {
if (serial == NULL && tcpClient == NULL) return; 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); setStatus(CANCon::NOT_CONNECTED);
//emit status(getStatus()); //emit status(getStatus());
@@ -952,6 +1022,7 @@ void GVRetSerial::handleTick()
} }
if (doValidation && serial && serial->isOpen()) sendCommValidation(); if (doValidation && serial && serial->isOpen()) sendCommValidation();
if (doValidation && tcpClient && tcpClient->isOpen()) sendCommValidation(); if (doValidation && tcpClient && tcpClient->isOpen()) sendCommValidation();
if (doValidation && udpClient && udpClient->isOpen()) sendCommValidation();
} }
@@ -959,7 +1030,6 @@ void GVRetSerial::sendCommValidation()
{ {
QByteArray output; QByteArray output;
gotValidated = false;
output.append((unsigned char)0xF1); //another command to the GVRET output.append((unsigned char)0xF1); //another command to the GVRET
output.append((unsigned char)0x09); //request a reply to get validation output.append((unsigned char)0x09); //request a reply to get validation
+6 -2
View File
@@ -6,6 +6,7 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include <QTcpSocket> #include <QTcpSocket>
#include <QUdpSocket>
/*************/ /*************/
#include <QDateTime> #include <QDateTime>
@@ -64,7 +65,7 @@ private slots:
void connectionTimeout(); void connectionTimeout();
void readSerialData(); void readSerialData();
void serialError(QSerialPort::SerialPortError err); void serialError(QSerialPort::SerialPortError err);
void tcpConnected(); void deviceConnected();
void handleTick(); void handleTick();
private: private:
@@ -73,18 +74,21 @@ private:
void sendCommValidation(); void sendCommValidation();
void rebuildLocalTimeBasis(); void rebuildLocalTimeBasis();
void sendToSerial(const QByteArray &bytes); void sendToSerial(const QByteArray &bytes);
void sendDebug(const QString debugText);
protected: protected:
QTimer mTimer; QTimer mTimer;
QThread mThread; QThread mThread;
bool doValidation; bool doValidation;
bool gotValidated; int validationCounter;
bool isAutoRestart; bool isAutoRestart;
bool continuousTimeSync; bool continuousTimeSync;
bool useTcp; bool useTcp;
bool espSerialMode; //special serial mode for ESP32 based boards - no flow control and much slower serial baud speed
QSerialPort *serial; QSerialPort *serial;
QTcpSocket *tcpClient; QTcpSocket *tcpClient;
QUdpSocket *udpClient;
int framesRapid; int framesRapid;
STATE rx_state; STATE rx_state;
uint32_t rx_step; uint32_t rx_step;
+27 -30
View File
@@ -11,8 +11,8 @@
/**** class definition ****/ /**** class definition ****/
/***********************************/ /***********************************/
SerialBusConnection::SerialBusConnection(QString portName) : SerialBusConnection::SerialBusConnection(QString portName, QString driverName) :
CANConnection(portName, CANCon::SOCKETCAN, 1, 4000, true), CANConnection(portName, driverName, CANCon::SERIALBUS, 1, 4000, true),
mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */ mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */
{ {
} }
@@ -26,6 +26,22 @@ SerialBusConnection::~SerialBusConnection()
void SerialBusConnection::piStarted() 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())); connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection()));
mTimer.setInterval(1000); mTimer.setInterval(1000);
mTimer.setSingleShot(false); //keep ticking mTimer.setSingleShot(false); //keep ticking
@@ -47,6 +63,7 @@ void SerialBusConnection::piSuspend(bool pSuspend)
void SerialBusConnection::piStop() { void SerialBusConnection::piStop() {
qDebug() << "piStop()";
mTimer.stop(); mTimer.stop();
disconnectDevice(); disconnectDevice();
} }
@@ -65,6 +82,8 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
if(0 != pBusIdx) if(0 != pBusIdx)
return; return;
if (!mDev_p) return;
/* disconnect device if we have one connected */ /* disconnect device if we have one connected */
disconnectDevice(); disconnectDevice();
@@ -75,20 +94,6 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
if(!bus.active) if(!bus.active)
return; 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 */ /* set configuration */
/*if (p.useConfigurationEnabled) { /*if (p.useConfigurationEnabled) {
foreach (const SettingsDialog::ConfigurationItem &item, p.configurations) 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. //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 */ /* connect device */
if (!mDev_p->connectDevice()) { if (!mDev_p->connectDevice()) {
@@ -115,8 +121,8 @@ bool SerialBusConnection::piSendFrame(const CANFrame& pFrame)
/* fill frame */ /* fill frame */
QCanBusFrame frame; QCanBusFrame frame;
frame.setFrameId(pFrame.ID);
frame.setExtendedFrameFormat(pFrame.extended); frame.setExtendedFrameFormat(pFrame.extended);
frame.setFrameId(pFrame.ID);
if (pFrame.remote) { if (pFrame.remote) {
frame.setFrameType(QCanBusFrame::FrameType::RemoteRequestFrame); frame.setFrameType(QCanBusFrame::FrameType::RemoteRequestFrame);
} else { } else {
@@ -137,8 +143,6 @@ bool SerialBusConnection::piSendFrame(const CANFrame& pFrame)
void SerialBusConnection::disconnectDevice() { void SerialBusConnection::disconnectDevice() {
if(mDev_p) { if(mDev_p) {
mDev_p->disconnectDevice(); mDev_p->disconnectDevice();
delete mDev_p;
mDev_p = nullptr;
} }
} }
@@ -255,13 +259,12 @@ void SerialBusConnection::framesReceived()
void SerialBusConnection::testConnection() { void SerialBusConnection::testConnection() {
QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort());
CANConStatus stats; CANConStatus stats;
switch(getStatus()) switch(getStatus())
{ {
case CANCon::CONNECTED: case CANCon::CONNECTED:
if (!dev_p || !dev_p->connectDevice()) { if (!mDev_p || mDev_p->state() == QCanBusDevice::UnconnectedState) {
/* we have lost connectivity */ /* we have lost connectivity */
disconnectDevice(); disconnectDevice();
@@ -269,11 +272,11 @@ void SerialBusConnection::testConnection() {
stats.conStatus = getStatus(); stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses; stats.numHardwareBuses = mNumBuses;
emit status(stats); emit status(stats);
piStop();
} }
break; break;
case CANCon::NOT_CONNECTED: case CANCon::NOT_CONNECTED:
if (dev_p && dev_p->connectDevice()) { if (mDev_p && mDev_p->state() == QCanBusDevice::UnconnectedState) {
if(!mDev_p) {
/* try to reconnect */ /* try to reconnect */
CANBus bus; CANBus bus;
if(getBusConfig(0, bus)) if(getBusConfig(0, bus))
@@ -281,9 +284,6 @@ void SerialBusConnection::testConnection() {
bus.setEnabled(true); bus.setEnabled(true);
setBusSettings(0, bus); setBusSettings(0, bus);
} }
}
/* disconnect test instance */
dev_p->disconnectDevice();
setStatus(CANCon::CONNECTED); setStatus(CANCon::CONNECTED);
stats.conStatus = getStatus(); stats.conStatus = getStatus();
@@ -293,7 +293,4 @@ void SerialBusConnection::testConnection() {
break; break;
default: {} default: {}
} }
if(dev_p)
delete dev_p;
} }
+1 -1
View File
@@ -12,7 +12,7 @@ class SerialBusConnection : public CANConnection
Q_OBJECT Q_OBJECT
public: public:
SerialBusConnection(QString portName); SerialBusConnection(QString portName, QString driverName);
virtual ~SerialBusConnection(); virtual ~SerialBusConnection();
protected: protected:
+70 -43
View File
@@ -8,21 +8,22 @@
#include <QApplication> #include <QApplication>
#include <QPalette> #include <QPalette>
#include "utility.h" #include "utility.h"
#include "connections/canconmanager.h"
DBCHandler* DBCHandler::instance = NULL; DBCHandler* DBCHandler::instance = nullptr;
DBC_SIGNAL* DBCSignalHandler::findSignalByIdx(int idx) DBC_SIGNAL* DBCSignalHandler::findSignalByIdx(int idx)
{ {
if (sigs.count() == 0) return NULL; if (sigs.count() == 0) return nullptr;
if (idx < 0) return NULL; if (idx < 0) return nullptr;
if (idx >= sigs.count()) return NULL; if (idx >= sigs.count()) return nullptr;
return &sigs[idx]; return &sigs[idx];
} }
DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name) 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++) for (int i = 0; i < sigs.count(); i++)
{ {
if (sigs[i].name.compare(name, Qt::CaseInsensitive) == 0) if (sigs[i].name.compare(name, Qt::CaseInsensitive) == 0)
@@ -30,7 +31,7 @@ DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name)
return &sigs[i]; return &sigs[i];
} }
} }
return NULL; return nullptr;
} }
bool DBCSignalHandler::addSignal(DBC_SIGNAL &sig) bool DBCSignalHandler::addSignal(DBC_SIGNAL &sig)
@@ -82,7 +83,7 @@ int DBCSignalHandler::getCount()
DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id) 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++) for (int i = 0; i < messages.count(); i++)
{ {
if (isJ1939Handler) if (isJ1939Handler)
@@ -115,20 +116,20 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id)
} }
} }
} }
return NULL; return nullptr;
} }
DBC_MESSAGE* DBCMessageHandler::findMsgByIdx(int idx) DBC_MESSAGE* DBCMessageHandler::findMsgByIdx(int idx)
{ {
if (messages.count() == 0) return NULL; if (messages.count() == 0) return nullptr;
if (idx < 0) return NULL; if (idx < 0) return nullptr;
if (idx >= messages.count()) return NULL; if (idx >= messages.count()) return nullptr;
return &messages[idx]; return &messages[idx];
} }
DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name) 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++) for (int i = 0; i < messages.count(); i++)
{ {
if (messages[i].name.compare(name, Qt::CaseInsensitive) == 0) if (messages[i].name.compare(name, Qt::CaseInsensitive) == 0)
@@ -136,7 +137,7 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name)
return &messages[i]; return &messages[i];
} }
} }
return NULL; return nullptr;
} }
bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg) bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg)
@@ -251,14 +252,14 @@ DBCFile& DBCFile::operator=(const DBCFile& cpy)
DBC_NODE* DBCFile::findNodeByIdx(int idx) DBC_NODE* DBCFile::findNodeByIdx(int idx)
{ {
if (idx < 0) return NULL; if (idx < 0) return nullptr;
if (idx >= dbc_nodes.count()) return NULL; if (idx >= dbc_nodes.count()) return nullptr;
return &dbc_nodes[idx]; return &dbc_nodes[idx];
} }
DBC_NODE* DBCFile::findNodeByName(QString name) 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++) for (int i = 0; i < dbc_nodes.length(); i++)
{ {
if (dbc_nodes[i].name.compare(name, Qt::CaseInsensitive) == 0) 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 &dbc_nodes[i];
} }
} }
return NULL; return nullptr;
} }
QString DBCFile::getFullFilename() QString DBCFile::getFullFilename()
@@ -291,14 +292,15 @@ int DBCFile::getAssocBus()
void DBCFile::setAssocBus(int bus) void DBCFile::setAssocBus(int bus)
{ {
int numBuses = CANConManager::getInstance()->getNumBuses();
if (bus < -1) return; if (bus < -1) return;
if (bus > 1) return; if (bus >= numBuses) return;
assocBuses = bus; assocBuses = bus;
} }
DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name) 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++) for (int i = 0; i < dbc_attributes.length(); i++)
{ {
if (dbc_attributes[i].name.compare(name, Qt::CaseInsensitive) == 0) 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 &dbc_attributes[i];
} }
} }
return NULL; return nullptr;
} }
DBC_ATTRIBUTE *DBCFile::findAttributeByIdx(int idx) DBC_ATTRIBUTE *DBCFile::findAttributeByIdx(int idx)
{ {
if (idx < 0) return NULL; if (idx < 0) return nullptr;
if (idx >= dbc_attributes.count()) return NULL; if (idx >= dbc_attributes.count()) return nullptr;
return &dbc_attributes[idx]; return &dbc_attributes[idx];
} }
@@ -345,8 +347,9 @@ DBC_MESSAGE* DBCFile::parseMessageLine(QString line)
DBC_MESSAGE msg; DBC_MESSAGE msg;
msg.ID = match.captured(1).toULong() & 0x7FFFFFFFul; //the ID is always stored in decimal format msg.ID = match.captured(1).toULong() & 0x7FFFFFFFul; //the ID is always stored in decimal format
msg.name = match.captured(2); msg.name = match.captured(2);
msg.len = match.captured(3).toInt(); msg.len = match.captured(3).toUInt();
msg.sender = findNodeByName(match.captured(4)); msg.sender = findNodeByName(match.captured(4));
if (!msg.sender) msg.sender = findNodeByIdx(0);
messageHandler->addMessage(msg); messageHandler->addMessage(msg);
msgPtr = messageHandler->findMsgByID(msg.ID); msgPtr = messageHandler->findMsgByID(msg.ID);
} }
@@ -453,6 +456,9 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg)
sig.receiver = findNodeByName(tmp); sig.receiver = findNodeByName(tmp);
} }
else sig.receiver = findNodeByName(match.captured(11 + offset)); 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; sig.parentMessage = msg;
msg->sigHandler->addSignal(sig); msg->sigHandler->addSignal(sig);
if (isMultiplexor) msg->multiplexorSignal = msg->sigHandler->findSignalByName(sig.name); if (isMultiplexor) msg->multiplexorSignal = msg->sigHandler->findSignalByName(sig.name);
@@ -476,11 +482,11 @@ bool DBCFile::parseValueLine(QString line)
if (match.hasMatch()) if (match.hasMatch())
{ {
//qDebug() << "Data was: " << match.captured(3); //qDebug() << "Data was: " << match.captured(3);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt()); DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
if (msg != NULL) if (msg != nullptr)
{ {
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2)); DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
if (sig != NULL) if (sig != nullptr)
{ {
QString tokenString = match.captured(3); QString tokenString = match.captured(3);
DBC_VAL_ENUM_ENTRY val; DBC_VAL_ENUM_ENTRY val;
@@ -525,7 +531,7 @@ bool DBCFile::parseAttributeLine(QString line)
if (foundAttr) if (foundAttr)
{ {
qDebug() << "That attribute does exist"; 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) if (foundMsg)
{ {
qDebug() << "It references a valid, registered message"; qDebug() << "It references a valid, registered message";
@@ -557,7 +563,7 @@ bool DBCFile::parseAttributeLine(QString line)
if (foundAttr) if (foundAttr)
{ {
qDebug() << "That attribute does exist"; 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) if (foundMsg)
{ {
qDebug() << "It references a valid, registered message"; qDebug() << "It references a valid, registered message";
@@ -662,7 +668,7 @@ void DBCFile::loadFile(QString fileName)
QString line, rawLine; QString line, rawLine;
QRegularExpression regex; QRegularExpression regex;
QRegularExpressionMatch match; QRegularExpressionMatch match;
DBC_MESSAGE *currentMessage = NULL; DBC_MESSAGE *currentMessage = nullptr;
DBC_ATTRIBUTE attr; DBC_ATTRIBUTE attr;
int numSigFaults = 0, numMsgFaults = 0; int numSigFaults = 0, numMsgFaults = 0;
@@ -746,11 +752,11 @@ void DBCFile::loadFile(QString fileName)
if (match.hasMatch()) if (match.hasMatch())
{ {
//qDebug() << "Comment was: " << match.captured(3); //qDebug() << "Comment was: " << match.captured(3);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt()); DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
if (msg != NULL) if (msg != nullptr)
{ {
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2)); DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
if (sig != NULL) if (sig != nullptr)
{ {
sig->comment = match.captured(3); sig->comment = match.captured(3);
} }
@@ -767,8 +773,8 @@ void DBCFile::loadFile(QString fileName)
if (match.hasMatch()) if (match.hasMatch())
{ {
//qDebug() << "Comment was: " << match.captured(2); //qDebug() << "Comment was: " << match.captured(2);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt()); DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
if (msg != NULL) if (msg != nullptr)
{ {
msg->comment = match.captured(2); msg->comment = match.captured(2);
} }
@@ -785,7 +791,7 @@ void DBCFile::loadFile(QString fileName)
{ {
//qDebug() << "Comment was: " << match.captured(2); //qDebug() << "Comment was: " << match.captured(2);
DBC_NODE *node = findNodeByName(match.captured(1)); DBC_NODE *node = findNodeByName(match.captured(1));
if (node != NULL) if (node != nullptr)
{ {
node->comment = match.captured(2); node->comment = match.captured(2);
} }
@@ -1036,6 +1042,9 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr)
void DBCFile::saveFile(QString fileName) void DBCFile::saveFile(QString fileName)
{ {
int nodeNumber = 1;
int msgNumber = 1;
int sigNumber = 1;
QFile *outFile = new QFile(fileName); QFile *outFile = new QFile(fileName);
QString nodesOutput, msgOutput, commentsOutput, valuesOutput; QString nodesOutput, msgOutput, commentsOutput, valuesOutput;
QString defaultsOutput, attrValOutput; QString defaultsOutput, attrValOutput;
@@ -1089,6 +1098,11 @@ void DBCFile::saveFile(QString fileName)
DBC_NODE node = dbc_nodes[x]; DBC_NODE node = dbc_nodes[x];
if (node.name.compare("Vector__XXX", Qt::CaseInsensitive) != 0) 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 + " "); nodesOutput.append(node.name + " ");
if (node.comment.length() > 0) if (node.comment.length() > 0)
{ {
@@ -1119,6 +1133,12 @@ void DBCFile::saveFile(QString fileName)
{ {
DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x); 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) + msgOutput.append("BO_ " + QString::number(msg->ID) + " " + msg->name + ": " + QString::number(msg->len) +
" " + msg->sender->name + "\n"); " " + msg->sender->name + "\n");
if (msg->comment.length() > 0) if (msg->comment.length() > 0)
@@ -1146,6 +1166,13 @@ void DBCFile::saveFile(QString fileName)
for (int s = 0; s < msg->sigHandler->getCount(); s++) for (int s = 0; s < msg->sigHandler->getCount(); s++)
{ {
DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(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); msgOutput.append(" SG_ " + sig->name);
if (sig->isMultiplexor) msgOutput.append(" M"); if (sig->isMultiplexor) msgOutput.append(" M");
@@ -1399,7 +1426,7 @@ DBCFile* DBCHandler::loadDBCFile(int idx)
return &loadedFiles.last(); return &loadedFiles.last();
} }
return NULL; return nullptr;
} }
void DBCHandler::removeDBCFile(int idx) 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()) if (loadedFiles[i].getAssocBus() == -1 || frame.bus == (unsigned int)loadedFiles[i].getAssocBus())
{ {
DBC_MESSAGE* msg = loadedFiles[i].messageHandler->findMsgByID(frame.ID); 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() int DBCHandler::getFileCount()
@@ -1452,15 +1479,15 @@ int DBCHandler::getFileCount()
DBCFile* DBCHandler::getFileByIdx(int idx) DBCFile* DBCHandler::getFileByIdx(int idx)
{ {
if (loadedFiles.count() == 0) return NULL; if (loadedFiles.count() == 0) return nullptr;
if (idx < 0) return NULL; if (idx < 0) return nullptr;
if (idx >= loadedFiles.count()) return NULL; if (idx >= loadedFiles.count()) return nullptr;
return &loadedFiles[idx]; return &loadedFiles[idx];
} }
DBCFile* DBCHandler::getFileByName(QString name) 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++) for (int i = 0; i < loadedFiles.count(); i++)
{ {
if (loadedFiles[i].getFilename().compare(name, Qt::CaseInsensitive) == 0) if (loadedFiles[i].getFilename().compare(name, Qt::CaseInsensitive) == 0)
@@ -1468,7 +1495,7 @@ DBCFile* DBCHandler::getFileByName(QString name)
return &loadedFiles[i]; return &loadedFiles[i];
} }
} }
return NULL; return nullptr;
} }
DBCHandler::DBCHandler() DBCHandler::DBCHandler()
+20 -1
View File
@@ -2,6 +2,7 @@
#include "ui_dbcloadsavewindow.h" #include "ui_dbcloadsavewindow.h"
#include <QCheckBox> #include <QCheckBox>
#include "helpwindow.h" #include "helpwindow.h"
#include "connections/canconmanager.h"
DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *parent) : DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent), QDialog(parent),
@@ -34,6 +35,7 @@ DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *p
connect(ui->tableFiles, &QTableWidget::cellDoubleClicked, this, &DBCLoadSaveWindow::cellDoubleClicked); connect(ui->tableFiles, &QTableWidget::cellDoubleClicked, this, &DBCLoadSaveWindow::cellDoubleClicked);
editorWindow = new DBCMainEditor(frames); editorWindow = new DBCMainEditor(frames);
currentlyEditingFile = nullptr;
installEventFilter(this); installEventFilter(this);
} }
@@ -108,11 +110,26 @@ void DBCLoadSaveWindow::saveFile()
void DBCLoadSaveWindow::removeFile() void DBCLoadSaveWindow::removeFile()
{ {
bool bContinue = true;
int idx = ui->tableFiles->currentRow(); int idx = ui->tableFiles->currentRow();
if (idx < 0) return; if (idx < 0) return;
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); dbcHandler->removeDBCFile(idx);
ui->tableFiles->removeRow(idx); ui->tableFiles->removeRow(idx);
} }
}
void DBCLoadSaveWindow::moveUp() void DBCLoadSaveWindow::moveUp()
{ {
@@ -146,7 +163,8 @@ void DBCLoadSaveWindow::cellChanged(int row, int col)
{ {
DBCFile *file = dbcHandler->getFileByIdx(row); DBCFile *file = dbcHandler->getFileByIdx(row);
int bus = ui->tableFiles->item(row, col)->text().toInt(); 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); file->setAssocBus(bus);
} }
@@ -185,6 +203,7 @@ void DBCLoadSaveWindow::cellChanged(int row, int col)
void DBCLoadSaveWindow::cellDoubleClicked(int row, int col) void DBCLoadSaveWindow::cellDoubleClicked(int row, int col)
{ {
Q_UNUSED(col) Q_UNUSED(col)
currentlyEditingFile = dbcHandler->getFileByIdx(row);
editorWindow->setFileIdx(row); editorWindow->setFileIdx(row);
editorWindow->show(); editorWindow->show();
} }
+1
View File
@@ -32,6 +32,7 @@ private slots:
private: private:
Ui::DBCLoadSaveWindow *ui; Ui::DBCLoadSaveWindow *ui;
DBCHandler *dbcHandler; DBCHandler *dbcHandler;
DBCFile *currentlyEditingFile;
const QVector<CANFrame> *referenceFrames; const QVector<CANFrame> *referenceFrames;
DBCMainEditor *editorWindow; DBCMainEditor *editorWindow;
+5 -1
View File
@@ -103,6 +103,7 @@ void DBCMainEditor::closeEvent(QCloseEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
writeSettings(); writeSettings();
sigEditor->close();
} }
void DBCMainEditor::readSettings() void DBCMainEditor::readSettings()
@@ -283,6 +284,9 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
newMsg.name = ""; newMsg.name = "";
newMsg.sender = node; newMsg.sender = node;
newMsg.len = 0; 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++) for (int i = 0; i < referenceFrames->length(); i++)
{ {
if ((uint) referenceFrames->at(i).ID == msgID) if ((uint) referenceFrames->at(i).ID == msgID)
@@ -547,7 +551,7 @@ void DBCMainEditor::insertBlankRow()
{ {
QTableWidgetItem *item = new QTableWidgetItem(""); QTableWidgetItem *item = new QTableWidgetItem("");
if (i == 4) item->setBackgroundColor(QApplication::palette().color(QPalette::WindowText)); //foreground color 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); item->setFlags(item->flags() & ~Qt::ItemIsEditable);
ui->MessagesTable->setItem(rowIdx, i, item); ui->MessagesTable->setItem(rowIdx, i, item);
} }
+5 -4
View File
@@ -156,7 +156,8 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
[=]() [=]()
{ {
if (currentSignal == NULL) return; 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. //need to update the list too.
ui->signalsList->currentItem()->setText(currentSignal->name); ui->signalsList->currentItem()->setText(currentSignal->name);
}); });
@@ -256,7 +257,7 @@ void DBCSignalEditor::readSettings()
QSettings settings; QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool()) 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()); move(settings.value("DBCSignalEditor/WindowPos", QPoint(100, 100)).toPoint());
} }
} }
@@ -371,8 +372,8 @@ void DBCSignalEditor::deleteCurrentSignal()
{ {
int currIdx = ui->signalsList->currentRow(); int currIdx = ui->signalsList->currentRow();
if(currIdx==ui->signalsList->count()-1) //if(currIdx==ui->signalsList->count()-1)
return; //return;
if (currIdx > -1) if (currIdx > -1)
{ {
+2 -2
View File
@@ -1,4 +1,4 @@
make qthelp make qthelp
~/Qt/5.9.1/gcc_64/bin/qcollectiongenerator build/qthelp/SavvyCAN.qhcp ~/Qt/5.12.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/assistant -collectionFile build/qthelp/SavvyCAN.qhc
+3 -3
View File
@@ -47,7 +47,7 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = u'SavvyCAN' project = u'SavvyCAN'
copyright = u'2017, EVTV' copyright = u'2018, EVTV'
author = u'Collin Kidder' author = u'Collin Kidder'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
@@ -55,9 +55,9 @@ author = u'Collin Kidder'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '181' version = '189'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '181' release = '189'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
+47 -19
View File
@@ -5,32 +5,60 @@ Connection Window
.. image:: ./images/ConnectionWindow.png .. 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. The connection window is used to add, remove, and modify connections. At the moment it is possible
At this time GVRET compatible devices are: EVTVDue, EVTV CANDue (1.3/2/2.1/2.2), Teensy 3.1-3.6, Macchina M2. 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 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. SavvyCAN is able to connect to GVRET compatible devices to capture new traffic. These
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 devices will present as serial ports on the connected PC.
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 To connect to a dongle select the proper serial port and click "Create New Connection".
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 If a valid device is found on that serial port the first statusbar section will update
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 and the currently set canbus speeds will show in the table at the left of the window.
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 These speeds can then be changed by clicking on the speed (or otherwise selecting the cell
dedicated single wire CAN buses and the relevant bus will show the checkbox. 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 SavvyCAN can also connect to a wide variety of CAN hardware through the built-in QT
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 SerialBus drivers. These drivers vary by operating system but support socketcan on LINUX
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 and Vector tools on both LINUX and Windows. When you select "QT SerialBus Devices" you will
for details on configuring such devices. 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 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 GVRET devices present as serial ports and have significant configuration options.
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" However, the ability to configure so many things and the ability to compile the firmware
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 yourself both come as a double edged sword. They present many opportunities for things
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 to go wrong. Because of this there is a debugging console present on the connection window.
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 Click a bus in the table then click "Enable Console" to cause it to start logging serial
configure things via a text console. Type ? and follow it up with some form of line ending (Cr, Lf, CrLf, any will work). 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 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: Contents:
+55 -2
View File
@@ -8,11 +8,64 @@ Sniffer Window
Using the 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 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.
+5 -2
View File
@@ -555,9 +555,9 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
thisFrame.isReceived = true; thisFrame.isReceived = true;
thisFrame.bus = 0; thisFrame.bus = 0;
if (line.at(28) == ' ') { if (line.at(28) == ' ') {
thisFrame.extended = true;
} else {
thisFrame.extended = false; thisFrame.extended = false;
} else {
thisFrame.extended = true;
} }
if (line.at(41) == 'R') { if (line.at(41) == 'R') {
@@ -657,6 +657,8 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
if (line.length() > 2) if (line.length() > 2)
{ {
QList<QByteArray> tokens = line.simplified().split(' '); QList<QByteArray> tokens = line.simplified().split(' ');
if (tokens.length() > 4)
{
thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0); thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0);
thisFrame.ID = tokens[2].toUInt(NULL, 16); thisFrame.ID = tokens[2].toUInt(NULL, 16);
thisFrame.len = tokens[5].toUInt(); thisFrame.len = tokens[5].toUInt();
@@ -676,6 +678,7 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
foundErrors = true; foundErrors = true;
} }
} }
}
frames->append(thisFrame); frames->append(thisFrame);
} }
//else foundErrors = true; //else foundErrors = true;
+13 -1
View File
@@ -12,7 +12,8 @@ FramePlaybackObject::FramePlaybackObject()
playbackActive = false; playbackActive = false;
playbackForward = true; playbackForward = true;
useOrigTiming = false; useOrigTiming = false;
whichBusSend = -1; whichBusSend = 0;
currentSeqItem = nullptr;
} }
FramePlaybackObject::~FramePlaybackObject() FramePlaybackObject::~FramePlaybackObject()
@@ -25,6 +26,12 @@ FramePlaybackObject::~FramePlaybackObject()
quint64 FramePlaybackObject::updatePosition(bool forward) quint64 FramePlaybackObject::updatePosition(bool forward)
{ {
//qDebug() << "updatePosition"; //qDebug() << "updatePosition";
if (!currentSeqItem) {
playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false;
currentPosition = 0;
return 0;
}
if (forward) if (forward)
{ {
if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going
@@ -231,6 +238,7 @@ void FramePlaybackObject::stepPlaybackForward()
playbackActive = false; playbackActive = false;
updatePosition(true); updatePosition(true);
CANConManager::getInstance()->sendFrames(sendingBuffer); CANConManager::getInstance()->sendFrames(sendingBuffer);
emit statusUpdate(currentPosition);
} }
void FramePlaybackObject::stepPlaybackBackward() void FramePlaybackObject::stepPlaybackBackward()
@@ -248,6 +256,7 @@ void FramePlaybackObject::stepPlaybackBackward()
updatePosition(false); updatePosition(false);
CANConManager::getInstance()->sendFrames(sendingBuffer); CANConManager::getInstance()->sendFrames(sendingBuffer);
emit statusUpdate(currentPosition);
} }
void FramePlaybackObject::stopPlayback() void FramePlaybackObject::stopPlayback()
@@ -262,6 +271,7 @@ void FramePlaybackObject::stopPlayback()
playbackTimer->stop(); //pushing this button halts automatic playback playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false; playbackActive = false;
currentPosition = 0; currentPosition = 0;
emit statusUpdate(currentPosition);
} }
void FramePlaybackObject::pausePlayback() void FramePlaybackObject::pausePlayback()
@@ -275,6 +285,7 @@ void FramePlaybackObject::pausePlayback()
playbackActive = false; playbackActive = false;
playbackTimer->stop(); playbackTimer->stop();
emit statusUpdate(currentPosition);
} }
void FramePlaybackObject::setSequenceObject(SequenceItem *item) void FramePlaybackObject::setSequenceObject(SequenceItem *item)
@@ -289,6 +300,7 @@ void FramePlaybackObject::setUseOriginalTiming(bool state)
void FramePlaybackObject::setSendingBus(int bus) void FramePlaybackObject::setSendingBus(int bus)
{ {
qDebug() << "Setting sending bus to " << bus;
whichBusSend = bus; whichBusSend = bus;
} }
+6 -1
View File
@@ -296,9 +296,14 @@ void FramePlaybackWindow::calculateWhichBus()
{ {
int idx = ui->comboCANBus->currentIndex(); int idx = ui->comboCANBus->currentIndex();
int maxIdx = ui->comboCANBus->count() - 1; int maxIdx = ui->comboCANBus->count() - 1;
if (maxIdx == 0) maxIdx = 2;
int out = idx; int out = idx;
qDebug() << idx << "***" << maxIdx;
if (idx == (maxIdx - 1) ) out = -1; if (idx == (maxIdx - 1) ) out = -1;
if (idx == maxIdx) out = -2; if (idx == maxIdx) out = -2;
if (idx < 0) out = 0;
playbackObject.setSendingBus(out); playbackObject.setSendingBus(out);
} }
@@ -534,6 +539,7 @@ void FramePlaybackWindow::btnReverseClick()
forward = false; forward = false;
isPlaying = true; isPlaying = true;
playbackObject.startPlaybackBackward(); playbackObject.startPlaybackBackward();
updateFrameLabel();
} }
void FramePlaybackWindow::btnStopClick() void FramePlaybackWindow::btnStopClick()
@@ -554,7 +560,6 @@ void FramePlaybackWindow::btnStopClick()
ui->tblSequence->setCurrentCell(0, 0); ui->tblSequence->setCurrentCell(0, 0);
refreshIDList(); refreshIDList();
} }
updateFrameLabel();
} }
void FramePlaybackWindow::btnPlayClick() void FramePlaybackWindow::btnPlayClick()
+4 -2
View File
@@ -820,6 +820,8 @@ void FrameSenderWindow::processCellChange(int line, int col)
sendingData[line].count = 0; sendingData[line].count = 0;
int numBuses = CANConManager::getInstance()->getNumBuses();
switch (col) switch (col)
{ {
case 0: //Enable check box case 0: //Enable check box
@@ -832,8 +834,8 @@ void FrameSenderWindow::processCellChange(int line, int col)
break; break;
case 1: //Bus designation case 1: //Bus designation
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text()); tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text());
if (tempVal < 0) tempVal = 0; if (tempVal < -1) tempVal = -1;
if (tempVal > 1) tempVal = 1; if (tempVal >= numBuses) tempVal = numBuses - 1;
sendingData[line].bus = tempVal; sendingData[line].bus = tempVal;
qDebug() << "Setting bus to " << tempVal; qDebug() << "Setting bus to " << tempVal;
break; break;
+1 -1
View File
@@ -67,7 +67,7 @@ HelpWindow* HelpWindow::getRef()
void HelpWindow::showHelp(QString help) void HelpWindow::showHelp(QString help)
{ {
if (m_helpEngine) { 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; qDebug() << "Searching for " << url;
QByteArray helpData = m_helpEngine->fileData(QUrl(url)); QByteArray helpData = m_helpEngine->fileData(QUrl(url));
qDebug() << "Help file size: " << helpData.length(); qDebug() << "Help file size: " << helpData.length();
+43 -25
View File
@@ -55,31 +55,34 @@ MainWindow::MainWindow(QWidget *parent) :
readSettings(); readSettings();
QHeaderView *verticalHeader = ui->canFramesView->verticalHeader();
verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
verticalHeader->setDefaultSectionSize(10);
QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader(); QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader();
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
connect(HorzHdr, SIGNAL(sectionClicked(int)), this, SLOT(headerClicked(int))); connect(HorzHdr, SIGNAL(sectionClicked(int)), this, SLOT(headerClicked(int)));
graphingWindow = NULL; graphingWindow = nullptr;
frameInfoWindow = NULL; frameInfoWindow = nullptr;
playbackWindow = NULL; playbackWindow = nullptr;
flowViewWindow = NULL; flowViewWindow = nullptr;
frameSenderWindow = NULL; frameSenderWindow = nullptr;
dbcMainEditor = NULL; dbcMainEditor = nullptr;
comparatorWindow = NULL; comparatorWindow = nullptr;
settingsDialog = NULL; settingsDialog = nullptr;
firmwareUploaderWindow = NULL; firmwareUploaderWindow = nullptr;
discreteStateWindow = NULL; discreteStateWindow = nullptr;
connectionWindow = NULL; connectionWindow = nullptr;
scriptingWindow = NULL; scriptingWindow = nullptr;
rangeWindow = NULL; rangeWindow = nullptr;
dbcFileWindow = NULL; dbcFileWindow = nullptr;
fuzzingWindow = NULL; fuzzingWindow = nullptr;
udsScanWindow = NULL; udsScanWindow = nullptr;
motorctrlConfigWindow = NULL; motorctrlConfigWindow = nullptr;
isoWindow = NULL; isoWindow = nullptr;
snifferWindow = NULL; snifferWindow = nullptr;
bisectWindow = NULL; bisectWindow = nullptr;
signalViewerWindow = NULL; signalViewerWindow = nullptr;
dbcHandler = DBCHandler::getReference(); dbcHandler = DBCHandler::getReference();
bDirty = false; bDirty = false;
inhibitFilterUpdate = false; inhibitFilterUpdate = false;
@@ -160,6 +163,10 @@ MainWindow::MainWindow(QWidget *parent) :
temp.bus = 0; temp.bus = 0;
temp.ID = 0x100; temp.ID = 0x100;
temp.len = 0; temp.len = 0;
temp.extended = false;
temp.isReceived = true;
temp.remote = false;
temp.timestamp = 100000000;
model->addFrame(temp, true); model->addFrame(temp, true);
qApp->processEvents(); qApp->processEvents();
tickGUIUpdate(); //force a GUI refresh so that the row exists to measure 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->actionFirmware_Update->setVisible(false);
ui->actionMotorControlConfig->setVisible(false); ui->actionMotorControlConfig->setVisible(false);
ui->actionSignal_Viewer->setVisible(false); ui->actionSignal_Viewer->setVisible(false);
//ui->actionSingle_Multi_State_2->setVisible(false); ui->actionSingle_Multi_State_2->setVisible(false);
installEventFilter(this); installEventFilter(this);
} }
@@ -293,7 +300,7 @@ void MainWindow::readSettings()
ui->canFramesView->setColumnWidth(5, settings.value("Main/BusColumn", 40).toUInt()); //bus 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(6, settings.value("Main/LengthColumn", 40).toUInt()); //length
ui->canFramesView->setColumnWidth(7, settings.value("Main/AsciiColumn", 50).toUInt()); //ascii 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()) 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/BusColumn", ui->canFramesView->columnWidth(5));
settings.setValue("Main/LengthColumn", ui->canFramesView->columnWidth(6)); settings.setValue("Main/LengthColumn", ui->canFramesView->columnWidth(6));
settings.setValue("Main/AsciiColumn", ui->canFramesView->columnWidth(7)); 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,12 +394,23 @@ void MainWindow::gridDoubleClicked(QModelIndex idx)
void MainWindow::interpretToggled(bool state) void MainWindow::interpretToggled(bool state)
{ {
model->setInterpetMode(state); model->setInterpetMode(state);
//ui->canFramesView->resizeRowsToContents(); //a VERY costly operation!
} }
void MainWindow::overwriteToggled(bool state) void MainWindow::overwriteToggled(bool 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); model->setOverwriteMode(state);
} }
else ui->cbOverwrite->setCheckState(Qt::Unchecked);
}
}
void MainWindow::updateFilterList() void MainWindow::updateFilterList()
{ {
@@ -466,7 +484,7 @@ void MainWindow::tickGUIUpdate()
framesPerSec = 0; framesPerSec = 0;
ui->lbNumFrames->setText(QString::number(model->rowCount())); 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)); ui->lbFPS->setText(QString::number(framesPerSec));
if (rxFrames > 0) if (rxFrames > 0)
{ {
+50 -7
View File
@@ -4,6 +4,10 @@
#include "helpwindow.h" #include "helpwindow.h"
#include <QtDebug> #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) : FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::FrameInfoWindow) ui(new Ui::FrameInfoWindow)
@@ -32,19 +36,40 @@ FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *paren
ui->graphHistogram->legend->setVisible(false); 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) if (useOpenGL)
{ {
ui->graphHistogram->setAntialiasedElements(QCP::aeAll); ui->graphHistogram->setAntialiasedElements(QCP::aeAll);
//ui->graphingView->setNoAntialiasingOnDrag(true);
ui->graphHistogram->setOpenGl(true); ui->graphHistogram->setOpenGl(true);
ui->graphBytes->setAntialiasedElements(QCP::aeAll);
ui->graphBytes->setOpenGl(true);
} }
else else
{ {
ui->graphHistogram->setOpenGl(false); ui->graphHistogram->setOpenGl(false);
ui->graphHistogram->setAntialiasedElements(QCP::aeNone); ui->graphHistogram->setAntialiasedElements(QCP::aeNone);
ui->graphBytes->setOpenGl(false);
ui->graphBytes->setAntialiasedElements(QCP::aeNone);
} }
installEventFilter(this); installEventFilter(this);
for (int i = 0; i < 8; i++)
{
bytePens[i].setColor(byteGraphColors[i]);
bytePens[i].setWidth(1);
}
} }
void FrameInfoWindow::showEvent(QShowEvent* event) void FrameInfoWindow::showEvent(QShowEvent* event)
@@ -94,7 +119,7 @@ void FrameInfoWindow::readSettings()
QSettings settings; QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool()) 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()); move(settings.value("FrameInfo/WindowPos", QPoint(50, 50)).toPoint());
} }
useOpenGL = settings.value("Main/UseOpenGL", false).toBool(); useOpenGL = settings.value("Main/UseOpenGL", false).toBool();
@@ -188,7 +213,8 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
int maxData[8]; int maxData[8];
int dataHistogram[256][8]; int dataHistogram[256][8];
int bitfieldHistogram[64]; int bitfieldHistogram[64];
QVector<double> graphX, graphY; QVector<double> histGraphX, histGraphY;
QVector<double> byteGraphX, byteGraphY[8];
double maxY = -1000.0; double maxY = -1000.0;
uint8_t changedBits[8]; uint8_t changedBits[8];
uint8_t referenceBits[8]; uint8_t referenceBits[8];
@@ -248,7 +274,7 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
baseNode->addChild(tempItem); baseNode->addChild(tempItem);
tempItem = new QTreeWidgetItem(); 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); baseNode->addChild(tempItem);
tempItem = new QTreeWidgetItem(); tempItem = new QTreeWidgetItem();
@@ -287,6 +313,12 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
//then find all data points //then find all data points
for (int j = 0; j < frameCache.count(); j++) 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) if (j != 0)
{ {
thisInterval = (frameCache[j].timestamp - frameCache[j-1].timestamp); 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])); + QString::number(c % 8) + ") :" + QString::number(bitfieldHistogram[c]));
dataBase->addChild(tempItem); dataBase->addChild(tempItem);
graphX.append(c); histGraphX.append(c);
graphY.append(bitfieldHistogram[c]); histGraphY.append(bitfieldHistogram[c]);
if (bitfieldHistogram[c] > maxY) maxY = bitfieldHistogram[c]; if (bitfieldHistogram[c] > maxY) maxY = bitfieldHistogram[c];
} }
baseNode->addChild(dataBase); baseNode->addChild(dataBase);
ui->treeDetails->insertTopLevelItem(0, baseNode); ui->treeDetails->insertTopLevelItem(0, baseNode);
ui->graphHistogram->clearGraphs(); ui->graphHistogram->clearGraphs();
ui->graphHistogram->addGraph(); 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 ui->graphHistogram->graph()->setLineStyle(QCPGraph::lsStepLeft); //connect points with lines
QBrush graphBrush; QBrush graphBrush;
graphBrush.setColor(Qt::red); graphBrush.setColor(Qt::red);
@@ -400,6 +433,16 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
ui->graphHistogram->yAxis->setRange(0, maxY * 1.02); ui->graphHistogram->yAxis->setRange(0, maxY * 1.02);
ui->graphHistogram->axisRect()->setupFullAxesBox(); ui->graphHistogram->axisRect()->setupFullAxesBox();
ui->graphHistogram->replot(); 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 else
{ {
+2
View File
@@ -33,6 +33,8 @@ private:
QList<CANFrame> frameCache; QList<CANFrame> frameCache;
const QVector<CANFrame> *modelFrames; const QVector<CANFrame> *modelFrames;
bool useOpenGL; bool useOpenGL;
static const QColor byteGraphColors[8];
static QPen bytePens[8];
void refreshIDList(); void refreshIDList();
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
+16 -11
View File
@@ -696,7 +696,7 @@ void GraphingWindow::saveSpreadsheet()
*/ */
QList<GraphParams>::iterator iter; QList<GraphParams>::iterator iter;
double xMin = 1000000000, xMax=-1000000000; double xMin = 10000000000000, xMax=-10000000000000;
int maxCount = 0; int maxCount = 0;
int numGraphs = 0; int numGraphs = 0;
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter) for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
@@ -732,6 +732,7 @@ void GraphingWindow::saveSpreadsheet()
for (int j = 1; j < (maxCount - 1); j++) for (int j = 1; j < (maxCount - 1); j++)
{ {
currentX = xMin + (j * sliceSize); currentX = xMin + (j * sliceSize);
qDebug() << "X: " << currentX;
outFile->write(QString::number(currentX).toUtf8()); outFile->write(QString::number(currentX).toUtf8());
for (int k = 0; k < graphParams.count(); k++) 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 span = graphParams[k].x[indices[k] + 1] - graphParams[k].x[indices[k]];
double progress = (currentX - graphParams[k].x[indices[k]]) / span; double progress = (currentX - graphParams[k].x[indices[k]]) / span;
value = Utility::Lerp(graphParams[k].y[indices[k]], graphParams[k].y[indices[k] + 1], progress); 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->putChar(',');
outFile->write(QString::number(value).toUtf8()); outFile->write(QString::number(value).toUtf8());
@@ -845,7 +847,7 @@ void GraphingWindow::loadDefinitions()
QStringList filters; QStringList filters;
filters.append(QString(tr("Graph definition (*.gdf)"))); filters.append(QString(tr("Graph definition (*.gdf)")));
if (dbcHandler == NULL) return; if (dbcHandler == nullptr) return;
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile(); if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
dialog.setFileMode(QFileDialog::ExistingFile); dialog.setFileMode(QFileDialog::ExistingFile);
@@ -871,10 +873,13 @@ void GraphingWindow::loadDefinitions()
if (tokens[0] == "X") //newest format based around signals if (tokens[0] == "X") //newest format based around signals
{ {
gp.ID = tokens[1].toInt(NULL, 16); gp.ID = tokens[1].toUInt(nullptr, 16);
gp.mask = tokens[2].toULongLong(NULL, 16); gp.mask = tokens[2].toULongLong(nullptr, 16);
gp.startBit = tokens[3].toInt(); gp.startBit = tokens[3].toInt();
if (gp.startBit < 0) gp.intelFormat = false; if (gp.startBit < 0) {
gp.intelFormat = false;
gp.startBit *= -1;
}
else gp.intelFormat = true; else gp.intelFormat = true;
gp.numBits = tokens[4].toInt(); gp.numBits = tokens[4].toInt();
if (tokens[5] == "Y") gp.isSigned = true; if (tokens[5] == "Y") gp.isSigned = true;
@@ -894,18 +899,18 @@ void GraphingWindow::loadDefinitions()
} }
else //one of the two older formats then 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 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 //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); DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(gp.ID);
if (msg != NULL) if (msg != nullptr)
{ {
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]); DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]);
if (sig) if (sig)
{ {
gp.mask = 0xFFFFFFFF; gp.mask = 0xFFFFFFFF;
gp.bias = sig->bias; gp.bias = (float)sig->bias;
gp.color.setRed(tokens[3].toInt()); gp.color.setRed(tokens[3].toInt());
gp.color.setGreen(tokens[4].toInt()); gp.color.setGreen(tokens[4].toInt());
gp.color.setBlue(tokens[5].toInt()); gp.color.setBlue(tokens[5].toInt());
@@ -914,7 +919,7 @@ void GraphingWindow::loadDefinitions()
if (sig->valType == SIGNED_INT) gp.isSigned = true; if (sig->valType == SIGNED_INT) gp.isSigned = true;
else gp.isSigned = false; else gp.isSigned = false;
gp.numBits = sig->signalSize; gp.numBits = sig->signalSize;
gp.scale = sig->factor; gp.scale = (float)sig->factor;
gp.startBit = sig->startBit; gp.startBit = sig->startBit;
gp.stride = 1; gp.stride = 1;
createGraph(gp, true); createGraph(gp, true);
@@ -926,7 +931,7 @@ void GraphingWindow::loadDefinitions()
//hard part - this all changed drastically //hard part - this all changed drastically
//the difference between intel and motorola format is whether //the difference between intel and motorola format is whether
//start is larger than end byte or not. //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 oldStart = tokens[2].toInt();
int oldEnd = tokens[3].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) void ISOTP_InterpreterWindow::headerClicked(int logicalIndex)
{ {
ui->tableIsoFrames->setSortingEnabled(false);
ui->tableIsoFrames->sortByColumn(logicalIndex); ui->tableIsoFrames->sortByColumn(logicalIndex);
} }
@@ -261,9 +262,13 @@ void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE msg)
messages.append(msg); messages.append(msg);
rowNum = ui->tableIsoFrames->rowCount(); rowNum = ui->tableIsoFrames->rowCount();
ui->tableIsoFrames->insertRow(rowNum); 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, 1, new QTableWidgetItem(QString::number(msg.ID, 16)));
ui->tableIsoFrames->setItem(rowNum, 2, new QTableWidgetItem(QString::number(msg.bus))); ui->tableIsoFrames->setItem(rowNum, 2, new QTableWidgetItem(QString::number(msg.bus)));
if (msg.isReceived) ui->tableIsoFrames->setItem(rowNum, 3, new QTableWidgetItem("Rx")); 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" #include "snifferitem.h"
SnifferItem::SnifferItem(const CANFrame& pFrame): SnifferItem::SnifferItem(const CANFrame& pFrame, quint32 seq):
mNotch(0),
mID(pFrame.ID) mID(pFrame.ID)
{ {
mMarker = {0,0}; for (int i = 0; i < 8; i++) {
mLastMarker = {0,0}; 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 */ /* that's dirty */
update(pFrame); update(pFrame, seq, false);
update(pFrame); update(pFrame, seq, false);
} }
@@ -30,57 +36,124 @@ float SnifferItem::getDelta() const
return ((float)(mCurrentTime-mLastTime))/1000000; 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 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 dc SnifferItem::dataChange(uchar i) const
{ {
if( i<mCurrent.len && if (i >= mCurrent.len) return dc::NO;
((uchar*) &mLastMarker.data)[i] &&
!((uchar*) &mNotch)[i] ) 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; return dc::NO;
} }
int SnifferItem::elapsed() const int SnifferItem::elapsed() const
{ {
return mTime.elapsed(); 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 */ /* copy current to last */
mLast = mCurrent; mLast = mCurrent;
mLastTime = mCurrentTime; mLastTime = mCurrentTime;
mCurrSeqVal = timeSeq;
/* copy new value */ /* 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; mCurrent.len = pFrame.len;
mCurrentTime = pFrame.timestamp; mCurrentTime = pFrame.timestamp;
/* update marker */ /* 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; mMarker.len |= mLast.len ^ mCurrent.len;
/* restart timeout */ /* restart timeout */
mTime.restart(); 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() void SnifferItem::updateMarker()
{ {
mLastMarker = mMarker; 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) void SnifferItem::notch(bool pNotch)
{ {
if(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 else
mNotch = 0; for (int i = 0; i < 8; i++) mNotch[i] = 0;
} }
+12 -5
View File
@@ -7,7 +7,8 @@
struct fstCan struct fstCan
{ {
quint64 data; quint8 data[8];
quint32 dataTimestamp[8];
int len; int len;
}; };
@@ -22,26 +23,32 @@ enum dc
class SnifferItem class SnifferItem
{ {
public: public:
explicit SnifferItem(const CANFrame& pFrame); explicit SnifferItem(const CANFrame& pFrame, quint32 seq);
virtual ~SnifferItem(); virtual ~SnifferItem();
quint64 getId() const; quint64 getId() const;
float getDelta() const; float getDelta() const;
int getData(uchar i) 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; dc dataChange(uchar) const;
int elapsed() const; int elapsed() const;
void update(const CANFrame& pFrame); void update(const CANFrame& pFrame, quint32 timeSeq, bool mute);
void updateMarker(); void updateMarker();
void notch(bool); void notch(bool);
private: private:
quint64 mID; quint32 mID;
struct fstCan mLast; struct fstCan mLast;
struct fstCan mCurrent; struct fstCan mCurrent;
struct fstCan mLastMarker; struct fstCan mLastMarker;
struct fstCan mMarker; struct fstCan mMarker;
quint64 mNotch; quint8 mNotch[8];
quint64 mLastTime; quint64 mLastTime;
quint64 mCurrentTime; quint64 mCurrentTime;
quint64 mCurrSeqVal;
QTime mTime; QTime mTime;
}; };
+55 -6
View File
@@ -1,11 +1,15 @@
#include <QDebug> #include <QDebug>
#include "sniffermodel.h" #include "sniffermodel.h"
#include "snifferwindow.h" #include "snifferwindow.h"
#include "SnifferDelegate.h"
SnifferModel::SnifferModel(QObject *parent) SnifferModel::SnifferModel(QObject *parent)
: QAbstractItemModel(parent), : QAbstractItemModel(parent),
mFilter(false) mFilter(false),
mNeverExpire(false),
mFadeInactive(false),
mMuteNotched(false),
mTimeSequence(0)
{ {
} }
@@ -57,10 +61,23 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const
{ {
int data = item->getData(col-tc::DATA_0); int data = item->getData(col-tc::DATA_0);
if(data >= 0) if(data >= 0)
{
return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper(); return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper();
} }
}
break; 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: case Qt::BackgroundRole:
{ {
if(tc::ID==col) if(tc::ID==col)
@@ -143,6 +160,35 @@ QModelIndex SnifferModel::parent(const QModelIndex &) const
return QModelIndex(); 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() void SnifferModel::clear()
{ {
@@ -154,20 +200,22 @@ void SnifferModel::clear()
endResetModel(); endResetModel();
} }
//Called from window with a timer (currently 200ms)
void SnifferModel::refresh() void SnifferModel::refresh()
{ {
QMap<quint32, SnifferItem*>::iterator i; QMap<quint32, SnifferItem*>::iterator i;
QVector<quint32> toRemove; QVector<quint32> toRemove;
SnifferItem* item; SnifferItem* item;
mTimeSequence++;
/* update markers */ /* update markers */
for (i = mMap.begin(); i != mMap.end(); ++i) for (i = mMap.begin(); i != mMap.end(); ++i)
{ {
i.value()->updateMarker(); i.value()->updateMarker();
if(i.value()->elapsed()>5000) if(i.value()->elapsed()>5000 && !mNeverExpire)
toRemove.append(i.key()); 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)); int index = std::distance(mMap.begin(), mMap.lowerBound(frame.ID));
/* add the frame */ /* add the frame */
beginInsertRows(QModelIndex(), index, index); 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(); endInsertRows();
emit idChange(frame.ID, true); emit idChange(frame.ID, true);
} }
else else
//updateData //updateData
mMap[frame.ID]->update(frame); mMap[frame.ID]->update(frame, mTimeSequence, mMuteNotched);
} }
} }
+11
View File
@@ -40,6 +40,13 @@ public:
void refresh(); void refresh();
void clear(); void clear();
void filter(fltType pType, int pId=0); 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: public slots:
void update(CANConnection*, QVector<CANFrame>&); void update(CANConnection*, QVector<CANFrame>&);
@@ -53,6 +60,10 @@ private:
QMap<quint32, SnifferItem*> mMap; QMap<quint32, SnifferItem*> mMap;
QMap<quint32, SnifferItem*> mFilters; QMap<quint32, SnifferItem*> mFilters;
bool mFilter; bool mFilter;
bool mNeverExpire;
bool mFadeInactive;
bool mMuteNotched;
quint32 mTimeSequence;
}; };
#endif // SNIFFERMODEL_H #endif // SNIFFERMODEL_H
+68 -3
View File
@@ -4,6 +4,7 @@
#include "ui_snifferwindow.h" #include "ui_snifferwindow.h"
#include "helpwindow.h" #include "helpwindow.h"
#include "connections/canconmanager.h" #include "connections/canconmanager.h"
#include "SnifferDelegate.h"
SnifferWindow::SnifferWindow(QWidget *parent) : SnifferWindow::SnifferWindow(QWidget *parent) :
QDialog(parent), QDialog(parent),
@@ -16,12 +17,17 @@ SnifferWindow::SnifferWindow(QWidget *parent) :
setWindowFlags(Qt::Window); setWindowFlags(Qt::Window);
ui->treeView->setModel(&mModel); ui->treeView->setModel(&mModel);
sniffDel = new SnifferDelegate();
defaultDel = ui->treeView->itemDelegate();
/* set column width */ /* set column width */
ui->treeView->setColumnWidth(tc::ID, 50); ui->treeView->setColumnWidth(tc::ID, 80);
ui->treeView->setColumnWidth(tc::LAST, 1); ui->treeView->setColumnWidth(tc::LAST, 1);
for(int i=tc::DATA_0 ; i<=tc::DATA_7 ; i++) 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->header()->setDefaultAlignment(Qt::AlignCenter);
//ui->treeView->setItemDelegate(new SnifferDelegate());
/* activate sorting */ /* activate sorting */
ui->listWidget->setSortingEnabled(true); ui->listWidget->setSortingEnabled(true);
@@ -38,20 +44,75 @@ SnifferWindow::SnifferWindow(QWidget *parent) :
connect(&mModel, &SnifferModel::idChange, this, &SnifferWindow::idChange); connect(&mModel, &SnifferModel::idChange, this, &SnifferWindow::idChange);
connect(ui->listWidget, &QListWidget::itemChanged, this, &SnifferWindow::itemChanged); 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() SnifferWindow::~SnifferWindow()
{ {
closeEvent(NULL); closeEvent(NULL);
delete sniffDel;
delete ui; 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) void SnifferWindow::showEvent(QShowEvent* event)
{ {
QDialog::showEvent(event); QDialog::showEvent(event);
connect(CANConManager::getInstance(), &CANConManager::framesReceived, &mModel, &SnifferModel::update); connect(CANConManager::getInstance(), &CANConManager::framesReceived, &mModel, &SnifferModel::update);
mTimer.start(); mTimer.start();
readSettings();
installEventFilter(this); installEventFilter(this);
qDebug() << "show"; qDebug() << "show";
} }
@@ -64,6 +125,7 @@ void SnifferWindow::closeEvent(QCloseEvent *event)
mTimer.stop(); mTimer.stop();
/* disconnect reception of frames */ /* disconnect reception of frames */
disconnect(CANConManager::getInstance(), 0, this, 0); disconnect(CANConManager::getInstance(), 0, this, 0);
writeSettings();
/* clear model */ /* clear model */
mModel.clear(); mModel.clear();
/* clean list */ /* 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(); QString text = QString("0x") + QString("%1").arg(pId, 3, 16, QLatin1Char('0')).toUpper();
item = new QListWidgetItem(text); item = new QListWidgetItem(text);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); 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); ui->listWidget->addItem(item);
mMap[pId] = item; mMap[pId] = item;
} }
+5
View File
@@ -4,6 +4,7 @@
#include <QDialog> #include <QDialog>
#include <QListWidgetItem> #include <QListWidgetItem>
#include "sniffermodel.h" #include "sniffermodel.h"
#include "SnifferDelegate.h"
namespace Ui { namespace Ui {
class snifferWindow; class snifferWindow;
@@ -46,12 +47,16 @@ public slots:
private: private:
void filter(bool pFilter); void filter(bool pFilter);
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
void readSettings();
void writeSettings();
Ui::snifferWindow* ui; Ui::snifferWindow* ui;
SnifferModel mModel; SnifferModel mModel;
QTimer mTimer; QTimer mTimer;
QMap<int, QListWidgetItem*> mMap; QMap<int, QListWidgetItem*> mMap;
bool mFilter; bool mFilter;
SnifferDelegate *sniffDel;
QAbstractItemDelegate *defaultDel;
}; };
#endif // SNIFFER_H #endif // SNIFFER_H
+13 -13
View File
@@ -81,16 +81,6 @@
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <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"> <item row="0" column="0">
<widget class="QRadioButton" name="rbGVRET"> <widget class="QRadioButton" name="rbGVRET">
<property name="text"> <property name="text">
@@ -101,17 +91,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="2" column="0">
<widget class="QRadioButton" name="rbSocketCAN"> <widget class="QRadioButton" name="rbSocketCAN">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>SocketCAN</string> <string>QT SerialBus Devices (SocketCAN, PeakCAN, etc)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="0">
<widget class="QRadioButton" name="rbRemote"> <widget class="QRadioButton" name="rbRemote">
<property name="text"> <property name="text">
<string>Remote Host</string> <string>Remote Host</string>
@@ -121,6 +111,16 @@
</layout> </layout>
</widget> </widget>
</item> </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> <item>
<widget class="QLabel" name="lPort"> <widget class="QLabel" name="lPort">
<property name="sizePolicy"> <property name="sizePolicy">
+57 -64
View File
@@ -6,16 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>884</width> <width>1239</width>
<height>915</height> <height>644</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Signal Editor</string> <string>Signal Editor</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="10,1,5"> <layout class="QVBoxLayout" name="verticalLayout" stretch="10,1,4">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2,1">
<item> <item>
<widget class="QListWidget" name="signalsList"/> <widget class="QListWidget" name="signalsList"/>
</item> </item>
@@ -52,118 +52,113 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> </layout>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>Bit Length:</string> <string>Bit Length:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="0" column="1">
<widget class="QLineEdit" name="txtBitLength"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Byte Order</string> <string>Byte Order</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="txtBitLength"/>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="cbIntelFormat"> <widget class="QCheckBox" name="cbIntelFormat">
<property name="text"> <property name="text">
<string>LSB First (Little Endian)</string> <string>LSB First (Little Endian)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>Type:</string> <string>Type:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="2" column="1">
<widget class="QComboBox" name="comboType"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
<string>Scale:</string> <string>Scale:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0"> <item row="3" column="1">
<widget class="QLineEdit" name="txtScale"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
<property name="text"> <property name="text">
<string>Bias:</string> <string>Bias:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="4" column="1">
<widget class="QLineEdit" name="txtBias"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_9">
<property name="text"> <property name="text">
<string>Min Value:</string> <string>Min Value:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="5" column="1">
<widget class="QLineEdit" name="txtMinVal"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_10"> <widget class="QLabel" name="label_10">
<property name="text"> <property name="text">
<string>Max Value:</string> <string>Max Value:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="0"> <item row="6" column="1">
<widget class="QLabel" name="label_11"> <widget class="QLineEdit" name="txtMaxVal"/>
<property name="text">
<string>Receiving Node:</string>
</property>
</widget>
</item> </item>
<item row="14" column="0"> <item row="7" 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"> <widget class="QLabel" name="label_12">
<property name="text"> <property name="text">
<string>Units Name:</string> <string>Units Name:</string>
</property> </property>
</widget> </widget>
</item> </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"> <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"/> <widget class="QLineEdit" name="txtUnitName"/>
</item> </item>
<item row="10" column="1"> <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"/> <widget class="QComboBox" name="comboReceiver"/>
</item> </item>
<item row="14" column="1"> <item row="9" column="0">
<widget class="QLineEdit" name="txtComment"/>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_14"> <widget class="QLabel" name="label_14">
<property name="text"> <property name="text">
<string>Multiplexing</string> <string>Multiplexing</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="1"> <item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<widget class="QRadioButton" name="rbNotMulti"> <widget class="QRadioButton" name="rbNotMulti">
@@ -188,19 +183,28 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="13" column="0"> <item row="10" column="0">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="label_15">
<property name="text"> <property name="text">
<string>Multiplex Value</string> <string>Multiplex Value</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="10" column="1">
<widget class="QLineEdit" name="txtMultiplexValue"/> <widget class="QLineEdit" name="txtMultiplexValue"/>
</item> </item>
</layout> <item row="11" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Comment:</string>
</property>
</widget> </widget>
</item> </item>
<item row="11" column="1">
<widget class="QLineEdit" name="txtComment"/>
</item>
</layout>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@@ -226,20 +230,9 @@
<tabstops> <tabstops>
<tabstop>signalsList</tabstop> <tabstop>signalsList</tabstop>
<tabstop>txtName</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>rbNotMulti</tabstop>
<tabstop>rbMultiplexed</tabstop> <tabstop>rbMultiplexed</tabstop>
<tabstop>rbMultiplexor</tabstop> <tabstop>rbMultiplexor</tabstop>
<tabstop>txtMultiplexValue</tabstop>
<tabstop>txtComment</tabstop>
<tabstop>valuesTable</tabstop> <tabstop>valuesTable</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
+412 -7
View File
@@ -13,9 +13,11 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Detailed Frame Information</string> <string>Detailed Frame Information</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="10,1,5"> <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,1">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
@@ -61,10 +63,6 @@
</column> </column>
</widget> </widget>
</item> </item>
</layout>
</item>
</layout>
</item>
<item> <item>
<widget class="QPushButton" name="btnSave"> <widget class="QPushButton" name="btnSave">
<property name="text"> <property name="text">
@@ -72,9 +70,417 @@
</property> </property>
</widget> </widget>
</item> </item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<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> <item>
<widget class="QCustomPlot" name="graphHistogram" native="true"/> <widget class="QCustomPlot" name="graphHistogram" native="true"/>
</item> </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> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
@@ -88,7 +494,6 @@
<tabstops> <tabstops>
<tabstop>listFrameID</tabstop> <tabstop>listFrameID</tabstop>
<tabstop>treeDetails</tabstop> <tabstop>treeDetails</tabstop>
<tabstop>btnSave</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>
+5 -1
View File
@@ -89,7 +89,11 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QListWidget" name="listFilter"/> <widget class="QListWidget" name="listFilter">
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
+29 -1
View File
@@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>602</width> <width>1097</width>
<height>752</height> <height>752</height>
</rect> </rect>
</property> </property>
@@ -82,6 +82,34 @@
</property> </property>
</widget> </widget>
</item> </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> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
+4 -4
View File
@@ -128,13 +128,13 @@ public:
return output; return output;
} }
static QString formatTimestamp(uint64_t timestamp) static QVariant formatTimestamp(uint64_t timestamp)
{ {
if (!sysTimeMode) { if (!sysTimeMode) {
if (!secondsMode) return QString::number(timestamp); if (!secondsMode) return (unsigned long long)(timestamp);
else return QString::number((double)timestamp / 1000000.0, 'f', 6); 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 //parses the input string to grab as much of it as possible while staying alpha numeric