Merge branch 'master' into support_multiple_signal_multiplex_values

This commit is contained in:
Collin Kidder
2025-05-05 20:53:25 -04:00
committed by GitHub
56 changed files with 2312 additions and 865 deletions
+44 -13
View File
@@ -4,16 +4,15 @@ on:
push: push:
branches: branches:
- "master" - "master"
jobs: jobs:
buildlinux: buildlinux:
name: Linux x64 name: Linux x64
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- name: Prepare Environment - name: Prepare Environment
run: | run: |
sudo apt-get install libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-randr0 libxkbcommon-x11-0 sudo apt-get install libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-randr0 libxkbcommon-x11-0 libfuse2
- name: Prepare Qt Libraries - name: Prepare Qt Libraries
uses: jurplel/install-qt-action@v3 uses: jurplel/install-qt-action@v3
@@ -33,14 +32,14 @@ jobs:
chmod a+x linuxdeployqt-continuous-x86_64.AppImage chmod a+x linuxdeployqt-continuous-x86_64.AppImage
./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/SavvyCAN.desktop -appimage -extra-plugins=iconengines,platformthemes/libqgtk3.so,canbus ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/SavvyCAN.desktop -appimage -extra-plugins=iconengines,platformthemes/libqgtk3.so,canbus
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: SavvyCAN-Linux_x64.AppImage name: SavvyCAN-Linux_x64.AppImage
path: SavvyCAN-*x86_64.AppImage path: SavvyCAN-*x86_64.AppImage
buildmacos: buildmacos86:
name: macOS x64 name: macOS x64
runs-on: macos-12 runs-on: macos-13
steps: steps:
- name: Prepare macOS Environment - name: Prepare macOS Environment
@@ -61,11 +60,42 @@ jobs:
mkdir -p SavvyCAN.app/Contents/MacOS/help mkdir -p SavvyCAN.app/Contents/MacOS/help
cp -R help/* SavvyCAN.app/Contents/MacOS/help cp -R help/* SavvyCAN.app/Contents/MacOS/help
macdeployqt SavvyCAN.app -dmg macdeployqt SavvyCAN.app -dmg
mv SavvyCAN.dmg SavvyCAN_x64.dmg
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: SavvyCAN-macOS_x64.dmg name: SavvyCAN-macOS_x64.dmg
path: SavvyCAN.dmg path: SavvyCAN_x64.dmg
buildmacos-arm64:
name: macOS ARM64
runs-on: macos-14
steps:
- name: Prepare macOS Environment
run: |
brew install qt5
brew link qt5 --force
- name: Clone
uses: actions/checkout@v3
- name: Compile
run: |
qmake CONFIG+=release CONFIG+=sdk_no_version_check SavvyCAN.pro
make -j`sysctl kern.aioprocmax | awk '{print $2}'`
- name: Package
run: |
mkdir -p SavvyCAN.app/Contents/MacOS/help
cp -R help/* SavvyCAN.app/Contents/MacOS/help
macdeployqt SavvyCAN.app -dmg
mv SavvyCAN.dmg SavvyCAN_arm64.dmg
- uses: actions/upload-artifact@v4
with:
name: SavvyCAN-macOS_ARM64.dmg
path: SavvyCAN_arm64.dmg
buildwindows: buildwindows:
name: Windows x64 name: Windows x64
@@ -113,7 +143,7 @@ jobs:
mkdir package/canbus mkdir package/canbus
copy "${Env:Qt5_Dir}/plugins/canbus/*.*" package/canbus/ copy "${Env:Qt5_Dir}/plugins/canbus/*.*" package/canbus/
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: SavvyCAN-Windows_x64 name: SavvyCAN-Windows_x64
path: package path: package
@@ -121,12 +151,12 @@ jobs:
pre-release: pre-release:
name: "pre-release" name: "pre-release"
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
needs: [buildwindows, buildmacos, buildlinux] needs: [buildwindows, buildmacos86, buildmacos-arm64, buildlinux]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4.1.7
- name: Display structure of downloaded files - name: Display structure of downloaded files
run: zip -r SavvyCAN-Windows_x64_CIBuild.zip SavvyCAN-Windows_x64 run: zip -r SavvyCAN-Windows_x64_CIBuild.zip SavvyCAN-Windows_x64
@@ -139,12 +169,13 @@ jobs:
files: | files: |
SavvyCAN-Linux_x64.AppImage/SavvyCAN-*x86_64.AppImage SavvyCAN-Linux_x64.AppImage/SavvyCAN-*x86_64.AppImage
SavvyCAN-Windows_x64_CIBuild.zip SavvyCAN-Windows_x64_CIBuild.zip
SavvyCAN-macOS_x64.dmg/SavvyCAN.dmg SavvyCAN-macOS_x64.dmg/SavvyCAN_x64.dmg
SavvyCAN-macOS_ARM64.dmg/SavvyCAN_arm64.dmg
notify: notify:
name: Notify Discord name: Notify Discord
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [buildwindows, buildmacos, buildlinux] needs: [buildwindows, buildmacos86, buildmacos-arm64, buildlinux]
steps: steps:
- id: msg_var - id: msg_var
name: remove newlines name: remove newlines
+1
View File
@@ -45,3 +45,4 @@ Makefile
SavvyCAN.pro.qtds SavvyCAN.pro.qtds
.xcode .xcode
SavvyCAN.xcodeproj SavvyCAN.xcodeproj
.vscode
+5 -6
View File
@@ -1,6 +1,6 @@
# SavvyCAN # SavvyCAN
Qt based cross platform canbus tool Qt based cross platform canbus tool
(C) 2015-2021 EVTV and Collin Kidder (C) 2015-2024 Collin Kidder
A Qt5 based cross platform tool which can be used to load, save, and capture canbus frames. A Qt5 based cross platform tool which can be used to load, save, and capture canbus frames.
This tool is designed to help with visualization, reverse engineering, debugging, and This tool is designed to help with visualization, reverse engineering, debugging, and
@@ -17,9 +17,6 @@ The CANDue board must be running the GVRET firmware which can also be found
within the collin80 repos. within the collin80 repos.
It is now possible to use any Qt SerialBus driver (socketcan, Vector, PeakCAN, TinyCAN). 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.
It should, however, be noted that use of a capture device is not required to make use It should, however, be noted that use of a capture device is not required to make use
of this program. It can load and save in several formats: of this program. It can load and save in several formats:
@@ -35,6 +32,7 @@ of this program. It can load and save in several formats:
9. Vehicle Spy log files 9. Vehicle Spy log files
10. CANDump / Kayak (Read only) 10. CANDump / Kayak (Read only)
11. PCAN Viewer (Read Only) 11. PCAN Viewer (Read Only)
12. Wireshark socketcan PCAP file (Read only)
## Dependencies ## Dependencies
@@ -50,8 +48,9 @@ to download it separately.
This project requires 5.14.0 or higher because of a dependency on QtSerialBus and other new additions to Qt. This project requires 5.14.0 or higher because of a dependency on QtSerialBus and other new additions to Qt.
NOTE: Qt6 currently lacks support for QtSerialBus and many other Qt sub-features. At this time you cannot NOTE: As the code in this master branch sits, it does compile with QT6. Support for QT6 is approximately "beta" quality. Most all functions should work, please send issues if found.
use Qt6 to compile SavvyCAN. Support for Qt6 should be possible around Qt6.2.
It appears that the current binary build for MacOS requires at least MacOS 10.15
## Instructions for compiling: ## Instructions for compiling:
+12 -2
View File
@@ -4,11 +4,15 @@
# #
#------------------------------------------------- #-------------------------------------------------
!versionAtLeast(QT_VERSION, 5.14.0) {
error("Current version of Qt ($${QT_VERSION}) is too old, this project requires Qt 5.14 or newer")
}
QT = core gui printsupport qml serialbus serialport widgets help network opengl QT = core gui printsupport qml serialbus serialport widgets help network opengl
CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT
CONFIG += c++11 CONFIG += c++17
CONFIG += NO_UNIT_TESTS CONFIG += NO_UNIT_TESTS
DEFINES += QCUSTOMPLOT_USE_OPENGL DEFINES += QCUSTOMPLOT_USE_OPENGL
@@ -26,6 +30,7 @@ SOURCES += main.cpp\
connections/lawicel_serial.cpp \ connections/lawicel_serial.cpp \
connections/mqtt_bus.cpp \ connections/mqtt_bus.cpp \
dbc/dbcnodeduplicateeditor.cpp \ dbc/dbcnodeduplicateeditor.cpp \
framesenderobject.cpp \
mqtt/qmqtt_client.cpp \ mqtt/qmqtt_client.cpp \
mqtt/qmqtt_client_p.cpp \ mqtt/qmqtt_client_p.cpp \
mqtt/qmqtt_frame.cpp \ mqtt/qmqtt_frame.cpp \
@@ -113,6 +118,7 @@ HEADERS += mainwindow.h \
connections/mqtt_bus.h \ connections/mqtt_bus.h \
dbc/dbcnodeduplicateeditor.h \ dbc/dbcnodeduplicateeditor.h \
dbc/dbcnoderebaseeditor.h \ dbc/dbcnoderebaseeditor.h \
framesenderobject.h \
mqtt/qmqtt.h \ mqtt/qmqtt.h \
mqtt/qmqtt_client.h \ mqtt/qmqtt_client.h \
mqtt/qmqtt_client_p.h \ mqtt/qmqtt_client_p.h \
@@ -255,12 +261,16 @@ unix {
DISTFILES += SavvyCAN.desktop DISTFILES += SavvyCAN.desktop
} }
windows {
RC_ICONS=icons/SavvyIcon.ico
}
examplefiles.files=examples examplefiles.files=examples
examplefiles.path = $$PREFIX/share/savvycan/examples examplefiles.path = $$PREFIX/share/savvycan/examples
INSTALLS += examplefiles INSTALLS += examplefiles
iconfiles.files=icons iconfiles.files=icons
iconfiles.path = $$PREFIX/share/icons iconfiles.path = $$PREFIX/share
INSTALLS += iconfiles INSTALLS += iconfiles
helpfiles.files=help/* helpfiles.files=help/*
+27 -6
View File
@@ -182,11 +182,11 @@ UDS_HANDLER::~UDS_HANDLER()
delete isoHandler; delete isoHandler;
} }
void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg) UDS_MESSAGE UDS_HANDLER::tryISOtoUDS(ISOTP_MESSAGE msg, bool *result)
{ {
qDebug() << "UDS handler got ISOTP frame";
const unsigned char *data = reinterpret_cast<const unsigned char *>(msg.payload().constData()); const unsigned char *data = reinterpret_cast<const unsigned char *>(msg.payload().constData());
int dataLen = msg.payload().count(); int dataLen = msg.payload().count();
*result = true;
UDS_MESSAGE udsMsg; UDS_MESSAGE udsMsg;
udsMsg.bus = msg.bus; udsMsg.bus = msg.bus;
udsMsg.setExtendedFrameFormat(msg.hasExtendedFrameFormat()); udsMsg.setExtendedFrameFormat(msg.hasExtendedFrameFormat());
@@ -208,9 +208,17 @@ void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg)
{ {
udsMsg.service = data[1]; udsMsg.service = data[1];
if (dataLen > 2) udsMsg.subFunc = data[2]; if (dataLen > 2) udsMsg.subFunc = data[2];
else return; else
{
*result = false;
return udsMsg;
};
} }
else return; else
{
*result = false;
return udsMsg;
};
udsMsg.payload().remove(0, 2); udsMsg.payload().remove(0, 2);
} }
else else
@@ -220,9 +228,22 @@ void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg)
udsMsg.payload().remove(0, 1); udsMsg.payload().remove(0, 1);
} }
} }
else return; else
{
*result = false;
};
return udsMsg;
}
emit newUDSMessage(udsMsg); void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg)
{
qDebug() << "UDS handler got ISOTP frame";
UDS_MESSAGE udsMsg;
bool result;
udsMsg = tryISOtoUDS(msg, &result);
if (result) emit newUDSMessage(udsMsg);
} }
void UDS_HANDLER::setFlowCtrl(bool state) void UDS_HANDLER::setFlowCtrl(bool state)
+1
View File
@@ -105,6 +105,7 @@ public:
QString getShortDesc(QVector<CODE_STRUCT> &codeVector, int code); QString getShortDesc(QVector<CODE_STRUCT> &codeVector, int code);
QString getLongDesc(QVector<CODE_STRUCT> &codeVector, int code); QString getLongDesc(QVector<CODE_STRUCT> &codeVector, int code);
QString getDetailedMessageAnalysis(const UDS_MESSAGE &msg); QString getDetailedMessageAnalysis(const UDS_MESSAGE &msg);
UDS_MESSAGE tryISOtoUDS(ISOTP_MESSAGE msg, bool *result);
public slots: public slots:
void gotISOTPFrame(ISOTP_MESSAGE msg); void gotISOTPFrame(ISOTP_MESSAGE msg);
+5 -1
View File
@@ -4,6 +4,7 @@
#include "can_structs.h" #include "can_structs.h"
#include <QList> #include <QList>
#include <QUuid>
enum TriggerMask enum TriggerMask
{ {
@@ -38,6 +39,7 @@ public:
//If ID is -1 then this is the temporary storage register. This is a shadow //If ID is -1 then this is the temporary storage register. This is a shadow
//register used to accumulate the results of a multi operation modifier. //register used to accumulate the results of a multi operation modifier.
//if ID is -2 then this is a look up of our own data bytes stored in the class data. //if ID is -2 then this is a look up of our own data bytes stored in the class data.
//Of course, if the ID is positive then we grab bytes or signals from newest message with that ID
class ModifierOperand class ModifierOperand
{ {
public: public:
@@ -45,6 +47,7 @@ public:
int bus; int bus;
int databyte; int databyte;
bool notOper; //should a bitwise NOT be applied to this prior to doing the actual calculation? bool notOper; //should a bitwise NOT be applied to this prior to doing the actual calculation?
QString signalName; //if ID is positive and there is text in here then we'll look up the signal and use its value
}; };
//list of operations that can be done between the two operands //list of operations that can be done between the two operands
@@ -73,7 +76,8 @@ public:
class Modifier class Modifier
{ {
public: public:
int destByte; int destByte; //if -1 then target one of this ID's signals instead
QString signalName;
QList<ModifierOp> operations; QList<ModifierOp> operations;
}; };
+10 -17
View File
@@ -13,21 +13,13 @@ CANBus::CANBus()
} }
CANBus::CANBus(const CANBus& pBus) :
speed(pBus.speed),
listenOnly(pBus.listenOnly),
singleWire(pBus.singleWire),
active(pBus.active),
canFD(pBus.canFD),
dataRate(pBus.dataRate){}
bool CANBus::operator==(const CANBus& bus) const{ bool CANBus::operator==(const CANBus& bus) const{
return speed == bus.speed && return speed == bus.speed &&
listenOnly == bus.listenOnly && listenOnly == bus.listenOnly &&
singleWire == bus.singleWire && singleWire == bus.singleWire &&
active == bus.active && active == bus.active &&
canFD == bus.canFD; canFD == bus.canFD &&
dataRate == bus.dataRate;
} }
void CANBus::setSpeed(int newSpeed){ void CANBus::setSpeed(int newSpeed){
@@ -55,11 +47,11 @@ void CANBus::setCanFD(bool mode){
canFD = mode; canFD = mode;
} }
int CANBus::getSpeed(){ int CANBus::getSpeed() const {
return speed; return speed;
} }
int CANBus::getDataRate(){ int CANBus::getDataRate() const {
return dataRate; return dataRate;
} }
@@ -68,29 +60,30 @@ void CANBus::setDataRate(int newSpeed){
dataRate = newSpeed; dataRate = newSpeed;
} }
bool CANBus::isListenOnly(){ bool CANBus::isListenOnly() const {
return listenOnly; return listenOnly;
} }
bool CANBus::isSingleWire(){ bool CANBus::isSingleWire() const {
return singleWire; return singleWire;
} }
bool CANBus::isActive(){ bool CANBus::isActive() const {
return active; return active;
} }
bool CANBus::isCanFD(){ bool CANBus::isCanFD() const {
return canFD; return canFD;
} }
QDataStream& operator<<( QDataStream & pStream, const CANBus& pCanBus ) QDataStream& operator<<(QDataStream & pStream, const CANBus& pCanBus)
{ {
pStream << pCanBus.speed; pStream << pCanBus.speed;
pStream << pCanBus.listenOnly; pStream << pCanBus.listenOnly;
pStream << pCanBus.singleWire; pStream << pCanBus.singleWire;
pStream << pCanBus.active; pStream << pCanBus.active;
// FIXME CANFD settings missing
return pStream; return pStream;
} }
+17 -16
View File
@@ -5,13 +5,6 @@
class CANBus class CANBus
{ {
public:
CANBus();
CANBus(const CANBus&);
bool operator==(const CANBus&) const;
CANBus& operator=(const CANBus& other) = default;
//virtual ~CANBus(){}
int speed; int speed;
bool listenOnly; bool listenOnly;
bool singleWire; bool singleWire;
@@ -19,28 +12,36 @@ public:
bool canFD; bool canFD;
int dataRate; int dataRate;
friend QDataStream& operator<<(QDataStream & pStream, const CANBus& pCanBus);
friend QDataStream& operator>>(QDataStream & pStream, CANBus& pCanBus);
public:
CANBus();
bool operator==(const CANBus&) const;
void setSpeed(int); // new speed void setSpeed(int); // new speed
void setListenOnly(bool); //bool for whether to only listen void setListenOnly(bool); //bool for whether to only listen
void setSingleWire(bool); //bool for whether to use single wire mode void setSingleWire(bool); //bool for whether to use single wire mode
void setActive(bool); //whether this bus should be enabled or not. void setActive(bool); //whether this bus should be enabled or not.
void setCanFD(bool); // enable or disable CANFD support void setCanFD(bool); // enable or disable CANFD support
int getSpeed();
int getDataRate();
void setDataRate(int newSpeed); void setDataRate(int newSpeed);
bool isListenOnly();
bool isSingleWire(); int getSpeed() const;
bool isActive(); int getDataRate() const;
bool isCanFD(); bool isListenOnly() const;
bool isSingleWire() const;
bool isActive() const;
bool isCanFD() const;
}; };
QDataStream& operator<<( QDataStream & pStream, const CANBus& pCanBus ); QDataStream& operator<<(QDataStream & pStream, const CANBus& pCanBus);
QDataStream & operator>>(QDataStream & pStream, CANBus& pCanBus); QDataStream& operator>>(QDataStream & pStream, CANBus& pCanBus);
Q_DECLARE_METATYPE(CANBus); Q_DECLARE_METATYPE(CANBus);
struct BusData { struct BusData {
CANBus mBus; CANBus mBus;
bool mConfigured; bool mConfigured = {};
QVector<CANFltObserver> mTargettedFrames; QVector<CANFltObserver> mTargettedFrames;
}; };
+1 -1
View File
@@ -14,7 +14,7 @@ CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDri
{ {
switch(pType) { switch(pType) {
case SERIALBUS: case SERIALBUS:
return new SerialBusConnection(pPortName, pDriverName); return new SerialBusConnection(pPortName, pDriverName, pBusSpeed, pDataRate, pCanFd);
case GVRET_SERIAL: case GVRET_SERIAL:
if(pPortName.contains(".") && !pPortName.contains("tty") && !pPortName.contains("serial")) if(pPortName.contains(".") && !pPortName.contains("tty") && !pPortName.contains("serial"))
return new GVRetSerial(pPortName, true); return new GVRetSerial(pPortName, true);
+1 -1
View File
@@ -222,7 +222,7 @@ bool CANConManager::sendFrame(const CANFrame& pFrame)
workingFrame.isReceived = false; workingFrame.isReceived = false;
if (useSystemTime) if (useSystemTime)
{ {
workingFrame.setTimeStamp(QCanBusFrame::TimeStamp(0,QDateTime::currentMSecsSinceEpoch() * 1000)); workingFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
} }
else else
{ {
+11 -2
View File
@@ -13,11 +13,11 @@ CANConnection::CANConnection(QString pPort,
int pQueueLen, int pQueueLen,
bool pUseThread) : bool pUseThread) :
mNumBuses(pNumBuses), mNumBuses(pNumBuses),
mSerialSpeed(pSerialSpeed),
mQueue(), mQueue(),
mPort(pPort), mPort(pPort),
mDriver(pDriver), mDriver(pDriver),
mType(pType), mType(pType),
mSerialSpeed(pSerialSpeed),
mIsCapSuspended(false), mIsCapSuspended(false),
mStatus(CANCon::NOT_CONNECTED), mStatus(CANCon::NOT_CONNECTED),
mStarted(false), mStarted(false),
@@ -41,7 +41,12 @@ CANConnection::CANConnection(QString pPort,
if (pBusSpeed > 0) mBusData[0].mBus.setSpeed(pBusSpeed); if (pBusSpeed > 0) mBusData[0].mBus.setSpeed(pBusSpeed);
mBusData[0].mBus.setCanFD(pCanFd); mBusData[0].mBus.setCanFD(pCanFd);
if (pDataRate > 0) mBusData[0].mBus.setDataRate(pDataRate); if (pDataRate > 0) {
mBusData[0].mBus.setDataRate(pDataRate);
if (pCanFd) {
mBusData[0].mBus.setCanFD(pCanFd);
}
}
/* if needed, create a thread and move ourself into it */ /* if needed, create a thread and move ourself into it */
if(pUseThread) { if(pUseThread) {
@@ -210,6 +215,10 @@ int CANConnection::getNumBuses() const{
return mNumBuses; return mNumBuses;
} }
int CANConnection::getSerialSpeed() const{
return mSerialSpeed;
}
bool CANConnection::isConfigured(int pBusId) { bool CANConnection::isConfigured(int pBusId) {
if( pBusId < 0 || pBusId >= getNumBuses()) if( pBusId < 0 || pBusId >= getNumBuses())
+6
View File
@@ -52,6 +52,12 @@ public:
*/ */
int getNumBuses() const; int getNumBuses() const;
/**
* @brief getserialSpeed
* @return returns the serial speed of the device
*/
int getSerialSpeed() const;
/** /**
* @brief getPort * @brief getPort
* @return returns the port name of the device * @return returns the port name of the device
+1 -1
View File
@@ -214,7 +214,7 @@ void CANserver::readNetworkData()
frame_p->setFrameType(QCanBusFrame::DataFrame); frame_p->setFrameType(QCanBusFrame::DataFrame);
frame_p->isReceived = true; frame_p->isReceived = true;
frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ul)); frame_p->setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
frame_p->setPayload(datagram.mid(dataByteLocation, length)); frame_p->setPayload(datagram.mid(dataByteLocation, length));
+36 -18
View File
@@ -79,12 +79,12 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
//Need to make sure it tries to share the address in case there are //Need to make sure it tries to share the address in case there are
//multiple instances of SavvyCAN running. //multiple instances of SavvyCAN running.
rxBroadcastGVRET->bind(QHostAddress::AnyIPv4, 17222, QAbstractSocket::ShareAddress); rxBroadcastGVRET->bind(QHostAddress::AnyIPv4, 17222, QAbstractSocket::ShareAddress);
connect(rxBroadcastGVRET, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); connect(rxBroadcastGVRET, &QUdpSocket::readyRead, this, &ConnectionWindow::readPendingDatagrams);
//Doing the same for socketcand/kayak hosts: //Doing the same for socketcand/kayak hosts:
rxBroadcastKayak = new QUdpSocket(this); rxBroadcastKayak = new QUdpSocket(this);
rxBroadcastKayak->bind(QHostAddress::AnyIPv4, 42000, QAbstractSocket::ShareAddress); rxBroadcastKayak->bind(QHostAddress::AnyIPv4, 42000, QAbstractSocket::ShareAddress);
connect(rxBroadcastKayak, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); connect(rxBroadcastKayak, &QUdpSocket::readyRead, this, &ConnectionWindow::readPendingDatagrams);
} }
@@ -236,12 +236,12 @@ void ConnectionWindow::consoleEnableChanged(bool checked) {
CANConnection* conn_p = connModel->getAtIdx(selIdx); CANConnection* conn_p = connModel->getAtIdx(selIdx);
if (checked) { //enable console if (checked) { //enable console
connect(conn_p, SIGNAL(debugOutput(QString)), this, SLOT(getDebugText(QString))); connect(conn_p, &CANConnection::debugOutput, this, &ConnectionWindow::getDebugText, Qt::UniqueConnection);
connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); connect(this, &ConnectionWindow::sendDebugData, conn_p, &CANConnection::debugInput, Qt::UniqueConnection);
} }
else { //turn it off else { //turn it off
disconnect(conn_p, SIGNAL(debugOutput(QString)), nullptr, nullptr); disconnect(conn_p, &CANConnection::debugOutput, nullptr, nullptr);
disconnect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); disconnect(this, &ConnectionWindow::sendDebugData, conn_p, &CANConnection::debugInput);
} }
} }
@@ -336,7 +336,9 @@ void ConnectionWindow::connectionStatus(CANConStatus pStatus)
Q_UNUSED(pStatus); Q_UNUSED(pStatus);
qDebug() << "Connectionstatus changed"; qDebug() << "Connectionstatus changed";
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
connModel->refresh(); connModel->refresh();
ui->tableConnections->selectRow(selIdx);
} }
void ConnectionWindow::setSuspendAll(bool pSuspend) void ConnectionWindow::setSuspendAll(bool pSuspend)
@@ -454,8 +456,8 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
int selIdx = current.row(); int selIdx = current.row();
CANConnection* prevConn = connModel->getAtIdx(previous.row()); CANConnection* prevConn = connModel->getAtIdx(previous.row());
if(prevConn != nullptr) if(prevConn != nullptr)
disconnect(prevConn, SIGNAL(debugOutput(QString)), nullptr, nullptr); disconnect(prevConn, &CANConnection::debugOutput, nullptr, nullptr);
disconnect(this, SIGNAL(sendDebugData(QByteArray)), nullptr, nullptr); disconnect(this, &ConnectionWindow::sendDebugData, nullptr, nullptr);
/* set parameters */ /* set parameters */
if (selIdx == -1) { if (selIdx == -1) {
@@ -472,7 +474,7 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
if(!conn_p) return; if(!conn_p) return;
//because this might have already been setup during the initial setup so tear that one down and then create the normal one. //because this might have already been setup during the initial setup so tear that one down and then create the normal one.
//disconnect(conn_p, SIGNAL(debugOutput(QString)), 0, 0); //disconnect(conn_p, &CANConnection::debugOutput, 0, 0);
numBuses = conn_p->getNumBuses(); numBuses = conn_p->getNumBuses();
int numB = ui->tabBuses->count(); int numB = ui->tabBuses->count();
@@ -485,8 +487,8 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
populateBusDetails(0); populateBusDetails(0);
if (ui->ckEnableConsole->isChecked()) if (ui->ckEnableConsole->isChecked())
{ {
connect(conn_p, SIGNAL(debugOutput(QString)), this, SLOT(getDebugText(QString))); connect(conn_p, &CANConnection::debugOutput, this, &ConnectionWindow::getDebugText, Qt::UniqueConnection);
connect(this, SIGNAL(sendDebugData(QByteArray)), conn_p, SLOT(debugInput(QByteArray))); connect(this, &ConnectionWindow::sendDebugData, conn_p, &CANConnection::debugInput, Qt::UniqueConnection);
} }
} }
} }
@@ -524,12 +526,11 @@ CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QS
if(conn_p) if(conn_p)
{ {
/* connect signal */ /* connect signal */
connect(conn_p, SIGNAL(status(CANConStatus)), connect(conn_p, &CANConnection::status, this, &ConnectionWindow::connectionStatus);
this, SLOT(connectionStatus(CANConStatus)));
if (ui->ckEnableConsole->isChecked()) if (ui->ckEnableConsole->isChecked())
{ {
//set up the debug console to operate if we've selected it. Doing so here allows debugging right away during set up //set up the debug console to operate if we've selected it. Doing so here allows debugging right away during set up
connect(conn_p, SIGNAL(debugOutput(QString)), this, SLOT(getDebugText(QString))); connect(conn_p, &CANConnection::debugOutput, this, &ConnectionWindow::getDebugText, Qt::UniqueConnection);
} }
/*TODO add return value and checks */ /*TODO add return value and checks */
conn_p->start(); conn_p->start();
@@ -552,13 +553,17 @@ void ConnectionWindow::loadConnections()
QVector<QString> driverNames = settings.value("connections/driverNames").value<QVector<QString>>(); QVector<QString> driverNames = settings.value("connections/driverNames").value<QVector<QString>>();
QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>(); QVector<int> devTypes = settings.value("connections/types").value<QVector<int>>();
QVector<int> busSpeeds = settings.value("connections/busSpeeds_0").value<QVector<int>>();
QVector<int> DataRates = settings.value("connections/DataRates_0").value<QVector<int>>();
QVector<int> isCanFds = settings.value("connections/isCanFds_0").value<QVector<int>>();
QVector<int> serialSpeeds = settings.value("connections/serialSpeeds").value<QVector<int>>();
//don't load the connections if the three setting arrays above aren't all the same size. //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; if (portNames.count() != driverNames.count() || devTypes.count() != driverNames.count() || busSpeeds.count() != driverNames.count() || isCanFds.count() != driverNames.count() ||
DataRates.count() != driverNames.count() || serialSpeeds.count() != driverNames.count() ) return;
for(int i = 0 ; i < portNames.count() ; i++) for(int i = 0 ; i < portNames.count() ; i++)
{ {
//TODO: add serial speed and bus speed to this properly. CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i], serialSpeeds[i], busSpeeds[i], isCanFds[i] ? true : false, DataRates[i]);
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i], 0, 0, false, 0);
/* add connection to model */ /* add connection to model */
connModel->add(conn_p); connModel->add(conn_p);
} }
@@ -578,10 +583,19 @@ void ConnectionWindow::saveConnections()
QVector<QString> driverNames; QVector<QString> driverNames;
QVector<int> serialSpeeds; QVector<int> serialSpeeds;
QVector<int> busSpeeds; QVector<int> busSpeeds;
QVector<int> DataRates;
QVector<int> CanFds;
/* save connections */ /* save connections */
foreach(CANConnection* conn_p, conns) foreach(CANConnection* conn_p, conns)
{ { CANBus bus;
if (conn_p->getBusSettings(0, bus)) {
busSpeeds.append(bus.getSpeed());
CanFds.append(bus.isCanFD() ? 1 : 0);
DataRates.append(bus.getDataRate());
}
serialSpeeds.append(conn_p->getSerialSpeed());
portNames.append(conn_p->getPort()); portNames.append(conn_p->getPort());
devTypes.append(conn_p->getType()); devTypes.append(conn_p->getType());
driverNames.append(conn_p->getDriver()); driverNames.append(conn_p->getDriver());
@@ -590,6 +604,10 @@ void ConnectionWindow::saveConnections()
settings.setValue("connections/portNames", QVariant::fromValue(portNames)); settings.setValue("connections/portNames", QVariant::fromValue(portNames));
settings.setValue("connections/types", QVariant::fromValue(devTypes)); settings.setValue("connections/types", QVariant::fromValue(devTypes));
settings.setValue("connections/driverNames", QVariant::fromValue(driverNames)); settings.setValue("connections/driverNames", QVariant::fromValue(driverNames));
settings.setValue("connections/busSpeeds_0", QVariant::fromValue(busSpeeds));
settings.setValue("connections/isCanFds_0", QVariant::fromValue(CanFds));
settings.setValue("connections/DataRates_0", QVariant::fromValue(DataRates));
settings.setValue("connections/serialSpeeds", QVariant::fromValue(serialSpeeds));
} }
void ConnectionWindow::moveConnUp() void ConnectionWindow::moveConnUp()
+6 -4
View File
@@ -685,9 +685,10 @@ void GVRetSerial::procRXChar(unsigned char c)
buildTimestamp += timeBasis; buildTimestamp += timeBasis;
if (useSystemTime) if (useSystemTime)
{ {
buildTimestamp = QDateTime::currentMSecsSinceEpoch() * 1000l; buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
} else {
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, buildTimestamp));
} }
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, buildTimestamp));
break; break;
case 4: case 4:
buildId = c; buildId = c;
@@ -770,9 +771,10 @@ void GVRetSerial::procRXChar(unsigned char c)
buildTimestamp += timeBasis; buildTimestamp += timeBasis;
if (useSystemTime) if (useSystemTime)
{ {
buildTimestamp = QDateTime::currentMSecsSinceEpoch() * 1000l; buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
} else {
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, buildTimestamp));
} }
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, buildTimestamp));
break; break;
case 4: case 4:
buildId = c; buildId = c;
+22 -1
View File
@@ -491,7 +491,26 @@ void LAWICELSerial::readSerialData()
{ {
qDebug() << "Got CR!"; qDebug() << "Got CR!";
buildFrame.setTimeStamp(QDateTime::currentMSecsSinceEpoch() * 1000l); if (useSystemTime)
{
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
}
else
{
//If total length is greater than command, header and data, timestamps must be enabled.
if (data.length() > (5 + mBuildLine.mid(4, 1).toInt() * 2 + 1))
{
//Four bytes after the end of the data bytes.
buildTimestamp = mBuildLine.mid(5 + mBuildLine.mid(4, 1).toInt() * 2, 4).toInt(nullptr, 16) * 1000l;
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, buildTimestamp));
}
else
{
//Default to system time if timestamps are disabled.
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
}
}
switch (mBuildLine[0].toLatin1()) switch (mBuildLine[0].toLatin1())
{ {
case 't': //standard frame case 't': //standard frame
@@ -551,6 +570,7 @@ void LAWICELSerial::readSerialData()
break; break;
case 'b': case 'b':
buildFrame.setBitrateSwitch(true); //BRS enabled buildFrame.setBitrateSwitch(true); //BRS enabled
[[fallthrough]];
case 'd': //standard fd frame, BRS disabled case 'd': //standard fd frame, BRS disabled
//tIIILDD //tIIILDD
buildFrame.setFlexibleDataRateFormat(true); buildFrame.setFlexibleDataRateFormat(true);
@@ -581,6 +601,7 @@ void LAWICELSerial::readSerialData()
break; break;
case 'B': case 'B':
buildFrame.setBitrateSwitch(true); //BRS enabled buildFrame.setBitrateSwitch(true); //BRS enabled
[[fallthrough]];
case 'D': //extended fd frame case 'D': //extended fd frame
//TIIIIIIIILDD. //TIIIIIIIILDD.
buildFrame.setFlexibleDataRateFormat(true); buildFrame.setFlexibleDataRateFormat(true);
+1
View File
@@ -61,6 +61,7 @@ protected:
QSerialPort *serial; QSerialPort *serial;
int framesRapid; int framesRapid;
CANFrame buildFrame; CANFrame buildFrame;
qint64 buildTimestamp;
bool can0Enabled; bool can0Enabled;
bool can0ListenOnly; bool can0ListenOnly;
bool canFd; bool canFd;
+1 -1
View File
@@ -302,7 +302,7 @@ void MQTT_BUS::clientMessageReceived(const QMQTT::Message& message)
frame_p->isReceived = true; frame_p->isReceived = true;
if (useSystemTime) if (useSystemTime)
{ {
frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ul)); frame_p->setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
} }
else frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, timeStamp)); else frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, timeStamp));
+10 -11
View File
@@ -11,8 +11,8 @@
/**** class definition ****/ /**** class definition ****/
/***********************************/ /***********************************/
SerialBusConnection::SerialBusConnection(QString portName, QString driverName) : SerialBusConnection::SerialBusConnection(QString portName, QString driverName, int pBusSpeed, int pDataRate, bool pCanFd) :
CANConnection(portName, driverName, CANCon::SERIALBUS,0 ,0, false, 0 ,1, 4000, true), CANConnection(portName, driverName, CANCon::SERIALBUS,0 ,pBusSpeed, pCanFd, pDataRate ,1, 4000, true),
mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */ mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */
{ {
} }
@@ -94,7 +94,7 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
setBusConfig(0, bus); setBusConfig(0, bus);
/* if bus is not active we are done */ /* if bus is not active we are done */
if(!bus.active) if(!bus.isActive())
return; return;
/* set configuration */ /* set configuration */
@@ -105,10 +105,10 @@ void SerialBusConnection::piSetBusSettings(int pBusIdx, CANBus bus)
//You cannot set the speed of a socketcan interface, it has to be set with console commands. //You cannot set the speed of a socketcan interface, it has to be set with console commands.
//But, you can probabaly set the speed of many of the other serialbus devices so go ahead and try //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); mDev_p->setConfigurationParameter(QCanBusDevice::BitRateKey, bus.getSpeed());
mDev_p->setConfigurationParameter(QCanBusDevice::CanFdKey, bus.canFD); mDev_p->setConfigurationParameter(QCanBusDevice::CanFdKey, bus.isCanFD());
if(bus.listenOnly) if(bus.isListenOnly())
sbusconfig |= EN_SILENT_MODE; sbusconfig |= EN_SILENT_MODE;
mDev_p->setConfigurationParameter(QCanBusDevice::UserKey, sbusconfig); mDev_p->setConfigurationParameter(QCanBusDevice::UserKey, sbusconfig);
@@ -188,6 +188,7 @@ void SerialBusConnection::framesReceived()
/* check frame */ /* check frame */
//if (recFrame.payload().length() <= 8) { //if (recFrame.payload().length() <= 8) {
if (true) {
CANFrame* frame_p = getQueue().get(); CANFrame* frame_p = getQueue().get();
if(frame_p) { if(frame_p) {
frame_p->setPayload(recFrame.payload()); frame_p->setPayload(recFrame.payload());
@@ -206,11 +207,11 @@ void SerialBusConnection::framesReceived()
frame_p->setTimeStamp(recFrame.timeStamp()); frame_p->setTimeStamp(recFrame.timeStamp());
frame_p->setFrameType(recFrame.frameType()); frame_p->setFrameType(recFrame.frameType());
frame_p->setError(recFrame.error()); frame_p->setError(recFrame.error());
/* If recorded frame has a local echo, it is a Tx message, and thus should not be marked as Rx */ /* If recorded frame has a local echo, it is a Tx message, and thus should not be marked as Rx */
frame_p->isReceived = !recFrame.hasLocalEcho(); frame_p->isReceived = !recFrame.hasLocalEcho();
if (useSystemTime) { if (useSystemTime) {
frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ul)); frame_p->setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul));
} }
else frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, (recFrame.timeStamp().seconds() * 1000000ul + recFrame.timeStamp().microSeconds()) - timeBasis)); else frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, (recFrame.timeStamp().seconds() * 1000000ul + recFrame.timeStamp().microSeconds()) - timeBasis));
@@ -218,11 +219,9 @@ void SerialBusConnection::framesReceived()
/* enqueue frame */ /* enqueue frame */
getQueue().queue(); getQueue().queue();
//} }
#if 0
else else
qDebug() << "can't get a frame, ERROR"; qDebug() << "can't get a frame, ERROR";
#endif
} }
} }
} }
+2 -1
View File
@@ -27,7 +27,8 @@ class SerialBusConnection : public CANConnection
Q_OBJECT Q_OBJECT
public: public:
SerialBusConnection(QString portName, QString driverName); SerialBusConnection(QString portName, QString driverName, int pBusSpeed,
int pDataRate, bool pCanFd);
virtual ~SerialBusConnection(); virtual ~SerialBusConnection();
protected: protected:
+2 -4
View File
@@ -219,8 +219,8 @@ void SocketCANd::connectDevice()
void SocketCANd::deviceConnected(int busNum) void SocketCANd::deviceConnected(int busNum)
{ {
sendDebug("Opening CAN on Kayak Device!"); sendDebug("Opening CAN on Kayak Device!");
const char* openCanCmd = ("< open " + hostCanIDs[busNum] + " >").toStdString().c_str(); QString openCanCmd("< open " % hostCanIDs[busNum] % " >");
sendStringToTCP(openCanCmd, busNum); sendStringToTCP(openCanCmd.toUtf8().data(), busNum);
QCoreApplication::processEvents(); QCoreApplication::processEvents();
} }
@@ -383,8 +383,6 @@ void SocketCANd::procRXData(QString data, int busNum)
mTimer.stop(); mTimer.stop();
mTimer.start(); mTimer.start();
} }
QByteArray output;
switch (rx_state.at(busNum)) switch (rx_state.at(busNum))
{ {
case IDLE: case IDLE:
+8 -4
View File
@@ -166,12 +166,16 @@ QString DBC_SIGNAL::processSignalTree(const CANFrame &frame)
if (sig->processAsText(frame, sigString)) if (sig->processAsText(frame, sigString))
{ {
qDebug() << "Returned value: " << sigString; qDebug() << "Returned value: " << sigString;
if (!build.isEmpty() && !sigString.isEmpty())
build.append("\n");
build.append(sigString); build.append(sigString);
build.append("\n");
if (sig->isMultiplexor) if (sig->isMultiplexor)
{ {
qDebug() << "Spelunkin!"; qDebug() << "Spelunkin!";
build.append(sig->processSignalTree(frame)); auto subTreeString = sig->processSignalTree(frame);
if (!build.isEmpty() && !subTreeString.isEmpty())
build.append("\n");
build.append(subTreeString);
} }
} }
} }
@@ -300,12 +304,12 @@ QString DBC_SIGNAL::makePrettyOutput(double floatVal, int64_t intVal, bool outpu
} }
} }
if (!foundVal) outputString += QString::number(intVal); if (!foundVal) outputString += QString::number(intVal);
if (outputUnit) outputString += unitName; if (outputUnit) outputString += " " + unitName;
} }
else //otherwise display the actual number and unit (if it exists) else //otherwise display the actual number and unit (if it exists)
{ {
outputString += (isInteger ? QString::number(intVal) : QString::number(floatVal)); outputString += (isInteger ? QString::number(intVal) : QString::number(floatVal));
if (outputUnit) outputString += unitName; if (outputUnit) outputString += " " + unitName;
} }
return outputString; return outputString;
} }
+47 -4
View File
@@ -674,6 +674,44 @@ bool DBCFile::parseSignalMultiplexValueLine(QString line)
return false; return false;
} }
bool DBCFile::parseSignalValueTypeLine(QString line)
{
QRegularExpression regex;
QRegularExpressionMatch match;
qDebug() << "Found a signal valtype line";
regex.setPattern("^SIG\\_VALTYPE\\_ *(\\d+) *([-\\w]+) *: *(\\d+);");
match = regex.match(line);
// captured 1 is the message id
// captured 2 is the signal name
// captured 3 is the valtype
if (!match.hasMatch()) { return false; }
uint32_t id = match.captured(1).toULong() & 0x1FFFFFFFUL;
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toULong() & 0x1FFFFFFFUL);
if (msg == nullptr) { return false; }
DBC_SIGNAL *thisSignal = msg->sigHandler->findSignalByName(match.captured(2));
if (thisSignal == nullptr) { return false; }
int valType = match.captured(3).toInt();
switch (valType) {
case 1: {
thisSignal->valType = SP_FLOAT;
break;
}
case 2: {
thisSignal->valType = DP_FLOAT;
break;
}
default: {
return false;
}
}
return true;
}
bool DBCFile::parseValueLine(QString line) bool DBCFile::parseValueLine(QString line)
{ {
QRegularExpression regex; QRegularExpression regex;
@@ -737,7 +775,7 @@ bool DBCFile::parseAttributeLine(QString line)
if (foundAttr) if (foundAttr)
{ {
qDebug() << "That message attribute does exist"; qDebug() << "That message attribute does exist";
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toUInt() & 0x1FFFFFFFul); DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toULong() & 0x1FFFFFFFul);
if (foundMsg) if (foundMsg)
{ {
qDebug() << "It references a valid, registered message"; qDebug() << "It references a valid, registered message";
@@ -769,7 +807,7 @@ bool DBCFile::parseAttributeLine(QString line)
if (foundAttr) if (foundAttr)
{ {
qDebug() << "That signal attribute does exist"; qDebug() << "That signal attribute does exist";
DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toUInt() & 0x1FFFFFFFUL); DBC_MESSAGE *foundMsg = messageHandler->findMsgByID(match.captured(2).toULong() & 0x1FFFFFFFUL);
if (foundMsg) if (foundMsg)
{ {
qDebug() << "It references a valid, registered message"; qDebug() << "It references a valid, registered message";
@@ -941,6 +979,11 @@ bool DBCFile::loadFile(QString fileName)
if (!parseSignalMultiplexValueLine(line)) numSigFaults++; if (!parseSignalMultiplexValueLine(line)) numSigFaults++;
} }
if (line.startsWith("SIG_VALTYPE_ ")) //defines a signal value type
{
if (!parseSignalValueTypeLine(line)) numSigFaults++;
}
if (line.startsWith("BU_:")) //line specifies the nodes on this canbus if (line.startsWith("BU_:")) //line specifies the nodes on this canbus
{ {
qDebug() << "Found a BU line"; qDebug() << "Found a BU line";
@@ -976,7 +1019,7 @@ bool DBCFile::loadFile(QString fileName)
if (match.hasMatch()) if (match.hasMatch())
{ {
//qDebug() << "Comment was: " << match.captured(3); //qDebug() << "Comment was: " << match.captured(3);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt()); DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toULong() & 0x1FFFFFFFul);
if (msg != nullptr) if (msg != nullptr)
{ {
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2)); DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
@@ -997,7 +1040,7 @@ bool DBCFile::loadFile(QString fileName)
if (match.hasMatch()) if (match.hasMatch())
{ {
//qDebug() << "Comment was: " << match.captured(2); //qDebug() << "Comment was: " << match.captured(2);
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toUInt()); DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toULong() & 0x1FFFFFFFul);
if (msg != nullptr) if (msg != nullptr)
{ {
msg->comment = match.captured(2); msg->comment = match.captured(2);
+1
View File
@@ -106,6 +106,7 @@ private:
bool parseSignalMultiplexValueLine(QString line); bool parseSignalMultiplexValueLine(QString line);
DBC_MESSAGE* parseMessageLine(QString line); DBC_MESSAGE* parseMessageLine(QString line);
bool parseValueLine(QString line); bool parseValueLine(QString line);
bool parseSignalValueTypeLine(QString line);
bool parseAttributeLine(QString line); bool parseAttributeLine(QString line);
bool parseDefaultAttrLine(QString line); bool parseDefaultAttrLine(QString line);
}; };
+39 -42
View File
@@ -133,38 +133,38 @@ void FirmwareUploaderWindow::timerElapsed()
void FirmwareUploaderWindow::sendFirmwareChunk() void FirmwareUploaderWindow::sendFirmwareChunk()
{ {
CANFrame *output = new CANFrame; CANFrame output;
int firmwareLocation = currentSendingPosition * 4; int firmwareLocation = currentSendingPosition * 4;
int xorByte = 0; int xorByte = 0;
output->setExtendedFrameFormat(false); output.setExtendedFrameFormat(false);
QByteArray bytes(7,0); QByteArray bytes(7,0);
output->bus = bus; output.bus = bus;
output->setFrameId(baseAddress + 0x16); output.setFrameId(baseAddress + 0x16);
output->payload()[0] = currentSendingPosition & 0xFF; bytes[0] = currentSendingPosition & 0xFF;
output->payload()[1] = (currentSendingPosition >> 8) & 0xFF; bytes[1] = (currentSendingPosition >> 8) & 0xFF;
output->payload()[2] = firmwareData[firmwareLocation++]; bytes[2] = firmwareData[firmwareLocation++];
output->payload()[3] = firmwareData[firmwareLocation++]; bytes[3] = firmwareData[firmwareLocation++];
output->payload()[4] = firmwareData[firmwareLocation++]; bytes[4] = firmwareData[firmwareLocation++];
output->payload()[5] = firmwareData[firmwareLocation++]; bytes[5] = firmwareData[firmwareLocation++];
for (int i = 0; i < 6; i++) xorByte = xorByte ^ static_cast<unsigned char>(output->payload()[i]); for (int i = 0; i < 6; i++) xorByte ^= static_cast<unsigned char>(bytes[i]);
output->payload()[6] = xorByte; bytes[6] = xorByte;
output->setPayload(bytes); output.setPayload(bytes);
CANConManager::getInstance()->sendFrame(*output); CANConManager::getInstance()->sendFrame(output);
timer->start(); timer->start();
} }
void FirmwareUploaderWindow::sendFirmwareEnding() void FirmwareUploaderWindow::sendFirmwareEnding()
{ {
CANFrame *output = new CANFrame; CANFrame output;
output->setExtendedFrameFormat(false); output.setExtendedFrameFormat(false);
output->bus = bus; output.bus = bus;
QByteArray bytes(4,0); QByteArray bytes(4,0);
output->setFrameId(baseAddress + 0x30); output.setFrameId(baseAddress + 0x30);
output->payload()[3] = 0xC0; bytes[3] = (char)0xC0;
output->payload()[2] = 0xDE; bytes[2] = (char)0xDE;
output->payload()[1] = 0xFA; bytes[1] = (char)0xFA;
output->payload()[0] = 0xDE; bytes[0] = (char)0xDE;
output->setPayload(bytes); output.setPayload(bytes);
//sendCANFrame(output, bus); //sendCANFrame(output, bus);
} }
@@ -182,23 +182,23 @@ void FirmwareUploaderWindow::handleStartStopTransfer()
qDebug() << "Base address: " + QString::number(baseAddress); qDebug() << "Base address: " + QString::number(baseAddress);
CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x10, 0x7FF, this); CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x10, 0x7FF, this);
CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x20, 0x7FF, this); CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x20, 0x7FF, this);
CANFrame *output = new CANFrame; CANFrame output;
output->setExtendedFrameFormat(false); output.setExtendedFrameFormat(false);
QByteArray bytes(8,0); QByteArray bytes(8,0);
output->bus = bus; output.bus = bus;
output->setFrameId(baseAddress); output.setFrameId(baseAddress);
output->setFrameType(QCanBusFrame::DataFrame); output.setFrameType(QCanBusFrame::DataFrame);
bytes[0] = 0xEF; bytes[0] = (char)0xEF;
bytes[1] = 0xBE; bytes[1] = (char)0xBE;
bytes[2] = 0xAD; bytes[2] = (char)0xAD;
bytes[3] = 0xDE; bytes[3] = (char)0xDE;
bytes[4] = token & 0xFF; bytes[4] = token & 0xFF;
bytes[5] = (token >> 8) & 0xFF; bytes[5] = (token >> 8) & 0xFF;
bytes[6] = (token >> 16) & 0xFF; bytes[6] = (token >> 16) & 0xFF;
bytes[7] = (token >> 24) & 0xFF; bytes[7] = (token >> 24) & 0xFF;
output->setPayload(bytes); output.setPayload(bytes);
CANConManager::getInstance()->sendFrame(*output); CANConManager::getInstance()->sendFrame(output);
} }
else //stop anything in process else //stop anything in process
{ {
@@ -209,7 +209,6 @@ void FirmwareUploaderWindow::handleStartStopTransfer()
void FirmwareUploaderWindow::handleLoadFile() void FirmwareUploaderWindow::handleLoadFile()
{ {
QString filename;
QFileDialog dialog; QFileDialog dialog;
QStringList filters; QStringList filters;
@@ -221,7 +220,7 @@ void FirmwareUploaderWindow::handleLoadFile()
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
filename = dialog.selectedFiles()[0]; QString filename = dialog.selectedFiles().constFirst();
loadBinaryFile(filename); loadBinaryFile(filename);
} }
@@ -232,22 +231,20 @@ void FirmwareUploaderWindow::loadBinaryFile(QString filename)
if (transferInProgress) handleStartStopTransfer(); if (transferInProgress) handleStartStopTransfer();
QFile *inFile = new QFile(filename); QFile inFile(filename);
if (!inFile->open(QIODevice::ReadOnly)) if (!inFile.open(QIODevice::ReadOnly))
{ {
delete inFile;
return; return;
} }
firmwareData = inFile->readAll(); firmwareData = inFile.readAll();
currentSendingPosition = 0; currentSendingPosition = 0;
firmwareSize = firmwareData.length(); firmwareSize = firmwareData.length();
updateProgress(); updateProgress();
inFile->close(); inFile.close();
delete inFile;
} }
+152 -28
View File
@@ -191,6 +191,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
filters.append(QString(tr("CLX000 (*.txt *.TXT)"))); filters.append(QString(tr("CLX000 (*.txt *.TXT)")));
filters.append(QString(tr("CANServer Binary Log (*.log *.LOG)"))); filters.append(QString(tr("CANServer Binary Log (*.log *.LOG)")));
filters.append(QString(tr("Wireshark (*.pcap *.PCAP *.pcapng *.PCAPNG)"))); filters.append(QString(tr("Wireshark (*.pcap *.PCAP *.pcapng *.PCAPNG)")));
filters.append(QString(tr("Wireshark SocketCAN (*.pcap *.PCAP")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString()); dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile); dialog.setFileMode(QFileDialog::ExistingFile);
@@ -237,6 +238,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
if (selectedNameFilter == filters[22]) result = loadCLX000File(filename, frameCache); if (selectedNameFilter == filters[22]) result = loadCLX000File(filename, frameCache);
if (selectedNameFilter == filters[23]) result = loadCANServerFile(filename, frameCache); if (selectedNameFilter == filters[23]) result = loadCANServerFile(filename, frameCache);
if (selectedNameFilter == filters[24]) result = loadWiresharkFile(filename, frameCache); if (selectedNameFilter == filters[24]) result = loadWiresharkFile(filename, frameCache);
if (selectedNameFilter == filters[25]) result = loadWiresharkSocketCANFile(filename, frameCache);
progress.cancel(); progress.cancel();
@@ -288,6 +290,28 @@ bool FrameFileIO::autoDetectLoadFile(QString filename, QVector<CANFrame>* frames
} }
} }
// Attempt to load socket CAN first to avoid generic wireshark logic catching it
qDebug() << "Attempting Wireshark Socket CAN Log";
if (isWiresharkSocketCANFile(filename))
{
if (loadWiresharkSocketCANFile(filename, frames))
{
qDebug() << "Loaded as Wireshark SocketCAN Log successfully!";
return true;
}
}
// This and the decoder above were both moved above TeslaAPFile as they match based on magic numbers and sometimes these files were falling into the TeslaAP decoder
qDebug() << "Attempting Wireshark Log";
if (isWiresharkFile(filename))
{
if (loadWiresharkFile(filename, frames))
{
qDebug() << "Loaded as Wireshark Log successfully!";
return true;
}
}
qDebug() << "Attempting Tesla AP Snapshot"; qDebug() << "Attempting Tesla AP Snapshot";
if (isTeslaAPFile(filename)) if (isTeslaAPFile(filename))
{ {
@@ -308,16 +332,6 @@ bool FrameFileIO::autoDetectLoadFile(QString filename, QVector<CANFrame>* frames
} }
} }
qDebug() << "Attempting Wireshark Log";
if (isWiresharkFile(filename))
{
if (loadWiresharkFile(filename, frames))
{
qDebug() << "Loaded as Wireshark Log successfully!";
return true;
}
}
qDebug() << "Attempting canalyzer ASC"; qDebug() << "Attempting canalyzer ASC";
if (isCanalyzerASC(filename)) if (isCanalyzerASC(filename))
{ {
@@ -1440,7 +1454,8 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
QByteArray bytes(numBytes, 0); QByteArray bytes(numBytes, 0);
thisFrame.isReceived = true; thisFrame.isReceived = true;
thisFrame.bus = 0; thisFrame.bus = 0;
if (thisFrame.frameId() > 0x10000000) if ((thisFrame.frameId() > 0x10000000) ||
(tokens[3].length() >= 8))
{ {
thisFrame.setExtendedFrameFormat(true); thisFrame.setExtendedFrameFormat(true);
} }
@@ -1492,7 +1507,8 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
//qDebug() << thisFrame.payload().length(); //qDebug() << thisFrame.payload().length();
thisFrame.isReceived = true; thisFrame.isReceived = true;
thisFrame.bus = tokens[2].toInt(); thisFrame.bus = tokens[2].toInt();
if (thisFrame.frameId() > 0x10000000) if ((thisFrame.frameId() > 0x10000000) ||
(tokens[4].length() >= 8))
{ {
thisFrame.setExtendedFrameFormat(true); thisFrame.setExtendedFrameFormat(true);
} }
@@ -1534,7 +1550,8 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
//qDebug() << thisFrame.payload().length(); //qDebug() << thisFrame.payload().length();
thisFrame.isReceived = true; thisFrame.isReceived = true;
thisFrame.bus = 0; thisFrame.bus = 0;
if (thisFrame.frameId() > 0x10000000) if ((thisFrame.frameId() > 0x10000000) ||
(tokens[3].length() >= 8))
{ {
thisFrame.setExtendedFrameFormat(true); thisFrame.setExtendedFrameFormat(true);
} }
@@ -1586,7 +1603,8 @@ bool FrameFileIO::loadPCANFile(QString filename, QVector<CANFrame>* frames)
//qDebug() << thisFrame.payload().length(); //qDebug() << thisFrame.payload().length();
thisFrame.isReceived = true; thisFrame.isReceived = true;
thisFrame.bus = tokens[3].toInt(); thisFrame.bus = tokens[3].toInt();
if (thisFrame.frameId() > 0x10000000) if ((thisFrame.frameId() > 0x10000000) ||
(tokens[4].length() >= 8))
{ {
thisFrame.setExtendedFrameFormat(true); thisFrame.setExtendedFrameFormat(true);
} }
@@ -1680,12 +1698,16 @@ bool FrameFileIO::isCanalyzerASC(QString filename)
//0.001371 CANFD 1 Rx 171 A0066_Unknown 0 0 8 8 00 00 07 76 23 00 00 00 230199 119 220000 62e7 46500250 460a0250 20011736 20010205 //0.001371 CANFD 1 Rx 171 A0066_Unknown 0 0 8 8 00 00 07 76 23 00 00 00 230199 119 220000 62e7 46500250 460a0250 20011736 20010205
//Version 16.0.0 //Version 16.0.0
//0.008600 1 358 Rx d 8 04 03 50 01 F0 40 54 2C Length = 233910 BitCount = 121 ID = 856 //0.008600 1 358 Rx d 8 04 03 50 01 F0 40 54 2C Length = 233910 BitCount = 121 ID = 856
//Time bus id dir ? len databytes (Ver 8.0) //Version 17.3.0
//Time type bus dir ID ? ? length length bytes then many values of unknown type (ver 8.1) //0.001684 CANFD 1 Rx 65b 1 0 d 32 f1 01 00 00 50 00 00 00 00 00 00 00 00 00 00 40 00 88 f5 77 17 78 00 00 c0 03 00 00 00 00 00 00 213797 356 303000 11729 46500250 4b140250 20011736 2001040d
//Time type bus dir ID SignalName ? ? length length bytes then many values of unknown type (ver 9.0)
//Time bus id dir ? len databytes additional crap (ver 16.0) //Time bus id dir ? len databytes (Ver 8.0)
//So it seems the file format is not entirely different based on version but rather on some other //Time bus id dir ? len databytes (addl info) (ver 16.0)
//settings... Fun! //Time type bus dir ID ? ? length length (bytes) (many values of unknown type) (ver 8.1)
//Time type bus dir ID SignalName ? ? length length bytes (then many values of unknown type)(ver 9.0)
//Time Type Bus Dir ID ? ? (length) (Real Length) (bytes) (many values of unknown type) (Ver 17.3)
//0 1 2 3 4 5 6 7 8 9 10
//This seems like a rather eclectic mix. It's almost arbitrary!
bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames) bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
{ {
QFile *inFile = new QFile(filename); QFile *inFile = new QFile(filename);
@@ -1736,7 +1758,7 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
} }
} }
if (inHeader) continue; if (inHeader) continue;
if (line.length() > 2) if (line.length() > 2 && !line.startsWith("//"))
{ {
tokens = line.simplified().split(' '); tokens = line.simplified().split(' ');
@@ -1766,7 +1788,7 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
int payloadLen = tokens[8].toInt(); int payloadLen = tokens[8].toInt();
qDebug() << "PayloadLen: " << payloadLen << " Tokens: " << tokens; qDebug() << "PayloadLen: " << payloadLen << " Tokens: " << tokens;
QByteArray bytes(payloadLen, 0); QByteArray bytes(payloadLen, 0);
if (payloadLen > 8) if (payloadLen > 64)
{ {
qDebug() << "Payload length too long. Original line: " << line; qDebug() << "Payload length too long. Original line: " << line;
return false; return false;
@@ -3766,12 +3788,17 @@ bool FrameFileIO::loadCanDumpFile(QString filename, QVector<CANFrame>* frames)
if (line.contains('[')) //the expanded format (second one from the above list) if (line.contains('[')) //the expanded format (second one from the above list)
{ {
//(1551774790.942758) can1 7A8 [8] F4 DC D1 83 0E 02 00 00 //(1551774790.942758) can1 7A8 [8] F4 DC D1 83 0E 02 00 00
//(1551774790.942758) can1 7A8 [08] F4 DC D1 83 0E 02 00 00
// 0 1 2 3 4 5 6 7 8 9 10 11 // 0 1 2 3 4 5 6 7 8 9 10 11
thisFrame.setFrameId(tokens[2].toLong(nullptr, 16)); thisFrame.setFrameId(tokens[2].toLong(nullptr, 16));
if (thisFrame.frameId() > 0x7FF) thisFrame.setExtendedFrameFormat(true); if (thisFrame.frameId() > 0x7FF) thisFrame.setExtendedFrameFormat(true);
else thisFrame.setExtendedFrameFormat(false); else thisFrame.setExtendedFrameFormat(false);
thisFrame.setFrameType(QCanBusFrame::DataFrame); thisFrame.setFrameType(QCanBusFrame::DataFrame);
int numBytes = tokens[3].at(1) - '0'; int numBytes;
if (tokens[3].at(2) == ']')
numBytes = tokens[3].at(1) - '0';
else
numBytes = (tokens[3].at(1) - '0')*10 + (tokens[3].at(2) - '0');
QByteArray bytes(numBytes, 0); QByteArray bytes(numBytes, 0);
for (int c = 0; c < numBytes; c++) for (int c = 0; c < numBytes; c++)
{ {
@@ -5019,7 +5046,7 @@ bool FrameFileIO::loadWiresharkFile(QString filename, QVector<CANFrame>* frames)
QByteArray ba = filename.toLocal8Bit(); QByteArray ba = filename.toLocal8Bit();
pcap_data_file = pcap_open_offline(ba.data(), errbuf); pcap_data_file = pcap_open_offline(ba.data(), errbuf, PCAP_LINKTYPE_ANY);
if (!pcap_data_file) { if (!pcap_data_file) {
return false; return false;
} }
@@ -5046,9 +5073,13 @@ bool FrameFileIO::loadWiresharkFile(QString filename, QVector<CANFrame>* frames)
thisFrame.isReceived = true; // TODO: check if tx detection is possible thisFrame.isReceived = true; // TODO: check if tx detection is possible
thisFrame.setFrameType(QCanBusFrame::DataFrame); thisFrame.setFrameType(QCanBusFrame::DataFrame);
thisFrame.setFrameId((0xff & *(packetData+17)) << 8 | (0xff & *(packetData+16))); if ((0x80 & *(packetData+19))) {
if (thisFrame.frameId() <= 0x7FF) thisFrame.setExtendedFrameFormat(false); thisFrame.setExtendedFrameFormat(true);
else thisFrame.setExtendedFrameFormat(true); thisFrame.setFrameId((0x3f & *(packetData+19))<<24 | (0xff & *(packetData+18)) << 16 | (0xff & *(packetData+17)) << 8 | (0xff & *(packetData+16)));
} else {
thisFrame.setExtendedFrameFormat(false);
thisFrame.setFrameId((0xff & *(packetData+17)) << 8 | (0xff & *(packetData+16)));
}
thisFrame.bus = 0; thisFrame.bus = 0;
int numBytes = *(packetData+20); int numBytes = *(packetData+20);
QByteArray bytes(numBytes, 0); QByteArray bytes(numBytes, 0);
@@ -5075,7 +5106,7 @@ bool FrameFileIO::isWiresharkFile(QString filename)
char errbuf[PCAP_ERRBUF_SIZE]; char errbuf[PCAP_ERRBUF_SIZE];
QByteArray ba = filename.toLocal8Bit(); QByteArray ba = filename.toLocal8Bit();
pcap_data_file = pcap_open_offline(ba.data(), errbuf); pcap_data_file = pcap_open_offline(ba.data(), errbuf, PCAP_LINKTYPE_ANY);
if (!pcap_data_file) { if (!pcap_data_file) {
return false; return false;
} }
@@ -5085,3 +5116,96 @@ bool FrameFileIO::isWiresharkFile(QString filename)
return true; return true;
} }
bool FrameFileIO::loadWiresharkSocketCANFile(QString filename, QVector<CANFrame>* frames)
{
pcap_t *pcap_data_file;
CANFrame thisFrame;
long long startTimestamp = 0;
long long timeStamp;
int lineCounter = 0;
bool foundErrors = false;
pcap_pkthdr packetHeader;
const char *packetData = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
QByteArray ba = filename.toLocal8Bit();
pcap_data_file = pcap_open_offline(ba.data(), errbuf, PCAP_LINKTYPE_SOCKETCAN);
if (!pcap_data_file) {
return false;
}
packetData = (const char*)pcap_next(pcap_data_file, &packetHeader);
while (packetData) {
lineCounter++;
if (lineCounter > 100) {
qApp->processEvents();
lineCounter = 0;
}
thisFrame.bus = 0;
// Timestamp
timeStamp = packetHeader.ts.tv_sec * 1000000 + packetHeader.ts.tv_usec;
if (0 == startTimestamp) {
startTimestamp = timeStamp;
}
timeStamp -= startTimestamp;
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, timeStamp));
// ID and extended frame format
const quint32 can_id = qFromBigEndian<quint32>(packetData);
if (can_id & 0x80000000) {
thisFrame.setExtendedFrameFormat(true);
thisFrame.setFrameId(0x1fffffff & can_id);
} else {
thisFrame.setExtendedFrameFormat(false);
thisFrame.setFrameId(0x7ff & can_id);
}
// Frame type
if (can_id & 0x20000000U) {
thisFrame.setFrameType(QCanBusFrame::ErrorFrame);
} else if (can_id & 0x40000000U) {
thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
} else {
thisFrame.setFrameType(QCanBusFrame::DataFrame);
}
// Direction - This isn't actually officially supported, but CAN Bus Debugger device logs set this byte to 1 to indicate a TX frame and 0 for RX
quint8 direction = (quint8) *(packetData + 6);
thisFrame.isReceived = (direction != 1);
// Data
quint8 numBytes = (quint8) *(packetData + 4);
if (numBytes > 8) {
numBytes = 8;
}
QByteArray bytes(numBytes, 0);
for (int d = 0; d < numBytes; d++) {
bytes[d] = *(packetData + 8 + d);
}
thisFrame.setPayload(bytes);
frames->append(thisFrame);
packetData = (const char*) pcap_next(pcap_data_file, &packetHeader);
}
pcap_close(pcap_data_file);
pcap_data_file = NULL;
return !foundErrors;
}
bool FrameFileIO::isWiresharkSocketCANFile(QString filename)
{
pcap_t *pcap_data_file;
char errbuf[PCAP_ERRBUF_SIZE];
QByteArray ba = filename.toLocal8Bit();
pcap_data_file = pcap_open_offline(ba.data(), errbuf, PCAP_LINKTYPE_SOCKETCAN);
if (!pcap_data_file) {
return false;
}
pcap_close(pcap_data_file);
pcap_data_file = NULL;
return true;
}
+2
View File
@@ -54,6 +54,7 @@ public:
static bool loadCLX000File(QString filename, QVector<CANFrame>* frames); static bool loadCLX000File(QString filename, QVector<CANFrame>* frames);
static bool loadCANServerFile(QString filename, QVector<CANFrame>* frames); static bool loadCANServerFile(QString filename, QVector<CANFrame>* frames);
static bool loadWiresharkFile(QString filename, QVector<CANFrame>* frames); static bool loadWiresharkFile(QString filename, QVector<CANFrame>* frames);
static bool loadWiresharkSocketCANFile(QString filename, QVector<CANFrame>* frames);
//functions that pre-scan a file to try to figure out if they could read it. Used to automatically determine //functions that pre-scan a file to try to figure out if they could read it. Used to automatically determine
//file type and load it. //file type and load it.
@@ -80,6 +81,7 @@ public:
static bool isCLX000File(QString filename); static bool isCLX000File(QString filename);
static bool isCANServerFile(QString filename); static bool isCANServerFile(QString filename);
static bool isWiresharkFile(QString filename); static bool isWiresharkFile(QString filename);
static bool isWiresharkSocketCANFile(QString filename);
static bool saveCRTDFile(QString, const QVector<CANFrame>*); static bool saveCRTDFile(QString, const QVector<CANFrame>*);
static bool saveNativeCSVFile(QString, const QVector<CANFrame>*); static bool saveNativeCSVFile(QString, const QVector<CANFrame>*);
+457
View File
@@ -0,0 +1,457 @@
#include "framesenderobject.h"
#include "mainwindow.h"
FrameSenderObject::FrameSenderObject(const QVector<CANFrame> *frames)
{
mThread_p = new QThread();
statusCounter = 0;
modelFrames = frames;
dbcHandler = DBCHandler::getReference();
}
FrameSenderObject::~FrameSenderObject()
{
mThread_p->quit();
mThread_p->wait();
delete mThread_p;
}
void FrameSenderObject::piStart()
{
sendingTimer = new QTimer();
sendingTimer->setTimerType(Qt::PreciseTimer);
sendingTimer->setInterval(1);
connect(sendingTimer, &QTimer::timeout, this, &FrameSenderObject::timerTriggered);
}
void FrameSenderObject::piStop()
{
sendingTimer->stop();
delete sendingTimer;
}
void FrameSenderObject::initialize()
{
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
/* move ourself to the thread */
moveToThread(mThread_p); /*TODO handle errors */
/* connect started() */
connect(mThread_p, SIGNAL(started()), this, SLOT(initialize()));
/* start the thread */
mThread_p->start(QThread::HighPriority);
return;
}
/* set started flag */
//mStarted = true;
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
/* in multithread case, this will be called before entering thread event loop */
return piStart();
}
void FrameSenderObject::finalize()
{
/* 1) execute in mThread_p context */
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
/* if thread is finished, it means we call this function for the second time so we can leave */
if( !mThread_p->isFinished() )
{
/* we need to call piStop() */
QMetaObject::invokeMethod(this, "finalize",
Qt::BlockingQueuedConnection);
/* 3) stop thread */
mThread_p->quit();
if(!mThread_p->wait()) {
qDebug() << "can't stop thread";
}
}
return;
}
/* 2) call piStop in mThread context */
return piStop();
}
void FrameSenderObject::startSending()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "startSending",
Qt::BlockingQueuedConnection);
return;
}
sendingElapsed.start();
sendingTimer->start();
}
void FrameSenderObject::stopSending()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "stopPlayback",
Qt::BlockingQueuedConnection);
return;
}
sendingTimer->stop(); //pushing this button halts automatic playback
//emit statusUpdate(currentPosition);
}
void FrameSenderObject::addSendRecord(FrameSendData record)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "addSendRecord",
Qt::BlockingQueuedConnection,
Q_ARG(FrameSendData, record));
return;
}
sendingData.append(record);
}
void FrameSenderObject::removeSendRecord(int idx)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "removeSendRecord",
Qt::BlockingQueuedConnection,
Q_ARG(int, idx));
return;
}
sendingData.removeAt(idx);
}
/*
* Note: Getting a reference to an item in a QList is a dangerous thing. If anyone
* or anything happens to reallocate the list you're screwed. So, call this, do the
* work, and drop the reference as soon as possible.
*/
FrameSendData *FrameSenderObject::getSendRecordRef(int idx)
{
if (idx < 0 || idx >= sendingData.count()) return nullptr;
return &sendingData[idx];
}
/// <summary>
/// Called every millisecond to set the system update figures and send frames if necessary.
/// </summary>
/// <param name="sender"></param>
/// <param name="timerEventArgs"></param>
///
void FrameSenderObject::timerTriggered()
{
FrameSendData *sendData;
Trigger *trigger;
sendingList.clear();
if(mutex.tryLock())
{
/*
* Requested tick interval was 1ms but the actual interval could be wildly different. So, we track
* by counting microseconds and accumulating. This creates decent stability even for long intervals
*/
quint64 elapsed = sendingElapsed.nsecsElapsed() / 1000ul;
if (elapsed == 0) elapsed = 1;
sendingElapsed.start();
sendingLastTimeStamp += elapsed;
//qDebug() << sendingLastTimeStamp;
//qDebug() << "El: " << elapsed;
statusCounter++;
for (int i = 0; i < sendingData.count(); i++)
{
sendData = &sendingData[i];
if (!sendData->enabled)
{
if (sendData->triggers.count() > 0)
{
for (int j = 0; j < sendData->triggers.count(); j++) //resetting currCount when line is disabled
{
sendData->triggers[j].currCount = 0;
}
}
continue; //abort any processing on this if it is not enabled.
}
if (sendData->triggers.count() == 0)
{
//qDebug() << "No triggers to process";
break;
}
for (int j = 0; j < sendData->triggers.count(); j++)
{
trigger = &sendData->triggers[j];
//if ( (trigger->currCount >= trigger->maxCount) || (trigger->maxCount == -1) ) continue; //don't process if we've sent max frames we were supposed to
if (!trigger->readyCount) continue; //don't tick if not ready to tick
//is it time to fire?
trigger->msCounter += elapsed; //gives proper tracking even if timer doesn't fire as fast as it should
//qDebug() << trigger->msCounter;
if (trigger->msCounter >= (trigger->milliseconds * 1000))
{
trigger->msCounter -= (trigger->milliseconds * 1000);
sendData->count++;
trigger->currCount++;
doModifiers(i);
//updateGridRow(i);
//qDebug() << "About to try to send a frame";
//CANConManager::getInstance()->sendFrame(sendingData[i]);
sendingList.append(sendingData[i]); //queue it instead of immediate sending
if (trigger->ID > 0) trigger->readyCount = false; //reset flag if this is a timed ID trigger
}
}
}
//if we have any frames to send after the above then send as a batch
if (sendingList.count() > 0) CANConManager::getInstance()->sendFrames(sendingList);
mutex.unlock();
}
else
{
qDebug() << "framesenderobject::handleTick() couldn't get mutex, elapsed is: " << sendingElapsed.elapsed();
}
}
void FrameSenderObject::buildFrameCache()
{
CANFrame thisFrame;
frameCache.clear();
for (int i = 0; i < modelFrames->count(); i++)
{
thisFrame = modelFrames->at(i);
if (!frameCache.contains(thisFrame.frameId()))
{
frameCache.insert(thisFrame.frameId(), thisFrame);
}
else
{
frameCache[thisFrame.frameId()] = thisFrame;
}
}
}
//remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames.
void FrameSenderObject::updatedFrames(int numFrames)
{
CANFrame thisFrame;
if (numFrames == -1) //all frames deleted.
{
}
else if (numFrames == -2) //all new set of frames.
{
buildFrameCache();
}
else //just got some new frames. See if they are relevant.
{
if (numFrames > modelFrames->count()) return;
qDebug() << "New frames in sender window";
//run through the supposedly new frames in order
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
{
thisFrame = modelFrames->at(i);
if (!frameCache.contains(thisFrame.frameId()))
{
frameCache.insert(thisFrame.frameId(), thisFrame);
}
else
{
frameCache[thisFrame.frameId()] = thisFrame;
}
processIncomingFrame(&thisFrame);
}
}
}
void FrameSenderObject::processIncomingFrame(CANFrame *frame)
{
for (int sd = 0; sd < sendingData.count(); sd++)
{
if (sendingData[sd].triggers.count() == 0) continue;
bool passedChecks = true;
for (int trig = 0; trig < sendingData[sd].triggers.count(); trig++)
{
Trigger *thisTrigger = &sendingData[sd].triggers[trig];
//need to ensure that this trigger is actually related to frames incoming.
//Otherwise ignore it here. Only frames that have BUS and/or ID set as trigger will work here.
if (!(thisTrigger->triggerMask & (TriggerMask::TRG_BUS | TriggerMask::TRG_ID) ) ) continue;
passedChecks = true;
//qDebug() << "Trigger ID: " << thisTrigger->ID;
//qDebug() << "Frame ID: " << frame->frameId();
//Check to see if we have a bus trigger condition and if so does it match
if (thisTrigger->bus != frame->bus && (thisTrigger->triggerMask & TriggerMask::TRG_BUS) )
passedChecks = false;
//check to see if we have an ID trigger condition and if so does it match
if ((thisTrigger->triggerMask & TriggerMask::TRG_ID) && (uint32_t)thisTrigger->ID != frame->frameId() )
passedChecks = false;
//check to see if we're limiting the trigger by max count and have we reached that count?
if ( (thisTrigger->triggerMask & TriggerMask::TRG_COUNT) && (thisTrigger->currCount >= thisTrigger->maxCount) )
passedChecks = false;
//if the above passed then are we triggering not only on ID but also signal?
if (passedChecks && (thisTrigger->triggerMask & (TriggerMask::TRG_SIGNAL | TriggerMask::TRG_ID) ) )
{
bool sigCheckPassed = false;
DBC_MESSAGE *msg = dbcHandler->findMessage(thisTrigger->ID);
if (msg)
{
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(thisTrigger->sigName);
if (sig)
{
//first of all, is this signal really in this message we got?
if (sig->isSignalInMessage(*frame)) sigCheckPassed = true;
//if it was and we're also filtering on value then try that next
if (sigCheckPassed && (thisTrigger->triggerMask & TriggerMask::TRG_SIGVAL))
{
double sigval = 0.0;
if (sig->processAsDouble(*frame, sigval))
{
if (abs(sigval - thisTrigger->sigValueDbl) > 0.001)
{
sigCheckPassed = false;
}
}
else sigCheckPassed = false;
}
}
else sigCheckPassed = false;
}
else sigCheckPassed = false;
passedChecks &= sigCheckPassed; //passedChecks can only be true if both are
}
//if all the above says it's OK then we'll go ahead and send that message.
//If a message that comes through here has a MS value then we use it as a delay
//after the check passes. This allows for delaying the sending of the frame if that
//is required. Otherwise, just send it immediately.
if (passedChecks)
{
if (thisTrigger->milliseconds == 0) //immediate reply
{
thisTrigger->currCount++;
sendingData[sd].count++;
doModifiers(sd);
//updateGridRow(sd);
CANConManager::getInstance()->sendFrame(sendingData[sd]);
}
else //delayed sending frame
{
thisTrigger->readyCount = true;
}
}
}
}
}
/// <summary>
/// given an index into the sendingData list we run the modifiers that it has set up
/// </summary>
/// <param name="idx">The index into the sendingData list</param>
void FrameSenderObject::doModifiers(int idx)
{
int shadowReg = 0; //shadow register we use to accumulate results
int first=0, second=0;
FrameSendData *sendData = &sendingData[idx];
Modifier *mod;
ModifierOp op;
if (sendData->modifiers.count() == 0) return; //if no modifiers just leave right now
//qDebug() << "Executing mods";
for (int i = 0; i < sendData->modifiers.count(); i++)
{
mod = &sendData->modifiers[i];
for (int j = 0; j < mod->operations.count(); j++)
{
op = mod->operations.at(j);
if (op.first.ID == -1)
{
first = shadowReg;
}
else first = fetchOperand(idx, op.first);
second = fetchOperand(idx, op.second);
switch (op.operation)
{
case ADDITION:
shadowReg = first + second;
break;
case AND:
shadowReg = first & second;
break;
case DIVISION:
shadowReg = first / second;
break;
case MULTIPLICATION:
shadowReg = first * second;
break;
case OR:
shadowReg = first | second;
break;
case SUBTRACTION:
shadowReg = first - second;
break;
case XOR:
shadowReg = first ^ second;
break;
case MOD:
shadowReg = first % second;
}
}
//Finally, drop the result into the proper data byte
QByteArray newArr(sendData->payload());
newArr[mod->destByte] = (char) shadowReg;
sendData->setPayload(newArr);
}
}
int FrameSenderObject::fetchOperand(int idx, ModifierOperand op)
{
CANFrame *tempFrame = nullptr;
if (op.ID == 0) //numeric constant
{
if (op.notOper) return ~op.databyte;
else return op.databyte;
}
else if (op.ID == -2) //fetch data from a data byte within the output frame
{
if (op.notOper) return ~((unsigned char)sendingData.at(idx).payload()[op.databyte]);
else return (unsigned char)sendingData.at(idx).payload()[op.databyte];
}
else //look up external data byte
{
tempFrame = lookupFrame(op.ID, op.bus);
if (tempFrame != nullptr)
{
if (op.notOper) return ~((unsigned char)tempFrame->payload()[op.databyte]);
else return (unsigned char)tempFrame->payload()[op.databyte];
}
else return 0;
}
}
/// <summary>
/// Try to find the most recent frame given the input criteria
/// </summary>
/// <param name="ID">The ID to find</param>
/// <param name="bus">Which bus to look on (-1 if you don't care)</param>
/// <returns></returns>
CANFrame* FrameSenderObject::lookupFrame(int ID, int bus)
{
if (!frameCache.contains(ID)) return nullptr;
if (bus == -1 || frameCache[ID].bus == bus) return &frameCache[ID];
return nullptr;
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef FRAMESENDEROBJECT_H
#define FRAMESENDEROBJECT_H
#include <QElapsedTimer>
#include <QTimer>
#include <QHash>
#include <QThread>
#include <QDebug>
#include <QMutex>
#include "can_structs.h"
#include "connections/canconmanager.h"
#include "can_trigger_structs.h"
#include "dbc/dbchandler.h"
class FrameSenderObject : public QObject
{
Q_OBJECT
public:
FrameSenderObject(const QVector<CANFrame> *frames);
~FrameSenderObject();
public slots:
/**
* @brief start the device. This calls piStarted
* @note starts the working thread if required (piStart is called in the working thread context)
*/
void initialize();
/**
* @brief stop the device. This calls piStop
* @note if a working thread is used, piStop is called before exiting the working thread
*/
void finalize();
void startSending();
void stopSending();
void addSendRecord(FrameSendData record);
void removeSendRecord(int idx);
FrameSendData *getSendRecordRef(int idx);
signals:
private slots:
void timerTriggered();
void updatedFrames(int);
private:
QList<CANFrame> sendingList;
int currentPosition;
QTimer *sendingTimer;
QElapsedTimer sendingElapsed;
quint64 sendingLastTimeStamp;
int statusCounter;
QList<FrameSendData> sendingData;
QThread* mThread_p;
QHash<int, CANFrame> frameCache; //hash with frame ID as the key and the most recent frame as the value
const QVector<CANFrame> *modelFrames;
bool inhibitChanged = false;
QMutex mutex;
DBCHandler *dbcHandler;
void doModifiers(int);
int fetchOperand(int, ModifierOperand);
CANFrame* lookupFrame(int, int);
void buildFrameCache();
void processIncomingFrame(CANFrame *frame);
/**
* @brief starts the device
*/
void piStart();
/**
* @brief stops the device
*/
void piStop();
};
#endif // FRAMESENDEROBJECT_H
+29 -14
View File
@@ -63,8 +63,8 @@ void FrameSenderWindow::setupGrid()
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_EXT, 50); ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_EXT, 50);
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_REM, 50); ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_REM, 50);
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_DATA, 220); ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_DATA, 220);
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_TRIGGER, 220); ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_TRIGGER, 270);
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_MODS, 220); ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_MODS, 270);
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_COUNT, 80); ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_COUNT, 80);
ui->tableSender->setHorizontalHeaderLabels(headers); ui->tableSender->setHorizontalHeaderLabels(headers);
} }
@@ -693,6 +693,12 @@ void FrameSenderWindow::processModifierText(int line)
//Example line: //Example line:
//d0 = D0 + 1,d1 = id:0x200:d3 + id:0x200:d4 AND 0xF0 - Original version //d0 = D0 + 1,d1 = id:0x200:d3 + id:0x200:d4 AND 0xF0 - Original version
//D0=D0+1,D1=ID:0x200:D3+ID:0x200:D4&0xF0 //D0=D0+1,D1=ID:0x200:D3+ID:0x200:D4&0xF0
//[BMS_TargetVoltage]=45 would set the value of signal BMS_TargetVoltage to 45
//[BMS_TargetVoltage]=[0x234:BMS_CurrentVoltage] + 4 would instead grab the value
//of BMS_CurrentVoltage from ID 0x234, add 4 to it, and set BMS_TargetVoltage to that value.
//This is certainly much harder to parse than the trigger definitions. //This is certainly much harder to parse than the trigger definitions.
//the left side of the = has to be D0 to D7. After that there is a string of //the left side of the = has to be D0 to D7. After that there is a string of
//data. Spaces used to be required but no longer are. This makes parsing harder but data entry easier //data. Spaces used to be required but no longer are. This makes parsing harder but data entry easier
@@ -710,22 +716,33 @@ void FrameSenderWindow::processModifierText(int line)
Modifier thisMod; Modifier thisMod;
thisMod.destByte = 0; thisMod.destByte = 0;
QString leftSide = Utility::grabAlphaNumeric(mods[i]); QRegularExpression regex;
if (leftSide.startsWith("D") && leftSide.length() == 2) QRegularExpressionMatch match;
regex.setPattern("^\\[(\\w+)]=(\\w+)");
match = regex.match(mods[i]);
if (match.hasMatch())
{ {
thisMod.destByte = leftSide.right(1).toInt(); thisMod.destByte = -1;
thisMod.signalName = match.captured(1);
mods[i] = match.captured(2);
thisMod.operations.clear(); thisMod.operations.clear();
} }
else else
{ {
qDebug() << "Something wrong with lefthand val"; QString leftSide = Utility::grabAlphaNumeric(mods[i]);
continue; if (leftSide.startsWith("D") && leftSide.length() == 2)
} {
if (!(Utility::grabOperation(mods[i]) == "=")) thisMod.destByte = leftSide.right(1).toInt();
{ thisMod.operations.clear();
qDebug() << "Err: No = after lefthand val"; if (!(Utility::grabOperation(mods[i]) == "="))
continue; {
qDebug() << "Err: No = after lefthand val";
continue;
}
}
} }
abort = false; abort = false;
token = Utility::grabAlphaNumeric(mods[i]); token = Utility::grabAlphaNumeric(mods[i]);
@@ -1054,8 +1071,6 @@ void FrameSenderWindow::processCellChange(int line, int col)
} }
break; break;
case ST_COLS::SENDTAB_COL_DATA: //Data bytes case ST_COLS::SENDTAB_COL_DATA: //Data bytes
for (int i = 0; i < 8; i++) sendingData[line].payload().data()[i] = 0;
#if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 ) #if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )
tokens = ui->tableSender->item(line, ST_COLS::SENDTAB_COL_DATA)->text().split(" ", Qt::SkipEmptyParts); tokens = ui->tableSender->item(line, ST_COLS::SENDTAB_COL_DATA)->text().split(" ", Qt::SkipEmptyParts);
#else #else
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

