Merge pull request #166 from collin80/WIP
Merge WIP changes into Master
@@ -1,12 +1,12 @@
|
||||
# SavvyCAN
|
||||
Qt based cross platform canbus tool
|
||||
(C) 2015-2017 EVTV and Collin Kidder
|
||||
(C) 2015-2018 EVTV and Collin Kidder
|
||||
|
||||
A Qt5 based cross platform tool which can be used to load, save, and capture canbus frames.
|
||||
This tool is designed to help with visualization, reverse engineering, debugging, and
|
||||
capturing of canbus frames.
|
||||
|
||||
Really requires at a resolution of at least 1024x768. Fully multi-monitor capable.
|
||||
Really requires at a resolution of at least 1024x768. Fully multi-monitor capable. Works on 4K monitors as well.
|
||||
|
||||
You are highly recommended to use the
|
||||
[CANDue board from EVTV](http://store.evtv.me/proddetail.php?prod=ArduinoDueCANBUS&cat=23).
|
||||
@@ -14,8 +14,8 @@ You are highly recommended to use the
|
||||
The CANDue board must be running the GVRET firmware which can also be found
|
||||
within the collin80 repos.
|
||||
|
||||
It is now possible to use any SocketCAN compatible device
|
||||
under LINUX. There may, however, be some loss of some functionality as
|
||||
It is now possible to use any QT SerialBus driver (socketcan, Vector, PeakCAN, TinyCAN).
|
||||
There may, however, be some loss of some functionality as
|
||||
some functions of SavvyCAN are designed for use directly with the
|
||||
EVTVDue and CANDue 2.0 boards.
|
||||
|
||||
@@ -46,7 +46,8 @@ http://www.qcustomplot.com/
|
||||
However, this source code is integrated into the source for SavvyCAN and one isn't required
|
||||
to download it separately.
|
||||
|
||||
This project requires 5.8.0 or higher because of a dependency on QSerialBus.
|
||||
This project requires 5.8.0 or higher because of a dependency on QSerialBus. However, you will get
|
||||
even more SerialBus goodness if you use QT 5.11 or 5.12
|
||||
|
||||
## Instructions for compiling:
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ SOURCES += main.cpp\
|
||||
jsedit.cpp \
|
||||
frameplaybackobject.cpp \
|
||||
helpwindow.cpp \
|
||||
blfhandler.cpp
|
||||
blfhandler.cpp \
|
||||
re/sniffer/SnifferDelegate.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
can_structs.h \
|
||||
@@ -121,7 +122,8 @@ HEADERS += mainwindow.h \
|
||||
jsedit.h \
|
||||
frameplaybackobject.h \
|
||||
helpwindow.h \
|
||||
blfhandler.h
|
||||
blfhandler.h \
|
||||
re/sniffer/SnifferDelegate.h
|
||||
|
||||
FORMS += ui/candatagrid.ui \
|
||||
ui/connectionwindow.ui \
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<QHelpCollectionProject version="1.0">
|
||||
<assistant>
|
||||
<title>SavvyCAN 181 documentation</title>
|
||||
<homePage>qthelp://org.sphinx.savvycan.181/doc/index.html</homePage>
|
||||
<startPage>qthelp://org.sphinx.savvycan.181/doc/index.html</startPage>
|
||||
<title>SavvyCAN 189 documentation</title>
|
||||
<homePage>qthelp://org.sphinx.savvycan.189/doc/index.html</homePage>
|
||||
<startPage>qthelp://org.sphinx.savvycan.189/doc/index.html</startPage>
|
||||
</assistant>
|
||||
<docFiles>
|
||||
<generate>
|
||||
@@ -16,4 +16,4 @@
|
||||
<file>SavvyCAN.qch</file>
|
||||
</register>
|
||||
</docFiles>
|
||||
</QHelpCollectionProject>
|
||||
</QHelpCollectionProject>
|
||||
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<QtHelpProject version="1.0">
|
||||
<namespace>org.sphinx.savvycan.181</namespace>
|
||||
<namespace>org.sphinx.savvycan.189</namespace>
|
||||
<virtualFolder>doc</virtualFolder>
|
||||
<customFilter name="SavvyCAN 181">
|
||||
<customFilter name="SavvyCAN 189">
|
||||
<filterAttribute>SavvyCAN</filterAttribute>
|
||||
<filterAttribute>181</filterAttribute>
|
||||
<filterAttribute>189</filterAttribute>
|
||||
</customFilter>
|
||||
<filterSection>
|
||||
<filterAttribute>SavvyCAN</filterAttribute>
|
||||
<filterAttribute>181</filterAttribute>
|
||||
<filterAttribute>189</filterAttribute>
|
||||
<toc>
|
||||
<section title="SavvyCAN 181 documentation" ref="index.html">
|
||||
<section title="SavvyCAN 189 documentation" ref="index.html">
|
||||
<section title="Main / Start Up Screen" ref="mainscreen.html"/>
|
||||
<section title="The Main Frame List" ref="mainscreen.html#the-main-frame-list"/>
|
||||
<section title="The Bottom Statusbar" ref="mainscreen.html#the-bottom-statusbar"/>
|
||||
@@ -58,6 +58,11 @@
|
||||
<section title="Sniffer Window" ref="sniffer.html"/>
|
||||
<section title="Using the Sniffer Window" ref="sniffer.html#using-the-sniffer-window"/>
|
||||
<section title="Notching and Unnotching" ref="sniffer.html#notching-and-unnotching"/>
|
||||
<section title="Advanced Options" ref="sniffer.html#advanced-options"/>
|
||||
<section title="Never Expire IDs" ref="sniffer.html#never-expire-ids"/>
|
||||
<section title="Mute notched bits" ref="sniffer.html#mute-notched-bits"/>
|
||||
<section title="Fade inactive bytes" ref="sniffer.html#fade-inactive-bytes"/>
|
||||
<section title="View Bits" ref="sniffer.html#view-bits"/>
|
||||
<section title="Frame Details Window" ref="framedetails.html"/>
|
||||
<section title="The Purpose of Frame Details Window" ref="framedetails.html#the-purpose-of-frame-details-window"/>
|
||||
<section title="File Comparison Window" ref="filecomparison.html"/>
|
||||
@@ -101,63 +106,65 @@
|
||||
|
||||
</keywords>
|
||||
<files>
|
||||
<file>flowview.html</file>
|
||||
<file>dbc_manager.html</file>
|
||||
<file>graphwindow.html</file>
|
||||
<file>framedetails.html</file>
|
||||
<file>rangestate.html</file>
|
||||
<file>filecomparison.html</file>
|
||||
<file>connectionwindow.html</file>
|
||||
<file>fuzzingwindow.html</file>
|
||||
<file>mainscreen.html</file>
|
||||
<file>signaleditor.html</file>
|
||||
<file>uds_scanner.html</file>
|
||||
<file>customsender.html</file>
|
||||
<file>graphsetup.html</file>
|
||||
<file>playbackwindow.html</file>
|
||||
<file>index.html</file>
|
||||
<file>scriptingwindow.html</file>
|
||||
<file>bisector.html</file>
|
||||
<file>firmwareuploader.html</file>
|
||||
<file>genindex.html</file>
|
||||
<file>sniffer.html</file>
|
||||
<file>isotp_decoder.html</file>
|
||||
<file>preferences.html</file>
|
||||
<file>connectionwindow.html</file>
|
||||
<file>customsender.html</file>
|
||||
<file>dbc_editor.html</file>
|
||||
<file>_static/file.png</file>
|
||||
<file>_static/down.png</file>
|
||||
<file>dbc_manager.html</file>
|
||||
<file>filecomparison.html</file>
|
||||
<file>firmwareuploader.html</file>
|
||||
<file>flowview.html</file>
|
||||
<file>framedetails.html</file>
|
||||
<file>fuzzingwindow.html</file>
|
||||
<file>genindex.html</file>
|
||||
<file>graphsetup.html</file>
|
||||
<file>graphwindow.html</file>
|
||||
<file>index.html</file>
|
||||
<file>isotp_decoder.html</file>
|
||||
<file>mainscreen.html</file>
|
||||
<file>playbackwindow.html</file>
|
||||
<file>preferences.html</file>
|
||||
<file>rangestate.html</file>
|
||||
<file>scriptingwindow.html</file>
|
||||
<file>search.html</file>
|
||||
<file>signaleditor.html</file>
|
||||
<file>sniffer.html</file>
|
||||
<file>uds_scanner.html</file>
|
||||
<file>_static/ajax-loader.gif</file>
|
||||
<file>_static/comment-close.png</file>
|
||||
<file>_static/minus.png</file>
|
||||
<file>_static/comment-bright.png</file>
|
||||
<file>_static/up-pressed.png</file>
|
||||
<file>_static/pygments.css</file>
|
||||
<file>_static/plus.png</file>
|
||||
<file>_static/nonav.css</file>
|
||||
<file>_static/alabaster.css</file>
|
||||
<file>_static/basic.css</file>
|
||||
<file>_static/down-pressed.png</file>
|
||||
<file>_static/up.png</file>
|
||||
<file>_static/comment-bright.png</file>
|
||||
<file>_static/comment-close.png</file>
|
||||
<file>_static/comment.png</file>
|
||||
<file>_images/SignalEditor.png</file>
|
||||
<file>_images/FrameInfoWindow.png</file>
|
||||
<file>_images/DBCEditor.png</file>
|
||||
<file>_images/UDS_Scanner.png</file>
|
||||
<file>_images/Sniffer.png</file>
|
||||
<file>_static/down-pressed.png</file>
|
||||
<file>_static/down.png</file>
|
||||
<file>_static/file.png</file>
|
||||
<file>_static/minus.png</file>
|
||||
<file>_static/nonav.css</file>
|
||||
<file>_static/plus.png</file>
|
||||
<file>_static/pygments.css</file>
|
||||
<file>_static/up-pressed.png</file>
|
||||
<file>_static/up.png</file>
|
||||
<file>_images/Bisector.png</file>
|
||||
<file>_images/FuzzingWindow.png</file>
|
||||
<file>_images/GraphingView.png</file>
|
||||
<file>_images/ScriptingWindow.png</file>
|
||||
<file>_images/DBCManager.png</file>
|
||||
<file>_images/GraphSetup.png</file>
|
||||
<file>_images/RangeState.png</file>
|
||||
<file>_images/Preferences.png</file>
|
||||
<file>_images/ConnectionWindow.png</file>
|
||||
<file>_images/CustomSender.png</file>
|
||||
<file>_images/DBCEditor.png</file>
|
||||
<file>_images/DBCManager.png</file>
|
||||
<file>_images/FileComparator.png</file>
|
||||
<file>_images/FlowView.png</file>
|
||||
<file>_images/FrameInfoWindow.png</file>
|
||||
<file>_images/FuzzingWindow.png</file>
|
||||
<file>_images/GraphSetup.png</file>
|
||||
<file>_images/GraphingView.png</file>
|
||||
<file>_images/ISOTPDecoder.png</file>
|
||||
<file>_images/MainScreen.png</file>
|
||||
<file>_images/FlowView.png</file>
|
||||
<file>_images/CustomSender.png</file>
|
||||
<file>_images/Playback.png</file>
|
||||
<file>_images/Preferences.png</file>
|
||||
<file>_images/RangeState.png</file>
|
||||
<file>_images/ScriptingWindow.png</file>
|
||||
<file>_images/SignalEditor.png</file>
|
||||
<file>_images/Sniffer.png</file>
|
||||
<file>_images/UDS_Scanner.png</file>
|
||||
</files>
|
||||
</filterSection>
|
||||
</QtHelpProject>
|
||||
</QtHelpProject>
|
||||
@@ -160,6 +160,7 @@ void CANFrameModel::setOverwriteMode(bool mode)
|
||||
{
|
||||
beginResetModel();
|
||||
overwriteDups = mode;
|
||||
recalcOverwrite();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -191,26 +192,20 @@ void CANFrameModel::recalcOverwrite()
|
||||
|
||||
mutex.lock();
|
||||
beginResetModel();
|
||||
for (int i = 1; i < frames.count(); i++)
|
||||
{
|
||||
found = false;
|
||||
for (int j = 0; j <= lastUnique; j++)
|
||||
{
|
||||
if (frames[i].ID == frames[j].ID)
|
||||
{
|
||||
frames.replace(j, frames[i]);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
lastUnique++;
|
||||
frames.replace(lastUnique, frames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
while (frames.count() > lastUnique) frames.removeLast();
|
||||
//Look at the current list of frames and turn it into just a list of unique IDs
|
||||
QHash<int, CANFrame> overWriteFrames;
|
||||
foreach(CANFrame frame, frames)
|
||||
{
|
||||
if (!overWriteFrames.contains(frame.ID))
|
||||
{
|
||||
overWriteFrames.insert(frame.ID, frame);
|
||||
}
|
||||
else overWriteFrames[frame.ID] = frame;
|
||||
}
|
||||
//Then replace the old list of frames with just the unique list
|
||||
frames.clear();
|
||||
frames.append(overWriteFrames.values().toVector());
|
||||
|
||||
filteredFrames.clear();
|
||||
filteredFrames.reserve(preallocSize);
|
||||
@@ -255,6 +250,11 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
return QColor(Qt::white);
|
||||
}
|
||||
|
||||
if (role == Qt::TextAlignmentRole)
|
||||
{
|
||||
return Qt::AlignLeft;
|
||||
}
|
||||
|
||||
if (role == Qt::TextColorRole)
|
||||
{
|
||||
if (dbcHandler != NULL && interpretFrames)
|
||||
@@ -300,7 +300,8 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
for (int i = 0; i < dLen; i++)
|
||||
{
|
||||
quint8 byt = thisFrame.data[i];
|
||||
if (byt < 0x20) byt = 0x2E; //A dot
|
||||
//0x20 through 0x7E are printable characters. Outside of that range they aren't. So use dots instead
|
||||
if (byt < 0x20) byt = 0x2E; //dot character
|
||||
if (byt > 0x7E) byt = 0x2E;
|
||||
tempString.append(QString::fromUtf8((char *)&byt, 1));
|
||||
}
|
||||
@@ -326,7 +327,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
|
||||
if (msg != NULL)
|
||||
{
|
||||
tempString.append("\n");
|
||||
tempString.append(" <Interpreted>\n");
|
||||
tempString.append(msg->name + "\n" + msg->comment + "\n");
|
||||
for (int j = 0; j < msg->sigHandler->getCount(); j++)
|
||||
{
|
||||
@@ -410,7 +411,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
|
||||
frames.append(tempFrame);
|
||||
if (filters[tempFrame.ID])
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
|
||||
filteredFrames.append(tempFrame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
}
|
||||
@@ -432,7 +433,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
|
||||
frames.append(tempFrame);
|
||||
if (filters[tempFrame.ID])
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
|
||||
filteredFrames.append(tempFrame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CONFIG
|
||||
#define CONFIG
|
||||
|
||||
#define VERSION 187
|
||||
#define VERSION 190
|
||||
|
||||
//try to keep this in sync.
|
||||
//SavvyCAN will complain if you connect a GVRET board with a revision
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace CANCon {
|
||||
{
|
||||
GVRET_SERIAL,
|
||||
KVASER,
|
||||
SOCKETCAN,
|
||||
SERIALBUS,
|
||||
REMOTE,
|
||||
NONE
|
||||
};
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
using namespace CANCon;
|
||||
|
||||
CANConnection* CanConFactory::create(type pType, QString pPortName)
|
||||
CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName)
|
||||
{
|
||||
switch(pType) {
|
||||
case SOCKETCAN:
|
||||
return new SerialBusConnection(pPortName);
|
||||
case SERIALBUS:
|
||||
return new SerialBusConnection(pPortName, pDriverName);
|
||||
case GVRET_SERIAL:
|
||||
return new GVRetSerial(pPortName, false);
|
||||
case REMOTE:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
class CanConFactory
|
||||
{
|
||||
public:
|
||||
static CANConnection* create(CANCon::type, QString pPortName);
|
||||
static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName);
|
||||
};
|
||||
|
||||
#endif // CANCONFACTORY_H
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "canconnection.h"
|
||||
|
||||
CANConnection::CANConnection(QString pPort,
|
||||
QString pDriver,
|
||||
CANCon::type pType,
|
||||
int pNumBuses,
|
||||
int pQueueLen,
|
||||
@@ -10,6 +11,7 @@ CANConnection::CANConnection(QString pPort,
|
||||
mQueue(),
|
||||
mNumBuses(pNumBuses),
|
||||
mPort(pPort),
|
||||
mDriver(pDriver),
|
||||
mType(pType),
|
||||
mIsCapSuspended(false),
|
||||
mStatus(CANCon::NOT_CONNECTED),
|
||||
@@ -227,6 +229,10 @@ QString CANConnection::getPort() {
|
||||
return mPort;
|
||||
}
|
||||
|
||||
QString CANConnection::getDriver()
|
||||
{
|
||||
return mDriver;
|
||||
}
|
||||
|
||||
LFQueue<CANFrame>& CANConnection::getQueue() {
|
||||
return mQueue;
|
||||
|
||||
@@ -19,13 +19,15 @@ protected:
|
||||
/**
|
||||
* @brief CANConnection constructor
|
||||
* @param pPort: string containing port name
|
||||
* @param pDriver: string containing driver name - Really only used for SerialBus connections
|
||||
* @param pType: the type of connection @ref CANCon::type
|
||||
* @param pNumBuses: the number of buses the device has
|
||||
* @param pQueueLen: the length of the lock free queue to use
|
||||
* @param pUseThread: if set to true, object will be execute in a dedicated thread
|
||||
*/
|
||||
CANConnection(QString pPort,
|
||||
CANCon::type pType,
|
||||
QString pDriver,
|
||||
CANCon::type pType,
|
||||
int pNumBuses,
|
||||
int pQueueLen,
|
||||
bool pUseThread);
|
||||
@@ -50,6 +52,13 @@ public:
|
||||
*/
|
||||
QString getPort();
|
||||
|
||||
/**
|
||||
* @brief getDriver
|
||||
* @return returns the name of the driver used for this device
|
||||
*/
|
||||
QString getDriver();
|
||||
|
||||
|
||||
/**
|
||||
* @brief getQueue
|
||||
* @return the lock free queue of the device
|
||||
@@ -294,6 +303,7 @@ protected:
|
||||
private:
|
||||
LFQueue<CANFrame> mQueue;
|
||||
const QString mPort;
|
||||
const QString mDriver;
|
||||
const CANCon::type mType;
|
||||
bool mIsCapSuspended;
|
||||
QAtomicInt mStatus;
|
||||
|
||||
@@ -87,10 +87,11 @@ Qt::ItemFlags CANConnectionModel::flags(const QModelIndex &index) const
|
||||
CANConnection *conn_p = getAtIdx(index.row(), busId);
|
||||
if (!conn_p) return Qt::ItemFlag::NoItemFlags;
|
||||
|
||||
//you can't set speed, single wire, or listen only on socketcan devices so
|
||||
//detect if we're using GVRET where you can and turn that functionality on
|
||||
bool editParams = false;
|
||||
if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true;
|
||||
//socketcan is limited for what you can set but the other serialbus
|
||||
//devices should be able to set the stuff. For now let anyone try
|
||||
//and the underlying drivers can do with them as they will
|
||||
bool editParams = true;
|
||||
//if (conn_p->getType() == CANCon::GVRET_SERIAL) editParams = true;
|
||||
|
||||
switch (Column(index.column()))
|
||||
{
|
||||
@@ -152,7 +153,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
|
||||
bool ret;
|
||||
if (!conn_p) return QVariant();
|
||||
ret = conn_p->getBusSettings(busId, bus);
|
||||
bool isSocketCAN = (conn_p->getType() == CANCon::SOCKETCAN) ? true: false;
|
||||
bool isSocketCAN = (conn_p->getType() == CANCon::SERIALBUS) ? true: false;
|
||||
|
||||
//qDebug() << "ConnP: " << conn_p << " ret " << ret;
|
||||
|
||||
@@ -167,7 +168,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
|
||||
if (conn_p)
|
||||
switch (conn_p->getType()) {
|
||||
case CANCon::KVASER: return "KVASER";
|
||||
case CANCon::SOCKETCAN: return "SocketCAN";
|
||||
case CANCon::SERIALBUS: return "SerialBus";
|
||||
case CANCon::GVRET_SERIAL: return "GVRET";
|
||||
default: {}
|
||||
}
|
||||
|
||||
@@ -44,16 +44,13 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
||||
/* load connection configuration */
|
||||
loadConnections();
|
||||
|
||||
ui->rbSocketCAN->setEnabled(isSocketCanAvailable());
|
||||
#ifdef Q_OS_WIN
|
||||
ui->rbKvaser->setEnabled(true);
|
||||
#endif
|
||||
ui->rbSocketCAN->setEnabled(isSerialBusAvailable());
|
||||
|
||||
connect(ui->btnOK, &QAbstractButton::clicked, this, &ConnectionWindow::handleOKButton);
|
||||
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->rbKvaser, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->rbRemote, &QAbstractButton::clicked, this, &ConnectionWindow::handleConnTypeChanged);
|
||||
connect(ui->cbDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConnectionWindow::handleDeviceTypeChanged);
|
||||
connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged);
|
||||
connect(ui->btnActivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleEnableAll);
|
||||
connect(ui->btnDeactivateAll, &QPushButton::clicked, this, &ConnectionWindow::handleDisableAll);
|
||||
@@ -63,6 +60,9 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
||||
connect(ui->btnSendHex, &QPushButton::clicked, this, &ConnectionWindow::handleSendHex);
|
||||
connect(ui->btnSendText, &QPushButton::clicked, this, &ConnectionWindow::handleSendText);
|
||||
connect(ui->ckEnableConsole, &QCheckBox::toggled, this, &ConnectionWindow::consoleEnableChanged);
|
||||
|
||||
ui->lblDeviceType->setHidden(true);
|
||||
ui->cbDeviceType->setHidden(true);
|
||||
}
|
||||
|
||||
ConnectionWindow::~ConnectionWindow()
|
||||
@@ -118,7 +118,7 @@ bool ConnectionWindow::eventFilter(QObject *obj, QEvent *event)
|
||||
// standard event processing
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
return false;
|
||||
//return false;
|
||||
}
|
||||
|
||||
void ConnectionWindow::readSettings()
|
||||
@@ -200,7 +200,7 @@ void ConnectionWindow::consoleEnableChanged(bool checked) {
|
||||
connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray)));
|
||||
}
|
||||
else { //turn it off
|
||||
disconnect(conn_p, SIGNAL(debugOutput(QString)), 0, 0);
|
||||
disconnect(conn_p, SIGNAL(debugOutput(QString)), nullptr, nullptr);
|
||||
disconnect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray)));
|
||||
}
|
||||
}
|
||||
@@ -226,11 +226,18 @@ void ConnectionWindow::handleDisableAll()
|
||||
void ConnectionWindow::handleConnTypeChanged()
|
||||
{
|
||||
if (ui->rbGVRET->isChecked()) selectSerial();
|
||||
if (ui->rbKvaser->isChecked()) selectKvaser();
|
||||
if (ui->rbSocketCAN->isChecked()) selectSocketCan();
|
||||
if (ui->rbRemote->isChecked()) selectRemote();
|
||||
}
|
||||
|
||||
void ConnectionWindow::handleDeviceTypeChanged()
|
||||
{
|
||||
ui->cbPort->clear();
|
||||
canDevices = QCanBus::instance()->availableDevices(ui->cbDeviceType->currentText());
|
||||
|
||||
for (int i = 0; i < canDevices.count(); i++)
|
||||
ui->cbPort->addItem(canDevices[i].name());
|
||||
}
|
||||
|
||||
/* status */
|
||||
void ConnectionWindow::connectionStatus(CANConStatus pStatus)
|
||||
@@ -244,12 +251,12 @@ void ConnectionWindow::connectionStatus(CANConStatus pStatus)
|
||||
|
||||
void ConnectionWindow::handleOKButton()
|
||||
{
|
||||
CANConnection* conn_p = NULL;
|
||||
CANConnection* conn_p = nullptr;
|
||||
|
||||
if( ! CANConManager::getInstance()->getByName(getPortName()) )
|
||||
{
|
||||
/* create connection */
|
||||
conn_p = create(getConnectionType(), getPortName());
|
||||
conn_p = create(getConnectionType(), getPortName(), getDriverName());
|
||||
if(!conn_p)
|
||||
return;
|
||||
/* add connection to model */
|
||||
@@ -281,7 +288,7 @@ return;
|
||||
ui->btnOK->setText(tr("Create New Connection"));
|
||||
ui->rbGVRET->setChecked(true);
|
||||
setSpeed(0);
|
||||
setPortName(CANCon::GVRET_SERIAL, "");
|
||||
setPortName(CANCon::GVRET_SERIAL, "", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -300,7 +307,7 @@ return;
|
||||
|
||||
ui->btnOK->setText(tr("Update Connection Settings"));
|
||||
setSpeed(bus.getSpeed());
|
||||
setPortName(conn_p->getType(), conn_p->getPort());
|
||||
setPortName(conn_p->getType(), conn_p->getPort(), conn_p->getDriver());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +340,8 @@ void ConnectionWindow::selectSerial()
|
||||
ui->lPort->setText("Port:");
|
||||
/* set combobox page visible */
|
||||
ui->stPort->setCurrentWidget(ui->cbPage);
|
||||
ui->lblDeviceType->setHidden(true);
|
||||
ui->cbDeviceType->setHidden(true);
|
||||
|
||||
ui->cbPort->clear();
|
||||
ports = QSerialPortInfo::availablePorts();
|
||||
@@ -341,41 +350,42 @@ void ConnectionWindow::selectSerial()
|
||||
ui->cbPort->addItem(ports[i].portName());
|
||||
}
|
||||
|
||||
void ConnectionWindow::selectKvaser()
|
||||
{
|
||||
ui->lPort->setText("Port:");
|
||||
/* set combobox page visible */
|
||||
ui->stPort->setCurrentWidget(ui->cbPage);
|
||||
}
|
||||
|
||||
void ConnectionWindow::selectSocketCan()
|
||||
{
|
||||
ui->lPort->setText("Port:");
|
||||
/* set edit text page visible */
|
||||
ui->stPort->setCurrentWidget(ui->etPage);
|
||||
ui->stPort->setCurrentWidget(ui->cbPage);
|
||||
ui->lblDeviceType->setHidden(false);
|
||||
ui->cbDeviceType->setHidden(false);
|
||||
|
||||
ui->cbDeviceType->clear();
|
||||
QStringList plugins;
|
||||
plugins = QCanBus::instance()->plugins();
|
||||
for (int i = 0; i < plugins.count(); i++)
|
||||
ui->cbDeviceType->addItem(plugins[i]);
|
||||
}
|
||||
|
||||
void ConnectionWindow::selectRemote()
|
||||
{
|
||||
ui->lPort->setText("IP Address:");
|
||||
ui->stPort->setCurrentWidget(ui->etPage);
|
||||
ui->lblDeviceType->setHidden(true);
|
||||
ui->cbDeviceType->setHidden(true);
|
||||
}
|
||||
|
||||
void ConnectionWindow::setSpeed(int speed0)
|
||||
{
|
||||
Q_UNUSED(speed0);
|
||||
}
|
||||
|
||||
void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
|
||||
void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName, QString pDriver)
|
||||
{
|
||||
switch(pType)
|
||||
{
|
||||
case CANCon::GVRET_SERIAL:
|
||||
ui->rbGVRET->setChecked(true);
|
||||
break;
|
||||
case CANCon::KVASER:
|
||||
ui->rbKvaser->setChecked(true);
|
||||
break;
|
||||
case CANCon::SOCKETCAN:
|
||||
case CANCon::SERIALBUS:
|
||||
ui->rbSocketCAN->setChecked(true);
|
||||
//you can't configure any of the below three with socketcan so dim them out
|
||||
break;
|
||||
@@ -394,7 +404,16 @@ void ConnectionWindow::setPortName(CANCon::type pType, QString pPortName)
|
||||
ui->cbPort->setCurrentIndex(idx);
|
||||
break;
|
||||
}
|
||||
case CANCon::SOCKETCAN:
|
||||
case CANCon::SERIALBUS:
|
||||
{
|
||||
int idx = ui->cbDeviceType->findText(pDriver);
|
||||
if (idx < 0) idx = 0;
|
||||
ui->cbDeviceType->setCurrentIndex(idx);
|
||||
idx = ui->cbPort->findText(pPortName);
|
||||
if( idx < 0 ) idx = 0;
|
||||
ui->cbPort->setCurrentIndex(idx);
|
||||
break;
|
||||
}
|
||||
case CANCon::REMOTE:
|
||||
{
|
||||
ui->lePort->setText(pPortName);
|
||||
@@ -415,9 +434,8 @@ QString ConnectionWindow::getPortName()
|
||||
{
|
||||
switch( getConnectionType() ) {
|
||||
case CANCon::GVRET_SERIAL:
|
||||
case CANCon::KVASER:
|
||||
case CANCon::SERIALBUS:
|
||||
return ui->cbPort->currentText();
|
||||
case CANCon::SOCKETCAN:
|
||||
case CANCon::REMOTE:
|
||||
return ui->lePort->text();
|
||||
default:
|
||||
@@ -427,11 +445,20 @@ QString ConnectionWindow::getPortName()
|
||||
return "";
|
||||
}
|
||||
|
||||
QString ConnectionWindow::getDriverName()
|
||||
{
|
||||
if (getConnectionType() == CANCon::SERIALBUS)
|
||||
{
|
||||
return ui->cbDeviceType->currentText();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
CANCon::type ConnectionWindow::getConnectionType()
|
||||
{
|
||||
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
|
||||
if (ui->rbKvaser->isChecked()) return CANCon::KVASER;
|
||||
if (ui->rbSocketCAN->isChecked()) return CANCon::SOCKETCAN;
|
||||
if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS;
|
||||
if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
|
||||
qDebug() << "getConnectionType: error";
|
||||
return CANCon::NONE;
|
||||
@@ -440,6 +467,7 @@ CANCon::type ConnectionWindow::getConnectionType()
|
||||
|
||||
void ConnectionWindow::setSWMode(bool mode)
|
||||
{
|
||||
Q_UNUSED(mode);
|
||||
}
|
||||
|
||||
bool ConnectionWindow::getSWMode()
|
||||
@@ -475,21 +503,19 @@ void ConnectionWindow::handleRevert()
|
||||
}
|
||||
|
||||
|
||||
bool ConnectionWindow::isSocketCanAvailable()
|
||||
bool ConnectionWindow::isSerialBusAvailable()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
if (QCanBus::instance()->plugins().contains(QStringLiteral("socketcan"))) return true;
|
||||
#endif
|
||||
if (QCanBus::instance()->plugins().count() > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName)
|
||||
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver)
|
||||
{
|
||||
CANConnection* conn_p;
|
||||
|
||||
/* create connection */
|
||||
conn_p = CanConFactory::create(pTye, pPortName);
|
||||
conn_p = CanConFactory::create(pTye, pPortName, pDriver);
|
||||
if(conn_p)
|
||||
{
|
||||
/* connect signal */
|
||||
@@ -512,11 +538,15 @@ void ConnectionWindow::loadConnections()
|
||||
|
||||
/* fill connection list */
|
||||
QVector<QString> portNames = settings.value("connections/portNames").value<QVector<QString>>();
|
||||
QVector<QString> driverNames = settings.value("connections/driverNames").value<QVector<QString>>();
|
||||
QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>();
|
||||
|
||||
for(int i=0 ; i<portNames.count() ; i++)
|
||||
//don't load the connections if the three setting arrays above aren't all the same size.
|
||||
if (portNames.count() != driverNames.count() || devTypes.count() != driverNames.count()) return;
|
||||
|
||||
for(int i = 0 ; i < portNames.count() ; i++)
|
||||
{
|
||||
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i]);
|
||||
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i]);
|
||||
/* add connection to model */
|
||||
connModel->add(conn_p);
|
||||
}
|
||||
@@ -533,14 +563,17 @@ void ConnectionWindow::saveConnections()
|
||||
QSettings settings;
|
||||
QVector<QString> portNames;
|
||||
QVector<int> devTypes;
|
||||
QVector<QString> driverNames;
|
||||
|
||||
/* save connections */
|
||||
foreach(CANConnection* conn_p, conns)
|
||||
{
|
||||
portNames.append(conn_p->getPort());
|
||||
devTypes.append(conn_p->getType());
|
||||
driverNames.append(conn_p->getDriver());
|
||||
}
|
||||
|
||||
settings.setValue("connections/portNames", QVariant::fromValue(portNames));
|
||||
settings.setValue("connections/types", QVariant::fromValue(devTypes));
|
||||
settings.setValue("connections/driverNames", QVariant::fromValue(driverNames));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
#include <QItemSelection>
|
||||
#include <QCanBusDeviceInfo>
|
||||
#include "canconnectionmodel.h"
|
||||
#include "connections/canconnection.h"
|
||||
|
||||
@@ -47,6 +48,7 @@ public slots:
|
||||
private slots:
|
||||
void handleOKButton();
|
||||
void handleConnTypeChanged();
|
||||
void handleDeviceTypeChanged();
|
||||
void currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void consoleEnableChanged(bool checked);
|
||||
void handleRemoveConn();
|
||||
@@ -63,6 +65,7 @@ private slots:
|
||||
private:
|
||||
Ui::ConnectionWindow *ui;
|
||||
QList<QSerialPortInfo> ports;
|
||||
QList<QCanBusDeviceInfo> canDevices;
|
||||
QSettings *settings;
|
||||
CANConnectionModel *connModel;
|
||||
|
||||
@@ -70,13 +73,14 @@ private:
|
||||
void selectKvaser();
|
||||
void selectSocketCan();
|
||||
void selectRemote();
|
||||
bool isSocketCanAvailable();
|
||||
bool isSerialBusAvailable();
|
||||
int getSpeed();
|
||||
QString getPortName();
|
||||
void setPortName(CANCon::type pType, QString pPortName);
|
||||
QString getDriverName();
|
||||
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
|
||||
|
||||
void setActiveAll(bool pActive);
|
||||
CANConnection* create(CANCon::type pTye, QString pPortName);
|
||||
CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver);
|
||||
void loadConnections();
|
||||
void saveConnections();
|
||||
void showEvent(QShowEvent *);
|
||||
|
||||
@@ -9,19 +9,20 @@
|
||||
#include "gvretserial.h"
|
||||
|
||||
GVRetSerial::GVRetSerial(QString portName, bool useTcp) :
|
||||
CANConnection(portName, CANCon::GVRET_SERIAL, 3, 4000, true),
|
||||
CANConnection(portName, "gvret", CANCon::GVRET_SERIAL, 3, 4000, true),
|
||||
useTcp(useTcp),
|
||||
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
|
||||
{
|
||||
qDebug() << "GVRetSerial()";
|
||||
debugOutput("GVRetSerial()");
|
||||
sendDebug("GVRetSerial()");
|
||||
|
||||
serial = NULL;
|
||||
tcpClient = NULL;
|
||||
udpClient = NULL;
|
||||
rx_state = IDLE;
|
||||
rx_step = 0;
|
||||
gotValidated = true;
|
||||
validationCounter = 10; //how many times we can miss validation before we die
|
||||
isAutoRestart = false;
|
||||
espSerialMode = true;
|
||||
|
||||
timeBasis = 0;
|
||||
lastSystemTimeBasis = 0;
|
||||
@@ -34,27 +35,38 @@ GVRetSerial::GVRetSerial(QString portName, bool useTcp) :
|
||||
GVRetSerial::~GVRetSerial()
|
||||
{
|
||||
stop();
|
||||
qDebug() << "~GVRetSerial()";
|
||||
debugOutput("~GVRetSerial()");
|
||||
sendDebug("~GVRetSerial()");
|
||||
}
|
||||
|
||||
void GVRetSerial::sendDebug(const QString debugText)
|
||||
{
|
||||
qDebug() << debugText;
|
||||
debugOutput(debugText);
|
||||
}
|
||||
|
||||
void GVRetSerial::sendToSerial(const QByteArray &bytes)
|
||||
{
|
||||
if (serial == NULL && tcpClient == NULL)
|
||||
if (serial == NULL && tcpClient == NULL && udpClient == NULL)
|
||||
{
|
||||
debugOutput("Attempt to write to serial port when it has not been initialized!");
|
||||
sendDebug("Attempt to write to serial port when it has not been initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (serial && !serial->isOpen())
|
||||
{
|
||||
debugOutput("Attempt to write to serial port when it is not open!");
|
||||
sendDebug("Attempt to write to serial port when it is not open!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tcpClient && !tcpClient->isOpen())
|
||||
{
|
||||
debugOutput("Attempt to write to TCP/IP port when it is not open!");
|
||||
sendDebug("Attempt to write to TCP/IP port when it is not open!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (udpClient && !udpClient->isOpen())
|
||||
{
|
||||
sendDebug("Attempt to write to UDP Socket when it is not open!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,10 +76,11 @@ void GVRetSerial::sendToSerial(const QByteArray &bytes)
|
||||
byt = (unsigned char)byt;
|
||||
buildDebug = buildDebug % QString::number(byt, 16) % " ";
|
||||
}
|
||||
debugOutput(buildDebug);
|
||||
sendDebug(buildDebug);
|
||||
|
||||
if (serial) serial->write(bytes);
|
||||
if (tcpClient) tcpClient->write(bytes);
|
||||
if (udpClient) udpClient->write(bytes);
|
||||
}
|
||||
|
||||
void GVRetSerial::piStarted()
|
||||
@@ -176,8 +189,7 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||
if (pBusIdx < 2) {
|
||||
/* update baud rates */
|
||||
QByteArray buffer;
|
||||
qDebug() << "Got signal to update bauds. 1: " << (can0Baud & 0xFFFFFFF) <<" 2: " << (can1Baud & 0xFFFFFFF);
|
||||
debugOutput("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
|
||||
sendDebug("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)) + " 2: " + QString::number((can1Baud & 0xFFFFFFF)));
|
||||
buffer[0] = (char)0xF1; //start of a command over serial
|
||||
buffer[1] = 5; //setup canbus
|
||||
buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first
|
||||
@@ -195,8 +207,7 @@ void GVRetSerial::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||
{
|
||||
/* update baud rates */
|
||||
QByteArray buffer;
|
||||
qDebug() << "Got signal to update extended bus speeds SWCAN: " << swcanBaud <<" LIN1: " << lin1Baud << " LIN2: " << lin2Baud;
|
||||
debugOutput("Got signal to update extended bus speeds SWCAN: " + QString::number(swcanBaud) + " LIN1: " + QString::number(lin1Baud) + " LIN2: " + QString::number(lin2Baud));
|
||||
sendDebug("Got signal to update extended bus speeds SWCAN: " + QString::number(swcanBaud) + " LIN1: " + QString::number(lin1Baud) + " LIN2: " + QString::number(lin2Baud));
|
||||
buffer[0] = (char)0xF1; //start of a command over serial
|
||||
buffer[1] = 14; //setup extended buses
|
||||
buffer[2] = (unsigned char)(swcanBaud & 0xFF); //four bytes of ID LSB first
|
||||
@@ -227,8 +238,10 @@ bool GVRetSerial::piSendFrame(const CANFrame& frame)
|
||||
|
||||
framesRapid++;
|
||||
|
||||
if (serial == NULL) return false;
|
||||
if (!serial->isOpen()) return false;
|
||||
if (serial == NULL && tcpClient == NULL && udpClient == NULL) return false;
|
||||
if (serial && !serial->isOpen()) return false;
|
||||
if (tcpClient && !tcpClient->isOpen()) return false;
|
||||
if (udpClient && !udpClient->isOpen()) return false;
|
||||
//if (!isConnected) return false;
|
||||
|
||||
// Doesn't make sense to send an error frame
|
||||
@@ -283,55 +296,84 @@ void GVRetSerial::connectDevice()
|
||||
disconnectDevice();
|
||||
if(tcpClient)
|
||||
disconnectDevice();
|
||||
if (udpClient)
|
||||
disconnectDevice();
|
||||
|
||||
/* open new device */
|
||||
|
||||
// this does the wrong thing if the serial port has a '.' in the name
|
||||
// if (getPort().contains('.')) //TCP/IP mode then since it looks like an IP address
|
||||
if (useTcp)
|
||||
{
|
||||
qDebug() << "TCP Connection to a GVRET device";
|
||||
// /*
|
||||
sendDebug("TCP Connection to a GVRET device");
|
||||
tcpClient = new QTcpSocket();
|
||||
tcpClient->connectToHost(getPort(), 23);
|
||||
connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readSerialData()));
|
||||
connect(tcpClient, SIGNAL(connected()), this, SLOT(tcpConnected()));
|
||||
connect(tcpClient, SIGNAL(connected()), this, SLOT(deviceConnected()));
|
||||
sendDebug("Created TCP Socket");
|
||||
// */
|
||||
/*
|
||||
qDebug() << "UDP Connection to a GVRET device";
|
||||
udpClient = new QUdpSocket();
|
||||
udpClient->connectToHost(getPort(), 17222);
|
||||
connect(udpClient, SIGNAL(readyRead()), this, SLOT(readSerialData()));
|
||||
//connect(udpClient, SIGNAL(connected()), this, SLOT(tcpConnected()));
|
||||
debugOutput("Created UDP Socket");
|
||||
tcpConnected();
|
||||
*/
|
||||
}
|
||||
else {
|
||||
qDebug() << "Serial connection to a GVRET device";
|
||||
sendDebug("Serial connection to a GVRET device");
|
||||
serial = new QSerialPort(QSerialPortInfo(getPort()));
|
||||
if(!serial) {
|
||||
qDebug() << "can't open serial port " << getPort();
|
||||
debugOutput("can't open serial port " + getPort());
|
||||
sendDebug("can't open serial port " + getPort());
|
||||
return;
|
||||
}
|
||||
debugOutput("Created Serial Port Object");
|
||||
sendDebug("Created Serial Port Object");
|
||||
|
||||
/* configure */
|
||||
serial->setDataBits(serial->Data8);
|
||||
serial->setFlowControl(serial->HardwareControl); //this is important though
|
||||
//serial->setFlowControl(serial->NoFlowControl);
|
||||
serial->setBaudRate(1000000);
|
||||
if (!serial->open(QIODevice::ReadWrite))
|
||||
{
|
||||
qDebug() << serial->errorString();
|
||||
}
|
||||
//serial->setDataTerminalReady(false); //you do need to set these or the fan gets dirty
|
||||
//serial->setRequestToSend(false);
|
||||
serial->setDataTerminalReady(true); //you do need to set these or the fan gets dirty
|
||||
serial->setRequestToSend(true);
|
||||
|
||||
debugOutput("Opened Serial Port");
|
||||
/* connect reading event */
|
||||
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
|
||||
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialError(QSerialPort::SerialPortError)));
|
||||
}
|
||||
|
||||
if (serial) tcpConnected(); //well, not a proper function name I guess...
|
||||
/* configure */
|
||||
serial->setBaudRate(1000000); //most GVRET devices ignore baud, ESP32 needs it set explicitly to the proper value
|
||||
serial->setDataBits(serial->Data8);
|
||||
|
||||
if (espSerialMode)
|
||||
{
|
||||
sendDebug("Trying ESP32 Serial Mode");
|
||||
serial->setFlowControl(serial->NoFlowControl);
|
||||
if (!serial->open(QIODevice::ReadWrite))
|
||||
{
|
||||
//sendDebug("Error returned during port opening: " + serial->errorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
serial->setDataTerminalReady(false); //ESP32 uses these for bootloader selection and reset so turn them off
|
||||
serial->setRequestToSend(false);
|
||||
QTimer::singleShot(3000, this, SLOT(deviceConnected())); //give ESP32 some time as it could have rebooted
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sendDebug("Trying Standard Serial Mode");
|
||||
serial->setFlowControl(serial->HardwareControl); //Most GVRET style devices use hardware flow control
|
||||
if (!serial->open(QIODevice::ReadWrite))
|
||||
{
|
||||
//sendDebug("Error returned during port opening: " + serial->errorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
//serial->setDataTerminalReady(true); //Seemingly these two lines used to be needed
|
||||
//serial->setRequestToSend(true); //But, really both ends should automatically handle these
|
||||
deviceConnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GVRetSerial::tcpConnected()
|
||||
void GVRetSerial::deviceConnected()
|
||||
{
|
||||
qDebug() << "Connected to GVRET Device!";
|
||||
sendDebug("Connecting to GVRET Device!");
|
||||
QByteArray output;
|
||||
output.append((unsigned char)0xE7); //this puts the device into binary comm mode
|
||||
output.append((unsigned char)0xE7);
|
||||
@@ -367,14 +409,8 @@ void GVRetSerial::tcpConnected()
|
||||
|
||||
sendToSerial(output);
|
||||
|
||||
/* start timer */
|
||||
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||
mTimer.setInterval(250); //tick four times per second
|
||||
mTimer.setSingleShot(false); //keep ticking
|
||||
mTimer.start();
|
||||
|
||||
if(doValidation) {
|
||||
QTimer::singleShot(1000, this, SLOT(connectionTimeout()));
|
||||
QTimer::singleShot(5000, this, SLOT(connectionTimeout()));
|
||||
}
|
||||
else {
|
||||
setStatus(CANCon::CONNECTED);
|
||||
@@ -390,7 +426,7 @@ void GVRetSerial::disconnectDevice() {
|
||||
{
|
||||
if (serial->isOpen())
|
||||
{
|
||||
serial->clear();
|
||||
//serial->clear();
|
||||
serial->close();
|
||||
|
||||
}
|
||||
@@ -408,6 +444,17 @@ void GVRetSerial::disconnectDevice() {
|
||||
delete tcpClient;
|
||||
tcpClient = NULL;
|
||||
}
|
||||
if (udpClient != NULL)
|
||||
{
|
||||
if (udpClient->isOpen())
|
||||
{
|
||||
udpClient->close();
|
||||
}
|
||||
udpClient->disconnect();
|
||||
delete udpClient;
|
||||
udpClient = NULL;
|
||||
}
|
||||
|
||||
setStatus(CANCon::NOT_CONNECTED);
|
||||
CANConStatus stats;
|
||||
stats.conStatus = getStatus();
|
||||
@@ -426,14 +473,17 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
|
||||
case QSerialPort::DeviceNotFoundError:
|
||||
errMessage = "Device not found error on serial";
|
||||
killConnection = true;
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::PermissionError:
|
||||
errMessage = "Permission error on serial port";
|
||||
killConnection = true;
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::OpenError:
|
||||
errMessage = "Open error on serial port";
|
||||
killConnection = true;
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::ParityError:
|
||||
errMessage = "Parity error on serial port";
|
||||
@@ -446,13 +496,16 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
|
||||
break;
|
||||
case QSerialPort::WriteError:
|
||||
errMessage = "Write error on serial port";
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::ReadError:
|
||||
errMessage = "Read error on serial port";
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::ResourceError:
|
||||
errMessage = "Serial port seems to have disappeared.";
|
||||
killConnection = true;
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::UnsupportedOperationError:
|
||||
errMessage = "Unsupported operation on serial port";
|
||||
@@ -461,23 +514,28 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
|
||||
case QSerialPort::UnknownError:
|
||||
errMessage = "Beats me what happened to the serial port.";
|
||||
killConnection = true;
|
||||
piStop();
|
||||
break;
|
||||
case QSerialPort::TimeoutError:
|
||||
errMessage = "Timeout error on serial port";
|
||||
killConnection = true;
|
||||
break;
|
||||
case QSerialPort::NotOpenError:
|
||||
errMessage = "The serial port isn't open dummy";
|
||||
errMessage = "The serial port isn't open";
|
||||
killConnection = true;
|
||||
piStop();
|
||||
break;
|
||||
}
|
||||
serial->clearError();
|
||||
serial->flush();
|
||||
serial->close();
|
||||
/*
|
||||
if (serial)
|
||||
{
|
||||
serial->clearError();
|
||||
serial->flush();
|
||||
serial->close();
|
||||
}*/
|
||||
if (errMessage.length() > 1)
|
||||
{
|
||||
qDebug() << errMessage;
|
||||
debugOutput(errMessage);
|
||||
sendDebug(errMessage);
|
||||
}
|
||||
if (killConnection)
|
||||
{
|
||||
@@ -490,13 +548,23 @@ void GVRetSerial::serialError(QSerialPort::SerialPortError err)
|
||||
void GVRetSerial::connectionTimeout()
|
||||
{
|
||||
//one second after trying to connect are we actually connected?
|
||||
//if (CANCon::NOT_CONNECTED==getStatus()) //no?
|
||||
if (!gotValidated)
|
||||
if (CANCon::NOT_CONNECTED==getStatus()) //no?
|
||||
{
|
||||
//then emit the the failure signal and see if anyone cares
|
||||
qDebug() << "Failed to connect to GVRET at that com port";
|
||||
sendDebug("Failed to connect to GVRET at that com port");
|
||||
|
||||
//toggle the serial mode and try again
|
||||
espSerialMode = !espSerialMode;
|
||||
disconnectDevice();
|
||||
connectDevice();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start timer */
|
||||
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||
mTimer.setInterval(250); //tick four times per second
|
||||
mTimer.setSingleShot(false); //keep ticking
|
||||
mTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,9 +577,9 @@ void GVRetSerial::readSerialData()
|
||||
|
||||
if (serial) data = serial->readAll();
|
||||
if (tcpClient) data = tcpClient->readAll();
|
||||
if (udpClient) data = udpClient->readAll();
|
||||
|
||||
debugOutput("Got data from serial. Len = " % QString::number(data.length()));
|
||||
//qDebug() << (tr("Got data from serial. Len = %0").arg(data.length()));
|
||||
sendDebug("Got data from serial. Len = " % QString::number(data.length()));
|
||||
for (int i = 0; i < data.length(); i++)
|
||||
{
|
||||
c = data.at(i);
|
||||
@@ -571,7 +639,7 @@ void GVRetSerial::procRXChar(unsigned char c)
|
||||
rx_step = 0;
|
||||
break;
|
||||
case 9:
|
||||
gotValidated = true;
|
||||
validationCounter = 10;
|
||||
//qDebug() << "Got validated";
|
||||
rx_state = IDLE;
|
||||
break;
|
||||
@@ -932,12 +1000,14 @@ void GVRetSerial::handleTick()
|
||||
|
||||
if( CANCon::CONNECTED == getStatus() )
|
||||
{
|
||||
if (!gotValidated && doValidation)
|
||||
if (doValidation) validationCounter--;
|
||||
//qDebug() << validationCounter;
|
||||
if (validationCounter == 0 && doValidation)
|
||||
{
|
||||
if (serial == NULL && tcpClient == NULL) return;
|
||||
if ( (serial && serial->isOpen()) || (tcpClient && tcpClient->isOpen())) //if it's still false we have a problem...
|
||||
if ( (serial && serial->isOpen()) || (tcpClient && tcpClient->isOpen()) || (udpClient && udpClient->isOpen())) //if it's still false we have a problem...
|
||||
{
|
||||
qDebug() << "Comm validation failed. ";
|
||||
sendDebug("Comm validation failed.");
|
||||
|
||||
setStatus(CANCon::NOT_CONNECTED);
|
||||
//emit status(getStatus());
|
||||
@@ -952,6 +1022,7 @@ void GVRetSerial::handleTick()
|
||||
}
|
||||
if (doValidation && serial && serial->isOpen()) sendCommValidation();
|
||||
if (doValidation && tcpClient && tcpClient->isOpen()) sendCommValidation();
|
||||
if (doValidation && udpClient && udpClient->isOpen()) sendCommValidation();
|
||||
}
|
||||
|
||||
|
||||
@@ -959,7 +1030,6 @@ void GVRetSerial::sendCommValidation()
|
||||
{
|
||||
QByteArray output;
|
||||
|
||||
gotValidated = false;
|
||||
output.append((unsigned char)0xF1); //another command to the GVRET
|
||||
output.append((unsigned char)0x09); //request a reply to get validation
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QTcpSocket>
|
||||
#include <QUdpSocket>
|
||||
|
||||
/*************/
|
||||
#include <QDateTime>
|
||||
@@ -64,7 +65,7 @@ private slots:
|
||||
void connectionTimeout();
|
||||
void readSerialData();
|
||||
void serialError(QSerialPort::SerialPortError err);
|
||||
void tcpConnected();
|
||||
void deviceConnected();
|
||||
void handleTick();
|
||||
|
||||
private:
|
||||
@@ -73,18 +74,21 @@ private:
|
||||
void sendCommValidation();
|
||||
void rebuildLocalTimeBasis();
|
||||
void sendToSerial(const QByteArray &bytes);
|
||||
void sendDebug(const QString debugText);
|
||||
|
||||
protected:
|
||||
QTimer mTimer;
|
||||
QThread mThread;
|
||||
|
||||
bool doValidation;
|
||||
bool gotValidated;
|
||||
int validationCounter;
|
||||
bool isAutoRestart;
|
||||
bool continuousTimeSync;
|
||||
bool useTcp;
|
||||
bool espSerialMode; //special serial mode for ESP32 based boards - no flow control and much slower serial baud speed
|
||||
QSerialPort *serial;
|
||||
QTcpSocket *tcpClient;
|
||||
QUdpSocket *udpClient;
|
||||
int framesRapid;
|
||||
STATE rx_state;
|
||||
uint32_t rx_step;
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
/**** class definition ****/
|
||||
/***********************************/
|
||||
|
||||
SerialBusConnection::SerialBusConnection(QString portName) :
|
||||
CANConnection(portName, CANCon::SOCKETCAN, 1, 4000, true),
|
||||
SerialBusConnection::SerialBusConnection(QString portName, QString driverName) :
|
||||
CANConnection(portName, driverName, CANCon::SERIALBUS, 1, 4000, true),
|
||||
mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */
|
||||
{
|
||||
}
|
||||
@@ -26,6 +26,22 @@ SerialBusConnection::~SerialBusConnection()
|
||||
|
||||
void SerialBusConnection::piStarted()
|
||||
{
|
||||
qDebug() << "piStarted()";
|
||||
/* create device */
|
||||
QString errorString;
|
||||
qDebug() << "Creating device instance";
|
||||
mDev_p = QCanBus::instance()->createDevice(getDriver(), getPort(), &errorString);
|
||||
if (!mDev_p) {
|
||||
disconnectDevice();
|
||||
qDebug() << "Error: createDevice(" << getType() << getDriver() << getPort() << "):" << errorString;
|
||||
return;
|
||||
}
|
||||
|
||||
/* connect slots */
|
||||
connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SerialBusConnection::errorReceived);
|
||||
connect(mDev_p, &QCanBusDevice::framesWritten, this, &SerialBusConnection::framesWritten);
|
||||
connect(mDev_p, &QCanBusDevice::framesReceived, this, &SerialBusConnection::framesReceived);
|
||||
|
||||
connect(&mTimer, SIGNAL(timeout()), this, SLOT(testConnection()));
|
||||
mTimer.setInterval(1000);
|
||||
mTimer.setSingleShot(false); //keep ticking
|
||||
@@ -47,6 +63,7 @@ void SerialBusConnection::piSuspend(bool pSuspend)
|
||||
|
||||
|
||||
void SerialBusConnection::piStop() {
|
||||
qDebug() << "piStop()";
|
||||
mTimer.stop();
|
||||
disconnectDevice();
|
||||
}
|
||||
@@ -65,6 +82,8 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||
if(0 != pBusIdx)
|
||||
return;
|
||||
|
||||
if (!mDev_p) return;
|
||||
|
||||
/* disconnect device if we have one connected */
|
||||
disconnectDevice();
|
||||
|
||||
@@ -75,20 +94,6 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||
if(!bus.active)
|
||||
return;
|
||||
|
||||
/* create device */
|
||||
QString errorString;
|
||||
mDev_p = QCanBus::instance()->createDevice("socketcan", getPort(), &errorString);
|
||||
if (!mDev_p) {
|
||||
disconnectDevice();
|
||||
qDebug() << "Error: createDevice(" << getType() << getPort() << "):" << errorString;
|
||||
return;
|
||||
}
|
||||
|
||||
/* connect slots */
|
||||
connect(mDev_p, &QCanBusDevice::errorOccurred, this, &SerialBusConnection::errorReceived);
|
||||
connect(mDev_p, &QCanBusDevice::framesWritten, this, &SerialBusConnection::framesWritten);
|
||||
connect(mDev_p, &QCanBusDevice::framesReceived, this, &SerialBusConnection::framesReceived);
|
||||
|
||||
/* set configuration */
|
||||
/*if (p.useConfigurationEnabled) {
|
||||
foreach (const SettingsDialog::ConfigurationItem &item, p.configurations)
|
||||
@@ -96,7 +101,8 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||
}*/
|
||||
|
||||
//You cannot set the speed of a socketcan interface, it has to be set with console commands.
|
||||
//mDev_p->setConfigurationParameter(QCanBusDevice::BitRateKey, bus.speed);
|
||||
//But, you can probabaly set the speed of many of the other serialbus devices so go ahead and try
|
||||
mDev_p->setConfigurationParameter(QCanBusDevice::BitRateKey, bus.speed);
|
||||
|
||||
/* connect device */
|
||||
if (!mDev_p->connectDevice()) {
|
||||
@@ -115,8 +121,8 @@ bool SerialBusConnection::piSendFrame(const CANFrame& pFrame)
|
||||
|
||||
/* fill frame */
|
||||
QCanBusFrame frame;
|
||||
frame.setFrameId(pFrame.ID);
|
||||
frame.setExtendedFrameFormat(pFrame.extended);
|
||||
frame.setFrameId(pFrame.ID);
|
||||
if (pFrame.remote) {
|
||||
frame.setFrameType(QCanBusFrame::FrameType::RemoteRequestFrame);
|
||||
} else {
|
||||
@@ -137,8 +143,6 @@ bool SerialBusConnection::piSendFrame(const CANFrame& pFrame)
|
||||
void SerialBusConnection::disconnectDevice() {
|
||||
if(mDev_p) {
|
||||
mDev_p->disconnectDevice();
|
||||
delete mDev_p;
|
||||
mDev_p = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,13 +259,12 @@ void SerialBusConnection::framesReceived()
|
||||
|
||||
|
||||
void SerialBusConnection::testConnection() {
|
||||
QCanBusDevice* dev_p = QCanBus::instance()->createDevice("socketcan", getPort());
|
||||
CANConStatus stats;
|
||||
|
||||
switch(getStatus())
|
||||
{
|
||||
case CANCon::CONNECTED:
|
||||
if (!dev_p || !dev_p->connectDevice()) {
|
||||
if (!mDev_p || mDev_p->state() == QCanBusDevice::UnconnectedState) {
|
||||
/* we have lost connectivity */
|
||||
disconnectDevice();
|
||||
|
||||
@@ -269,21 +272,18 @@ void SerialBusConnection::testConnection() {
|
||||
stats.conStatus = getStatus();
|
||||
stats.numHardwareBuses = mNumBuses;
|
||||
emit status(stats);
|
||||
piStop();
|
||||
}
|
||||
break;
|
||||
case CANCon::NOT_CONNECTED:
|
||||
if (dev_p && dev_p->connectDevice()) {
|
||||
if(!mDev_p) {
|
||||
/* try to reconnect */
|
||||
CANBus bus;
|
||||
if(getBusConfig(0, bus))
|
||||
{
|
||||
bus.setEnabled(true);
|
||||
setBusSettings(0, bus);
|
||||
}
|
||||
if (mDev_p && mDev_p->state() == QCanBusDevice::UnconnectedState) {
|
||||
/* try to reconnect */
|
||||
CANBus bus;
|
||||
if(getBusConfig(0, bus))
|
||||
{
|
||||
bus.setEnabled(true);
|
||||
setBusSettings(0, bus);
|
||||
}
|
||||
/* disconnect test instance */
|
||||
dev_p->disconnectDevice();
|
||||
|
||||
setStatus(CANCon::CONNECTED);
|
||||
stats.conStatus = getStatus();
|
||||
@@ -293,7 +293,4 @@ void SerialBusConnection::testConnection() {
|
||||
break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
if(dev_p)
|
||||
delete dev_p;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class SerialBusConnection : public CANConnection
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SerialBusConnection(QString portName);
|
||||
SerialBusConnection(QString portName, QString driverName);
|
||||
virtual ~SerialBusConnection();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -8,21 +8,22 @@
|
||||
#include <QApplication>
|
||||
#include <QPalette>
|
||||
#include "utility.h"
|
||||
#include "connections/canconmanager.h"
|
||||
|
||||
DBCHandler* DBCHandler::instance = NULL;
|
||||
DBCHandler* DBCHandler::instance = nullptr;
|
||||
|
||||
DBC_SIGNAL* DBCSignalHandler::findSignalByIdx(int idx)
|
||||
{
|
||||
if (sigs.count() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= sigs.count()) return NULL;
|
||||
if (sigs.count() == 0) return nullptr;
|
||||
if (idx < 0) return nullptr;
|
||||
if (idx >= sigs.count()) return nullptr;
|
||||
|
||||
return &sigs[idx];
|
||||
}
|
||||
|
||||
DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name)
|
||||
{
|
||||
if (sigs.count() == 0) return NULL;
|
||||
if (sigs.count() == 0) return nullptr;
|
||||
for (int i = 0; i < sigs.count(); i++)
|
||||
{
|
||||
if (sigs[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
@@ -30,7 +31,7 @@ DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name)
|
||||
return &sigs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DBCSignalHandler::addSignal(DBC_SIGNAL &sig)
|
||||
@@ -82,7 +83,7 @@ int DBCSignalHandler::getCount()
|
||||
|
||||
DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id)
|
||||
{
|
||||
if (messages.count() == 0) return NULL;
|
||||
if (messages.count() == 0) return nullptr;
|
||||
for (int i = 0; i < messages.count(); i++)
|
||||
{
|
||||
if (isJ1939Handler)
|
||||
@@ -115,20 +116,20 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DBC_MESSAGE* DBCMessageHandler::findMsgByIdx(int idx)
|
||||
{
|
||||
if (messages.count() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= messages.count()) return NULL;
|
||||
if (messages.count() == 0) return nullptr;
|
||||
if (idx < 0) return nullptr;
|
||||
if (idx >= messages.count()) return nullptr;
|
||||
return &messages[idx];
|
||||
}
|
||||
|
||||
DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name)
|
||||
{
|
||||
if (messages.count() == 0) return NULL;
|
||||
if (messages.count() == 0) return nullptr;
|
||||
for (int i = 0; i < messages.count(); i++)
|
||||
{
|
||||
if (messages[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
@@ -136,7 +137,7 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name)
|
||||
return &messages[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg)
|
||||
@@ -251,14 +252,14 @@ DBCFile& DBCFile::operator=(const DBCFile& cpy)
|
||||
|
||||
DBC_NODE* DBCFile::findNodeByIdx(int idx)
|
||||
{
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= dbc_nodes.count()) return NULL;
|
||||
if (idx < 0) return nullptr;
|
||||
if (idx >= dbc_nodes.count()) return nullptr;
|
||||
return &dbc_nodes[idx];
|
||||
}
|
||||
|
||||
DBC_NODE* DBCFile::findNodeByName(QString name)
|
||||
{
|
||||
if (dbc_nodes.length() == 0) return NULL;
|
||||
if (dbc_nodes.length() == 0) return nullptr;
|
||||
for (int i = 0; i < dbc_nodes.length(); i++)
|
||||
{
|
||||
if (dbc_nodes[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
@@ -266,7 +267,7 @@ DBC_NODE* DBCFile::findNodeByName(QString name)
|
||||
return &dbc_nodes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString DBCFile::getFullFilename()
|
||||
@@ -291,14 +292,15 @@ int DBCFile::getAssocBus()
|
||||
|
||||
void DBCFile::setAssocBus(int bus)
|
||||
{
|
||||
int numBuses = CANConManager::getInstance()->getNumBuses();
|
||||
if (bus < -1) return;
|
||||
if (bus > 1) return;
|
||||
if (bus >= numBuses) return;
|
||||
assocBuses = bus;
|
||||
}
|
||||
|
||||
DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name)
|
||||
{
|
||||
if (dbc_attributes.length() == 0) return NULL;
|
||||
if (dbc_attributes.length() == 0) return nullptr;
|
||||
for (int i = 0; i < dbc_attributes.length(); i++)
|
||||
{
|
||||
if (dbc_attributes[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
@@ -306,13 +308,13 @@ DBC_ATTRIBUTE *DBCFile::findAttributeByName(QString name)
|
||||
return &dbc_attributes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DBC_ATTRIBUTE *DBCFile::findAttributeByIdx(int idx)
|
||||
{
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= dbc_attributes.count()) return NULL;
|
||||
if (idx < 0) return nullptr;
|
||||
if (idx >= dbc_attributes.count()) return nullptr;
|
||||
return &dbc_attributes[idx];
|
||||
}
|
||||
|
||||
@@ -345,8 +347,9 @@ DBC_MESSAGE* DBCFile::parseMessageLine(QString line)
|
||||
DBC_MESSAGE msg;
|
||||
msg.ID = match.captured(1).toULong() & 0x7FFFFFFFul; //the ID is always stored in decimal format
|
||||
msg.name = match.captured(2);
|
||||
msg.len = match.captured(3).toInt();
|
||||
msg.len = match.captured(3).toUInt();
|
||||
msg.sender = findNodeByName(match.captured(4));
|
||||
if (!msg.sender) msg.sender = findNodeByIdx(0);
|
||||
messageHandler->addMessage(msg);
|
||||
msgPtr = messageHandler->findMsgByID(msg.ID);
|
||||
}
|
||||
@@ -450,9 +453,12 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg)
|
||||
if (match.captured(11 + offset).contains(','))
|
||||
{
|
||||
QString tmp = match.captured(11 + offset).split(',')[0];
|
||||
sig.receiver = findNodeByName(tmp);
|
||||
sig.receiver = findNodeByName(tmp);
|
||||
}
|
||||
else sig.receiver = findNodeByName(match.captured(11 + offset));
|
||||
|
||||
if (!sig.receiver) sig.receiver = findNodeByIdx(0); //apply default if there was no match
|
||||
|
||||
sig.parentMessage = msg;
|
||||
msg->sigHandler->addSignal(sig);
|
||||
if (isMultiplexor) msg->multiplexorSignal = msg->sigHandler->findSignalByName(sig.name);
|
||||
@@ -476,11 +482,11 @@ bool DBCFile::parseValueLine(QString line)
|
||||
if (match.hasMatch())
|
||||
{
|
||||
//qDebug() << "Data was: " << match.captured(3);
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
|
||||
if (msg != NULL)
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
|
||||
if (msg != nullptr)
|
||||
{
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
|
||||
if (sig != NULL)
|
||||
if (sig != nullptr)
|
||||
{
|
||||
QString tokenString = match.captured(3);
|
||||
DBC_VAL_ENUM_ENTRY val;
|
||||
@@ -525,7 +531,7 @@ bool DBCFile::parseAttributeLine(QString line)
|
||||
if (foundAttr)
|
||||
{
|
||||
qDebug() << "That attribute does exist";
|
||||
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toInt());
|
||||
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toUInt());
|
||||
if (foundMsg)
|
||||
{
|
||||
qDebug() << "It references a valid, registered message";
|
||||
@@ -557,7 +563,7 @@ bool DBCFile::parseAttributeLine(QString line)
|
||||
if (foundAttr)
|
||||
{
|
||||
qDebug() << "That attribute does exist";
|
||||
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toInt());
|
||||
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toUInt());
|
||||
if (foundMsg)
|
||||
{
|
||||
qDebug() << "It references a valid, registered message";
|
||||
@@ -662,7 +668,7 @@ void DBCFile::loadFile(QString fileName)
|
||||
QString line, rawLine;
|
||||
QRegularExpression regex;
|
||||
QRegularExpressionMatch match;
|
||||
DBC_MESSAGE *currentMessage = NULL;
|
||||
DBC_MESSAGE *currentMessage = nullptr;
|
||||
DBC_ATTRIBUTE attr;
|
||||
int numSigFaults = 0, numMsgFaults = 0;
|
||||
|
||||
@@ -746,11 +752,11 @@ void DBCFile::loadFile(QString fileName)
|
||||
if (match.hasMatch())
|
||||
{
|
||||
//qDebug() << "Comment was: " << match.captured(3);
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
|
||||
if (msg != NULL)
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
|
||||
if (msg != nullptr)
|
||||
{
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
|
||||
if (sig != NULL)
|
||||
if (sig != nullptr)
|
||||
{
|
||||
sig->comment = match.captured(3);
|
||||
}
|
||||
@@ -767,8 +773,8 @@ void DBCFile::loadFile(QString fileName)
|
||||
if (match.hasMatch())
|
||||
{
|
||||
//qDebug() << "Comment was: " << match.captured(2);
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
|
||||
if (msg != NULL)
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt());
|
||||
if (msg != nullptr)
|
||||
{
|
||||
msg->comment = match.captured(2);
|
||||
}
|
||||
@@ -785,7 +791,7 @@ void DBCFile::loadFile(QString fileName)
|
||||
{
|
||||
//qDebug() << "Comment was: " << match.captured(2);
|
||||
DBC_NODE *node = findNodeByName(match.captured(1));
|
||||
if (node != NULL)
|
||||
if (node != nullptr)
|
||||
{
|
||||
node->comment = match.captured(2);
|
||||
}
|
||||
@@ -1036,6 +1042,9 @@ bool DBCFile::parseAttribute(QString inpString, DBC_ATTRIBUTE &attr)
|
||||
|
||||
void DBCFile::saveFile(QString fileName)
|
||||
{
|
||||
int nodeNumber = 1;
|
||||
int msgNumber = 1;
|
||||
int sigNumber = 1;
|
||||
QFile *outFile = new QFile(fileName);
|
||||
QString nodesOutput, msgOutput, commentsOutput, valuesOutput;
|
||||
QString defaultsOutput, attrValOutput;
|
||||
@@ -1089,6 +1098,11 @@ void DBCFile::saveFile(QString fileName)
|
||||
DBC_NODE node = dbc_nodes[x];
|
||||
if (node.name.compare("Vector__XXX", Qt::CaseInsensitive) != 0)
|
||||
{
|
||||
if (node.name.length() < 1) //detect an empty string and fill it out with something
|
||||
{
|
||||
node.name = "NODE" + QString::number(nodeNumber);
|
||||
nodeNumber++;
|
||||
}
|
||||
nodesOutput.append(node.name + " ");
|
||||
if (node.comment.length() > 0)
|
||||
{
|
||||
@@ -1119,6 +1133,12 @@ void DBCFile::saveFile(QString fileName)
|
||||
{
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x);
|
||||
|
||||
if (msg->name.length() < 1) //detect an empty string and fill it out with something
|
||||
{
|
||||
msg->name = "MSG" + QString::number(msgNumber);
|
||||
msgNumber++;
|
||||
}
|
||||
|
||||
msgOutput.append("BO_ " + QString::number(msg->ID) + " " + msg->name + ": " + QString::number(msg->len) +
|
||||
" " + msg->sender->name + "\n");
|
||||
if (msg->comment.length() > 0)
|
||||
@@ -1146,6 +1166,13 @@ void DBCFile::saveFile(QString fileName)
|
||||
for (int s = 0; s < msg->sigHandler->getCount(); s++)
|
||||
{
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(s);
|
||||
|
||||
if (sig->name.length() < 1) //detect an empty string and fill it out with something
|
||||
{
|
||||
sig->name = "SIG" + QString::number(sigNumber);
|
||||
sigNumber++;
|
||||
}
|
||||
|
||||
msgOutput.append(" SG_ " + sig->name);
|
||||
|
||||
if (sig->isMultiplexor) msgOutput.append(" M");
|
||||
@@ -1399,7 +1426,7 @@ DBCFile* DBCHandler::loadDBCFile(int idx)
|
||||
return &loadedFiles.last();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DBCHandler::removeDBCFile(int idx)
|
||||
@@ -1439,10 +1466,10 @@ DBC_MESSAGE* DBCHandler::findMessage(const CANFrame &frame)
|
||||
if (loadedFiles[i].getAssocBus() == -1 || frame.bus == (unsigned int)loadedFiles[i].getAssocBus())
|
||||
{
|
||||
DBC_MESSAGE* msg = loadedFiles[i].messageHandler->findMsgByID(frame.ID);
|
||||
if (msg != NULL) return msg;
|
||||
if (msg != nullptr) return msg;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int DBCHandler::getFileCount()
|
||||
@@ -1452,15 +1479,15 @@ int DBCHandler::getFileCount()
|
||||
|
||||
DBCFile* DBCHandler::getFileByIdx(int idx)
|
||||
{
|
||||
if (loadedFiles.count() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= loadedFiles.count()) return NULL;
|
||||
if (loadedFiles.count() == 0) return nullptr;
|
||||
if (idx < 0) return nullptr;
|
||||
if (idx >= loadedFiles.count()) return nullptr;
|
||||
return &loadedFiles[idx];
|
||||
}
|
||||
|
||||
DBCFile* DBCHandler::getFileByName(QString name)
|
||||
{
|
||||
if (loadedFiles.count() == 0) return NULL;
|
||||
if (loadedFiles.count() == 0) return nullptr;
|
||||
for (int i = 0; i < loadedFiles.count(); i++)
|
||||
{
|
||||
if (loadedFiles[i].getFilename().compare(name, Qt::CaseInsensitive) == 0)
|
||||
@@ -1468,7 +1495,7 @@ DBCFile* DBCHandler::getFileByName(QString name)
|
||||
return &loadedFiles[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DBCHandler::DBCHandler()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "ui_dbcloadsavewindow.h"
|
||||
#include <QCheckBox>
|
||||
#include "helpwindow.h"
|
||||
#include "connections/canconmanager.h"
|
||||
|
||||
DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@@ -34,6 +35,7 @@ DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *p
|
||||
connect(ui->tableFiles, &QTableWidget::cellDoubleClicked, this, &DBCLoadSaveWindow::cellDoubleClicked);
|
||||
|
||||
editorWindow = new DBCMainEditor(frames);
|
||||
currentlyEditingFile = nullptr;
|
||||
|
||||
installEventFilter(this);
|
||||
}
|
||||
@@ -108,10 +110,25 @@ void DBCLoadSaveWindow::saveFile()
|
||||
|
||||
void DBCLoadSaveWindow::removeFile()
|
||||
{
|
||||
bool bContinue = true;
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
if (idx < 0) return;
|
||||
dbcHandler->removeDBCFile(idx);
|
||||
ui->tableFiles->removeRow(idx);
|
||||
|
||||
if (currentlyEditingFile == dbcHandler->getFileByIdx(idx))
|
||||
{
|
||||
bContinue = false;
|
||||
QMessageBox::StandardButton confirmDialog;
|
||||
confirmDialog = QMessageBox::question(this, "Confirm Deletion", "This DBC is currently open for editing.\nMake sure you've saved any changes!\nAre you sure you want to remove this DBC?",
|
||||
QMessageBox::Yes|QMessageBox::No);
|
||||
if (confirmDialog == QMessageBox::Yes) bContinue = true;
|
||||
}
|
||||
|
||||
if (bContinue)
|
||||
{
|
||||
editorWindow->close();
|
||||
dbcHandler->removeDBCFile(idx);
|
||||
ui->tableFiles->removeRow(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::moveUp()
|
||||
@@ -146,7 +163,8 @@ void DBCLoadSaveWindow::cellChanged(int row, int col)
|
||||
{
|
||||
DBCFile *file = dbcHandler->getFileByIdx(row);
|
||||
int bus = ui->tableFiles->item(row, col)->text().toInt();
|
||||
if (bus > -2 && bus < 2)
|
||||
int numBuses = CANConManager::getInstance()->getNumBuses();
|
||||
if (bus > -2 && bus < numBuses)
|
||||
{
|
||||
file->setAssocBus(bus);
|
||||
}
|
||||
@@ -185,6 +203,7 @@ void DBCLoadSaveWindow::cellChanged(int row, int col)
|
||||
void DBCLoadSaveWindow::cellDoubleClicked(int row, int col)
|
||||
{
|
||||
Q_UNUSED(col)
|
||||
currentlyEditingFile = dbcHandler->getFileByIdx(row);
|
||||
editorWindow->setFileIdx(row);
|
||||
editorWindow->show();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ private slots:
|
||||
private:
|
||||
Ui::DBCLoadSaveWindow *ui;
|
||||
DBCHandler *dbcHandler;
|
||||
DBCFile *currentlyEditingFile;
|
||||
const QVector<CANFrame> *referenceFrames;
|
||||
DBCMainEditor *editorWindow;
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ void DBCMainEditor::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
writeSettings();
|
||||
sigEditor->close();
|
||||
}
|
||||
|
||||
void DBCMainEditor::readSettings()
|
||||
@@ -153,7 +154,7 @@ void DBCMainEditor::deleteCurrentNode()
|
||||
int thisRow = ui->NodesTable->currentRow();
|
||||
QString nodeName = ui->NodesTable->item(thisRow, 0)->text();
|
||||
if (nodeName.length() > 0 && nodeName.compare("Vector__XXX", Qt::CaseInsensitive) != 0)
|
||||
{
|
||||
{
|
||||
ui->NodesTable->removeRow(thisRow);
|
||||
dbcFile->dbc_nodes.removeAt(thisRow);
|
||||
inhibitCellChanged = true;
|
||||
@@ -283,6 +284,9 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
newMsg.name = "";
|
||||
newMsg.sender = node;
|
||||
newMsg.len = 0;
|
||||
newMsg.fgColor = ui->MessagesTable->item(row, 4)->backgroundColor();
|
||||
newMsg.bgColor = ui->MessagesTable->item(row, 5)->backgroundColor();
|
||||
|
||||
for (int i = 0; i < referenceFrames->length(); i++)
|
||||
{
|
||||
if ((uint) referenceFrames->at(i).ID == msgID)
|
||||
@@ -547,7 +551,7 @@ void DBCMainEditor::insertBlankRow()
|
||||
{
|
||||
QTableWidgetItem *item = new QTableWidgetItem("");
|
||||
if (i == 4) item->setBackgroundColor(QApplication::palette().color(QPalette::WindowText)); //foreground color
|
||||
//if (i == 5) item->setBackgroundColor(ui->MessagesTable->palette().color(ui->MessagesTable->backgroundRole())); //background color
|
||||
if (i == 5) item->setBackgroundColor(QApplication::palette().color(QPalette::Base));
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
ui->MessagesTable->setItem(rowIdx, i, item);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,8 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
|
||||
[=]()
|
||||
{
|
||||
if (currentSignal == NULL) return;
|
||||
currentSignal->name = ui->txtName->text().simplified().replace(' ', '_');
|
||||
QString tempNameStr = ui->txtName->text().simplified().replace(' ', '_');
|
||||
if (tempNameStr.length() > 0) currentSignal->name = tempNameStr;
|
||||
//need to update the list too.
|
||||
ui->signalsList->currentItem()->setText(currentSignal->name);
|
||||
});
|
||||
@@ -256,7 +257,7 @@ void DBCSignalEditor::readSettings()
|
||||
QSettings settings;
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
resize(settings.value("DBCSignalEditor/WindowSize", QSize(800, 572)).toSize());
|
||||
resize(settings.value("DBCSignalEditor/WindowSize", QSize(1000, 600)).toSize());
|
||||
move(settings.value("DBCSignalEditor/WindowPos", QPoint(100, 100)).toPoint());
|
||||
}
|
||||
}
|
||||
@@ -371,8 +372,8 @@ void DBCSignalEditor::deleteCurrentSignal()
|
||||
{
|
||||
int currIdx = ui->signalsList->currentRow();
|
||||
|
||||
if(currIdx==ui->signalsList->count()-1)
|
||||
return;
|
||||
//if(currIdx==ui->signalsList->count()-1)
|
||||
//return;
|
||||
|
||||
if (currIdx > -1)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
make qthelp
|
||||
~/Qt/5.9.1/gcc_64/bin/qcollectiongenerator build/qthelp/SavvyCAN.qhcp
|
||||
~/Qt/5.9.1/gcc_64/bin/assistant -collectionFile build/qthelp/SavvyCAN.qhc
|
||||
~/Qt/5.12.1/gcc_64/bin/qcollectiongenerator build/qthelp/SavvyCAN.qhcp
|
||||
~/Qt/5.12.1/gcc_64/bin/assistant -collectionFile build/qthelp/SavvyCAN.qhc
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'SavvyCAN'
|
||||
copyright = u'2017, EVTV'
|
||||
copyright = u'2018, EVTV'
|
||||
author = u'Collin Kidder'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -55,9 +55,9 @@ author = u'Collin Kidder'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '181'
|
||||
version = '189'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '181'
|
||||
release = '189'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -5,32 +5,60 @@ Connection Window
|
||||
|
||||
.. image:: ./images/ConnectionWindow.png
|
||||
|
||||
The connection window is used to add, remove, and modify connections. At the moment it is possible to use any SocketCAN compatible device (in LINUX) and any GVRET compatible device in any of the supported operating systems.
|
||||
At this time GVRET compatible devices are: EVTVDue, EVTV CANDue (1.3/2/2.1/2.2), Teensy 3.1-3.6, Macchina M2.
|
||||
The connection window is used to add, remove, and modify connections. At the moment it is possible
|
||||
to use any QT SerialBus compatible device and any GVRET compatible device in any of the supported
|
||||
operating systems. SerialBus supports socketcan on linux, passthrough on Linux and Windows 32
|
||||
bit, and Vector, PeakCAN, and TinyCAN on supported OS's.
|
||||
|
||||
At this time GVRET compatible devices are: EVTVDue, EVTV CANDue (1.3/2/2.1/2.2),
|
||||
Teensy 3.1-3.6, Macchina M2, EVTV ESP32 Due.
|
||||
|
||||
|
||||
Connecting To A Dongle
|
||||
==============================
|
||||
|
||||
SavvyCAN is able to connect to GVRET compatible devices to capture new traffic. These devices will present as serial ports on the connected PC.
|
||||
To connect to a dongle select the proper serial port and click "Create New Connection". If a valid device is found on that serial port the first
|
||||
statusbar section will update and the currently set canbus speeds will show in the table at the left of the window. These speeds can then
|
||||
be changed by clicking on the speed (or otherwise selecting the cell in the table) and typing in a new value. Leaving the cell will update the speed to the new value. GVRET devices also support
|
||||
setting "listen only" on each bus. This mode causes the device to not acknowledge any traffic or try to modify the bus at all. It is as it says, a mode where you can only listen to whatever traffic
|
||||
is found on the bus. Some older GVRET devices supported a mode where you could change the second bus between single wire CAN and normal CAN. This is deprecated. However, newer GVRET devices have
|
||||
dedicated single wire CAN buses and the relevant bus will show the checkbox.
|
||||
SavvyCAN is able to connect to GVRET compatible devices to capture new traffic. These
|
||||
devices will present as serial ports on the connected PC.
|
||||
To connect to a dongle select the proper serial port and click "Create New Connection".
|
||||
If a valid device is found on that serial port the first statusbar section will update
|
||||
and the currently set canbus speeds will show in the table at the left of the window.
|
||||
These speeds can then be changed by clicking on the speed (or otherwise selecting the cell
|
||||
in the table) and typing in a new value. Leaving the cell will update the speed to the new
|
||||
value. GVRET devices also support setting "listen only" on each bus. This mode causes the
|
||||
device to not acknowledge any traffic or try to modify the bus at all. It is as it says,
|
||||
a mode where you can only listen to whatever traffic is found on the bus. Some older GVRET
|
||||
devices supported a mode where you could change the second bus between single wire CAN
|
||||
and normal CAN. This is deprecated. However, newer GVRET devices have dedicated single
|
||||
wire CAN buses and the relevant bus will show the checkbox.
|
||||
|
||||
SavvyCAN can also connect to SocketCAN devices in LINUX. Select "SocketCAN" as the connection type and then type in the device name. This should be just the same as you would provide to the can-utils
|
||||
programs. That is, do not enter /dev/can0 but rather can0. Then push "Create New Connection" and you should see the new connection in the table on the left of the window. Note that SocketCAN devices don't
|
||||
support changing the baud rate within a program. You must do this when you set up the connection via console commands. This is outside the scope of this documentation. Consult the SocketCAN documentation
|
||||
for details on configuring such devices.
|
||||
SavvyCAN can also connect to a wide variety of CAN hardware through the built-in QT
|
||||
SerialBus drivers. These drivers vary by operating system but support socketcan on LINUX
|
||||
and Vector tools on both LINUX and Windows. When you select "QT SerialBus Devices" you will
|
||||
get a list of device types supported. Select a device type and for most devices you should see
|
||||
the Port list fill out with all registered and valid ports for that driver. Socketcan devices, for
|
||||
instance, are automatically detected now. Then push "Create New Connection" and you should
|
||||
see the new connection in the table on the left of the window. Note that SocketCAN devices
|
||||
don't support changing the baud rate within a program. You must do this when you set up
|
||||
the connection via console commands. This is outside the scope of this documentation.
|
||||
Consult the SocketCAN documentation for details on configuring such devices.
|
||||
|
||||
The last connection option is "Remote Host." If you select this option then Port will change
|
||||
to a textbox. Enter the IP address of the remote (but still local to your LAN) IP address. Currently
|
||||
this works with EVTV ESP32 boards and M2 boards.
|
||||
|
||||
Debugging Connection Problems
|
||||
==============================
|
||||
GVRET devices present as serial ports and have significant configuration options. However, the ability to configure so many things and the ability to compile the firmware yourself both come as a
|
||||
double edged sword. They present many opportunities for things to go wrong. Because of this there is a debugging console present on the connection window. Click a bus in the table then click "Enable Console"
|
||||
to cause it to start logging serial traffic. From this console you can see what is going on. It shows what SavvyCAN is sending and what it is getting back. It has extended status messages that might help to narrow down
|
||||
what is going wrong. Additionally, if you're feeling adventurous you can send traffic to the serial device from the Send line. "Send Hex" accepts a set of hex values separated by spaces. "Send Text" will send the raw
|
||||
text you type on the line. GVRET traffic is ordinarily binary so "Send Text" won't work very well for that. But, there is also a text console possible on GVRET devices. If you connect to them with a serial program you can
|
||||
configure things via a text console. Type ? and follow it up with some form of line ending (Cr, Lf, CrLf, any will work).
|
||||
GVRET devices present as serial ports and have significant configuration options.
|
||||
However, the ability to configure so many things and the ability to compile the firmware
|
||||
yourself both come as a double edged sword. They present many opportunities for things
|
||||
to go wrong. Because of this there is a debugging console present on the connection window.
|
||||
Click a bus in the table then click "Enable Console" to cause it to start logging serial
|
||||
traffic. From this console you can see what is going on. It shows what SavvyCAN is sending
|
||||
and what it is getting back. It has extended status messages that might help to narrow down
|
||||
what is going wrong. Additionally, if you're feeling adventurous you can send traffic to
|
||||
the serial device from the Send line. "Send Hex" accepts a set of hex values separated
|
||||
by spaces. "Send Text" will send the raw text you type on the line. GVRET traffic is
|
||||
ordinarily binary so "Send Text" won't work very well for that. But, there is also a
|
||||
text console possible on GVRET devices. If you connect to them with a serial program you can
|
||||
configure things via a text console. Type ? and follow it up with some form of line
|
||||
ending (Cr, Lf, CrLf, any will work).
|
||||
|
||||
@@ -8,4 +8,12 @@ Frame Details Window
|
||||
The Purpose of Frame Details Window
|
||||
===================================
|
||||
|
||||
This window is used to get detailed statistics about frames. It provides information about a given frame ID across all frames with that ID. You can get such information as the number of frames, the number of data bytes that frame ID has, the average interval between frames with that ID, and the minimum and maximum interval. Also listed are detailed statistics for each data byte in that frame. Each byte has listed which bits changed, the range of values found, and a histogram both graphically (at the bottom of the window) and textually. The textual representation shows the number of times a specific value occurred. Also listed at the bottom is a histogram of each bit and how many times it was set. The graph is a histogram of all the bits and the number of times each bit was set. This can be used to quickly visually see where data has changed. All information can be saved to a text file for later analysis.
|
||||
This window is used to get detailed statistics about frames.
|
||||
|
||||
It provides information about a given frame ID across all frames with that ID. You can get such information as the number of frames, the number of data bytes that frame ID has, the average interval between frames with that ID, and the minimum and maximum interval.
|
||||
|
||||
Also listed are detailed statistics for each data byte in that frame. Each byte has listed which bits changed, the range of values found, and a histogram both graphically (at the righthand side of the window) and textually. The textual representation shows the number of times a specific value occurred.
|
||||
|
||||
The top right graph is a histogram of all the bits and the number of times each bit was set. This can be used to quickly visually see where data has changed.
|
||||
|
||||
The bottom right graph is of each individual byte as its value varies over time. All textual information can be saved to a text file for later analysis.
|
||||
|
||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 135 KiB |
@@ -1,5 +1,5 @@
|
||||
|
||||
Welcome to SavvyCAN V181 documentation!
|
||||
Welcome to SavvyCAN V189 documentation!
|
||||
=========================================
|
||||
|
||||
Contents:
|
||||
|
||||
@@ -8,11 +8,64 @@ Sniffer Window
|
||||
Using the Sniffer Window
|
||||
=========================
|
||||
|
||||
This window is essentially a graphical version of the linux can_utils. The general idea here is to display a list of frames such that you only see frames that are actively updating. If a given ID has not been seen in 4 seconds the ID portion will turn RED and then disappear from the list. In this way only frames that are updating are in the list. They are ordered by last update time. Bytes that have deincremented will be red and bytes that have incremented will be green. You can use the "Filters" area to mask away some IDs so that they never show up. This can help to declutter the list.
|
||||
This window is essentially a turbo charged graphical version of the linux
|
||||
can_utils program "cansniffer". The general idea here is to display a list
|
||||
of frames such that you only see frames that are actively updating. If a given
|
||||
ID has not been seen in 5 seconds the ID portion will turn RED and then disappear
|
||||
from the list. In this way only frames that are updating are in the list. They are
|
||||
ordered by ID. Bytes that have deincremented will be red and bytes that have incremented
|
||||
will be green. You can use the "Filters" area to mask away some IDs so that they never
|
||||
show up. This can help to declutter the list.
|
||||
|
||||
This window updates with a 200ms interval.
|
||||
|
||||
Notching and Unnotching
|
||||
========================
|
||||
|
||||
Honestly, I don't know. It seems that notching means to store the current value of the data bytes for each frame and then use that notch data for the comparison for increment / deincrement to color the bytes. Unnotching would then be clearing that out so that it uses the previous value from the last time the frame ID was seen. But, don't quote me on that. This should be figured out definitively and corrected.
|
||||
While the window is running it keeps a running list each 200ms cycle of all the bits that
|
||||
changed in that timespan. Each 200ms this list is backed up and reset. If you push the
|
||||
notch button the system will remember all the bits that were set in the last 200ms window
|
||||
and will not color the output if those bits are toggled in the future. They will thus somewhat
|
||||
be ignored except that you can visually still see them updating. If you click the Notch
|
||||
button repeatedly it will add any new changed bits to the old changed bits. In this way you
|
||||
can build up a set of bits to ignore. Un-notching causes all notched (ignored) bits to be
|
||||
reset and thus all changes will be colored once again.
|
||||
|
||||
Advanced Options
|
||||
==================
|
||||
|
||||
All of the above was valid if you do not check any of the four checkboxes. With the checkboxes
|
||||
unchecked this window is very close to cansniffer on the command line. But, what fun is that?
|
||||
These checkboxes modify the way the window works in a variety of ways.
|
||||
|
||||
Never Expire IDs
|
||||
==================
|
||||
|
||||
This checkbox will do exactly what it says on the tin. Instead of frame ID's expiring after
|
||||
5 seconds of inactivity they will stick around forever. This can be useful so that the ID you
|
||||
are watching doesn't jump up and down as IDs expire and potentially come back later on or new IDs
|
||||
are seen. With no expiration you will get a more consistent view of the IDs. You are still free
|
||||
to filter away IDs you are not interested in.
|
||||
|
||||
Mute notched bits
|
||||
===================
|
||||
|
||||
This checkbox might sound a bit strange. With this checked any bytes that you have notched will
|
||||
ignore any notched bits and not even change the display to update if only notched bits were changed.
|
||||
This completely hides all notched data. The view of the frames will then NOT perfectly or correctly
|
||||
represent the actual most up to date data for each ID. So, use this option with caution. But, it
|
||||
is handy when you are looking for a needle in a haystack and you don't want things changing if you've
|
||||
already told the program to notch them away.
|
||||
|
||||
Fade inactive bytes
|
||||
====================
|
||||
|
||||
This can be used with mute or without but has a similar purpose. When this is checked any bytes
|
||||
that haven't updated recently will begin to fade away to white. They never quite get all the way
|
||||
to disappearing but will fade to be very light. In this way only data which is actively changing will
|
||||
be very visible. This drastically aids in helping you to ignore any bytes that are not changing.
|
||||
|
||||
View Bits
|
||||
==========
|
||||
|
||||
This option changes the view very starkly. This is the view shown in the picture associated with this topic. When View Bits is selected the display will change to show each bit within the bytes as separate blocks that each can separately be black when set and unchanged, white when unset and unchanged, red when freshly unset, and green when freshly set. This allows for a very fine grained view. Fade inactive, and never expire still work as usual. This mode might be a bit "busy" and lowers the number of IDs you can see at once. But, the choice is yours. You give up some density in exchange for verbosity.
|
||||
|
||||
@@ -555,9 +555,9 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.bus = 0;
|
||||
if (line.at(28) == ' ') {
|
||||
thisFrame.extended = true;
|
||||
} else {
|
||||
thisFrame.extended = false;
|
||||
} else {
|
||||
thisFrame.extended = true;
|
||||
}
|
||||
|
||||
if (line.at(41) == 'R') {
|
||||
@@ -655,25 +655,28 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
|
||||
}
|
||||
if (inHeader) continue;
|
||||
if (line.length() > 2)
|
||||
{
|
||||
{
|
||||
QList<QByteArray> tokens = line.simplified().split(' ');
|
||||
thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0);
|
||||
thisFrame.ID = tokens[2].toUInt(NULL, 16);
|
||||
thisFrame.len = tokens[5].toUInt();
|
||||
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
|
||||
thisFrame.bus = tokens[1].toUInt();
|
||||
thisFrame.extended = (thisFrame.ID > 0x7FF);
|
||||
thisFrame.remote = false;
|
||||
for (unsigned int d = 6; d < (6 + thisFrame.len); d++)
|
||||
if (tokens.length() > 4)
|
||||
{
|
||||
if (tokens.count() > d)
|
||||
{
|
||||
thisFrame.data[d - 6] = tokens[d].toInt(NULL, 16);
|
||||
}
|
||||
else //expected byte wasn't there to read. Set it zero and set error flag
|
||||
thisFrame.timestamp = (uint32_t)(tokens[0].toFloat() * 1000000.0);
|
||||
thisFrame.ID = tokens[2].toUInt(NULL, 16);
|
||||
thisFrame.len = tokens[5].toUInt();
|
||||
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
|
||||
thisFrame.bus = tokens[1].toUInt();
|
||||
thisFrame.extended = (thisFrame.ID > 0x7FF);
|
||||
thisFrame.remote = false;
|
||||
for (unsigned int d = 6; d < (6 + thisFrame.len); d++)
|
||||
{
|
||||
if (tokens.count() > d)
|
||||
{
|
||||
thisFrame.data[d - 6] = tokens[d].toInt(NULL, 16);
|
||||
}
|
||||
else //expected byte wasn't there to read. Set it zero and set error flag
|
||||
{
|
||||
thisFrame.data[d - 6] = 0;
|
||||
foundErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
frames->append(thisFrame);
|
||||
|
||||
@@ -12,7 +12,8 @@ FramePlaybackObject::FramePlaybackObject()
|
||||
playbackActive = false;
|
||||
playbackForward = true;
|
||||
useOrigTiming = false;
|
||||
whichBusSend = -1;
|
||||
whichBusSend = 0;
|
||||
currentSeqItem = nullptr;
|
||||
}
|
||||
|
||||
FramePlaybackObject::~FramePlaybackObject()
|
||||
@@ -25,6 +26,12 @@ FramePlaybackObject::~FramePlaybackObject()
|
||||
quint64 FramePlaybackObject::updatePosition(bool forward)
|
||||
{
|
||||
//qDebug() << "updatePosition";
|
||||
if (!currentSeqItem) {
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
currentPosition = 0;
|
||||
return 0;
|
||||
}
|
||||
if (forward)
|
||||
{
|
||||
if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going
|
||||
@@ -231,6 +238,7 @@ void FramePlaybackObject::stepPlaybackForward()
|
||||
playbackActive = false;
|
||||
updatePosition(true);
|
||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
||||
emit statusUpdate(currentPosition);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::stepPlaybackBackward()
|
||||
@@ -248,6 +256,7 @@ void FramePlaybackObject::stepPlaybackBackward()
|
||||
|
||||
updatePosition(false);
|
||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
||||
emit statusUpdate(currentPosition);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::stopPlayback()
|
||||
@@ -262,6 +271,7 @@ void FramePlaybackObject::stopPlayback()
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
currentPosition = 0;
|
||||
emit statusUpdate(currentPosition);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::pausePlayback()
|
||||
@@ -275,6 +285,7 @@ void FramePlaybackObject::pausePlayback()
|
||||
|
||||
playbackActive = false;
|
||||
playbackTimer->stop();
|
||||
emit statusUpdate(currentPosition);
|
||||
}
|
||||
|
||||
void FramePlaybackObject::setSequenceObject(SequenceItem *item)
|
||||
@@ -289,6 +300,7 @@ void FramePlaybackObject::setUseOriginalTiming(bool state)
|
||||
|
||||
void FramePlaybackObject::setSendingBus(int bus)
|
||||
{
|
||||
qDebug() << "Setting sending bus to " << bus;
|
||||
whichBusSend = bus;
|
||||
}
|
||||
|
||||
|
||||
@@ -296,9 +296,14 @@ void FramePlaybackWindow::calculateWhichBus()
|
||||
{
|
||||
int idx = ui->comboCANBus->currentIndex();
|
||||
int maxIdx = ui->comboCANBus->count() - 1;
|
||||
if (maxIdx == 0) maxIdx = 2;
|
||||
int out = idx;
|
||||
|
||||
qDebug() << idx << "***" << maxIdx;
|
||||
|
||||
if (idx == (maxIdx - 1) ) out = -1;
|
||||
if (idx == maxIdx) out = -2;
|
||||
if (idx < 0) out = 0;
|
||||
|
||||
playbackObject.setSendingBus(out);
|
||||
}
|
||||
@@ -534,6 +539,7 @@ void FramePlaybackWindow::btnReverseClick()
|
||||
forward = false;
|
||||
isPlaying = true;
|
||||
playbackObject.startPlaybackBackward();
|
||||
updateFrameLabel();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnStopClick()
|
||||
@@ -554,7 +560,6 @@ void FramePlaybackWindow::btnStopClick()
|
||||
ui->tblSequence->setCurrentCell(0, 0);
|
||||
refreshIDList();
|
||||
}
|
||||
updateFrameLabel();
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnPlayClick()
|
||||
|
||||
@@ -820,6 +820,8 @@ void FrameSenderWindow::processCellChange(int line, int col)
|
||||
|
||||
sendingData[line].count = 0;
|
||||
|
||||
int numBuses = CANConManager::getInstance()->getNumBuses();
|
||||
|
||||
switch (col)
|
||||
{
|
||||
case 0: //Enable check box
|
||||
@@ -831,9 +833,9 @@ void FrameSenderWindow::processCellChange(int line, int col)
|
||||
qDebug() << "Setting enabled to " << sendingData[line].enabled;
|
||||
break;
|
||||
case 1: //Bus designation
|
||||
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text());
|
||||
if (tempVal < 0) tempVal = 0;
|
||||
if (tempVal > 1) tempVal = 1;
|
||||
tempVal = Utility::ParseStringToNum(ui->tableSender->item(line, 1)->text());
|
||||
if (tempVal < -1) tempVal = -1;
|
||||
if (tempVal >= numBuses) tempVal = numBuses - 1;
|
||||
sendingData[line].bus = tempVal;
|
||||
qDebug() << "Setting bus to " << tempVal;
|
||||
break;
|
||||
|
||||
@@ -67,7 +67,7 @@ HelpWindow* HelpWindow::getRef()
|
||||
void HelpWindow::showHelp(QString help)
|
||||
{
|
||||
if (m_helpEngine) {
|
||||
QString url = "qthelp://org.sphinx.savvycan.181/doc/" + help;
|
||||
QString url = "qthelp://org.sphinx.savvycan.189/doc/" + help;
|
||||
qDebug() << "Searching for " << url;
|
||||
QByteArray helpData = m_helpEngine->fileData(QUrl(url));
|
||||
qDebug() << "Help file size: " << helpData.length();
|
||||
|
||||
@@ -55,31 +55,34 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
readSettings();
|
||||
|
||||
QHeaderView *verticalHeader = ui->canFramesView->verticalHeader();
|
||||
verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
|
||||
verticalHeader->setDefaultSectionSize(10);
|
||||
QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader();
|
||||
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
|
||||
connect(HorzHdr, SIGNAL(sectionClicked(int)), this, SLOT(headerClicked(int)));
|
||||
|
||||
graphingWindow = NULL;
|
||||
frameInfoWindow = NULL;
|
||||
playbackWindow = NULL;
|
||||
flowViewWindow = NULL;
|
||||
frameSenderWindow = NULL;
|
||||
dbcMainEditor = NULL;
|
||||
comparatorWindow = NULL;
|
||||
settingsDialog = NULL;
|
||||
firmwareUploaderWindow = NULL;
|
||||
discreteStateWindow = NULL;
|
||||
connectionWindow = NULL;
|
||||
scriptingWindow = NULL;
|
||||
rangeWindow = NULL;
|
||||
dbcFileWindow = NULL;
|
||||
fuzzingWindow = NULL;
|
||||
udsScanWindow = NULL;
|
||||
motorctrlConfigWindow = NULL;
|
||||
isoWindow = NULL;
|
||||
snifferWindow = NULL;
|
||||
bisectWindow = NULL;
|
||||
signalViewerWindow = NULL;
|
||||
graphingWindow = nullptr;
|
||||
frameInfoWindow = nullptr;
|
||||
playbackWindow = nullptr;
|
||||
flowViewWindow = nullptr;
|
||||
frameSenderWindow = nullptr;
|
||||
dbcMainEditor = nullptr;
|
||||
comparatorWindow = nullptr;
|
||||
settingsDialog = nullptr;
|
||||
firmwareUploaderWindow = nullptr;
|
||||
discreteStateWindow = nullptr;
|
||||
connectionWindow = nullptr;
|
||||
scriptingWindow = nullptr;
|
||||
rangeWindow = nullptr;
|
||||
dbcFileWindow = nullptr;
|
||||
fuzzingWindow = nullptr;
|
||||
udsScanWindow = nullptr;
|
||||
motorctrlConfigWindow = nullptr;
|
||||
isoWindow = nullptr;
|
||||
snifferWindow = nullptr;
|
||||
bisectWindow = nullptr;
|
||||
signalViewerWindow = nullptr;
|
||||
dbcHandler = DBCHandler::getReference();
|
||||
bDirty = false;
|
||||
inhibitFilterUpdate = false;
|
||||
@@ -160,6 +163,10 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
temp.bus = 0;
|
||||
temp.ID = 0x100;
|
||||
temp.len = 0;
|
||||
temp.extended = false;
|
||||
temp.isReceived = true;
|
||||
temp.remote = false;
|
||||
temp.timestamp = 100000000;
|
||||
model->addFrame(temp, true);
|
||||
qApp->processEvents();
|
||||
tickGUIUpdate(); //force a GUI refresh so that the row exists to measure
|
||||
@@ -180,7 +187,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
ui->actionFirmware_Update->setVisible(false);
|
||||
ui->actionMotorControlConfig->setVisible(false);
|
||||
ui->actionSignal_Viewer->setVisible(false);
|
||||
//ui->actionSingle_Multi_State_2->setVisible(false);
|
||||
ui->actionSingle_Multi_State_2->setVisible(false);
|
||||
|
||||
installEventFilter(this);
|
||||
}
|
||||
@@ -293,7 +300,7 @@ void MainWindow::readSettings()
|
||||
ui->canFramesView->setColumnWidth(5, settings.value("Main/BusColumn", 40).toUInt()); //bus
|
||||
ui->canFramesView->setColumnWidth(6, settings.value("Main/LengthColumn", 40).toUInt()); //length
|
||||
ui->canFramesView->setColumnWidth(7, settings.value("Main/AsciiColumn", 50).toUInt()); //ascii
|
||||
ui->canFramesView->setColumnWidth(8, settings.value("Main/DataColumn", 225).toUInt()); //data
|
||||
//ui->canFramesView->setColumnWidth(8, settings.value("Main/DataColumn", 225).toUInt()); //data
|
||||
}
|
||||
if (settings.value("Main/AutoScroll", false).toBool())
|
||||
{
|
||||
@@ -338,7 +345,7 @@ void MainWindow::writeSettings()
|
||||
settings.setValue("Main/BusColumn", ui->canFramesView->columnWidth(5));
|
||||
settings.setValue("Main/LengthColumn", ui->canFramesView->columnWidth(6));
|
||||
settings.setValue("Main/AsciiColumn", ui->canFramesView->columnWidth(7));
|
||||
settings.setValue("Main/DataColumn", ui->canFramesView->columnWidth(8));
|
||||
//settings.setValue("Main/DataColumn", ui->canFramesView->columnWidth(8));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,11 +394,22 @@ void MainWindow::gridDoubleClicked(QModelIndex idx)
|
||||
void MainWindow::interpretToggled(bool state)
|
||||
{
|
||||
model->setInterpetMode(state);
|
||||
//ui->canFramesView->resizeRowsToContents(); //a VERY costly operation!
|
||||
}
|
||||
|
||||
void MainWindow::overwriteToggled(bool state)
|
||||
{
|
||||
model->setOverwriteMode(state);
|
||||
if (state)
|
||||
{
|
||||
QMessageBox::StandardButton confirmDialog;
|
||||
confirmDialog = QMessageBox::question(this, "Danger Will Robinson", "Enabling Overwrite mode will\ndelete your captured frames\nand replace them with one\nframe per ID.\n\nAre you ready to do that?",
|
||||
QMessageBox::Yes|QMessageBox::No);
|
||||
if (confirmDialog == QMessageBox::Yes)
|
||||
{
|
||||
model->setOverwriteMode(state);
|
||||
}
|
||||
else ui->cbOverwrite->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateFilterList()
|
||||
@@ -466,7 +484,7 @@ void MainWindow::tickGUIUpdate()
|
||||
framesPerSec = 0;
|
||||
|
||||
ui->lbNumFrames->setText(QString::number(model->rowCount()));
|
||||
if (allowCapture && ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
||||
if (rxFrames > 0 && /*allowCapture && */ ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
||||
ui->lbFPS->setText(QString::number(framesPerSec));
|
||||
if (rxFrames > 0)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "helpwindow.h"
|
||||
#include <QtDebug>
|
||||
|
||||
const QColor FrameInfoWindow::byteGraphColors[8] = {Qt::blue, Qt::green, Qt::black, Qt::red, //0 1 2 3
|
||||
Qt::gray, Qt::yellow, Qt::cyan, Qt::darkMagenta}; //4 5 6 7
|
||||
QPen FrameInfoWindow::bytePens[8];
|
||||
|
||||
FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FrameInfoWindow)
|
||||
@@ -32,19 +36,40 @@ FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *paren
|
||||
|
||||
ui->graphHistogram->legend->setVisible(false);
|
||||
|
||||
ui->graphBytes->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes |
|
||||
QCP::iSelectLegend | QCP::iSelectPlottables);
|
||||
|
||||
ui->graphBytes->xAxis->setRange(0, 63);
|
||||
ui->graphBytes->yAxis->setRange(0, 265);
|
||||
ui->graphBytes->axisRect()->setupFullAxesBox();
|
||||
|
||||
ui->graphBytes->xAxis->setLabel("Time");
|
||||
ui->graphBytes->yAxis->setLabel("Value");
|
||||
|
||||
ui->graphBytes->legend->setVisible(false);
|
||||
|
||||
if (useOpenGL)
|
||||
{
|
||||
ui->graphHistogram->setAntialiasedElements(QCP::aeAll);
|
||||
//ui->graphingView->setNoAntialiasingOnDrag(true);
|
||||
ui->graphHistogram->setOpenGl(true);
|
||||
ui->graphBytes->setAntialiasedElements(QCP::aeAll);
|
||||
ui->graphBytes->setOpenGl(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->graphHistogram->setOpenGl(false);
|
||||
ui->graphHistogram->setAntialiasedElements(QCP::aeNone);
|
||||
ui->graphBytes->setOpenGl(false);
|
||||
ui->graphBytes->setAntialiasedElements(QCP::aeNone);
|
||||
}
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
bytePens[i].setColor(byteGraphColors[i]);
|
||||
bytePens[i].setWidth(1);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameInfoWindow::showEvent(QShowEvent* event)
|
||||
@@ -94,7 +119,7 @@ void FrameInfoWindow::readSettings()
|
||||
QSettings settings;
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
resize(settings.value("FrameInfo/WindowSize", QSize(794, 494)).toSize());
|
||||
resize(settings.value("FrameInfo/WindowSize", QSize(794, 694)).toSize());
|
||||
move(settings.value("FrameInfo/WindowPos", QPoint(50, 50)).toPoint());
|
||||
}
|
||||
useOpenGL = settings.value("Main/UseOpenGL", false).toBool();
|
||||
@@ -188,7 +213,8 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
int maxData[8];
|
||||
int dataHistogram[256][8];
|
||||
int bitfieldHistogram[64];
|
||||
QVector<double> graphX, graphY;
|
||||
QVector<double> histGraphX, histGraphY;
|
||||
QVector<double> byteGraphX, byteGraphY[8];
|
||||
double maxY = -1000.0;
|
||||
uint8_t changedBits[8];
|
||||
uint8_t referenceBits[8];
|
||||
@@ -248,7 +274,7 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
baseNode->addChild(tempItem);
|
||||
|
||||
tempItem = new QTreeWidgetItem();
|
||||
tempItem->setText(0, tr("PGN: ") + Utility::formatNumber(jid.pgn));
|
||||
tempItem->setText(0, tr("PGN: ") + Utility::formatNumber(jid.pgn) + "(" + QString::number(jid.pgn) + ")");
|
||||
baseNode->addChild(tempItem);
|
||||
|
||||
tempItem = new QTreeWidgetItem();
|
||||
@@ -287,6 +313,12 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
//then find all data points
|
||||
for (int j = 0; j < frameCache.count(); j++)
|
||||
{
|
||||
byteGraphX.append(j);
|
||||
for (int bytcnt = 0; bytcnt < frameCache[j].len; bytcnt++)
|
||||
{
|
||||
byteGraphY[bytcnt].append(frameCache[j].data[bytcnt]);
|
||||
}
|
||||
|
||||
if (j != 0)
|
||||
{
|
||||
thisInterval = (frameCache[j].timestamp - frameCache[j-1].timestamp);
|
||||
@@ -381,16 +413,17 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
+ QString::number(c % 8) + ") :" + QString::number(bitfieldHistogram[c]));
|
||||
|
||||
dataBase->addChild(tempItem);
|
||||
graphX.append(c);
|
||||
graphY.append(bitfieldHistogram[c]);
|
||||
histGraphX.append(c);
|
||||
histGraphY.append(bitfieldHistogram[c]);
|
||||
if (bitfieldHistogram[c] > maxY) maxY = bitfieldHistogram[c];
|
||||
}
|
||||
baseNode->addChild(dataBase);
|
||||
|
||||
ui->treeDetails->insertTopLevelItem(0, baseNode);
|
||||
|
||||
ui->graphHistogram->clearGraphs();
|
||||
ui->graphHistogram->addGraph();
|
||||
ui->graphHistogram->graph()->setData(graphX, graphY);
|
||||
ui->graphHistogram->graph()->setData(histGraphX, histGraphY);
|
||||
ui->graphHistogram->graph()->setLineStyle(QCPGraph::lsStepLeft); //connect points with lines
|
||||
QBrush graphBrush;
|
||||
graphBrush.setColor(Qt::red);
|
||||
@@ -400,6 +433,16 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
ui->graphHistogram->yAxis->setRange(0, maxY * 1.02);
|
||||
ui->graphHistogram->axisRect()->setupFullAxesBox();
|
||||
ui->graphHistogram->replot();
|
||||
|
||||
ui->graphBytes->clearGraphs();
|
||||
for (int graphs = 0; graphs < 8; graphs++)
|
||||
{
|
||||
ui->graphBytes->addGraph();
|
||||
ui->graphBytes->graph()->setData(byteGraphX, byteGraphY[graphs]);
|
||||
ui->graphBytes->graph()->setPen(bytePens[graphs]);
|
||||
}
|
||||
ui->graphBytes->xAxis->setRange(0, byteGraphX.count());
|
||||
ui->graphBytes->replot();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@ private:
|
||||
QList<CANFrame> frameCache;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
bool useOpenGL;
|
||||
static const QColor byteGraphColors[8];
|
||||
static QPen bytePens[8];
|
||||
|
||||
void refreshIDList();
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
@@ -696,7 +696,7 @@ void GraphingWindow::saveSpreadsheet()
|
||||
*/
|
||||
|
||||
QList<GraphParams>::iterator iter;
|
||||
double xMin = 1000000000, xMax=-1000000000;
|
||||
double xMin = 10000000000000, xMax=-10000000000000;
|
||||
int maxCount = 0;
|
||||
int numGraphs = 0;
|
||||
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
|
||||
@@ -732,6 +732,7 @@ void GraphingWindow::saveSpreadsheet()
|
||||
for (int j = 1; j < (maxCount - 1); j++)
|
||||
{
|
||||
currentX = xMin + (j * sliceSize);
|
||||
qDebug() << "X: " << currentX;
|
||||
outFile->write(QString::number(currentX).toUtf8());
|
||||
for (int k = 0; k < graphParams.count(); k++)
|
||||
{
|
||||
@@ -764,9 +765,10 @@ void GraphingWindow::saveSpreadsheet()
|
||||
double span = graphParams[k].x[indices[k] + 1] - graphParams[k].x[indices[k]];
|
||||
double progress = (currentX - graphParams[k].x[indices[k]]) / span;
|
||||
value = Utility::Lerp(graphParams[k].y[indices[k]], graphParams[k].y[indices[k] + 1], progress);
|
||||
qDebug() << "Span: " << span << " Prog: " << progress << " Value: " << value;
|
||||
}
|
||||
|
||||
if (currentX >= graphParams[k].x[indices[k] + 1]) indices[k]++;
|
||||
if (currentX >= graphParams[k].x[indices[k]]) indices[k]++;
|
||||
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(value).toUtf8());
|
||||
@@ -845,7 +847,7 @@ void GraphingWindow::loadDefinitions()
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("Graph definition (*.gdf)")));
|
||||
|
||||
if (dbcHandler == NULL) return;
|
||||
if (dbcHandler == nullptr) return;
|
||||
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
@@ -871,11 +873,14 @@ void GraphingWindow::loadDefinitions()
|
||||
|
||||
if (tokens[0] == "X") //newest format based around signals
|
||||
{
|
||||
gp.ID = tokens[1].toInt(NULL, 16);
|
||||
gp.mask = tokens[2].toULongLong(NULL, 16);
|
||||
gp.ID = tokens[1].toUInt(nullptr, 16);
|
||||
gp.mask = tokens[2].toULongLong(nullptr, 16);
|
||||
gp.startBit = tokens[3].toInt();
|
||||
if (gp.startBit < 0) gp.intelFormat = false;
|
||||
else gp.intelFormat = true;
|
||||
if (gp.startBit < 0) {
|
||||
gp.intelFormat = false;
|
||||
gp.startBit *= -1;
|
||||
}
|
||||
else gp.intelFormat = true;
|
||||
gp.numBits = tokens[4].toInt();
|
||||
if (tokens[5] == "Y") gp.isSigned = true;
|
||||
else gp.isSigned = false;
|
||||
@@ -894,18 +899,18 @@ void GraphingWindow::loadDefinitions()
|
||||
}
|
||||
else //one of the two older formats then
|
||||
{
|
||||
gp.ID = tokens[0].toInt(NULL, 16);
|
||||
gp.ID = tokens[0].toUInt(nullptr, 16);
|
||||
if (tokens[1] == "S") //old signal based graph definition
|
||||
{
|
||||
//tokens[2] is the signal name. Need to use the message ID and this name to look it up
|
||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(gp.ID);
|
||||
if (msg != NULL)
|
||||
if (msg != nullptr)
|
||||
{
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]);
|
||||
if (sig)
|
||||
{
|
||||
gp.mask = 0xFFFFFFFF;
|
||||
gp.bias = sig->bias;
|
||||
gp.bias = (float)sig->bias;
|
||||
gp.color.setRed(tokens[3].toInt());
|
||||
gp.color.setGreen(tokens[4].toInt());
|
||||
gp.color.setBlue(tokens[5].toInt());
|
||||
@@ -914,7 +919,7 @@ void GraphingWindow::loadDefinitions()
|
||||
if (sig->valType == SIGNED_INT) gp.isSigned = true;
|
||||
else gp.isSigned = false;
|
||||
gp.numBits = sig->signalSize;
|
||||
gp.scale = sig->factor;
|
||||
gp.scale = (float)sig->factor;
|
||||
gp.startBit = sig->startBit;
|
||||
gp.stride = 1;
|
||||
createGraph(gp, true);
|
||||
@@ -926,7 +931,7 @@ void GraphingWindow::loadDefinitions()
|
||||
//hard part - this all changed drastically
|
||||
//the difference between intel and motorola format is whether
|
||||
//start is larger than end byte or not.
|
||||
uint64_t oldMask = tokens[1].toULongLong(NULL, 16);
|
||||
uint64_t oldMask = tokens[1].toULongLong(nullptr, 16);
|
||||
int oldStart = tokens[2].toInt();
|
||||
int oldEnd = tokens[3].toInt();
|
||||
|
||||
|
||||
@@ -179,6 +179,7 @@ void ISOTP_InterpreterWindow::updatedFrames(int numFrames)
|
||||
|
||||
void ISOTP_InterpreterWindow::headerClicked(int logicalIndex)
|
||||
{
|
||||
ui->tableIsoFrames->setSortingEnabled(false);
|
||||
ui->tableIsoFrames->sortByColumn(logicalIndex);
|
||||
}
|
||||
|
||||
@@ -261,9 +262,13 @@ void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE msg)
|
||||
messages.append(msg);
|
||||
|
||||
rowNum = ui->tableIsoFrames->rowCount();
|
||||
|
||||
ui->tableIsoFrames->insertRow(rowNum);
|
||||
|
||||
ui->tableIsoFrames->setItem(rowNum, 0, new QTableWidgetItem(Utility::formatTimestamp(msg.timestamp)));
|
||||
QTableWidgetItem *item = new QTableWidgetItem;
|
||||
item->setData(Qt::EditRole, Utility::formatTimestamp(msg.timestamp));
|
||||
//ui->tableIsoFrames->setItem(rowNum, 0, (double)msg.timestamp, Utility::formatTimestamp(msg.timestamp)));
|
||||
ui->tableIsoFrames->setItem(rowNum, 0, item);
|
||||
ui->tableIsoFrames->setItem(rowNum, 1, new QTableWidgetItem(QString::number(msg.ID, 16)));
|
||||
ui->tableIsoFrames->setItem(rowNum, 2, new QTableWidgetItem(QString::number(msg.bus)));
|
||||
if (msg.isReceived) ui->tableIsoFrames->setItem(rowNum, 3, new QTableWidgetItem("Rx"));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -3,15 +3,21 @@
|
||||
#include "snifferitem.h"
|
||||
|
||||
|
||||
SnifferItem::SnifferItem(const CANFrame& pFrame):
|
||||
mNotch(0),
|
||||
SnifferItem::SnifferItem(const CANFrame& pFrame, quint32 seq):
|
||||
mID(pFrame.ID)
|
||||
{
|
||||
mMarker = {0,0};
|
||||
mLastMarker = {0,0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mNotch[i] =0;
|
||||
mMarker.data[i] = 0;
|
||||
mMarker.dataTimestamp[i] = 0;
|
||||
mCurrent.data[i] = pFrame.data[i];
|
||||
mCurrent.dataTimestamp[i] = seq;
|
||||
}
|
||||
mLastMarker = mMarker;
|
||||
mCurrent.len = pFrame.len;
|
||||
/* that's dirty */
|
||||
update(pFrame);
|
||||
update(pFrame);
|
||||
update(pFrame, seq, false);
|
||||
update(pFrame, seq, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,57 +36,124 @@ float SnifferItem::getDelta() const
|
||||
return ((float)(mCurrentTime-mLastTime))/1000000;
|
||||
}
|
||||
|
||||
//Get a data byte by index 0-7 (but not more than the length of the actual frame)
|
||||
int SnifferItem::getData(uchar i) const
|
||||
{
|
||||
return (i>=mCurrent.len) ? -1 : ((uchar*) &mCurrent.data)[i];
|
||||
return (i >= mCurrent.len) ? -1 : mCurrent.data[i];
|
||||
}
|
||||
|
||||
quint8 SnifferItem::getNotchPattern(uchar i) const
|
||||
{
|
||||
return (i >= mCurrent.len) ? -1 : mNotch[i];
|
||||
}
|
||||
|
||||
quint8 SnifferItem::getLastData(uchar i) const
|
||||
{
|
||||
return (i >= mLast.len) ? -1 : mLast.data[i];
|
||||
}
|
||||
|
||||
quint32 SnifferItem::getDataTimestamp(uchar i) const
|
||||
{
|
||||
return (i >= mCurrent.len) ? 0 : mCurrent.dataTimestamp[i];
|
||||
}
|
||||
|
||||
quint32 SnifferItem::getSeqInterval(uchar i) const
|
||||
{
|
||||
return mCurrSeqVal - getDataTimestamp(i);
|
||||
}
|
||||
|
||||
//Return whether a given data byte (by index 0-7) has incremented, deincremented, or stayed the same
|
||||
//since the last message
|
||||
//The If checks first that we aren't past the actual data length
|
||||
// then checks whether lastMarker shows that some bits have changed in the previous 200ms cycle
|
||||
// then we check if the byte in mNotch has bits set and if it does we say nothing changed (notched out)
|
||||
dc SnifferItem::dataChange(uchar i) const
|
||||
{
|
||||
if( i<mCurrent.len &&
|
||||
((uchar*) &mLastMarker.data)[i] &&
|
||||
!((uchar*) &mNotch)[i] )
|
||||
if (i >= mCurrent.len) return dc::NO;
|
||||
|
||||
uchar notch = mNotch[i];
|
||||
uchar byt = mCurrent.data[i];
|
||||
uchar last = mLast.data[i];
|
||||
uchar lastMark = mLastMarker.data[i];
|
||||
if( lastMark )
|
||||
{
|
||||
return ((uchar*) &mCurrent.data)[i] >= ((uchar*) &mLast.data)[i] ? dc::INC : dc::DEINC;
|
||||
if (!notch) //if no notching is set
|
||||
return (byt >= last ? dc::INC : dc::DEINC);
|
||||
else //mNotch contained a bit pattern so use masks and do things more complicated
|
||||
{
|
||||
byt &= ~notch; //mask off bits that were notched
|
||||
if (byt == 0) return dc::NO; //and if result is null then nothing changed (other than maybe notched bits and they don't count)
|
||||
last &= ~notch; //need to mask last too
|
||||
if (last == byt) return dc::NO;
|
||||
return (byt >= last ? dc::INC : dc::DEINC); //then compare the masked copies to see which way the bit(s) went
|
||||
}
|
||||
}
|
||||
|
||||
return dc::NO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SnifferItem::elapsed() const
|
||||
{
|
||||
return mTime.elapsed();
|
||||
}
|
||||
|
||||
void SnifferItem::update(const CANFrame& pFrame)
|
||||
//called when a new frame comes in that matches our same ID
|
||||
//timeSeq is stored so we can figure out the last time a specific byte was updated
|
||||
//mute is used to specify whether to mask the byte against the notching filter
|
||||
//in order to hide any updates of the notched bits. This is toggleable
|
||||
void SnifferItem::update(const CANFrame& pFrame, quint32 timeSeq, bool mute)
|
||||
{
|
||||
unsigned char maskedCurr, maskedData;
|
||||
//qDebug() << "update with ts: " << timeSeq;
|
||||
/* copy current to last */
|
||||
mLast = mCurrent;
|
||||
mLastTime = mCurrentTime;
|
||||
mCurrSeqVal = timeSeq;
|
||||
|
||||
/* copy new value */
|
||||
memcpy(&mCurrent.data, pFrame.data, 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
maskedData = pFrame.data[i];
|
||||
if (mute) maskedData &= ~mNotch[i];
|
||||
maskedCurr = mCurrent.data[i];
|
||||
if (mute) maskedCurr &= ~mNotch[i];
|
||||
if (maskedCurr != maskedData)
|
||||
{
|
||||
mCurrent.data[i] = pFrame.data[i];
|
||||
mCurrent.dataTimestamp[i] = timeSeq;
|
||||
}
|
||||
}
|
||||
mCurrent.len = pFrame.len;
|
||||
mCurrentTime = pFrame.timestamp;
|
||||
|
||||
/* update marker */
|
||||
mMarker.data |= mLast.data ^ mCurrent.data;
|
||||
//We "OR" our stored marker with the changed bits.
|
||||
//this accumulates changed bits into the marker
|
||||
for (int i = 0 ; i < 8; i++) mMarker.data[i] |= mLast.data[i] ^ mCurrent.data[i]; //XOR causes only changed bits to be 1's
|
||||
mMarker.len |= mLast.len ^ mCurrent.len;
|
||||
|
||||
/* restart timeout */
|
||||
mTime.restart();
|
||||
}
|
||||
|
||||
//Called in refresh from the model. Interval about 200ms currently.
|
||||
//So, this means the marker only accumulates for 200ms then resets
|
||||
void SnifferItem::updateMarker()
|
||||
{
|
||||
mLastMarker = mMarker;
|
||||
mMarker = {0, 0};
|
||||
for (int i = 0; i < 8; i++) mMarker.data[i] = 0;
|
||||
}
|
||||
|
||||
//Notch or un-notch this snifferitem / frame
|
||||
void SnifferItem::notch(bool pNotch)
|
||||
{
|
||||
if(pNotch)
|
||||
mNotch |= mLastMarker.data;
|
||||
{
|
||||
for (int i = 0; i < 8; i++) mNotch[i] |= mLastMarker.data[i]; //add changed bits to notch value
|
||||
}
|
||||
|
||||
else
|
||||
mNotch = 0;
|
||||
for (int i = 0; i < 8; i++) mNotch[i] = 0;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
struct fstCan
|
||||
{
|
||||
quint64 data;
|
||||
quint8 data[8];
|
||||
quint32 dataTimestamp[8];
|
||||
int len;
|
||||
};
|
||||
|
||||
@@ -22,26 +23,32 @@ enum dc
|
||||
class SnifferItem
|
||||
{
|
||||
public:
|
||||
explicit SnifferItem(const CANFrame& pFrame);
|
||||
explicit SnifferItem(const CANFrame& pFrame, quint32 seq);
|
||||
virtual ~SnifferItem();
|
||||
|
||||
quint64 getId() const;
|
||||
float getDelta() const;
|
||||
int getData(uchar i) const;
|
||||
quint8 getNotchPattern(uchar i) const;
|
||||
quint8 getLastData(uchar i) const;
|
||||
quint32 getDataTimestamp(uchar i) const;
|
||||
quint32 getSeqInterval(uchar i) const;
|
||||
dc dataChange(uchar) const;
|
||||
int elapsed() const;
|
||||
void update(const CANFrame& pFrame);
|
||||
void update(const CANFrame& pFrame, quint32 timeSeq, bool mute);
|
||||
void updateMarker();
|
||||
void notch(bool);
|
||||
|
||||
private:
|
||||
quint64 mID;
|
||||
quint32 mID;
|
||||
struct fstCan mLast;
|
||||
struct fstCan mCurrent;
|
||||
struct fstCan mLastMarker;
|
||||
struct fstCan mMarker;
|
||||
quint64 mNotch;
|
||||
quint8 mNotch[8];
|
||||
quint64 mLastTime;
|
||||
quint64 mCurrentTime;
|
||||
quint64 mCurrSeqVal;
|
||||
|
||||
QTime mTime;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#include <QDebug>
|
||||
#include "sniffermodel.h"
|
||||
#include "snifferwindow.h"
|
||||
|
||||
#include "SnifferDelegate.h"
|
||||
|
||||
SnifferModel::SnifferModel(QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
mFilter(false)
|
||||
mFilter(false),
|
||||
mNeverExpire(false),
|
||||
mFadeInactive(false),
|
||||
mMuteNotched(false),
|
||||
mTimeSequence(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,16 +60,29 @@ QVariant SnifferModel::data(const QModelIndex &index, int role) const
|
||||
if(tc::DATA_0<=col && col <=tc::DATA_7)
|
||||
{
|
||||
int data = item->getData(col-tc::DATA_0);
|
||||
if(data>=0)
|
||||
if(data >= 0)
|
||||
{
|
||||
return QString("%1").arg(data, 2, 16, QLatin1Char('0')).toUpper();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
if (!mFadeInactive || col < 2) return QBrush(Qt::black);
|
||||
int v = item->getSeqInterval(col - 2) * 10;
|
||||
//qDebug() << "mTS: " << mTimeSequence << " gDT(" << (col - 2) << ") " << item->getDataTimestamp(col - 2);
|
||||
if (v > 225) v = 225;
|
||||
if (v < 0) v = 0;
|
||||
return QBrush(QColor(v,v,v,255));
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::BackgroundRole:
|
||||
{
|
||||
if(tc::ID==col)
|
||||
{
|
||||
if(item->elapsed()>4000)
|
||||
if(item->elapsed() > 4000)
|
||||
return QBrush(Qt::red);
|
||||
}
|
||||
else if(tc::DATA_0<=col && col<=tc::DATA_7)
|
||||
@@ -143,6 +160,35 @@ QModelIndex SnifferModel::parent(const QModelIndex &) const
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
bool SnifferModel::getNeverExpire()
|
||||
{
|
||||
return mNeverExpire;
|
||||
}
|
||||
|
||||
bool SnifferModel::getFadeInactive()
|
||||
{
|
||||
return mFadeInactive;
|
||||
}
|
||||
|
||||
bool SnifferModel::getMuteNotched()
|
||||
{
|
||||
return mMuteNotched;
|
||||
}
|
||||
|
||||
void SnifferModel::setNeverExpire(bool val)
|
||||
{
|
||||
mNeverExpire = val;
|
||||
}
|
||||
|
||||
void SnifferModel::setFadeInactive(bool val)
|
||||
{
|
||||
mFadeInactive = val;
|
||||
}
|
||||
|
||||
void SnifferModel::setMuteNotched(bool val)
|
||||
{
|
||||
mMuteNotched = val;
|
||||
}
|
||||
|
||||
void SnifferModel::clear()
|
||||
{
|
||||
@@ -154,20 +200,22 @@ void SnifferModel::clear()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
|
||||
//Called from window with a timer (currently 200ms)
|
||||
void SnifferModel::refresh()
|
||||
{
|
||||
QMap<quint32, SnifferItem*>::iterator i;
|
||||
QVector<quint32> toRemove;
|
||||
SnifferItem* item;
|
||||
|
||||
mTimeSequence++;
|
||||
|
||||
/* update markers */
|
||||
|
||||
|
||||
for (i = mMap.begin(); i != mMap.end(); ++i)
|
||||
{
|
||||
i.value()->updateMarker();
|
||||
if(i.value()->elapsed()>5000)
|
||||
if(i.value()->elapsed()>5000 && !mNeverExpire)
|
||||
toRemove.append(i.key());
|
||||
}
|
||||
|
||||
@@ -237,14 +285,15 @@ void SnifferModel::update(CANConnection*, QVector<CANFrame>& pFrames)
|
||||
int index = std::distance(mMap.begin(), mMap.lowerBound(frame.ID));
|
||||
/* add the frame */
|
||||
beginInsertRows(QModelIndex(), index, index);
|
||||
mMap[frame.ID] = new SnifferItem(frame);
|
||||
mMap[frame.ID] = new SnifferItem(frame, mTimeSequence);
|
||||
mMap[frame.ID]->update(frame, mTimeSequence, mMuteNotched);
|
||||
endInsertRows();
|
||||
|
||||
emit idChange(frame.ID, true);
|
||||
}
|
||||
else
|
||||
//updateData
|
||||
mMap[frame.ID]->update(frame);
|
||||
mMap[frame.ID]->update(frame, mTimeSequence, mMuteNotched);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,13 @@ public:
|
||||
void refresh();
|
||||
void clear();
|
||||
void filter(fltType pType, int pId=0);
|
||||
bool getNeverExpire();
|
||||
bool getFadeInactive();
|
||||
bool getMuteNotched();
|
||||
void setNeverExpire(bool val);
|
||||
void setFadeInactive(bool val);
|
||||
void setMuteNotched(bool val);
|
||||
|
||||
|
||||
public slots:
|
||||
void update(CANConnection*, QVector<CANFrame>&);
|
||||
@@ -53,6 +60,10 @@ private:
|
||||
QMap<quint32, SnifferItem*> mMap;
|
||||
QMap<quint32, SnifferItem*> mFilters;
|
||||
bool mFilter;
|
||||
bool mNeverExpire;
|
||||
bool mFadeInactive;
|
||||
bool mMuteNotched;
|
||||
quint32 mTimeSequence;
|
||||
};
|
||||
|
||||
#endif // SNIFFERMODEL_H
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "ui_snifferwindow.h"
|
||||
#include "helpwindow.h"
|
||||
#include "connections/canconmanager.h"
|
||||
#include "SnifferDelegate.h"
|
||||
|
||||
SnifferWindow::SnifferWindow(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@@ -16,12 +17,17 @@ SnifferWindow::SnifferWindow(QWidget *parent) :
|
||||
setWindowFlags(Qt::Window);
|
||||
ui->treeView->setModel(&mModel);
|
||||
|
||||
sniffDel = new SnifferDelegate();
|
||||
defaultDel = ui->treeView->itemDelegate();
|
||||
|
||||
/* set column width */
|
||||
ui->treeView->setColumnWidth(tc::ID, 50);
|
||||
ui->treeView->setColumnWidth(tc::ID, 80);
|
||||
ui->treeView->setColumnWidth(tc::LAST, 1);
|
||||
for(int i=tc::DATA_0 ; i<=tc::DATA_7 ; i++)
|
||||
ui->treeView->setColumnWidth(i, 30);
|
||||
ui->treeView->setColumnWidth(i, 92);
|
||||
ui->treeView->setUniformRowHeights(true);
|
||||
ui->treeView->header()->setDefaultAlignment(Qt::AlignCenter);
|
||||
//ui->treeView->setItemDelegate(new SnifferDelegate());
|
||||
|
||||
/* activate sorting */
|
||||
ui->listWidget->setSortingEnabled(true);
|
||||
@@ -38,20 +44,75 @@ SnifferWindow::SnifferWindow(QWidget *parent) :
|
||||
connect(&mModel, &SnifferModel::idChange, this, &SnifferWindow::idChange);
|
||||
connect(ui->listWidget, &QListWidget::itemChanged, this, &SnifferWindow::itemChanged);
|
||||
|
||||
connect(ui->cbFadeInactive, &QCheckBox::stateChanged, this, [this](int val){mModel.setFadeInactive(val);sniffDel->setFadeInactive(val);});
|
||||
connect(ui->cbMuteNotched, &QCheckBox::stateChanged, this, [this](int val){mModel.setMuteNotched(val);});
|
||||
connect(ui->cbNoExpire, &QCheckBox::stateChanged, this, [this](int val){mModel.setNeverExpire(val);});
|
||||
connect(ui->cbViewBits, &QCheckBox::stateChanged, this,
|
||||
[this](int val)
|
||||
{
|
||||
if (val) ui->treeView->setItemDelegate(sniffDel);
|
||||
else
|
||||
{
|
||||
ui->treeView->setItemDelegate(defaultDel);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
SnifferWindow::~SnifferWindow()
|
||||
{
|
||||
closeEvent(NULL);
|
||||
delete sniffDel;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SnifferWindow::readSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
resize(settings.value("Sniffer/WindowSize", QSize(1100, 750)).toSize());
|
||||
move(settings.value("Sniffer/WindowPos", QPoint(50, 50)).toPoint());
|
||||
ui->treeView->setColumnWidth(0, settings.value("Sniffer/DeltaColumn", 110).toUInt());
|
||||
ui->treeView->setColumnWidth(1, settings.value("Sniffer/IDColumn", 70).toUInt());
|
||||
ui->treeView->setColumnWidth(2, settings.value("Sniffer/Data0Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(3, settings.value("Sniffer/Data1Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(4, settings.value("Sniffer/Data2Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(5, settings.value("Sniffer/Data3Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(6, settings.value("Sniffer/Data4Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(7, settings.value("Sniffer/Data5Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(8, settings.value("Sniffer/Data6Column", 92).toUInt());
|
||||
ui->treeView->setColumnWidth(9, settings.value("Sniffer/Data7Column", 92).toUInt());
|
||||
}
|
||||
}
|
||||
|
||||
void SnifferWindow::writeSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
settings.setValue("Sniffer/WindowSize", size());
|
||||
settings.setValue("Sniffer/WindowPos", pos());
|
||||
settings.setValue("Sniffer/DeltaColumn", ui->treeView->columnWidth(0));
|
||||
settings.setValue("Sniffer/IDColumn", ui->treeView->columnWidth(1));
|
||||
settings.setValue("Sniffer/Data0Column", ui->treeView->columnWidth(2));
|
||||
settings.setValue("Sniffer/Data1Column", ui->treeView->columnWidth(3));
|
||||
settings.setValue("Sniffer/Data2Column", ui->treeView->columnWidth(4));
|
||||
settings.setValue("Sniffer/Data3Column", ui->treeView->columnWidth(5));
|
||||
settings.setValue("Sniffer/Data4Column", ui->treeView->columnWidth(6));
|
||||
settings.setValue("Sniffer/Data5Column", ui->treeView->columnWidth(7));
|
||||
settings.setValue("Sniffer/Data6Column", ui->treeView->columnWidth(8));
|
||||
settings.setValue("Sniffer/Data7Column", ui->treeView->columnWidth(9));
|
||||
}
|
||||
}
|
||||
|
||||
void SnifferWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
connect(CANConManager::getInstance(), &CANConManager::framesReceived, &mModel, &SnifferModel::update);
|
||||
mTimer.start();
|
||||
readSettings();
|
||||
installEventFilter(this);
|
||||
qDebug() << "show";
|
||||
}
|
||||
@@ -64,6 +125,7 @@ void SnifferWindow::closeEvent(QCloseEvent *event)
|
||||
mTimer.stop();
|
||||
/* disconnect reception of frames */
|
||||
disconnect(CANConManager::getInstance(), 0, this, 0);
|
||||
writeSettings();
|
||||
/* clear model */
|
||||
mModel.clear();
|
||||
/* clean list */
|
||||
@@ -127,7 +189,10 @@ void SnifferWindow::idChange(int pId, bool pAdd)
|
||||
QString text = QString("0x") + QString("%1").arg(pId, 3, 16, QLatin1Char('0')).toUpper();
|
||||
item = new QListWidgetItem(text);
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked);
|
||||
//item->setCheckState(mFilter ? Qt::Unchecked : Qt::Checked);
|
||||
//always check new IDs now. Otherwise any that expire then come back will not be selected
|
||||
//and that might be a bigger issue than defaulting them unselected.
|
||||
item->setCheckState(Qt::Checked);
|
||||
ui->listWidget->addItem(item);
|
||||
mMap[pId] = item;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
#include "sniffermodel.h"
|
||||
#include "SnifferDelegate.h"
|
||||
|
||||
namespace Ui {
|
||||
class snifferWindow;
|
||||
@@ -46,12 +47,16 @@ public slots:
|
||||
private:
|
||||
void filter(bool pFilter);
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
Ui::snifferWindow* ui;
|
||||
SnifferModel mModel;
|
||||
QTimer mTimer;
|
||||
QMap<int, QListWidgetItem*> mMap;
|
||||
bool mFilter;
|
||||
SnifferDelegate *sniffDel;
|
||||
QAbstractItemDelegate *defaultDel;
|
||||
};
|
||||
|
||||
#endif // SNIFFER_H
|
||||
|
||||
@@ -81,16 +81,6 @@
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QRadioButton" name="rbKvaser">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Kvaser</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="rbGVRET">
|
||||
<property name="text">
|
||||
@@ -101,17 +91,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="rbSocketCAN">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SocketCAN</string>
|
||||
<string>QT SerialBus Devices (SocketCAN, PeakCAN, etc)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="rbRemote">
|
||||
<property name="text">
|
||||
<string>Remote Host</string>
|
||||
@@ -121,6 +111,16 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblDeviceType">
|
||||
<property name="text">
|
||||
<string>Device Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbDeviceType"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lPort">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>884</width>
|
||||
<height>915</height>
|
||||
<width>1239</width>
|
||||
<height>644</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Signal Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="10,1,5">
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="10,1,4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2,1">
|
||||
<item>
|
||||
<widget class="QListWidget" name="signalsList"/>
|
||||
</item>
|
||||
@@ -52,155 +52,159 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Bit Length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Byte Order</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="txtBitLength"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="cbIntelFormat">
|
||||
<property name="text">
|
||||
<string>LSB First (Little Endian)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Bias:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Min Value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Max Value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Receiving Node:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Comment:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Units Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboType"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="txtScale"/>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="txtBias"/>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLineEdit" name="txtMinVal"/>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLineEdit" name="txtMaxVal"/>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="txtUnitName"/>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QComboBox" name="comboReceiver"/>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QLineEdit" name="txtComment"/>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Multiplexing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbNotMulti">
|
||||
<property name="text">
|
||||
<string>Not multiplexed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbMultiplexed">
|
||||
<property name="text">
|
||||
<string>Multiplexed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbMultiplexor">
|
||||
<property name="text">
|
||||
<string>Multiplexor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Multiplex Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QLineEdit" name="txtMultiplexValue"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Bit Length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtBitLength"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Byte Order</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="cbIntelFormat">
|
||||
<property name="text">
|
||||
<string>LSB First (Little Endian)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboType"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="txtScale"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Bias:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="txtBias"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Min Value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="txtMinVal"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Max Value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="txtMaxVal"/>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Units Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLineEdit" name="txtUnitName"/>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Receiving Node:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QComboBox" name="comboReceiver"/>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Multiplexing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbNotMulti">
|
||||
<property name="text">
|
||||
<string>Not multiplexed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbMultiplexed">
|
||||
<property name="text">
|
||||
<string>Multiplexed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbMultiplexor">
|
||||
<property name="text">
|
||||
<string>Multiplexor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Multiplex Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="txtMultiplexValue"/>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Comment:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QLineEdit" name="txtComment"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -226,20 +230,9 @@
|
||||
<tabstops>
|
||||
<tabstop>signalsList</tabstop>
|
||||
<tabstop>txtName</tabstop>
|
||||
<tabstop>txtBitLength</tabstop>
|
||||
<tabstop>cbIntelFormat</tabstop>
|
||||
<tabstop>comboType</tabstop>
|
||||
<tabstop>txtScale</tabstop>
|
||||
<tabstop>txtBias</tabstop>
|
||||
<tabstop>txtMinVal</tabstop>
|
||||
<tabstop>txtMaxVal</tabstop>
|
||||
<tabstop>txtUnitName</tabstop>
|
||||
<tabstop>comboReceiver</tabstop>
|
||||
<tabstop>rbNotMulti</tabstop>
|
||||
<tabstop>rbMultiplexed</tabstop>
|
||||
<tabstop>rbMultiplexor</tabstop>
|
||||
<tabstop>txtMultiplexValue</tabstop>
|
||||
<tabstop>txtComment</tabstop>
|
||||
<tabstop>valuesTable</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
|
||||
@@ -13,67 +13,473 @@
|
||||
<property name="windowTitle">
|
||||
<string>Detailed Frame Information</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="10,1,5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,1">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFrameID">
|
||||
<property name="text">
|
||||
<string>Frame IDs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFrameID">
|
||||
<property name="text">
|
||||
<string>Frame IDs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFrameID">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFrameID">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Details:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeDetails">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Details:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeDetails">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSave">
|
||||
<property name="text">
|
||||
<string>Save details to file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSave">
|
||||
<property name="text">
|
||||
<string>Save details to file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCustomPlot" name="graphHistogram" native="true"/>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,1,0,1,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Bit Histograph</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCustomPlot" name="graphHistogram" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Bytes Graph</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCustomPlot" name="graphBytes" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>52</red>
|
||||
<green>101</green>
|
||||
<blue>164</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>52</red>
|
||||
<green>101</green>
|
||||
<blue>164</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>78</red>
|
||||
<green>154</green>
|
||||
<blue>6</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>78</red>
|
||||
<green>154</green>
|
||||
<blue>6</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>204</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>204</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>136</red>
|
||||
<green>138</green>
|
||||
<blue>133</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>136</red>
|
||||
<green>138</green>
|
||||
<blue>133</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>252</red>
|
||||
<green>233</green>
|
||||
<blue>79</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>252</red>
|
||||
<green>233</green>
|
||||
<blue>79</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>5</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>114</red>
|
||||
<green>159</green>
|
||||
<blue>207</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>114</red>
|
||||
<green>159</green>
|
||||
<blue>207</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>6</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>173</red>
|
||||
<green>127</green>
|
||||
<blue>168</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>173</red>
|
||||
<green>127</green>
|
||||
<blue>168</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>190</red>
|
||||
<green>190</green>
|
||||
<blue>190</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>13</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>7</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -88,7 +494,6 @@
|
||||
<tabstops>
|
||||
<tabstop>listFrameID</tabstop>
|
||||
<tabstop>treeDetails</tabstop>
|
||||
<tabstop>btnSave</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -89,7 +89,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFilter"/>
|
||||
<widget class="QListWidget" name="listFilter">
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<width>1097</width>
|
||||
<height>752</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -82,6 +82,34 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbNoExpire">
|
||||
<property name="text">
|
||||
<string>Never Expire IDs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbMuteNotched">
|
||||
<property name="text">
|
||||
<string>Mute notched bits</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbFadeInactive">
|
||||
<property name="text">
|
||||
<string>Fade inactive bytes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbViewBits">
|
||||
<property name="text">
|
||||
<string>View Bits</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -128,13 +128,13 @@ public:
|
||||
return output;
|
||||
}
|
||||
|
||||
static QString formatTimestamp(uint64_t timestamp)
|
||||
static QVariant formatTimestamp(uint64_t timestamp)
|
||||
{
|
||||
if (!sysTimeMode) {
|
||||
if (!secondsMode) return QString::number(timestamp);
|
||||
else return QString::number((double)timestamp / 1000000.0, 'f', 6);
|
||||
if (!secondsMode) return (unsigned long long)(timestamp);
|
||||
else return (double)timestamp / 1000000.0;
|
||||
}
|
||||
else return QDateTime::fromMSecsSinceEpoch(timestamp / 1000).toString(timeFormat);
|
||||
else return QDateTime::fromMSecsSinceEpoch(timestamp / 1000);
|
||||
}
|
||||
|
||||
//parses the input string to grab as much of it as possible while staying alpha numeric
|
||||
|
||||