+79
View File
@@ -0,0 +1,79 @@
#!/bin/bash
APP_PATH="/usr/bin/SavvyCAN"
DESKTOP_PATH="/usr/share/applications/savvycan.desktop"
ICON_PATH="/usr/share/pixmaps/SavvyCAN.png"
require_root() {
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run as root."
exit 1
fi
}
show_help() {
echo "Usage: $0 [option]"
echo ""
echo "Options:"
echo " --help Show this help message"
echo " --uninstall Remove SavvyCAN from the system"
echo " (no option) Install or reinstall SavvyCAN"
}
install_error() {
echo "SavvyCAN installation failed."
exit 1
}
uninstall_error() {
echo "SavvyCAN uninstallation failed."
exit 1
}
if [ "$1" = "--help" ]; then
show_help
exit 0
fi
require_root
# Uninstall
if [ "$1" = "--uninstall" ]; then
echo "Uninstalling SavvyCAN..."
trap uninstall_error ERR
rm -f "$APP_PATH" "$DESKTOP_PATH" "$ICON_PATH"
trap - ERR
echo "SavvyCAN has been uninstalled."
exit 0
fi
# Check required files
if [ ! -f "SavvyCAN" ]; then
echo "Missing file \"SavvyCAN\". You need to build first."
install_error
fi
if [ ! -f "SavvyCAN.desktop" ]; then
echo "Missing file \"SavvyCAN.desktop\"."
install_error
fi
if [ ! -f "icons/SavvyIcon.png" ]; then
echo "Missing file \"icons/SavvyIcon.png\"."
install_error
fi
# Install
if [ -f "$APP_PATH" ]; then
echo "Re-installing SavvyCAN..."
else
echo "Installing SavvyCAN..."
fi
trap install_error ERR
install -Dm755 SavvyCAN "$APP_PATH"
install -Dm644 SavvyCAN.desktop "$DESKTOP_PATH"
install -Dm644 icons/SavvyIcon.png "$ICON_PATH"
trap - ERR
echo "SavvyCAN is installed."
+206
View File
@@ -164,6 +164,8 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->btnExpandAll, &QAbstractButton::clicked, this, &MainWindow::expandAllRows); connect(ui->btnExpandAll, &QAbstractButton::clicked, this, &MainWindow::expandAllRows);
connect(ui->btnCollapseAll, &QAbstractButton::clicked, this, &MainWindow::collapseAllRows); connect(ui->btnCollapseAll, &QAbstractButton::clicked, this, &MainWindow::collapseAllRows);
connect(ui->tableSimpleSender, SIGNAL(cellChanged(int,int)), this, SLOT(onSenderCellChanged(int,int)));
lbStatusConnected.setText(tr("Connected to 0 buses")); lbStatusConnected.setText(tr("Connected to 0 buses"));
lbHelp.setText(tr("Press F1 on any screen for help")); lbHelp.setText(tr("Press F1 on any screen for help"));
lbHelp.setAlignment(Qt::AlignCenter); lbHelp.setAlignment(Qt::AlignCenter);
@@ -227,12 +229,34 @@ MainWindow::MainWindow(QWidget *parent) :
ui->actionMotorControlConfig->setVisible(false); ui->actionMotorControlConfig->setVisible(false);
ui->actionSingle_Multi_State_2->setVisible(false); ui->actionSingle_Multi_State_2->setVisible(false);
QStringList headers;
headers << "En" << "Bus" << "ID" << "Ext" << "Rem" << "Data"
<< "Interval" << "Count";
ui->tableSimpleSender->setColumnCount(8);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_EN, 70);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_BUS, 70);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_ID, 70);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_EXT, 70);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_REM, 70);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_DATA, 300);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_INTERVAL, 100);
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_COUNT, 100);
ui->tableSimpleSender->setHorizontalHeaderLabels(headers);
createSenderRow();
frameSender = new FrameSenderObject(model->getListReference());
frameSender->initialize(); //creates the thread and sets things up
frameSender->startSending(); //start the timer in the object so enabled things can send
installEventFilter(this); installEventFilter(this);
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
updateTimer.stop(); updateTimer.stop();
frameSender->stopSending();
killEmAll(); //Ride the lightning killEmAll(); //Ride the lightning
delete ui; delete ui;
delete model; delete model;
@@ -438,6 +462,171 @@ void MainWindow::writeSettings()
} }
} }
void MainWindow::onSenderCellChanged(int row, int col)
{
if (inhibitSenderChanged) return;
qDebug() << "onCellChanged";
if (row == ui->tableSimpleSender->rowCount() - 1)
{
createSenderRow();
}
processSenderCellChange(row, col);
}
void MainWindow::processSenderCellChange(int line, int col)
{
qDebug() << "processSenderCellChange";
FrameSendData *tempData;
QStringList tokens;
int tempVal;
int numBuses = CANConManager::getInstance()->getNumBuses();
QByteArray arr;
tempData = frameSender->getSendRecordRef(line);
if (!tempData)
{
qDebug() << "Need to set up a new entry in senders";
FrameSendData dat;
dat.enabled = false;
dat.count = 0;
dat.frameCount = 0;
dat.bus = 0;
frameSender->addSendRecord(dat);
tempData = frameSender->getSendRecordRef(line);
}
if (!tempData)
{
qDebug() << "No data to modify in processSenderCellChange. This is a bug!";
return;
}
switch (col)
{
case SIMP_COL::SC_COL_EN: //Enable check box
if (ui->tableSimpleSender->item(line, 0)->checkState() == Qt::Checked)
{
tempData->enabled = true;
}
else tempData->enabled = false;
qDebug() << "Setting enabled to " << tempData->enabled;
break;
case SIMP_COL::SC_COL_BUS: //Bus designation
tempVal = Utility::ParseStringToNum(ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_BUS)->text());
if (tempVal < -1) tempVal = -1;
if (tempVal >= numBuses) tempVal = numBuses - 1;
tempData->bus = tempVal;
qDebug() << "Setting bus to " << tempVal;
break;
case SIMP_COL::SC_COL_ID: //ID field
tempVal = Utility::ParseStringToNum(ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_ID)->text());
if (tempVal < 0) tempVal = 0;
if (tempVal > 0x7FFFFFFF) tempVal = 0x7FFFFFFF;
tempData->setFrameId(tempVal);
if (tempData->frameId() > 0x7FF) {
tempData->setExtendedFrameFormat(true);
ui->tableSimpleSender->blockSignals(true);
ui->tableSimpleSender->item(line, ST_COLS::SENDTAB_COL_EXT)->setCheckState(Qt::Checked);
ui->tableSimpleSender->blockSignals(false);
}
qDebug() << "setting ID to " << tempVal;
break;
case SIMP_COL::SC_COL_EXT:
if (ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_EXT)->checkState() == Qt::Checked) {
tempData->setExtendedFrameFormat(true);
} else {
tempData->setExtendedFrameFormat(false);
}
break;
case SIMP_COL::SC_COL_REM:
if (ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_REM)->checkState() == Qt::Checked) {
tempData->setFrameType(QCanBusFrame::RemoteRequestFrame);
} else {
tempData->setFrameType(QCanBusFrame::DataFrame);
}
break;
case SIMP_COL::SC_COL_DATA: //Data bytes
for (int i = 0; i < 8; i++) tempData->payload().data()[i] = 0;
#if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )
tokens = ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_DATA)->text().split(" ", Qt::SkipEmptyParts);
#else
tokens = ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_DATA)->text().split(" ", QString::SkipEmptyParts);
#endif
arr.clear();
arr.reserve(tokens.count());
for (int j = 0; j < tokens.count(); j++)
{
arr.append((uint8_t)Utility::ParseStringToNum(tokens[j]));
}
tempData->setPayload(arr);
break;
case SIMP_COL::SC_COL_INTERVAL: //interval in ms
QString trigger = ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_INTERVAL)->text().toUpper();
Trigger thisTrigger;
thisTrigger.bus = -1; //-1 means we don't care which
thisTrigger.ID = -1; //the rest of these being -1 means nothing has changed it
thisTrigger.maxCount = -1;
thisTrigger.milliseconds = -1;
thisTrigger.currCount = 0;
thisTrigger.msCounter = 0;
thisTrigger.triggerMask = 0;
thisTrigger.readyCount = true;
tempData->triggers.clear();
tempData->triggers.reserve(1);
if (trigger != "")
{
thisTrigger.milliseconds = Utility::ParseStringToNum(trigger);
thisTrigger.triggerMask |= TriggerMask::TRG_MS;
}
if (thisTrigger.milliseconds < 1) thisTrigger.milliseconds = 1;
tempData->triggers.append(thisTrigger);
break;
}
}
void MainWindow::createSenderRow()
{
int row = ui->tableSimpleSender->rowCount();
ui->tableSimpleSender->insertRow(row);
QTableWidgetItem *item = new QTableWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
inhibitSenderChanged = true;
ui->tableSimpleSender->setItem(row, SIMP_COL::SC_COL_EN, item);
item = new QTableWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
ui->tableSimpleSender->setItem(row, SIMP_COL::SC_COL_EXT, item);
item = new QTableWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
ui->tableSimpleSender->setItem(row, SIMP_COL::SC_COL_REM, item);
for (int i = 1; i <= SIMP_COL::SC_COL_COUNT; i++)
{
if (i != SIMP_COL::SC_COL_EXT && i != SIMP_COL::SC_COL_REM) {
item = new QTableWidgetItem("");
ui->tableSimpleSender->setItem(row, i, item);
}
}
inhibitSenderChanged = false;
}
void MainWindow::updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1) void MainWindow::updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1)
{ {
Q_UNUSED(connectionType); Q_UNUSED(connectionType);
@@ -825,6 +1014,18 @@ void MainWindow::tickGUIUpdate()
} }
} }
//refresh the count for all the frame senders
FrameSendData *tempData;
int numRows = ui->tableSimpleSender->rowCount();
for (int i = 0; i < numRows; i++)
{
tempData = frameSender->getSendRecordRef(i);
if (tempData)
{
ui->tableSimpleSender->item(i, SIMP_COL::SC_COL_COUNT)->setText(QString::number( tempData->count ));
}
}
rxFrames = 0; rxFrames = 0;
//} //}
} }
@@ -1371,6 +1572,11 @@ CANFrameModel* MainWindow::getCANFrameModel()
return model; return model;
} }
/*
* All functions past this point set up the various other windows that can be opened
*/
void MainWindow::showSettingsDialog() void MainWindow::showSettingsDialog()
{ {
if (!settingsDialog) if (!settingsDialog)
+18 -1
View File
@@ -10,7 +10,7 @@
#include "framefileio.h" #include "framefileio.h"
#include "dbc/dbchandler.h" #include "dbc/dbchandler.h"
#include "bus_protocols/isotp_handler.h" #include "bus_protocols/isotp_handler.h"
#include "framesenderobject.h"
#include "re/graphingwindow.h" #include "re/graphingwindow.h"
#include "re/frameinfowindow.h" #include "re/frameinfowindow.h"
#include "frameplaybackwindow.h" #include "frameplaybackwindow.h"
@@ -40,6 +40,18 @@ class ConnectionWindow;
class ISOTP_InterpreterWindow; class ISOTP_InterpreterWindow;
class ScriptingWindow; class ScriptingWindow;
enum SIMP_COL
{
SC_COL_EN = 0,
SC_COL_BUS = 1,
SC_COL_ID = 2,
SC_COL_EXT = 3,
SC_COL_REM = 4,
SC_COL_DATA = 5,
SC_COL_INTERVAL = 6,
SC_COL_COUNT = 7,
};
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
} }
@@ -114,6 +126,7 @@ private slots:
void filterClearAll(); void filterClearAll();
void headerClicked (int logicalIndex); void headerClicked (int logicalIndex);
void DBCSettingsUpdated(); void DBCSettingsUpdated();
void onSenderCellChanged(int, int);
public slots: public slots:
void gotFrames(int); void gotFrames(int);
@@ -142,6 +155,7 @@ private:
QByteArray inputBuffer; QByteArray inputBuffer;
QTimer updateTimer; QTimer updateTimer;
QElapsedTimer *elapsedTime; QElapsedTimer *elapsedTime;
FrameSenderObject *frameSender;
int framesPerSec; int framesPerSec;
int rxFrames; int rxFrames;
bool inhibitFilterUpdate; bool inhibitFilterUpdate;
@@ -151,6 +165,7 @@ private:
bool CSVAbsTime; bool CSVAbsTime;
bool bDirty; //have frames been added or subtracted since the last save/load? bool bDirty; //have frames been added or subtracted since the last save/load?
bool useFiltered; //should sub-windows use the unfiltered or filtered frames list? bool useFiltered; //should sub-windows use the unfiltered or filtered frames list?
bool inhibitSenderChanged;
bool continuousLogging; bool continuousLogging;
int continuousLogFlushCounter; int continuousLogFlushCounter;
@@ -211,6 +226,8 @@ private:
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
void manageRowExpansion(); void manageRowExpansion();
void disableAutoRowExpansion(); void disableAutoRowExpansion();
void createSenderRow();
void processSenderCellChange(int line, int col);
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H
+18 -3
View File
@@ -19,7 +19,7 @@
static unsigned char pcap_buffer[MAX_CAN_PACKET_SIZE]; static unsigned char pcap_buffer[MAX_CAN_PACKET_SIZE];
static pcap_t p; static pcap_t p;
pcap *pcap_open_offline(const char *filename, char *error_text) { pcap *pcap_open_offline(const char *filename, char *error_text, int expected_link_type) {
FILE *file; FILE *file;
snprintf(error_text, PCAP_ERRBUF_SIZE, "OK"); snprintf(error_text, PCAP_ERRBUF_SIZE, "OK");
@@ -48,6 +48,23 @@ pcap *pcap_open_offline(const char *filename, char *error_text) {
return (NULL); return (NULL);
} }
unsigned int link_type;
fseek(file, PCAP_FILE_HEADER_LENGTH - 4, SEEK_SET);
bytes_read = fread(&link_type, 1, sizeof(link_type), file);
if (bytes_read != sizeof(link_type)) {
snprintf(error_text, PCAP_ERRBUF_SIZE, "Cannot read linktype word");
fclose(file);
return (NULL);
}
if (expected_link_type >= 0) {
// Check the link type
if ((int) link_type != expected_link_type) {
snprintf(error_text, PCAP_ERRBUF_SIZE, "This link type is not supported by this decoder");
fclose(file);
return (NULL);
}
}
// set the format // set the format
// and seek past file header // and seek past file header
if (MAGIC_NG == magic) { if (MAGIC_NG == magic) {
@@ -61,14 +78,12 @@ pcap *pcap_open_offline(const char *filename, char *error_text) {
return (NULL); return (NULL);
} }
fseek(file, section_length, SEEK_SET); fseek(file, section_length, SEEK_SET);
} else { } else {
p.is_ng = 0; p.is_ng = 0;
fseek(file, PCAP_FILE_HEADER_LENGTH, SEEK_SET); fseek(file, PCAP_FILE_HEADER_LENGTH, SEEK_SET);
} }
p.file = file; p.file = file;
return(&p); return(&p);
} }
+4 -2
View File
@@ -8,7 +8,9 @@
#include <winsock.h> #include <winsock.h>
#endif #endif
#define PCAP_ERRBUF_SIZE 256 #define PCAP_ERRBUF_SIZE (256)
#define PCAP_LINKTYPE_SOCKETCAN (227)
#define PCAP_LINKTYPE_ANY (-1)
struct pcap_pkthdr { struct pcap_pkthdr {
struct timeval ts; /* time stamp */ struct timeval ts; /* time stamp */
@@ -23,7 +25,7 @@ struct pcap {
typedef struct pcap pcap_t; typedef struct pcap pcap_t;
pcap *pcap_open_offline(const char *, char *); pcap *pcap_open_offline(const char *, char *, int);
const unsigned char *pcap_next(pcap_t *, struct pcap_pkthdr *); const unsigned char *pcap_next(pcap_t *, struct pcap_pkthdr *);
+6 -4
View File
@@ -222,8 +222,8 @@ void DBCComparatorWindow::calculateDetails()
ui->treeDetails->addTopLevelItem(msgDiffRoot); ui->treeDetails->addTopLevelItem(msgDiffRoot);
QTreeWidgetItem *msgItem; QTreeWidgetItem *msgItem {};
QTreeWidgetItem *sigTemp; QTreeWidgetItem *sigTemp {};
for (int i = 0; i < firstDBC->messageHandler->getCount(); i++) for (int i = 0; i < firstDBC->messageHandler->getCount(); i++)
{ {
@@ -257,7 +257,8 @@ void DBCComparatorWindow::calculateDetails()
msgItem->setText(0, msgName + " (" + Utility::formatCANID(thisMsg->ID) + ")"); msgItem->setText(0, msgName + " (" + Utility::formatCANID(thisMsg->ID) + ")");
sigDiffTwo->addChild(msgItem); sigDiffTwo->addChild(msgItem);
} }
msgItem->addChild(missingSigItem); if (msgItem)
msgItem->addChild(missingSigItem);
} }
else //signal exists on both sides. See if it as changed position or length else //signal exists on both sides. See if it as changed position or length
{ {
@@ -301,7 +302,8 @@ void DBCComparatorWindow::calculateDetails()
sigTemp->setText(0, msgName + " (" + Utility::formatCANID(thisMsg->ID) + ")"); sigTemp->setText(0, msgName + " (" + Utility::formatCANID(thisMsg->ID) + ")");
sigModifiedRoot->addChild(sigTemp); sigModifiedRoot->addChild(sigTemp);
} }
sigTemp->addChild(sigItem); if (sigTemp)
sigTemp->addChild(sigItem);
} }
} }
} }
+1 -1
View File
@@ -851,7 +851,7 @@ void FlowViewWindow::updatePosition(bool forward)
int maxVal = qMin(chunk * 8 + 8, frameCache.at(currentPosition).payload().length()); int maxVal = qMin(chunk * 8 + 8, frameCache.at(currentPosition).payload().length());
for (int i = chunk * 8; i < maxVal; i++) for (int i = chunk * 8; i < maxVal; i++)
{ {
unsigned char thisByte = static_cast<unsigned char>(frameCache.at(currentPosition).payload().data()[i]); unsigned char thisByte = static_cast<unsigned char>(frameCache.at(currentPosition).payload()[i]);
cngByte = currBytes[i] ^ thisByte; cngByte = currBytes[i] ^ thisByte;
changedBits |= (uint64_t)cngByte << (8ull * (i & 7)); changedBits |= (uint64_t)cngByte << (8ull * (i & 7));
} }
+30
View File
@@ -19,6 +19,9 @@ FuzzingWindow::FuzzingWindow(const QVector<CANFrame> *frames, QWidget *parent) :
fuzzTimer = new QTimer(); fuzzTimer = new QTimer();
connect(ui->btnMarkAllHigh, &QPushButton::clicked, this, &FuzzingWindow::markAllHigh);
connect(ui->btnMarkAllLow, &QPushButton::clicked, this, &FuzzingWindow::markAllLow);
connect(ui->btnMarkAllAuto, &QPushButton::clicked, this, &FuzzingWindow::markAllAuto);
connect(ui->btnStartStop, &QPushButton::clicked, this, &FuzzingWindow::toggleFuzzing); connect(ui->btnStartStop, &QPushButton::clicked, this, &FuzzingWindow::toggleFuzzing);
connect(ui->btnAllFilters, &QPushButton::clicked, this, &FuzzingWindow::setAllFilters); connect(ui->btnAllFilters, &QPushButton::clicked, this, &FuzzingWindow::setAllFilters);
connect(ui->btnNoFilters, &QPushButton::clicked, this, &FuzzingWindow::clearAllFilters); connect(ui->btnNoFilters, &QPushButton::clicked, this, &FuzzingWindow::clearAllFilters);
@@ -508,3 +511,30 @@ void FuzzingWindow::redrawGrid()
ui->bitfield->setReference(refBytes, false); ui->bitfield->setReference(refBytes, false);
ui->bitfield->updateData(dataBytes, true); ui->bitfield->updateData(dataBytes, true);
} }
void FuzzingWindow::markAllHigh()
{
for (int i = 0; i < 512; i++)
{
bitGrid[i] = 2;
}
redrawGrid();
}
void FuzzingWindow::markAllLow()
{
for (int i = 0; i < 512; i++)
{
bitGrid[i] = 0;
}
redrawGrid();
}
void FuzzingWindow::markAllAuto()
{
for (int i = 0; i < 512; i++)
{
bitGrid[i] = 1;
}
redrawGrid();
}
+3
View File
@@ -42,6 +42,9 @@ private slots:
void bitfieldClicked(int); void bitfieldClicked(int);
void changedNumDataBytes(int newVal); void changedNumDataBytes(int newVal);
void updatedFrames(int numFrames); void updatedFrames(int numFrames);
void markAllHigh();
void markAllLow();
void markAllAuto();
private: private:
Ui::FuzzingWindow *ui; Ui::FuzzingWindow *ui;
+100 -105
View File
@@ -39,7 +39,7 @@ GraphingWindow::GraphingWindow(const QVector<CANFrame> *frames, QWidget *parent)
if (Utility::timeStyle == TS_CLOCK) if (Utility::timeStyle == TS_CLOCK)
{ {
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime); QSharedPointer timeTicker = QSharedPointer<QCPAxisTickerTime>::create();
timeTicker->setTimeFormat("%h:%m:%s.%z"); timeTicker->setTimeFormat("%h:%m:%s.%z");
ui->graphingView->xAxis->setTicker(timeTicker); ui->graphingView->xAxis->setTicker(timeTicker);
} }
@@ -571,7 +571,7 @@ void GraphingWindow::removeSelectedGraph()
int idx = -1; int idx = -1;
for (int i = 0; i < graphParams.count(); i++) for (int i = 0; i < graphParams.count(); i++)
{ {
if (graphParams[i].ref == ui->graphingView->selectedGraphs().first()) if (graphParams[i].ref == ui->graphingView->selectedGraphs().constFirst())
{ {
idx = i; idx = i;
break; break;
@@ -590,7 +590,7 @@ void GraphingWindow::removeSelectedGraph()
graphParams.removeAt(idx); graphParams.removeAt(idx);
ui->graphingView->removeGraph(ui->graphingView->selectedGraphs().first()); ui->graphingView->removeGraph(ui->graphingView->selectedGraphs().constFirst());
if (graphParams.count() == 0) needScaleSetup = true; if (graphParams.count() == 0) needScaleSetup = true;
@@ -605,7 +605,7 @@ void GraphingWindow::editSelectedGraph()
int idx = -1; int idx = -1;
for (int i = 0; i < graphParams.count(); i++) for (int i = 0; i < graphParams.count(); i++)
{ {
if (graphParams[i].ref == ui->graphingView->selectedGraphs().first()) if (graphParams[i].ref == ui->graphingView->selectedGraphs().constFirst())
{ {
idx = i; idx = i;
break; break;
@@ -701,7 +701,6 @@ void GraphingWindow::contextMenuRequest(QPoint pos)
void GraphingWindow::saveGraphs() void GraphingWindow::saveGraphs()
{ {
QString filename;
QFileDialog dialog(this); QFileDialog dialog(this);
QSettings settings; QSettings settings;
@@ -718,7 +717,7 @@ void GraphingWindow::saveGraphs()
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
filename = dialog.selectedFiles()[0]; QString filename = dialog.selectedFiles().constFirst();
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path()); settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
if (dialog.selectedNameFilter() == filters[0]) if (dialog.selectedNameFilter() == filters[0])
@@ -741,7 +740,6 @@ void GraphingWindow::saveGraphs()
void GraphingWindow::saveSpreadsheet() void GraphingWindow::saveSpreadsheet()
{ {
QString filename;
QFileDialog dialog(this); QFileDialog dialog(this);
QSettings settings; QSettings settings;
@@ -756,14 +754,14 @@ void GraphingWindow::saveSpreadsheet()
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
filename = dialog.selectedFiles()[0]; QString filename = dialog.selectedFiles().constFirst();
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path()); settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".csv"; if (!filename.contains('.')) filename += ".csv";
QFile *outFile = new QFile(filename); QFile outFile(filename);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text))
return; return;
/* /*
@@ -779,12 +777,12 @@ void GraphingWindow::saveSpreadsheet()
QList<GraphParams>::iterator iter; QList<GraphParams>::iterator iter;
double xMin = std::numeric_limits<double>::max(), double xMin = std::numeric_limits<double>::max(),
xMax = std::numeric_limits<double>::min(); xMax = std::numeric_limits<double>::min();
size_t maxCount = 0; int maxCount = 0;
size_t numGraphs = graphParams.length(); int numGraphs = graphParams.length();
for (auto && graph : graphParams) { for (auto && graph : graphParams) {
xMin = std::min(xMin, graph.x[0]); xMin = std::min(xMin, graph.x[0]);
xMax = std::max(xMax, graph.x[graph.x.count() - 1]); xMax = std::max(xMax, graph.x[graph.x.count() - 1]);
maxCount = std::max(maxCount, static_cast<size_t>(graph.x.count())); maxCount = std::max(maxCount, graph.x.count());
} }
qDebug() << "xMin: " << xMin; qDebug() << "xMin: " << xMin;
qDebug() << "xMax: " << xMax; qDebug() << "xMax: " << xMax;
@@ -795,27 +793,25 @@ void GraphingWindow::saveSpreadsheet()
double xSize = xMax - xMin; double xSize = xMax - xMin;
double sliceSize = xSize / ((double)maxCount); double sliceSize = xSize / ((double)maxCount);
double equivValue = sliceSize / 100.0; double equivValue = sliceSize / 100.0;
double currentX;
double value;
QList<int> indices; QList<int> indices;
indices.reserve(numGraphs); indices.reserve(numGraphs);
outFile->write("TimeStamp"); outFile.write("TimeStamp");
for (auto && graph : graphParams) { for (auto && graph : graphParams) {
indices.append(0); indices.append(0);
outFile->putChar(','); outFile.putChar(',');
outFile->write(graph.graphName.toUtf8()); outFile.write(graph.graphName.toUtf8());
} }
outFile->write("\n"); outFile.write("\n");
for (size_t j = 1; j < (maxCount - 1); j++) for (int j = 1; j < (maxCount - 1); j++)
{ {
currentX = xMin + (j * sliceSize); double currentX = xMin + (j * sliceSize);
qDebug() << "X: " << currentX; qDebug() << "X: " << currentX;
outFile->write(QString::number(currentX, 'f').toUtf8()); outFile.write(QString::number(currentX, 'f').toUtf8());
for (size_t k = 0; k < numGraphs; k++) for (int k = 0; k < numGraphs; k++)
{ {
value = 0.0; double value = 0.0;
// move cursor to last sample before currentX // move cursor to last sample before currentX
while (graphParams[k].x[indices[k]+1] < currentX) while (graphParams[k].x[indices[k]+1] < currentX)
@@ -849,27 +845,26 @@ void GraphingWindow::saveSpreadsheet()
else else
{ {
// find index, where x >= currentX // find index, where x >= currentX
size_t cursor = indices[k]; int cursor = indices[k];
double span = graphParams[k].x[cursor+1] - graphParams[k].x[cursor]; double span = graphParams[k].x[cursor+1] - graphParams[k].x[cursor];
double progress = (currentX - graphParams[k].x[cursor]) / span; double progress = (currentX - graphParams[k].x[cursor]) / span;
Q_ASSERT(progress >= 0.0 && progress <= 1.0); Q_ASSERT(progress >= 0.0 && progress <= 1.0);
value = Utility::Lerp(graphParams[k].y[cursor], graphParams[k].y[cursor+1], progress); value = Utility::Lerp(graphParams[k].y[cursor], graphParams[k].y[cursor+1], progress);
qDebug() << "Span: " << span << " Prog: " << progress << " Value: " << value; qDebug() << "Span: " << span << " Prog: " << progress << " Value: " << value;
} }
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(value).toUtf8()); outFile.write(QString::number(value).toUtf8());
} }
outFile->write("\n"); outFile.write("\n");
} }
outFile->close(); outFile.close();
} }
} }
void GraphingWindow::saveDefinitions() void GraphingWindow::saveDefinitions()
{ {
QString filename;
QFileDialog dialog(this); QFileDialog dialog(this);
QSettings settings; QSettings settings;
@@ -884,79 +879,78 @@ void GraphingWindow::saveDefinitions()
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
filename = dialog.selectedFiles()[0]; QString filename = dialog.selectedFiles().constFirst();
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path()); settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".gdf"; if (!filename.contains('.')) filename += ".gdf";
QFile *outFile = new QFile(filename); QFile outFile(filename);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text))
return; return;
QList<GraphParams>::iterator iter; QList<GraphParams>::iterator iter;
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter) for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
{ {
outFile->write("Z,"); outFile.write("Z,");
outFile->write(QString::number(iter->ID, 16).toUtf8()); outFile.write(QString::number(iter->ID, 16).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->mask, 16).toUtf8()); outFile.write(QString::number(iter->mask, 16).toUtf8());
outFile->putChar(','); outFile.putChar(',');
if (iter->intelFormat) outFile->write(QString::number(iter->startBit).toUtf8()); if (iter->intelFormat) outFile.write(QString::number(iter->startBit).toUtf8());
else outFile->write(QString::number(iter->startBit * -1).toUtf8()); else outFile.write(QString::number(iter->startBit * -1).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->numBits).toUtf8()); outFile.write(QString::number(iter->numBits).toUtf8());
outFile->putChar(','); outFile.putChar(',');
if (iter->isSigned) outFile->putChar('Y'); if (iter->isSigned) outFile.putChar('Y');
else outFile->putChar('N'); else outFile.putChar('N');
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->bias).toUtf8()); outFile.write(QString::number(iter->bias).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->scale).toUtf8()); outFile.write(QString::number(iter->scale).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->stride).toUtf8()); outFile.write(QString::number(iter->stride).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->bus).toUtf8()); outFile.write(QString::number(iter->bus).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->lineColor.red()).toUtf8()); outFile.write(QString::number(iter->lineColor.red()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->lineColor.green()).toUtf8()); outFile.write(QString::number(iter->lineColor.green()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->lineColor.blue()).toUtf8()); outFile.write(QString::number(iter->lineColor.blue()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(iter->graphName.toUtf8()); outFile.write(iter->graphName.toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->fillColor.red()).toUtf8()); outFile.write(QString::number(iter->fillColor.red()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->fillColor.green()).toUtf8()); outFile.write(QString::number(iter->fillColor.green()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->fillColor.blue()).toUtf8()); outFile.write(QString::number(iter->fillColor.blue()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->fillColor.alpha()).toUtf8()); outFile.write(QString::number(iter->fillColor.alpha()).toUtf8());
outFile->putChar(','); outFile.putChar(',');
if (iter->drawOnlyPoints) outFile->putChar('Y'); if (iter->drawOnlyPoints) outFile.putChar('Y');
else outFile->putChar('N'); else outFile.putChar('N');
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->pointType).toUtf8()); outFile.write(QString::number(iter->pointType).toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(QString::number(iter->lineWidth).toUtf8()); outFile.write(QString::number(iter->lineWidth).toUtf8());
if (iter->associatedSignal) if (iter->associatedSignal)
{ {
outFile->putChar(','); outFile.putChar(',');
outFile->write(iter->associatedSignal->parentMessage->name.toUtf8()); outFile.write(iter->associatedSignal->parentMessage->name.toUtf8());
outFile->putChar(','); outFile.putChar(',');
outFile->write(iter->associatedSignal->name.toUtf8()); outFile.write(iter->associatedSignal->name.toUtf8());
} }
outFile->write("\n"); outFile.write("\n");
} }
outFile->close(); outFile.close();
} }
} }
void GraphingWindow::loadDefinitions() void GraphingWindow::loadDefinitions()
{ {
QString filename;
QFileDialog dialog; QFileDialog dialog;
QSettings settings; QSettings settings;
@@ -973,17 +967,17 @@ void GraphingWindow::loadDefinitions()
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
filename = dialog.selectedFiles()[0]; QString filename = dialog.selectedFiles().constFirst();
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path()); settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
QFile *inFile = new QFile(filename); QFile inFile(filename);
QByteArray line; QByteArray line;
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text)) if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text))
return; return;
while (!inFile->atEnd()) { while (!inFile.atEnd()) {
line = inFile->readLine().simplified(); line = inFile.readLine().simplified();
if (line.length() > 2) if (line.length() > 2)
{ {
GraphParams gp; GraphParams gp;
@@ -1205,7 +1199,7 @@ void GraphingWindow::loadDefinitions()
} }
} }
} }
inFile->close(); inFile.close();
} }
} }
@@ -1325,10 +1319,8 @@ void GraphingWindow::createGraph(GraphParams &params, bool createGraphParam)
double yminval=10000000.0, ymaxval = -1000000.0; double yminval=10000000.0, ymaxval = -1000000.0;
double xminval=10000000000.0, xmaxval = -10000000000.0; double xminval=10000000000.0, xmaxval = -10000000000.0;
GraphParams *refParam = &params; GraphParams *refParam = &params;
int sBit, bits;
bool intelFormat, isSigned;
QString tempStr; QString tempStr;
double x,y; double x{}, y{};
qDebug() << "New Graph ID: " << params.ID; qDebug() << "New Graph ID: " << params.ID;
qDebug() << "Start bit: " << params.startBit; qDebug() << "Start bit: " << params.startBit;
@@ -1341,7 +1333,8 @@ void GraphingWindow::createGraph(GraphParams &params, bool createGraphParam)
for (int i = 0; i < modelFrames->count(); i++) for (int i = 0; i < modelFrames->count(); i++)
{ {
CANFrame thisFrame = modelFrames->at(i); CANFrame thisFrame = modelFrames->at(i);
if (thisFrame.frameId() == params.ID && thisFrame.frameType() == QCanBusFrame::DataFrame && ( ( params.bus == -1) || (params.bus == thisFrame.bus) ) ) frameCache.append(thisFrame); if ( (thisFrame.frameId() == params.ID) && (thisFrame.frameType() == QCanBusFrame::DataFrame)
&& ( ( params.bus == -1) || (params.bus == thisFrame.bus) ) ) frameCache.append(thisFrame);
} }
//to fix weirdness where a graph that has no data won't be able to be edited, selected, or deleted properly //to fix weirdness where a graph that has no data won't be able to be edited, selected, or deleted properly
@@ -1360,15 +1353,17 @@ void GraphingWindow::createGraph(GraphParams &params, bool createGraphParam)
int numEntries = frameCache.count() / params.stride; int numEntries = frameCache.count() / params.stride;
if (numEntries < 1) numEntries = 1; //could happen if stride is larger than frame count if (numEntries < 1) numEntries = 1; //could happen if stride is larger than frame count
params.x.clear();
params.y.clear();
params.x.reserve(numEntries); params.x.reserve(numEntries);
params.y.reserve(numEntries); params.y.reserve(numEntries);
//params.x.fill(0, numEntries); //params.x.fill(0, numEntries);
//params.y.fill(0, numEntries); //params.y.fill(0, numEntries);
sBit = params.startBit; int sBit = params.startBit;
bits = params.numBits; int bits = params.numBits;
intelFormat = params.intelFormat; bool intelFormat = params.intelFormat;
isSigned = params.isSigned; bool isSigned = params.isSigned;
for (int j = 0; j < numEntries; j++) for (int j = 0; j < numEntries; j++)
{ {
@@ -1558,16 +1553,16 @@ void GraphingWindow::createGraph(GraphParams &params, bool createGraphParam)
void GraphingWindow::moveLegend() void GraphingWindow::moveLegend()
{ {
qDebug() << "moveLegend"; qDebug() << "moveLegend";
if (QAction* contextAction = qobject_cast<QAction*>(sender())) // make sure this slot is really called by a context menu action, so it carries the data we need if (QAction* contextAction = qobject_cast<QAction*>(sender())) // make sure this slot is really called by a context menu action, so it carries the data we need
{
bool ok;
int dataInt = contextAction->data().toInt(&ok);
if (ok)
{ {
ui->graphingView->axisRect()->insetLayout()->setInsetAlignment(0, (Qt::Alignment)dataInt); bool ok;
ui->graphingView->replot(); int dataInt = contextAction->data().toInt(&ok);
if (ok)
{
ui->graphingView->axisRect()->insetLayout()->setInsetAlignment(0, (Qt::Alignment)dataInt);
ui->graphingView->replot();
}
} }
}
} }
GraphParams::GraphParams() GraphParams::GraphParams()
+75
View File
@@ -31,6 +31,7 @@ ISOTP_InterpreterWindow::ISOTP_InterpreterWindow(const QVector<CANFrame> *frames
connect(ui->tableIsoFrames, &QTableWidget::itemSelectionChanged, this, &ISOTP_InterpreterWindow::showDetailView); connect(ui->tableIsoFrames, &QTableWidget::itemSelectionChanged, this, &ISOTP_InterpreterWindow::showDetailView);
connect(ui->btnClearList, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::clearList); connect(ui->btnClearList, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::clearList);
connect(ui->btnSaveList, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::saveList);
connect(ui->cbUseExtendedAddressing, SIGNAL(toggled(bool)), this, SLOT(useExtendedAddressing(bool))); connect(ui->cbUseExtendedAddressing, SIGNAL(toggled(bool)), this, SLOT(useExtendedAddressing(bool)));
QStringList headers; QStringList headers;
@@ -172,6 +173,80 @@ void ISOTP_InterpreterWindow::clearList()
//idFilters.clear(); //idFilters.clear();
} }
/*
* A bit complicated as the list doesn't have the detailed analysis in it. Have to take each list entry
* and process it to get the details then save those details to the file as well.
*/
void ISOTP_InterpreterWindow::saveList()
{
QString buildString;
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Text File (*.txt)")));
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("FrameInfo/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
settings.setValue("FrameInfo/LoadSaveDirectory", dialog.directory().path());
filename = dialog.selectedFiles()[0];
if (!filename.contains('.')) filename += ".txt";
if (dialog.selectedNameFilter() == filters[0])
{
QFile *outFile = new QFile(filename);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
{
delete outFile;
return;
}
int rows = messages.count();
for (int r = 0 ; r < rows; r++)
{
ISOTP_MESSAGE msg = messages.at(r);
const unsigned char *data = reinterpret_cast<const unsigned char *>(msg.payload().constData());
int dataLen = msg.payload().length();
if (msg.reportedLength != dataLen)
{
continue;
}
buildString.append(QString::number(msg.timeStamp().microSeconds()) + " " + QString::number(msg.frameId(), 16) + " ");
//buildString.append(tr("Raw Payload: "));
for (int i = 0; i < dataLen; i++)
{
buildString.append(Utility::formatNumber(data[i]));
buildString.append(" ");
}
buildString.append("\n\n");
UDS_MESSAGE udsMsg;
bool result;
udsMsg = udsDecoder->tryISOtoUDS(msg, &result);
if (result)
buildString.append(udsDecoder->getDetailedMessageAnalysis(udsMsg));
buildString.append("\n*********************************************************\n");
outFile->write(buildString.toUtf8());
}
outFile->close();
delete outFile;
}
}
}
void ISOTP_InterpreterWindow::useExtendedAddressing(bool checked) void ISOTP_InterpreterWindow::useExtendedAddressing(bool checked)
{ {
decoder->setExtendedAddressing(checked); decoder->setExtendedAddressing(checked);
+1
View File
@@ -26,6 +26,7 @@ private slots:
void showDetailView(); void showDetailView();
void updatedFrames(int); void updatedFrames(int);
void clearList(); void clearList();
void saveList();
void listFilterItemChanged(QListWidgetItem *item); void listFilterItemChanged(QListWidgetItem *item);
void filterAll(); void filterAll();
void filterNone(); void filterNone();
-1
View File
@@ -361,7 +361,6 @@ void NewGraphDialog::loadNodes()
void NewGraphDialog::loadMessages(int idx) void NewGraphDialog::loadMessages(int idx)
{ {
int numFiles = 0; int numFiles = 0;
DBC_MESSAGE *msg;
ui->cbMessages->clear(); ui->cbMessages->clear();
if (dbcHandler == nullptr) return; if (dbcHandler == nullptr) return;
if ((numFiles = dbcHandler->getFileCount()) == 0) return; if ((numFiles = dbcHandler->getFileCount()) == 0) return;
+1 -1
View File
@@ -181,7 +181,7 @@ void SnifferWindow::notchTick()
} }
else else
{ {
ui->lblNotch->setBackgroundRole(QPalette::Background); ui->lblNotch->setBackgroundRole(QPalette::Window);
ui->lblNotch->repaint(); ui->lblNotch->repaint();
//qDebug() << "Tock"; //qDebug() << "Tock";
} }
+89
View File
@@ -41,8 +41,11 @@ ScriptingWindow::ScriptingWindow(const QVector<CANFrame> *frames, QWidget *paren
connect(ui->btnRecompile, &QAbstractButton::pressed, this, &ScriptingWindow::recompileScript); connect(ui->btnRecompile, &QAbstractButton::pressed, this, &ScriptingWindow::recompileScript);
connect(ui->btnRemoveScript, &QAbstractButton::pressed, this, &ScriptingWindow::deleteCurrentScript); connect(ui->btnRemoveScript, &QAbstractButton::pressed, this, &ScriptingWindow::deleteCurrentScript);
connect(ui->btnRevertScript, &QAbstractButton::pressed, this, &ScriptingWindow::revertScript); connect(ui->btnRevertScript, &QAbstractButton::pressed, this, &ScriptingWindow::revertScript);
connect(ui->btnReloadScript, &QAbstractButton::pressed, this, &ScriptingWindow::reloadScript);
connect(ui->btnSaveScript, &QAbstractButton::pressed, this, &ScriptingWindow::saveScript); connect(ui->btnSaveScript, &QAbstractButton::pressed, this, &ScriptingWindow::saveScript);
connect(ui->btnSaveAsScript, &QAbstractButton::pressed, this, &ScriptingWindow::saveAsScript);
connect(ui->btnClearLog, &QAbstractButton::pressed, this, &ScriptingWindow::clickedLogClear); connect(ui->btnClearLog, &QAbstractButton::pressed, this, &ScriptingWindow::clickedLogClear);
connect(ui->btnSaveLog, &QAbstractButton::pressed, this, &ScriptingWindow::saveLog);
connect(ui->listLoadedScripts, &QListWidget::currentRowChanged, this, &ScriptingWindow::changeCurrentScript); connect(ui->listLoadedScripts, &QListWidget::currentRowChanged, this, &ScriptingWindow::changeCurrentScript);
connect(ui->tableVariables, SIGNAL(cellChanged(int,int)), this, SLOT(updatedValue(int, int))); connect(ui->tableVariables, SIGNAL(cellChanged(int,int)), this, SLOT(updatedValue(int, int)));
@@ -301,6 +304,21 @@ void ScriptingWindow::refreshSourceWindow()
} }
void ScriptingWindow::saveScript() void ScriptingWindow::saveScript()
{
QFile *outFile = new QFile(currentScript->filePath);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
{
delete outFile;
return;
}
outFile->write(editor->toPlainText().toUtf8());
currentScript->scriptText = editor->toPlainText();
outFile->close();
delete outFile;
}
void ScriptingWindow::saveAsScript()
{ {
QString filename; QString filename;
QFileDialog dialog(this); QFileDialog dialog(this);
@@ -358,6 +376,38 @@ void ScriptingWindow::revertScript()
} }
} }
void ScriptingWindow::reloadScript()
{
QMessageBox msgBox;
msgBox.setText("Are you sure you'd like to reload from disk?");
msgBox.setInformativeText("Really do it?");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Cancel);
int ret = msgBox.exec();
switch (ret)
{
case QMessageBox::Yes:
{
// get the latest version from disk and set in the editor/state
QFile scriptFile(currentScript->filePath);
if (scriptFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
QString contents = scriptFile.readAll();
scriptFile.close();
editor->setPlainText(contents);
currentScript->scriptText = contents;
currentScript->compileScript();
}
break;
}
case QMessageBox::No:
break;
default:
// should never be reached
break;
}
}
void ScriptingWindow::recompileScript() void ScriptingWindow::recompileScript()
{ {
if (currentScript) if (currentScript)
@@ -373,6 +423,45 @@ void ScriptingWindow::clickedLogClear()
elapsedTime.start(); elapsedTime.start();
} }
void ScriptingWindow::saveLog()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Log File (*.log)")));
dialog.setDirectory(settings.value("ScriptingWindow/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
if (!filename.contains('.')) filename += ".log";
if (dialog.selectedNameFilter() == filters[0])
{
QFile *outFile = new QFile(filename);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
{
delete outFile;
return;
}
int c = ui->listLog ->count();
for (int row = 0; row < c; row++) {
outFile->write(ui->listLog->item(row)->data(Qt::DisplayRole).toString().toUtf8() + "\n");
}
outFile->close();
delete outFile;
settings.setValue("ScriptingWindow/LoadSaveDirectory", dialog.directory().path());
}
}
}
void ScriptingWindow::log(QString text) void ScriptingWindow::log(QString text)
{ {
ScriptContainer *cont = qobject_cast<ScriptContainer*>(sender()); ScriptContainer *cont = qobject_cast<ScriptContainer*>(sender());
+3
View File
@@ -37,7 +37,9 @@ private slots:
void deleteCurrentScript(); void deleteCurrentScript();
void refreshSourceWindow(); void refreshSourceWindow();
void saveScript(); void saveScript();
void saveAsScript();
void revertScript(); void revertScript();
void reloadScript();
void recompileScript(); void recompileScript();
void changeCurrentScript(); void changeCurrentScript();
void newFrames(const CANConnection*, const QVector<CANFrame>&); void newFrames(const CANConnection*, const QVector<CANFrame>&);
@@ -49,6 +51,7 @@ private:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void readSettings(); void readSettings();
void writeSettings(); void writeSettings();
void saveLog();
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
Ui::ScriptingWindow *ui; Ui::ScriptingWindow *ui;
+9 -6
View File
@@ -98,15 +98,18 @@ void SignalViewerWindow::processFrame(CANFrame &frame)
if (!sig) return; if (!sig) return;
if (sig->parentMessage->ID == frame.frameId()) if (sig->parentMessage->ID == frame.frameId())
{ {
if (sig->processAsText(frame, sigString, false)) //if true we could interpret the signal so update it in the list if (sig->isSignalInMessage(frame)) //filter out multiplexed signals that aren't in this message.
{ {
QTableWidgetItem *item = ui->tableViewer->item(i, VALUE_COL); if (sig->processAsText(frame, sigString, false)) //if true we could interpret the signal so update it in the list
if (!item)
{ {
item = new QTableWidgetItem(sigString); QTableWidgetItem *item = ui->tableViewer->item(i, VALUE_COL);
ui->tableViewer->setItem(i, VALUE_COL, item); if (!item)
{
item = new QTableWidgetItem(sigString);
ui->tableViewer->setItem(i, VALUE_COL, item);
}
else item->setText(sigString);
} }
else item->setText(sigString);
} }
} }
} }
+1 -1
View File
@@ -120,7 +120,7 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="layoutWidget"> <widget class="QWidget" name="layoutWidget_2">
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="2,0,2"> <layout class="QVBoxLayout" name="verticalLayout_4" stretch="2,0,2">
<item> <item>
<layout class="QGridLayout" name="gridUpper"/> <layout class="QGridLayout" name="gridUpper"/>
+1 -1
View File
@@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1008</width> <width>1350</width>
<height>611</height> <height>611</height>
</rect> </rect>
</property> </property>
+24
View File
@@ -487,6 +487,27 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="btnMarkAllHigh">
<property name="text">
<string>All High</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMarkAllLow">
<property name="text">
<string>All Low</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnMarkAllAuto">
<property name="text">
<string>All Auto</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="btnStartStop"> <widget class="QPushButton" name="btnStartStop">
<property name="text"> <property name="text">
@@ -534,6 +555,9 @@
<tabstop>listID</tabstop> <tabstop>listID</tabstop>
<tabstop>btnAllFilters</tabstop> <tabstop>btnAllFilters</tabstop>
<tabstop>btnNoFilters</tabstop> <tabstop>btnNoFilters</tabstop>
<tabstop>btnMarkAllHigh</tabstop>
<tabstop>btnMarkAllLow</tabstop>
<tabstop>btnMarkAllAuto</tabstop>
<tabstop>btnStartStop</tabstop> <tabstop>btnStartStop</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
+7
View File
@@ -40,6 +40,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="btnSaveList">
<property name="text">
<string>Save List</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item alignment="Qt::AlignLeft"> <item alignment="Qt::AlignLeft">
+336 -322
View File
@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>1177</width>
<height>682</height> <height>717</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@@ -26,336 +26,350 @@
<string>SavvyCAN</string> <string>SavvyCAN</string>
</property> </property>
<widget class="QWidget" name="centralWidget"> <widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0"> <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0">
<item> <item>
<widget class="QTableView" name="canFramesView"> <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="3,1">
<property name="font">
<font>
<pointsize>11</pointsize>
<bold>false</bold>
</font>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QLabel" name="lblRemoteConn"> <layout class="QVBoxLayout" name="verticalLayout_3" stretch="4,1">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Remote Connection Active:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineRemoteKey">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>1000</width>
<height>50</height>
</size>
</property>
<property name="baseSize">
<size>
<width>150</width>
<height>50</height>
</size>
</property>
<property name="font">
<font>
<bold>false</bold>
</font>
</property>
<property name="maxLength">
<number>8</number>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblContMsg">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Total Frames Captured:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="lbNumFrames">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Frames Per Second:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="lbFPS">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCaptureToggle">
<property name="text">
<string>Suspend Capturing</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNormalize">
<property name="text">
<string>Normalize Frame Timing</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClearFrames">
<property name="text">
<string>Clear Frames</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbPersistentFilters">
<property name="text">
<string>Keep Filters When Clearing</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbAutoScroll">
<property name="text">
<string>Auto Scroll Window</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbOverwrite">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Overwrite Mode</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbInterpret">
<property name="text">
<string>Interpret Frames</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnExpandAll">
<property name="text">
<string>Expand All Rows</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCollapseAll">
<property name="text">
<string>Collapse All Rows</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Bus Filtering:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listBusFilters">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>175</width>
<height>40</height>
</size>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Frame Filtering:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listFilters">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>160</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>175</width>
<height>16777215</height>
</size>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
<widget class="QPushButton" name="btnFilterAll"> <widget class="QTableView" name="canFramesView">
<property name="font">
<font>
<pointsize>11</pointsize>
<bold>false</bold>
</font>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableSimpleSender"/>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblRemoteConn">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text"> <property name="text">
<string>All</string> <string>Remote Connection Active:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="btnFilterNone"> <widget class="QLineEdit" name="lineRemoteKey">
<property name="text"> <property name="enabled">
<string>None</string> <bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>1000</width>
<height>50</height>
</size>
</property>
<property name="baseSize">
<size>
<width>150</width>
<height>50</height>
</size>
</property>
<property name="font">
<font>
<bold>false</bold>
</font>
</property>
<property name="maxLength">
<number>8</number>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="lblContMsg">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Total Frames Captured:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="lbNumFrames">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Frames Per Second:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="lbFPS">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCaptureToggle">
<property name="text">
<string>Suspend Capturing</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNormalize">
<property name="text">
<string>Normalize Frame Timing</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClearFrames">
<property name="text">
<string>Clear Frames</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbPersistentFilters">
<property name="text">
<string>Keep Filters When Clearing</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbAutoScroll">
<property name="text">
<string>Auto Scroll Window</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbOverwrite">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Overwrite Mode</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbInterpret">
<property name="text">
<string>Interpret Frames</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnExpandAll">
<property name="text">
<string>Expand All Rows</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCollapseAll">
<property name="text">
<string>Collapse All Rows</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Bus Filtering:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listBusFilters">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>175</width>
<height>40</height>
</size>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Frame Filtering:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listFilters">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>160</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>1000</width>
<height>16777215</height>
</size>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="btnFilterAll">
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnFilterNone">
<property name="text">
<string>None</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@@ -367,7 +381,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>1177</width>
<height>26</height> <height>26</height>
</rect> </rect>
</property> </property>
+223 -212
View File
@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>681</width> <width>681</width>
<height>828</height> <height>797</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -15,7 +15,7 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,2"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="3,1,2">
<item> <item>
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<item row="0" column="0"> <item row="0" column="0">
@@ -49,216 +49,27 @@
<widget class="CANDataGrid" name="gridData" native="true"> <widget class="CANDataGrid" name="gridData" native="true">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>300</width> <width>280</width>
<height>300</height> <height>280</height>
</size> </size>
</property> </property>
<property name="baseSize"> <property name="baseSize">
<size> <size>
<width>300</width> <width>280</width>
<height>300</height> <height>280</height>
</size> </size>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Data Len:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="txtDataLen"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Little Endian</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="cbIntel">
<property name="text">
<string> (LSB First)</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Signed:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="cbSigned">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string>Mask:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="txtMask"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Bias:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="txtBias"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="txtScale"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Stride</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="txtStride"/>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Only Points</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QCheckBox" name="cbOnlyPoints">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Point Style</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QComboBox" name="coPointStyle"/>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Line Thickness</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QSpinBox" name="spinLineWidth">
<property name="maximum">
<number>15</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Line Color</string>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QPushButton" name="colorSwatch">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>CHANGE</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label55">
<property name="text">
<string>Fill Color</string>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QPushButton" name="fillSwatch">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>CHANGE</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QPushButton" name="btnAddGraph">
<property name="text">
<string>Add this graph</string>
</property>
</widget>
</item>
<item row="10" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Associated Bus</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLineEdit" name="editBus">
<property name="text">
<string>-1</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
@@ -356,7 +167,7 @@
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>40</height> <height>30</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@@ -365,6 +176,215 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,1">
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Bit Len:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="txtDataLen"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Little Endian</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="cbIntel">
<property name="text">
<string> (LSB First)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Signed:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="cbSigned">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string>Mask:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="txtMask"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<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_6">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="txtScale"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Stride</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="txtStride"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Associated Bus</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="editBus">
<property name="text">
<string>-1</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Only Points</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="cbOnlyPoints">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Point Style</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="coPointStyle"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Line Thickness</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinLineWidth">
<property name="maximum">
<number>15</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Line Color</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="colorSwatch">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>CHANGE</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label55">
<property name="text">
<string>Fill Color</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="fillSwatch">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>CHANGE</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="btnAddGraph">
<property name="text">
<string>Add this graph</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
@@ -378,15 +398,6 @@
<tabstops> <tabstops>
<tabstop>txtName</tabstop> <tabstop>txtName</tabstop>
<tabstop>txtID</tabstop> <tabstop>txtID</tabstop>
<tabstop>txtDataLen</tabstop>
<tabstop>cbIntel</tabstop>
<tabstop>cbSigned</tabstop>
<tabstop>txtMask</tabstop>
<tabstop>txtBias</tabstop>
<tabstop>txtScale</tabstop>
<tabstop>txtStride</tabstop>
<tabstop>colorSwatch</tabstop>
<tabstop>btnAddGraph</tabstop>
<tabstop>cbMessages</tabstop> <tabstop>cbMessages</tabstop>
<tabstop>cbSignals</tabstop> <tabstop>cbSignals</tabstop>
<tabstop>btnCopySignal</tabstop> <tabstop>btnCopySignal</tabstop>
+37 -5
View File
@@ -108,6 +108,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="btnSaveAsScript">
<property name="text">
<string>Sa&amp;ve As</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="btnRevertScript"> <widget class="QPushButton" name="btnRevertScript">
<property name="text"> <property name="text">
@@ -115,6 +122,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="btnReloadScript">
<property name="text">
<string>R&amp;eload</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="btnRecompile"> <widget class="QPushButton" name="btnRecompile">
<property name="text"> <property name="text">
@@ -151,11 +165,26 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="btnClearLog"> <layout class="QHBoxLayout" name="horizontalLayout_log">
<property name="text"> <property name="alignment">
<string>Clear Log &amp;Window</string> <set>Qt::AlignCenter</set>
</property> </property>
</widget> <property name="contentsMargins">10, 0, 10, 0</property>
<item>
<widget class="QPushButton" name="btnClearLog">
<property name="text">
<string>Clear Log &amp;Window</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSaveLog">
<property name="text">
<string>Save L&amp;og</string>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</item> </item>
@@ -169,10 +198,13 @@
<tabstop>listLoadedScripts</tabstop> <tabstop>listLoadedScripts</tabstop>
<tabstop>tableVariables</tabstop> <tabstop>tableVariables</tabstop>
<tabstop>btnSaveScript</tabstop> <tabstop>btnSaveScript</tabstop>
<tabstop>btnSaveAsScript</tabstop>
<tabstop>btnRevertScript</tabstop> <tabstop>btnRevertScript</tabstop>
<tabstop>btnReloadScript</tabstop>
<tabstop>btnRecompile</tabstop> <tabstop>btnRecompile</tabstop>
<tabstop>cbAutoScroll</tabstop> <tabstop>cbAutoScroll</tabstop>
<tabstop>btnClearLog</tabstop> <tabstop>btnClearLog</tabstop>
<tabstop>btnSaveLog</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>