Merge branch 'fix_socketcandpartialframedrop' of github.com:qurrent-llc/SavvyCAN into fix_socketcandpartialframedrop

This commit is contained in:
Andy Huska
2022-10-17 10:45:58 -05:00
35 changed files with 2805 additions and 609 deletions
+9
View File
@@ -20,7 +20,9 @@ QMAKE_INFO_PLIST = Info.plist.template
ICON = icons/SavvyIcon.icns
SOURCES += main.cpp\
connections/lawicel_serial.cpp \
connections/mqtt_bus.cpp \
dbc/dbcnodeduplicateeditor.cpp \
mqtt/qmqtt_client.cpp \
mqtt/qmqtt_client_p.cpp \
mqtt/qmqtt_frame.cpp \
@@ -67,6 +69,7 @@ SOURCES += main.cpp\
dbc/dbcmaineditor.cpp \
dbc/dbcnodeeditor.cpp \
dbc/dbcsignaleditor.cpp \
dbc/dbcnoderebaseeditor.cpp \
re/discretestatewindow.cpp \
re/filecomparatorwindow.cpp \
re/flowviewwindow.cpp \
@@ -98,8 +101,11 @@ SOURCES += main.cpp\
HEADERS += mainwindow.h \
can_structs.h \
canframemodel.h \
connections/lawicel_serial.h \
connections/socketcand.h \
connections/mqtt_bus.h \
dbc/dbcnodeduplicateeditor.h \
dbc/dbcnoderebaseeditor.h \
mqtt/qmqtt.h \
mqtt/qmqtt_client.h \
mqtt/qmqtt_client_p.h \
@@ -183,11 +189,14 @@ HEADERS += mainwindow.h \
pcaplite.h
FORMS += ui/candatagrid.ui \
ui/dbcnodeduplicateeditor.ui \
ui/dbccomparatorwindow.ui \
ui/dbcmessageeditor.ui \
ui/connectionwindow.ui \
ui/dbcloadsavewindow.ui \
ui/dbcmaineditor.ui \
ui/dbcnodeduplicateeditor.ui \
ui/dbcnoderebaseeditor.ui \
ui/dbcsignaleditor.ui \
ui/dbcnodeeditor.ui \
ui/discretestatewindow.ui \
+1
View File
@@ -20,6 +20,7 @@ namespace CANCon {
REMOTE,
KAYAK,
MQTT,
LAWICEL,
NONE
};
}
+4 -1
View File
@@ -4,10 +4,11 @@
#include "gvretserial.h"
#include "mqtt_bus.h"
#include "socketcand.h"
#include "lawicel_serial.h"
using namespace CANCon;
CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName)
CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDriverName, int pSerialSpeed, int pBusSpeed)
{
switch(pType) {
case SERIALBUS:
@@ -19,6 +20,8 @@ CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDri
return new GVRetSerial(pPortName, false);
case REMOTE:
return new GVRetSerial(pPortName, true); //it's a special case of GVRET connected over TCP/IP so it uses the same class
case LAWICEL:
return new LAWICELSerial(pPortName, pSerialSpeed, pBusSpeed);
case KAYAK:
return new SocketCANd(pPortName);
case MQTT:
+1 -1
View File
@@ -7,7 +7,7 @@
class CanConFactory
{
public:
static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName);
static CANConnection* create(CANCon::type, QString pPortName, QString pDriverName, int pSerialSpeed, int pBusSpeed);
};
#endif // CANCONFACTORY_H
+5
View File
@@ -5,6 +5,8 @@
CANConnection::CANConnection(QString pPort,
QString pDriver,
CANCon::type pType,
int pSerialSpeed,
int pBusSpeed,
int pNumBuses,
int pQueueLen,
bool pUseThread) :
@@ -13,6 +15,7 @@ CANConnection::CANConnection(QString pPort,
mPort(pPort),
mDriver(pDriver),
mType(pType),
mSerialSpeed(pSerialSpeed),
mIsCapSuspended(false),
mStatus(CANCon::NOT_CONNECTED),
mStarted(false),
@@ -34,6 +37,8 @@ CANConnection::CANConnection(QString pPort,
mBusData[i].mConfigured = false;
}
if (pBusSpeed > 0) mBusData[0].mBus.setSpeed(pBusSpeed);
/* if needed, create a thread and move ourself into it */
if(pUseThread) {
mThread_p = new QThread();
+6 -1
View File
@@ -21,13 +21,17 @@ protected:
* @param pPort: string containing port name
* @param pDriver: string containing driver name - Really only used for SerialBus connections
* @param pType: the type of connection @ref CANCon::type
* @param pSerialSpeed: for devices with variable serial speed this is that speed.
* @param pBusSpeed: set an initial speed when opening this connection
* @param pNumBuses: the number of buses the device has
* @param pQueueLen: the length of the lock free queue to use
* @param pUseThread: if set to true, object will be execute in a dedicated thread
*/
CANConnection(QString pPort,
QString pDriver,
CANCon::type pType,
CANCon::type pType,
int pSerialSpeed,
int pBusSpeed,
int pNumBuses,
int pQueueLen,
bool pUseThread);
@@ -201,6 +205,7 @@ protected:
int mNumBuses; //protected to allow connected device to figure out how many buses are available
QVector<BusData> mBusData;
bool mConsoleOutput; //send debugging info to the console?
int mSerialSpeed;
//determine if the passed frame is part of a filter or not.
void checkTargettedFrame(CANFrame &frame);
+1
View File
@@ -86,6 +86,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
case CANCon::SERIALBUS: return "SerialBus";
case CANCon::GVRET_SERIAL: return "GVRET";
case CANCon::KAYAK: return "socketcand";
case CANCon::LAWICEL: return "LAWICEL";
default: {}
}
else qDebug() << "Tried to show connection type but connection was nullptr";
+16 -5
View File
@@ -64,6 +64,7 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
ui->cbBusSpeed->addItem("33333");
ui->cbBusSpeed->addItem("50000");
ui->cbBusSpeed->addItem("83333");
ui->cbBusSpeed->addItem("100000");
ui->cbBusSpeed->addItem("125000");
ui->cbBusSpeed->addItem("250000");
@@ -250,6 +251,8 @@ void ConnectionWindow::handleNewConn()
CANCon::type newType;
QString newPort;
QString newDriver;
int newSerialSpeed;
int newBusSpeed;
CANConnection *conn;
if (thisDialog->exec() == QDialog::Accepted)
@@ -257,7 +260,9 @@ void ConnectionWindow::handleNewConn()
newType = thisDialog->getConnectionType();
newPort = thisDialog->getPortName();
newDriver = thisDialog->getDriverName();
conn = create(newType, newPort, newDriver);
newSerialSpeed = thisDialog->getSerialSpeed();
newBusSpeed = thisDialog->getBusSpeed();
conn = create(newType, newPort, newDriver, newSerialSpeed, newBusSpeed);
if (conn)
{
connModel->add(conn);
@@ -292,6 +297,7 @@ void ConnectionWindow::handleResetConn()
{
QString port, driver;
CANCon::type type;
int serSpeed, busSpeed;
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
if (selIdx <0) return;
@@ -304,13 +310,15 @@ void ConnectionWindow::handleResetConn()
type = conn_p->getType();
port = conn_p->getPort();
driver = conn_p->getDriver();
serSpeed = 0; //TODO: implement these
busSpeed = 0;
/* stop and delete connection */
conn_p->stop();
conn_p = nullptr;
conn_p = create(type, port, driver);
conn_p = create(type, port, driver, serSpeed, busSpeed);
if (conn_p) connModel->replace(selIdx, conn_p);
}
@@ -476,12 +484,12 @@ void ConnectionWindow::handleSendText() {
emit sendDebugData(bytes);
}
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver)
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver, int pSerialSpeed, int pBusSpeed)
{
CANConnection* conn_p;
/* create connection */
conn_p = CanConFactory::create(pTye, pPortName, pDriver);
conn_p = CanConFactory::create(pTye, pPortName, pDriver, pSerialSpeed, pBusSpeed);
if(conn_p)
{
/* connect signal */
@@ -518,7 +526,8 @@ void ConnectionWindow::loadConnections()
for(int i = 0 ; i < portNames.count() ; i++)
{
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i]);
//TODO: add serial speed and bus speed to this properly.
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], driverNames[i], 0, 0);
/* add connection to model */
connModel->add(conn_p);
}
@@ -536,6 +545,8 @@ void ConnectionWindow::saveConnections()
QVector<QString> portNames;
QVector<int> devTypes;
QVector<QString> driverNames;
QVector<int> serialSpeeds;
QVector<int> busSpeeds;
/* save connections */
foreach(CANConnection* conn_p, conns)
+1 -1
View File
@@ -65,7 +65,7 @@ private:
QVector<QString> remoteDeviceIPGVRET;
QVector<QString> remoteDeviceKayak;
CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver);
CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver, int pSerialSpeed, int pBusSpeed);
void populateBusDetails(int offset);
void loadConnections();
void saveConnections();
+1 -1
View File
@@ -9,7 +9,7 @@
#include "gvretserial.h"
GVRetSerial::GVRetSerial(QString portName, bool useTcp) :
CANConnection(portName, "gvret", CANCon::GVRET_SERIAL, 3, 4000, true),
CANConnection(portName, "gvret", CANCon::GVRET_SERIAL, 0, 0, 3, 4000, true),
mTimer(this), /*NB: set this as parent of timer to manage it from working thread */
useTcp(useTcp)
{
+496
View File
@@ -0,0 +1,496 @@
#include <QObject>
#include <QDebug>
#include <QCanBusFrame>
#include <QSerialPortInfo>
#include <QSettings>
#include <QStringBuilder>
#include <QtNetwork>
#include "lawicel_serial.h"
#include "utility.h"
LAWICELSerial::LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed) :
CANConnection(portName, "LAWICEL", CANCon::LAWICEL,serialSpeed, lawicelSpeed, 3, 4000, true),
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{
sendDebug("LAWICELSerial()");
serial = nullptr;
isAutoRestart = false;
readSettings();
}
LAWICELSerial::~LAWICELSerial()
{
stop();
sendDebug("~LAWICELSerial()");
}
void LAWICELSerial::sendDebug(const QString debugText)
{
qDebug() << debugText;
debugOutput(debugText);
}
void LAWICELSerial::sendToSerial(const QByteArray &bytes)
{
if (serial == nullptr)
{
sendDebug("Attempt to write to serial port when it has not been initialized!");
return;
}
if (serial && !serial->isOpen())
{
sendDebug("Attempt to write to serial port when it is not open!");
return;
}
QString buildDebug;
buildDebug = "Write to serial -> ";
foreach (int byt, bytes) {
byt = (unsigned char)byt;
buildDebug = buildDebug % QString::number(byt, 16) % " ";
}
sendDebug(buildDebug);
if (serial) serial->write(bytes);
}
void LAWICELSerial::piStarted()
{
connectDevice();
}
void LAWICELSerial::piSuspend(bool pSuspend)
{
/* update capSuspended */
setCapSuspended(pSuspend);
/* flush queue if we are suspended */
if(isCapSuspended())
getQueue().flush();
}
void LAWICELSerial::piStop()
{
mTimer.stop();
disconnectDevice();
}
bool LAWICELSerial::piGetBusSettings(int pBusIdx, CANBus& pBus)
{
return getBusConfig(pBusIdx, pBus);
}
void LAWICELSerial::piSetBusSettings(int pBusIdx, CANBus bus)
{
/* sanity checks */
if( (pBusIdx < 0) || pBusIdx >= getNumBuses())
return;
/* copy bus config */
setBusConfig(pBusIdx, bus);
/*
qDebug() << "About to update bus " << pBusIdx << " on GVRET";
if (pBusIdx == 0)
{
can0Baud = bus.getSpeed();
can0Baud |= 0x80000000;
if (bus.isActive())
{
can0Baud |= 0x40000000;
can0Enabled = true;
}
else can0Enabled = false;
if (bus.isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
else can0ListenOnly = false;
}
*/
if (pBusIdx < 2) {
/* update baud rates */
QByteArray buffer;
//sendDebug("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)));
buffer[0] = (char)0xF1; //start of a command over serial
//sendToSerial(buffer);
}
}
bool LAWICELSerial::piSendFrame(const CANFrame& frame)
{
QByteArray buffer;
int c;
quint32 ID;
//qDebug() << "Sending out lawicel frame with id " << frame.ID << " on bus " << frame.bus;
framesRapid++;
if (serial == nullptr) return false;
if (serial && !serial->isOpen()) return false;
//if (!isConnected) return false;
// Doesn't make sense to send an error frame
// to an adapter
if (frame.frameId() & 0x20000000) {
return true;
}
ID = frame.frameId();
if (frame.hasExtendedFrameFormat()) ID |= 1u << 31;
int idx = 0;
QString buildStr;
if (frame.hasExtendedFrameFormat())
{
buildStr = QString::asprintf("T%08X%u", ID, frame.payload().length());
}
else
{
buildStr = QString::asprintf("t%03X%u", ID, frame.payload().length());
}
foreach (QChar chr, buildStr)
{
buffer[idx] = chr.toLatin1();
idx++;
}
for (c = 0; c < frame.payload().length(); c++)
{
QString byt = Utility::formatByteAsHex(frame.payload()[c]);
buffer[idx + (c * 2)] = byt[0].toLatin1();
buffer[idx + (c * 2) + 1] = byt[1].toLatin1();
}
buffer[idx + (frame.payload().length() * 2)] = 13; //CR
sendToSerial(buffer);
return true;
}
/****************************************************************/
void LAWICELSerial::readSettings()
{
QSettings settings;
}
void LAWICELSerial::connectDevice()
{
QSettings settings;
/* disconnect device */
if(serial)
disconnectDevice();
/* open new device */
qDebug() << "Serial port: " << getPort();
serial = new QSerialPort(QSerialPortInfo(getPort()));
if(!serial) {
sendDebug("can't open serial port " + getPort());
return;
}
sendDebug("Created Serial Port Object");
/* connect reading event */
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialError(QSerialPort::SerialPortError)));
/* configure */
serial->setBaudRate(mSerialSpeed);
serial->setDataBits(serial->Data8);
serial->setFlowControl(serial->HardwareControl);
//serial->setFlowControl(serial->NoFlowControl);
if (!serial->open(QIODevice::ReadWrite))
{
//sendDebug("Error returned during port opening: " + serial->errorString());
}
else
{
//serial->setDataTerminalReady(true); //Seemingly these two lines used to be needed
//serial->setRequestToSend(true); //But, really both ends should automatically handle these
deviceConnected();
}
}
void LAWICELSerial::deviceConnected()
{
sendDebug("Connecting to LAWICEL Device!");
QByteArray output;
output.clear();
output.append('C'); //close the bus in case it was already up
output.append(13);
sendToSerial(output);
output.clear();
output.append('S'); //configure speed of bus
switch (this->mBusData[0].mBus.getSpeed())
{
case 10000:
output.append('0');
break;
case 20000:
output.append('1');
break;
case 50000:
output.append('2');
break;
case 100000:
output.append('3');
break;
case 125000:
output.append('4');
break;
case 250000:
output.append('5');
break;
case 500000:
output.append('6');
break;
case 800000:
output.append('7');
break;
case 1000000:
output.append('8');
break;
default:
output.append('6');
break;
}
output.append('\x0D');
sendToSerial(output);
output.clear();
output.append('O'); //open bus now that we set the speed
output.append(13);
sendToSerial(output);
mNumBuses = 1;
setStatus(CANCon::CONNECTED);
CANConStatus stats;
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
mBusData[0].mConfigured = true;
mBusData[0].mBus.setActive(true);
//mBusData[0].mBus.setSpeed();
emit status(stats);
}
void LAWICELSerial::disconnectDevice() {
if (serial != nullptr)
{
if (serial->isOpen())
{
//serial->clear();
serial->close();
}
serial->disconnect(); //disconnect all signals
delete serial;
serial = nullptr;
}
setStatus(CANCon::NOT_CONNECTED);
CANConStatus stats;
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
}
void LAWICELSerial::serialError(QSerialPort::SerialPortError err)
{
QString errMessage;
bool killConnection = false;
switch (err)
{
case QSerialPort::NoError:
return;
case QSerialPort::DeviceNotFoundError:
errMessage = "Device not found error on serial";
killConnection = true;
piStop();
break;
case QSerialPort::PermissionError:
errMessage = "Permission error on serial port";
killConnection = true;
piStop();
break;
case QSerialPort::OpenError:
errMessage = "Open error on serial port";
killConnection = true;
piStop();
break;
case QSerialPort::ParityError:
errMessage = "Parity error on serial port";
break;
case QSerialPort::FramingError:
errMessage = "Framing error on serial port";
break;
case QSerialPort::BreakConditionError:
errMessage = "Break error on serial port";
break;
case QSerialPort::WriteError:
errMessage = "Write error on serial port";
piStop();
break;
case QSerialPort::ReadError:
errMessage = "Read error on serial port";
piStop();
break;
case QSerialPort::ResourceError:
errMessage = "Serial port seems to have disappeared.";
killConnection = true;
piStop();
break;
case QSerialPort::UnsupportedOperationError:
errMessage = "Unsupported operation on serial port";
killConnection = true;
break;
case QSerialPort::UnknownError:
errMessage = "Beats me what happened to the serial port.";
killConnection = true;
piStop();
break;
case QSerialPort::TimeoutError:
errMessage = "Timeout error on serial port";
killConnection = true;
break;
case QSerialPort::NotOpenError:
errMessage = "The serial port isn't open";
killConnection = true;
piStop();
break;
}
/*
if (serial)
{
serial->clearError();
serial->flush();
serial->close();
}*/
if (errMessage.length() > 1)
{
sendDebug(errMessage);
}
if (killConnection)
{
qDebug() << "Shooting the serial object in the head. It deserves it.";
disconnectDevice();
}
}
void LAWICELSerial::connectionTimeout()
{
//one second after trying to connect are we actually connected?
if (CANCon::NOT_CONNECTED==getStatus()) //no?
{
//then emit the the failure signal and see if anyone cares
sendDebug("Failed to connect to LAWICEL at that com port");
disconnectDevice();
connectDevice();
}
else
{
/* start timer */
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
mTimer.setInterval(250); //tick four times per second
mTimer.setSingleShot(false); //keep ticking
mTimer.start();
}
}
void LAWICELSerial::readSerialData()
{
QByteArray data;
unsigned char c;
QString debugBuild;
CANFrame buildFrame;
QByteArray buildData;
if (serial) data = serial->readAll();
sendDebug("Got data from serial. Len = " % QString::number(data.length()));
for (int i = 0; i < data.length(); i++)
{
c = data.at(i);
//qDebug() << c << " " << QString::number(c, 16) << " " << QString(c);
debugBuild = debugBuild % QString::number(c, 16).rightJustified(2,'0') % " ";
//procRXChar(c);
mBuildLine.append(c);
if (c == 13) //all lawicel commands end in CR
{
qDebug() << "Got CR!";
switch (mBuildLine[0].toLatin1())
{
case 't': //standard frame
//tIIILDD
buildFrame.setFrameId(mBuildLine.mid(1, 3).toInt(nullptr, 16));
buildFrame.isReceived = true;
buildFrame.setFrameType(QCanBusFrame::FrameType::DataFrame);
buildData.resize(mBuildLine.mid(4, 1).toInt());
for (int c = 0; c < buildData.size(); c++)
{
buildData[c] = mBuildLine.mid(5 + (c*2), 2).toInt(nullptr, 16);
}
buildFrame.setPayload(buildData);
if (!isCapSuspended())
{
/* get frame from queue */
CANFrame* frame_p = getQueue().get();
if(frame_p) {
//qDebug() << "Lawicel got frame on bus " << frame_p->bus;
/* copy frame */
*frame_p = buildFrame;
checkTargettedFrame(buildFrame);
/* enqueue frame */
getQueue().queue();
}
else
qDebug() << "can't get a frame, ERROR";
}
break;
case 'T': //extended frame
break;
}
mBuildLine.clear();
}
}
debugOutput(debugBuild);
//qDebug() << debugBuild;
}
//Debugging data sent from connection window. Inject it into Comm traffic.
void LAWICELSerial::debugInput(QByteArray bytes) {
sendToSerial(bytes);
}
void LAWICELSerial::handleTick()
{
//qDebug() << "Tick!";
}
+66
View File
@@ -0,0 +1,66 @@
#ifndef LAWICELSERIAL_H
#define LAWICELSERIAL_H
#include <QSerialPort>
#include <QCanBusDevice>
#include <QThread>
#include <QTimer>
/*************/
#include <QDateTime>
/*************/
#include "canframemodel.h"
#include "canconnection.h"
#include "canconmanager.h"
class LAWICELSerial : public CANConnection
{
Q_OBJECT
public:
LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed);
virtual ~LAWICELSerial();
protected:
virtual void piStarted();
virtual void piStop();
virtual void piSetBusSettings(int pBusIdx, CANBus pBus);
virtual bool piGetBusSettings(int pBusIdx, CANBus& pBus);
virtual void piSuspend(bool pSuspend);
virtual bool piSendFrame(const CANFrame&) ;
void disconnectDevice();
public slots:
void debugInput(QByteArray bytes);
private slots:
void connectDevice();
void connectionTimeout();
void readSerialData();
void serialError(QSerialPort::SerialPortError err);
void deviceConnected();
void handleTick();
private:
void readSettings();
void rebuildLocalTimeBasis();
void sendToSerial(const QByteArray &bytes);
void sendDebug(const QString debugText);
protected:
QTimer mTimer;
QThread mThread;
QString mBuildLine;
bool isAutoRestart;
QSerialPort *serial;
int framesRapid;
CANFrame buildFrame;
bool can0Enabled;
bool can0ListenOnly;
};
#endif // LAWICELSERIAL_H
+1 -1
View File
@@ -9,7 +9,7 @@
#include "mqtt_bus.h"
MQTT_BUS::MQTT_BUS(QString topicName) :
CANConnection(topicName, "mqtt_client", CANCon::MQTT, 1, 4000, true),
CANConnection(topicName, "mqtt_client", CANCon::MQTT, 0, 0, 1, 4000, true),
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{
+97
View File
@@ -27,12 +27,17 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* gvretips, QVector<QSt
connect(ui->rbRemote, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbKayak, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbMQTT, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbLawicel, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->cbDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NewConnectionDialog::handleDeviceTypeChanged);
connect(ui->btnOK, &QPushButton::clicked, this, &NewConnectionDialog::handleCreateButton);
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
selectSerial();
qDebug() << "Was passed " << remoteDeviceIPGVRET->count() << " remote GVRET IPs";
@@ -53,6 +58,7 @@ void NewConnectionDialog::handleConnTypeChanged()
{
if (ui->rbGVRET->isChecked()) selectSerial();
if (ui->rbSocketCAN->isChecked()) selectSocketCan();
if (ui->rbLawicel->isChecked()) selectLawicel();
if (ui->rbRemote->isChecked()) selectRemote();
if (ui->rbKayak->isChecked()) selectKayak();
if (ui->rbMQTT->isChecked()) selectMQTT();
@@ -68,12 +74,58 @@ void NewConnectionDialog::handleDeviceTypeChanged()
ui->cbPort->addItem(canDevices[i].name());
}
void NewConnectionDialog::selectLawicel()
{
ui->lPort->setText("Serial Port:");
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(false);
ui->cbSerialSpeed->setHidden(false);
ui->lblCANSpeed->setHidden(false);
ui->lblSerialSpeed->setHidden(false);
ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts();
for (int i = 0; i < ports.count(); i++)
ui->cbPort->addItem(ports[i].portName());
if (ui->cbCANSpeed->count() == 0)
{
ui->cbCANSpeed->addItem("10000");
ui->cbCANSpeed->addItem("20000");
ui->cbCANSpeed->addItem("50000");
ui->cbCANSpeed->addItem("83333");
ui->cbCANSpeed->addItem("100000");
ui->cbCANSpeed->addItem("125000");
ui->cbCANSpeed->addItem("250000");
ui->cbCANSpeed->addItem("500000");
ui->cbCANSpeed->addItem("1000000");
}
if (ui->cbSerialSpeed->count() == 0)
{
ui->cbSerialSpeed->addItem("115200");
ui->cbSerialSpeed->addItem("150000");
ui->cbSerialSpeed->addItem("250000");
ui->cbSerialSpeed->addItem("500000");
ui->cbSerialSpeed->addItem("1000000");
ui->cbSerialSpeed->addItem("2000000");
}
}
void NewConnectionDialog::selectSerial()
{
ui->lPort->setText("Serial Port:");
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts();
@@ -87,6 +139,10 @@ void NewConnectionDialog::selectSocketCan()
ui->lPort->setText("Port:");
ui->lblDeviceType->setHidden(false);
ui->cbDeviceType->setHidden(false);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
ui->cbDeviceType->clear();
QStringList plugins;
@@ -99,8 +155,14 @@ void NewConnectionDialog::selectSocketCan()
void NewConnectionDialog::selectRemote()
{
ui->lPort->setText("IP Address:");
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
ui->cbPort->clear();
foreach(QString pName, *remoteDeviceIPGVRET)
{
@@ -111,8 +173,14 @@ void NewConnectionDialog::selectRemote()
void NewConnectionDialog::selectKayak()
{
ui->lPort->setText("Available Bus(ses):");
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
ui->cbPort->clear();
foreach(QString pName, *remoteBusKayak)
{
@@ -123,8 +191,14 @@ void NewConnectionDialog::selectKayak()
void NewConnectionDialog::selectMQTT()
{
ui->lPort->setText("Topic Name:");
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
ui->cbPort->clear();
}
@@ -148,6 +222,8 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
case CANCon::MQTT:
ui->rbMQTT->setChecked(true);
break;
case CANCon::LAWICEL:
ui->rbLawicel->setChecked(true);
default: {}
}
@@ -157,6 +233,7 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
switch(pType)
{
case CANCon::GVRET_SERIAL:
case CANCon::LAWICEL:
{
int idx = ui->cbPort->findText(pPortName);
if( idx<0 ) idx=0;
@@ -201,6 +278,7 @@ QString NewConnectionDialog::getPortName()
case CANCon::SERIALBUS:
case CANCon::REMOTE:
case CANCon::MQTT:
case CANCon::LAWICEL:
return ui->cbPort->currentText();
case CANCon::KAYAK:
return ui->cbPort->currentText();
@@ -220,6 +298,24 @@ QString NewConnectionDialog::getDriverName()
return "N/A";
}
int NewConnectionDialog::getSerialSpeed()
{
if (getConnectionType() == CANCon::LAWICEL)
{
return ui->cbSerialSpeed->currentText().toInt();
}
else return 0;
}
int NewConnectionDialog::getBusSpeed()
{
if (getConnectionType() == CANCon::LAWICEL)
{
return ui->cbCANSpeed->currentText().toInt();
}
else return 0;
}
CANCon::type NewConnectionDialog::getConnectionType()
{
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
@@ -227,6 +323,7 @@ CANCon::type NewConnectionDialog::getConnectionType()
if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
if (ui->rbKayak->isChecked()) return CANCon::KAYAK;
if (ui->rbMQTT->isChecked()) return CANCon::MQTT;
if (ui->rbLawicel->isChecked()) return CANCon::LAWICEL;
qDebug() << "getConnectionType: error";
return CANCon::NONE;
+3
View File
@@ -24,6 +24,8 @@ public:
CANCon::type getConnectionType();
QString getPortName();
QString getDriverName();
int getSerialSpeed();
int getBusSpeed();
public slots:
void handleConnTypeChanged();
@@ -43,6 +45,7 @@ private:
void selectRemote();
void selectKayak();
void selectMQTT();
void selectLawicel();
bool isSerialBusAvailable();
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
};
+1 -1
View File
@@ -12,7 +12,7 @@
/***********************************/
SerialBusConnection::SerialBusConnection(QString portName, QString driverName) :
CANConnection(portName, driverName, CANCon::SERIALBUS, 1, 4000, true),
CANConnection(portName, driverName, CANCon::SERIALBUS,0 ,0 ,1, 4000, true),
mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */
{
}
+1 -1
View File
@@ -10,7 +10,7 @@
#include "socketcand.h"
SocketCANd::SocketCANd(QString portName) :
CANConnection(portName, "kayak", CANCon::KAYAK, 1, 4000, true),
CANConnection(portName, "kayak", CANCon::KAYAK, 0, 0, 1, 4000, true),
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{
+27 -3
View File
@@ -177,6 +177,24 @@ DBC_MESSAGE* DBCMessageHandler::findMsgByPartialName(QString name)
return nullptr;
}
QList<DBC_MESSAGE*> DBCMessageHandler::findMsgsByNode(DBC_NODE* node)
{
QList<DBC_MESSAGE*> messagesForNode;
if (messages.count() == 0)
return messagesForNode;
for (int i = 0; i < messages.count(); i++)
{
if (messages[i].sender == node)
{
messagesForNode.append(&messages[i]);
}
}
return messagesForNode;
}
bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg)
{
messages.append(msg);
@@ -453,7 +471,7 @@ DBC_MESSAGE* DBCFile::parseMessageLine(QString line)
DBC_MESSAGE msg;
uint32_t ID = match.captured(1).toULong(); //the ID is always stored in decimal format
msg.ID = ID & 0x1FFFFFFFul;
msg.extendedID = (ID & 80000000ul) ? true : false;
msg.extendedID = (ID & 0x80000000ul) ? true : false;
msg.name = match.captured(2);
msg.len = match.captured(3).toUInt();
msg.sender = findNodeByName(match.captured(4));
@@ -1369,7 +1387,10 @@ bool DBCFile::saveFile(QString fileName)
}
uint32_t ID = msg->ID;
if (msg->ID > 0x7FF || msg->extendedID) msg->ID += 0x80000000ul; //set bit 31 if this ID is extended.
if (msg->ID > 0x7FF || msg->extendedID)
{
msg->ID += 0x80000000ul; //set bit 31 if this ID is extended.
}
msgOutput.append("BO_ " + QString::number(ID) + " " + msg->name + ": " + QString::number(msg->len) +
" " + msg->sender->name + "\n");
@@ -1565,7 +1586,10 @@ bool DBCFile::saveFile(QString fileName)
DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x);
uint32_t ID = msg->ID;
if (msg->ID > 0x7FF || msg->extendedID) msg->ID += 0x80000000ul; //set bit 31 if this ID is extended.
if (msg->ID > 0x7FF || msg->extendedID)
{
msg->ID += 0x80000000ul; //set bit 31 if this ID is extended.
}
for (int s = 0; s < msg->sigHandler->getCount(); s++)
{
+1
View File
@@ -43,6 +43,7 @@ public:
DBC_MESSAGE *findMsgByIdx(int idx);
DBC_MESSAGE *findMsgByName(QString name);
DBC_MESSAGE *findMsgByPartialName(QString name);
QList<DBC_MESSAGE*> findMsgsByNode(DBC_NODE *node);
bool addMessage(DBC_MESSAGE &msg);
bool removeMessage(DBC_MESSAGE *msg);
bool removeMessageByIndex(int idx);
+168 -3
View File
@@ -21,25 +21,35 @@ DBCMainEditor::DBCMainEditor( const QVector<CANFrame> *frames, QWidget *parent)
dbcHandler = DBCHandler::getReference();
referenceFrames = frames;
ui->treeDBC->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->btnSearch, &QAbstractButton::clicked, this, &DBCMainEditor::handleSearch);
connect(ui->lineSearch, &QLineEdit::returnPressed, this, &DBCMainEditor::handleSearch);
connect(ui->btnSearchNext, &QAbstractButton::clicked, this, &DBCMainEditor::handleSearchForward);
connect(ui->btnSearchPrev, &QAbstractButton::clicked, this, &DBCMainEditor::handleSearchBackward);
connect(ui->treeDBC, &QTreeWidget::doubleClicked, this, &DBCMainEditor::onTreeDoubleClicked);
connect(ui->treeDBC, &QTreeWidget::customContextMenuRequested, this, &DBCMainEditor::onTreeContextMenu);
connect(ui->treeDBC, &QTreeWidget::currentItemChanged, this, &DBCMainEditor::currentItemChanged);
connect(ui->btnDelete, &QAbstractButton::clicked, this, &DBCMainEditor::deleteCurrentTreeItem);
connect(ui->btnNewNode, &QAbstractButton::clicked, this, &DBCMainEditor::newNode);
connect(ui->btnNewNode, &QAbstractButton::clicked, this, QOverload<>::of(&DBCMainEditor::newNode));
connect(ui->btnNewMessage, &QAbstractButton::clicked, this, &DBCMainEditor::newMessage);
connect(ui->btnNewSignal, &QAbstractButton::clicked, this, &DBCMainEditor::newSignal);
sigEditor = new DBCSignalEditor(this);
msgEditor = new DBCMessageEditor(this);
nodeEditor = new DBCNodeEditor(this);
nodeRebaseEditor = new DBCNodeRebaseEditor(this);
nodeDuplicateEditor = new DBCNodeDuplicateEditor(this);
//all three might potentially change the data stored and force the tree to be updated
connect(sigEditor, &DBCSignalEditor::updatedTreeInfo, this, &DBCMainEditor::updatedSignal);
connect(msgEditor, &DBCMessageEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage);
connect(nodeEditor, &DBCNodeEditor::updatedTreeInfo, this, &DBCMainEditor::updatedNode);
connect(nodeRebaseEditor, &DBCNodeRebaseEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage);
connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::updatedTreeInfo, this, &DBCMainEditor::updatedMessage);
connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::createNode, this, QOverload<QString>::of(&DBCMainEditor::newNode));
connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::cloneMessageToNode, this, &DBCMainEditor::copyMessageToNode);
connect(nodeDuplicateEditor, &DBCNodeDuplicateEditor::nodeAdded, this, &DBCMainEditor::refreshTree);
nodeIcon = QIcon(":/icons/images/node.png");
messageIcon = QIcon(":/icons/images/message.png");
@@ -298,6 +308,83 @@ void DBCMainEditor::onTreeDoubleClicked(const QModelIndex &index)
}
}
void DBCMainEditor::onTreeContextMenu(const QPoint & pos)
{
QTreeWidgetItem* firstCol = ui->treeDBC->currentItem();
bool ret = false;
DBC_MESSAGE *msg;
DBC_SIGNAL *sig;
DBC_NODE *node;
uint32_t msgID;
QString idString;
qDebug() << firstCol->data(0, Qt::UserRole) << " - " << firstCol->text(0);
switch (firstCol->data(0, Qt::UserRole).toInt())
{
case 1: //a node
idString = firstCol->text(0).split(" ")[0];
node = dbcFile->findNodeByName(idString);
QAction *actionRebase = new QAction(QIcon(":/Resource/warning32.ico"), tr("Rebase all messages"), this);
actionRebase->setStatusTip(tr("Rebase all messages in node"));
connect(actionRebase, SIGNAL(triggered()), this, SLOT(onRebaseMessages()));
QAction *actionDupe = new QAction(QIcon(":/Resource/warning32.ico"), tr("Duplicate node"), this);
actionDupe->setStatusTip(tr("Duplicate node and messages"));
connect(actionDupe, SIGNAL(triggered()), this, SLOT(onDuplicateNode()));
QMenu menu(this);
menu.addAction(actionRebase);
menu.addAction(actionDupe);
QPoint pt(pos);
menu.exec( ui->treeDBC->mapToGlobal(pos) );
break;
}
}
void DBCMainEditor::onRebaseMessages()
{
QTreeWidgetItem* firstCol = ui->treeDBC->currentItem();
bool ret = false;
DBC_MESSAGE *msg;
DBC_SIGNAL *sig;
DBC_NODE *node;
uint32_t msgID;
QString idString;
idString = firstCol->text(0).split(" ")[0];
node = dbcFile->findNodeByName(idString);
nodeRebaseEditor->setFileIdx(fileIdx);
nodeRebaseEditor->setNodeRef(node);
if(nodeRebaseEditor->refreshView())
{
nodeRebaseEditor->setModal(true);
nodeRebaseEditor->show();
}
}
void DBCMainEditor::onDuplicateNode()
{
QTreeWidgetItem* firstCol = ui->treeDBC->currentItem();
bool ret = false;
DBC_MESSAGE *msg;
DBC_SIGNAL *sig;
DBC_NODE *node;
uint32_t msgID;
QString idString;
idString = firstCol->text(0).split(" ")[0];
node = dbcFile->findNodeByName(idString);
nodeDuplicateEditor->setFileIdx(fileIdx);
nodeDuplicateEditor->setNodeRef(node);
if(nodeDuplicateEditor->refreshView())
{
nodeDuplicateEditor->setModal(true);
nodeDuplicateEditor->show();
}
}
/*
* Recreate the whole tree with pretty icons and custom user roles that give the rest of code an easy way to figure out whether a given tree node
@@ -481,11 +568,18 @@ void DBCMainEditor::updatedSignal(DBC_SIGNAL *sig)
else qDebug() << "That signal doesn't exist. That's a bug dude.";
}
void DBCMainEditor::newNode()
void DBCMainEditor::newNode(QString nodeName)
{
DBC_NODE node;
DBC_NODE *nodePtr;
node.name = "Unnamed" + QString::number(randGen.bounded(50000));
if(nodeName.isEmpty())
{
node.name = "Unnamed" + QString::number(randGen.bounded(50000));
}
else
{
node.name = nodeName;
}
dbcFile->dbc_nodes.append(node);
nodePtr = dbcFile->findNodeByName(node.name);
QTreeWidgetItem *nodeItem = new QTreeWidgetItem();
@@ -499,6 +593,77 @@ void DBCMainEditor::newNode()
dbcFile->setDirtyFlag();
}
void DBCMainEditor::newNode()
{
newNode(QString());
}
void DBCMainEditor::copyMessageToNode(DBC_NODE *parentNode, DBC_MESSAGE *source, uint newMsgId)
{
DBC_NODE *node = parentNode;
if (!node) node = dbcFile->findNodeByIdx(0);
QTreeWidgetItem *nodeItem = nullptr;
DBC_MESSAGE msg;
DBC_MESSAGE *msgPtr;
nodeItem = ui->treeDBC->currentItem();
msg.name = source->name;
msg.ID = newMsgId;
msg.len = source->len;
msg.bgColor = source->bgColor;
msg.fgColor = source->fgColor;
msg.comment = source->comment;
msg.sender = node;
DBC_SIGNAL *sigSource;
int sigCount = source->sigHandler->getCount();
for(int i=0; i<sigCount; i++)
{
sigSource = source->sigHandler->findSignalByIdx(i);
DBC_SIGNAL sig;
//Does not properly handle multiplexed signals, for now
sig.name = sigSource->name;
sig.bias = sigSource->bias;
sig.isMultiplexed = false; //sigSource->isMultiplexed;
sig.isMultiplexor = false; //sigSource->isMultiplexor;
sig.max = sigSource->max;
sig.min = sigSource->min;
sig.multiplexLowValue = sigSource->multiplexLowValue;
sig.multiplexHighValue = sigSource->multiplexHighValue;
sig.factor = sigSource->factor;
sig.intelByteOrder = sigSource->intelByteOrder;
sig.parentMessage = &msg;
sig.multiplexParent = nullptr; //need to learn about multiplexed signals and track them when copying
sig.receiver = node;
sig.signalSize = sigSource->signalSize;
sig.startBit = sigSource->startBit;
sig.valType = sigSource->valType;
sig.parentMessage = &msg;
msg.sigHandler->addSignal(sig);
}
msg.sigHandler->sort();
dbcFile->messageHandler->addMessage(msg);
msgPtr = dbcFile->messageHandler->findMsgByIdx(dbcFile->messageHandler->getCount() - 1);
QTreeWidgetItem *newMsgItem = new QTreeWidgetItem();
QString msgInfo = Utility::formatCANID(msg.ID) + " " + msg.name;
if (msg.comment.count() > 0) msgInfo.append(" - ").append(msg.comment);
newMsgItem->setText(0, msgInfo);
newMsgItem->setIcon(0, messageIcon);
newMsgItem->setData(0, Qt::UserRole, 2);
messageToItem.insert(msgPtr, newMsgItem);
itemToMessage.insert(newMsgItem, msgPtr);
nodeItem->addChild(newMsgItem);
//ui->treeDBC->setCurrentItem(newMsgItem);
dbcFile->setDirtyFlag();
}
//create a new message with it's parent being the node we're currently within
void DBCMainEditor::newMessage()
+10 -1
View File
@@ -10,6 +10,8 @@
#include "dbcsignaleditor.h"
#include "dbcmessageeditor.h"
#include "dbcnodeeditor.h"
#include "dbcnoderebaseeditor.h"
#include "dbcnodeduplicateeditor.h"
#include "utility.h"
namespace Ui {
@@ -32,6 +34,7 @@ public slots:
private slots:
void onTreeDoubleClicked(const QModelIndex &index);
void onTreeContextMenu(const QPoint & pos);
void currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *prev);
void onCustomMenuTree(QPoint);
void deleteCurrentTreeItem();
@@ -41,9 +44,13 @@ private slots:
void handleSearch();
void handleSearchForward();
void handleSearchBackward();
void newNode(QString nodeName);
void newNode();
void copyMessageToNode(DBC_NODE *node, DBC_MESSAGE *source, uint newMsgId);
void newMessage();
void newSignal();
void newSignal();
void onRebaseMessages();
void onDuplicateNode();
private:
Ui::DBCMainEditor *ui;
@@ -52,6 +59,8 @@ private:
DBCSignalEditor *sigEditor;
DBCMessageEditor *msgEditor;
DBCNodeEditor *nodeEditor;
DBCNodeRebaseEditor *nodeRebaseEditor;
DBCNodeDuplicateEditor *nodeDuplicateEditor;
DBCFile *dbcFile;
int fileIdx;
QIcon nodeIcon;
+204
View File
@@ -0,0 +1,204 @@
#include "dbcnodeduplicateeditor.h"
#include "ui_dbcnodeduplicateeditor.h"
#include <QSettings>
#include <QKeyEvent>
#include <QColorDialog>
#include <QMessageBox>
#include "helpwindow.h"
#include "utility.h"
DBCNodeDuplicateEditor::DBCNodeDuplicateEditor(QWidget *parent) :
QDialog(parent),
ui(new Ui::DBCNodeDuplicateEditor)
{
ui->setupUi(this);
readSettings();
dbcHandler = DBCHandler::getReference();
dbcNode = nullptr;
connect(ui->btnDuplicate, &QPushButton::pressed,
[=]()
{
if (dbcNode == nullptr) return;
if (lowestMsgId > 0x1FFFFFFFul) return;
uint newBase = Utility::ParseStringToNum(ui->lineNewBaseId->text());
if(newBase <= 0 || newBase > 0x1FFFFFFFul)
{
QMessageBox::question(this, "Invalid Address", "The new address is outside of the valid range.",
QMessageBox::Ok);
return;
}
if(newBase == lowestMsgId)
{
QMessageBox::question(this, "Invalid Address", "The new address is the same as the original.",
QMessageBox::Ok);
return;
}
uint rebaseDiff = newBase - lowestMsgId;
QList<DBC_MESSAGE*> messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode);
if(messagesForNode.count() == 0)
{
QMessageBox::question(this, "No Messages", "The node has no messages to duplicate.",
QMessageBox::Ok);
return;
}
if(ui->lineNodeName->text().isEmpty())
{
QMessageBox::question(this, "No Name", "The new node needs a name before it can be created.",
QMessageBox::Ok);
return;
}
QString newNodeName = ui->lineNodeName->text();
emit createNode(newNodeName);
DBC_NODE *nodePtr = dbcFile->findNodeByName(newNodeName);
if(nodePtr == nullptr)
{
QMessageBox::question(this, "Node Invalid", "There was an problem identifying the selected node.",
QMessageBox::Ok);
return;
}
for (int i=0; i<messagesForNode.count(); i++)
{
uint newMsgId = messagesForNode[i]->ID + rebaseDiff;
if(newMsgId < 0 || newMsgId > 0x1FFFFFFFul)
{
QMessageBox::question(this, "Invalid Address Range", "The new starting address would cause a message to be outside of the valid address range.",
QMessageBox::Ok);
return;
}
}
for (int i=0; i<messagesForNode.count(); i++)
{
uint newMsgId = messagesForNode[i]->ID + rebaseDiff;
emit cloneMessageToNode(nodePtr, messagesForNode[i], newMsgId);
}
dbcFile->setDirtyFlag();
emit nodeAdded();
this->close();
});
connect(ui->btnCancel, &QPushButton::pressed,
[=]()
{
this->close();
});
installEventFilter(this);
}
DBCNodeDuplicateEditor::~DBCNodeDuplicateEditor()
{
removeEventFilter(this);
delete ui;
}
void DBCNodeDuplicateEditor::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
writeSettings();
}
bool DBCNodeDuplicateEditor::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyRelease) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch (keyEvent->key())
{
case Qt::Key_F1:
HelpWindow::getRef()->showHelp("nodeeditor.md");
break;
}
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
return false;
}
void DBCNodeDuplicateEditor::setFileIdx(int idx)
{
if (idx < 0 || idx > dbcHandler->getFileCount() - 1) return;
dbcFile = dbcHandler->getFileByIdx(idx);
}
void DBCNodeDuplicateEditor::readSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("DBCNodeDuplicateEditor/WindowSize", QSize(312, 128)).toSize());
move(Utility::constrainedWindowPos(settings.value("DBCNodeDuplicateEditor/WindowPos", QPoint(100, 100)).toPoint()));
}
}
void DBCNodeDuplicateEditor::writeSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
settings.setValue("DBCNodeDuplicateEditor/WindowSize", size());
settings.setValue("DBCNodeDuplicateEditor/WindowPos", pos());
}
}
void DBCNodeDuplicateEditor::setNodeRef(DBC_NODE *node)
{
dbcNode = node;
}
void DBCNodeDuplicateEditor::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
refreshView();
}
bool DBCNodeDuplicateEditor::refreshView()
{
ui->lineNewBaseId->setText("");
if(dbcNode)
{
QList<DBC_MESSAGE*> messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode);
lowestMsgId = 0xFFFFFFFF;
if(messagesForNode.count() == 0)
{
return false;
}
for (int i=0; i<messagesForNode.count(); i++)
{
if(messagesForNode[i]->ID < lowestMsgId)
lowestMsgId = messagesForNode[i]->ID;
}
ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul));
ui->lineNodeName->setText(dbcNode->name + QString("_Copy"));
return true;
}
return false;
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef DBCNODEDUPLICATEEDITOR_H
#define DBCNODEDUPLICATEEDITOR_H
#include <QDialog>
#include "dbc_classes.h"
#include "dbchandler.h"
namespace Ui {
class DBCNodeDuplicateEditor;
}
class DBCNodeDuplicateEditor : public QDialog
{
Q_OBJECT
public:
explicit DBCNodeDuplicateEditor(QWidget *parent = nullptr);
~DBCNodeDuplicateEditor();
void showEvent(QShowEvent*);
void setNodeRef(DBC_NODE *node);
void setFileIdx(int idx);
bool refreshView();
signals:
void updatedTreeInfo(DBC_MESSAGE *msg);
void createNode(QString nodeName);
void cloneMessageToNode(DBC_NODE *parentNode, DBC_MESSAGE *source, uint newMsgId);
void nodeAdded();
private:
Ui::DBCNodeDuplicateEditor *ui;
DBCHandler *dbcHandler;
DBC_NODE *dbcNode;
DBCFile *dbcFile;
void closeEvent(QCloseEvent *event);
bool eventFilter(QObject *obj, QEvent *event);
void readSettings();
void writeSettings();
uint lowestMsgId;
};
#endif // DBCNODEDUPLICATEEDITOR_H
+195
View File
@@ -0,0 +1,195 @@
#include "dbcnoderebaseeditor.h"
#include "ui_dbcnoderebaseeditor.h"
#include <QSettings>
#include <QKeyEvent>
#include <QColorDialog>
#include <QMessageBox>
#include "helpwindow.h"
#include "utility.h"
DBCNodeRebaseEditor::DBCNodeRebaseEditor(QWidget *parent) :
QDialog(parent),
ui(new Ui::DBCNodeRebaseEditor)
{
ui->setupUi(this);
readSettings();
dbcHandler = DBCHandler::getReference();
dbcNode = nullptr;
connect(ui->btnDoRebase, &QPushButton::pressed,
[=]()
{
if (dbcNode == nullptr)
{
QMessageBox::question(this, "Node Invalid", "There was an problem identifying the selected node.",
QMessageBox::Ok);
return;
}
if (lowestMsgId > 0x1FFFFFFFul)
{
QMessageBox::question(this, "No Valid Messages", "The node has no valid messages to change.",
QMessageBox::Ok);
return;
}
uint newBase = Utility::ParseStringToNum(ui->lineNewBaseId->text());
if(newBase <= 0 || newBase > 0x1FFFFFFFul)
{
QMessageBox::question(this, "Invalid Address", "The new address is outside of the valid range.",
QMessageBox::Ok);
return;
}
if(newBase == lowestMsgId)
{
QMessageBox::question(this, "Invalid Address", "The new address is the same as the original.",
QMessageBox::Ok);
return;
}
uint rebaseDiff = newBase - lowestMsgId;
QList<DBC_MESSAGE*> messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode);
if(messagesForNode.count() == 0)
{
QMessageBox::question(this, "No Messages", "The node has no messages to change.",
QMessageBox::Ok);
return;
}
for (int i=0; i<messagesForNode.count(); i++)
{
uint newMsgId = messagesForNode[i]->ID + rebaseDiff;
if(newMsgId < 0 || newMsgId > 0x1FFFFFFFul)
{
QMessageBox::question(this, "Invalid Address Range", "The new starting address would cause a message to be outside of the valid address range.",
QMessageBox::Ok);
return;
}
}
for (int i=0; i<messagesForNode.count(); i++)
{
messagesForNode[i]->ID += rebaseDiff;
emit updatedTreeInfo(messagesForNode[i]);
}
dbcFile->setDirtyFlag();
this->close();
});
connect(ui->btnCancel, &QPushButton::pressed,
[=]()
{
this->close();
});
installEventFilter(this);
}
DBCNodeRebaseEditor::~DBCNodeRebaseEditor()
{
removeEventFilter(this);
delete ui;
}
void DBCNodeRebaseEditor::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
writeSettings();
}
bool DBCNodeRebaseEditor::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyRelease) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch (keyEvent->key())
{
case Qt::Key_F1:
HelpWindow::getRef()->showHelp("nodeeditor.md");
break;
}
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
return false;
}
void DBCNodeRebaseEditor::setFileIdx(int idx)
{
if (idx < 0 || idx > dbcHandler->getFileCount() - 1) return;
dbcFile = dbcHandler->getFileByIdx(idx);
}
void DBCNodeRebaseEditor::readSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("DBCNodeRebaseEditor/WindowSize", QSize(312, 128)).toSize());
move(Utility::constrainedWindowPos(settings.value("DBCNodeRebaseEditor/WindowPos", QPoint(100, 100)).toPoint()));
}
}
void DBCNodeRebaseEditor::writeSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
settings.setValue("DBCNodeRebaseEditor/WindowSize", size());
settings.setValue("DBCNodeRebaseEditor/WindowPos", pos());
}
}
void DBCNodeRebaseEditor::setNodeRef(DBC_NODE *node)
{
dbcNode = node;
}
void DBCNodeRebaseEditor::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
refreshView();
}
bool DBCNodeRebaseEditor::refreshView()
{
ui->lineNewBaseId->setText("");
if(dbcNode)
{
QList<DBC_MESSAGE*> messagesForNode = dbcFile->messageHandler->findMsgsByNode(dbcNode);
lowestMsgId = 0xFFFFFFFF;
if(messagesForNode.count() == 0)
{
return false;
}
for (int i=0; i<messagesForNode.count(); i++)
{
if(messagesForNode[i]->ID < lowestMsgId)
lowestMsgId = messagesForNode[i]->ID;
}
ui->lineOriginalBaseId->setText(Utility::formatCANID(lowestMsgId & 0x1FFFFFFFul));
ui->lineNodeName->setText(dbcNode->name);
return true;
}
return false;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef DBCNODEREBASEEDITOR_H
#define DBCNODEREBASEEDITOR_H
#include <QDialog>
#include "dbc_classes.h"
#include "dbchandler.h"
namespace Ui {
class DBCNodeRebaseEditor;
}
class DBCNodeRebaseEditor : public QDialog
{
Q_OBJECT
public:
explicit DBCNodeRebaseEditor(QWidget *parent = nullptr);
~DBCNodeRebaseEditor();
void showEvent(QShowEvent*);
void setNodeRef(DBC_NODE *node);
void setFileIdx(int idx);
bool refreshView();
signals:
void updatedTreeInfo(DBC_MESSAGE *msg);
private:
Ui::DBCNodeRebaseEditor *ui;
DBCHandler *dbcHandler;
DBC_NODE *dbcNode;
DBCFile *dbcFile;
void closeEvent(QCloseEvent *event);
bool eventFilter(QObject *obj, QEvent *event);
void readSettings();
void writeSettings();
uint lowestMsgId;
};
#endif // DBCNODEREBASEEDITOR_H
+1 -1
View File
@@ -84,7 +84,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
break;
case 4:
currentSignal->valType = STRING;
break;
break;
}
dbcFile->setDirtyFlag();
fillSignalForm(currentSignal);
+103 -83
View File
@@ -1599,10 +1599,13 @@ bool FrameFileIO::isCanalyzerASC(QString filename)
//47.971842 2 248 Rx d 8 FF FF FF FF FF FF FF FF
//version 8.1
//47244640.194244 CANFD 1 Rx 122 0 0 6 6 00 00 18 12 D2 00 0 0 200000 0 0 0 0 0
//Version 9.0
//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
//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)
//Time type bus dir ID ? ? length length bytes then 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 bus id dir ? len databytes additional crap (ver 16.0)
//So it seems the file format is not entirely different based on version but rather on some other
//settings... Fun!
@@ -1660,104 +1663,74 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
{
tokens = line.simplified().split(' ');
if (tokens[0].contains("Begin")) continue; //probably begin triggerblock but we're ignoring that.
//try to do some investigating to see if this line is a CAN frame or not. The file format has many other potential line types it seems...
if (tokens.length() > 5)
{
if (tokens[5].at(0) >= '0' && tokens[5].at(0) <= '9')
if (tokens[3].toUpper().startsWith("RX") || tokens[3].toUpper().startsWith("TX"))
{
if (tokens[3].toUpper().startsWith("RX") || tokens[3].toUpper().startsWith("TX"))
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<uint64_t>(tokens[0].toDouble() * 1000000.0)));
if (tokens[1].contains("CAN")) //the different format I haven't seen a whole lot of, seems to support CANFD in this format
{
int payloadLen = tokens[5].toInt();
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<uint64_t>(tokens[0].toDouble() * 1000000.0)));
//Time bus id dir ? len databytes (Ver 8.0)
//Time type bus dir ID ? ? length length bytes then many values of unknown type (ver 8.1)
if (tokens[1].contains("CAN")) //the different format I haven't seen a whole lot of, seems to support CANFD in this format
if (tokens[4].endsWith('x'))
{
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<uint64_t>(tokens[0].toDouble() * 1000000.0)));
if (tokens[4].endsWith('x'))
{
QByteArray copied_id = tokens[4];
copied_id.chop(1);
thisFrame.setFrameId(copied_id.toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(true);
}
else
{
thisFrame.setFrameId(tokens[4].toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x'
}
int payloadLen = tokens[8].toInt();
QByteArray bytes(payloadLen, 0);
if (payloadLen > 8)
{
qDebug() << "Payload length too long. Original line: " << line;
return false;
}
if (payloadLen < 0)
{
qDebug() << "Payload length negative! Original line: " << line;
return false;
}
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[2].toInt();
if (tokens[5] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
for (int d = 9; d < (9 + payloadLen); d++)
{
if (tokens.count() > d)
{
bytes[d - 9] = static_cast<char>(tokens[d].toInt(nullptr, 16));
}
else //expected byte wasn't there to read. Set it zero and set error flag
{
bytes[d - 9] = 0;
foundErrors = true;
qDebug() << "D:" << d << " Count:" << tokens.count();
qDebug() << "Expected byte missing! Original line: " << line;
}
}
thisFrame.setPayload(bytes);
QByteArray copied_id = tokens[4];
copied_id.chop(1);
thisFrame.setFrameId(copied_id.toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(true);
}
else
{
if (tokens[2].endsWith('x'))
{
QByteArray copied_id = tokens[2];
copied_id.chop(1);
thisFrame.setFrameId(copied_id.toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(true);
}
else
{
thisFrame.setFrameId(tokens[2].toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x'
}
QByteArray bytes(payloadLen, 0);
thisFrame.setFrameId(tokens[4].toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x'
}
if (payloadLen > 8)
{
qDebug() << "Payload length too long. Original line: " << line;
return false;
}
if (payloadLen < 0)
{
qDebug() << "Payload length negative! Original line: " << line;
return false;
}
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[1].toInt();
if (tokens[4] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
for (int d = 6; d < (6 + payloadLen); d++)
int payloadLen = tokens[8].toInt();
qDebug() << "PayloadLen: " << payloadLen << " Tokens: " << tokens;
QByteArray bytes(payloadLen, 0);
if (payloadLen > 8)
{
qDebug() << "Payload length too long. Original line: " << line;
return false;
}
if (payloadLen < 0)
{
qDebug() << "Payload length negative! Original line: " << line;
return false;
}
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[2].toInt();
if (tokens[5].at(0) >= '0' && tokens[5].at(0) <= '9')
{
for (int d = 9; d < (9 + payloadLen); d++)
{
if (tokens.count() > d)
{
bytes[d - 6] = static_cast<char>(tokens[d].toInt(nullptr, 16));
bytes[d - 9] = static_cast<char>(tokens[d].toInt(nullptr, 16));
}
else //expected byte wasn't there to read. Set it zero and set error flag
{
bytes[d - 6] = 0;
bytes[d - 9] = 0;
foundErrors = true;
qDebug() << "D:" << d << " Count:" << tokens.count();
qDebug() << "Expected byte missing! Original line: " << line;
}
}
thisFrame.setPayload(bytes);
}
else
{
for (int d = 10; d < (10 + payloadLen); d++)
{
if (tokens.count() > d)
{
bytes[d - 10] = static_cast<char>(tokens[d].toInt(nullptr, 16));
}
else //expected byte wasn't there to read. Set it zero and set error flag
{
bytes[d - 10] = 0;
foundErrors = true;
qDebug() << "D:" << d << " Count:" << tokens.count();
qDebug() << "Expected byte missing! Original line: " << line;
@@ -1765,8 +1738,55 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
}
thisFrame.setPayload(bytes);
}
frames->append(thisFrame);
}
else
{
int payloadLen = tokens[5].toInt();
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<uint64_t>(tokens[0].toDouble() * 1000000.0)));
if (tokens[2].endsWith('x'))
{
QByteArray copied_id = tokens[2];
copied_id.chop(1);
thisFrame.setFrameId(copied_id.toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(true);
}
else
{
thisFrame.setFrameId(tokens[2].toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x'
}
QByteArray bytes(payloadLen, 0);
if (payloadLen > 8)
{
qDebug() << "Payload length too long. Original line: " << line;
return false;
}
if (payloadLen < 0)
{
qDebug() << "Payload length negative! Original line: " << line;
return false;
}
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[1].toInt();
if (tokens[4] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
for (int d = 6; d < (6 + payloadLen); d++)
{
if (tokens.count() > d)
{
bytes[d - 6] = static_cast<char>(tokens[d].toInt(nullptr, 16));
}
else //expected byte wasn't there to read. Set it zero and set error flag
{
bytes[d - 6] = 0;
foundErrors = true;
qDebug() << "D:" << d << " Count:" << tokens.count();
qDebug() << "Expected byte missing! Original line: " << line;
}
}
thisFrame.setPayload(bytes);
}
frames->append(thisFrame);
}
}
}
+541 -150
View File
@@ -6,6 +6,23 @@
#include "utility.h"
#include "helpwindow.h"
static QVector<QString> SCANTYPE_NAMES = {
QString("Tester Present"),
QString("Session Control"),
QString("Communication Control"),
QString("ECU Reset"),
QString("Clear DTCs"),
QString("Read DTCs"),
QString("Security Access"),
QString("Read By ID"),
QString("Read By Address"),
QString("Read Scaling Data By ID"),
QString("IO Control"),
QString("Routine Control"),
QString("Custom UDS"),
};
UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
ui(new Ui::UDSScanWindow)
@@ -21,15 +38,23 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
waitTimer->setInterval(100);
udsHandler = new UDS_HANDLER;
inhibitUpdates = false;
for (int i = 0; i < 13; i++) ui->cbScanType->addItem(SCANTYPE_NAMES[i]);
ui->cbSessType->addItem("No Change");
ui->cbSessType->addItem("Default");
ui->cbSessType->addItem("Programming");
ui->cbSessType->addItem("Extended Diag");
ui->cbSessType->addItem("Safety Sys Diag");
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
connect(udsHandler, &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply);
connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS);
connect(ui->btnScanAll, &QPushButton::clicked, this, &UDSScanWindow::scanAll);
connect(ui->btnScanSelected, &QPushButton::clicked, this, &UDSScanWindow::scanSelected);
connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut);
connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults);
connect(ui->ckWildcard, &QCheckBox::toggled, this, &UDSScanWindow::wildcardToggled);
connect(ui->ckReadByAddr, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled);
connect(ui->ckReadByID, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled);
connect(ui->cbScanType, &QComboBox::currentTextChanged, this, &UDSScanWindow::changedScanType);
connect(ui->cbAllowAdaptiveOffset, &QCheckBox::toggled, this, &UDSScanWindow::adaptiveToggled);
connect(ui->spinNumBytes, SIGNAL(valueChanged(int)), this, SLOT(numBytesChanged()));
connect(ui->spinLowerService, SIGNAL(valueChanged(int)), this, SLOT(checkServiceRange()));
@@ -38,10 +63,23 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
connect(ui->spinUpperSubfunc, SIGNAL(valueChanged(int)), this, SLOT(checkSubFuncRange()));
connect(ui->spinStartID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange()));
connect(ui->spinEndID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange()));
connect(ui->btnAdd, &QPushButton::clicked, this, &UDSScanWindow::addNewScan);
connect(ui->btnDelete, &QPushButton::clicked, this, &UDSScanWindow::deleteSelectedScan);
connect(ui->btnSave, &QPushButton::clicked, this, &UDSScanWindow::saveScans);
connect(ui->btnLoad, &QPushButton::clicked, this, &UDSScanWindow::loadScans);
connect(ui->listScansToRun, &QListWidget::currentRowChanged, this, &UDSScanWindow::displayScanEntry);
connect(ui->ckShowNoReply, &QCheckBox::toggled, this, &UDSScanWindow::setNoReplyVal);
connect(ui->spinDelay, SIGNAL(valueChanged(int)), this, SLOT(setMaxDelayVal()));
connect(ui->spinIncrement, SIGNAL(valueChanged(int)), this, SLOT(setIncrementVal()));
connect(ui->spinReplyOffset, SIGNAL(valueChanged(int)), this, SLOT(setReplyOffset()));
connect(ui->cbSessType, &QComboBox::currentTextChanged, this, &UDSScanWindow::setSessType);
//not handling show no reply, max reply delay, reply offset, increment
int numBuses = CANConManager::getInstance()->getNumBuses();
for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n));
installEventFilter(this);
addNewScan();
}
UDSScanWindow::~UDSScanWindow()
@@ -71,74 +109,368 @@ bool UDSScanWindow::eventFilter(QObject *obj, QEvent *event)
return false;
}
void UDSScanWindow::displayScanEntry(int idx)
{
if (inhibitUpdates) return;
if (idx == -1) return;
currEditEntry = &scanEntries.data()[idx];
ui->spinStartID->setValue(currEditEntry->startID);
ui->spinEndID->setValue(currEditEntry->endID);
ui->spinReplyOffset->setValue(currEditEntry->idOffset);
ui->cbAllowAdaptiveOffset->setChecked(currEditEntry->bAdaptiveOffset);
ui->ckShowNoReply->setChecked(currEditEntry->bShowNoReplies);
ui->cbBuses->setCurrentIndex(currEditEntry->busToScan);
ui->spinDelay->setValue(currEditEntry->maxWaitTime);
ui->cbScanType->setCurrentIndex((int)currEditEntry->scanType);
ui->cbSessType->setCurrentIndex(currEditEntry->sessType);
ui->spinNumBytes->setValue(currEditEntry->subfunctLen);
ui->spinLowerService->setValue(currEditEntry->serviceLower);
ui->spinUpperService->setValue(currEditEntry->serviceUpper);
ui->spinLowerSubfunc->setValue(currEditEntry->subfunctLower);
ui->spinUpperSubfunc->setValue(currEditEntry->subfunctUpper);
ui->spinIncrement->setValue(currEditEntry->subfunctIncrement);
}
void UDSScanWindow::deleteSelectedScan()
{
int idx = ui->listScansToRun->currentRow();
if (idx == -1) return;
scanEntries.removeAt(idx);
QListWidgetItem *item = ui->listScansToRun->takeItem(idx);
delete item;
int rows = ui->listScansToRun->count();
ui->listScansToRun->setCurrentRow(rows - 1);
for (int i = 0; i < rows; i++)
{
QListWidgetItem *item = ui->listScansToRun->item(i);
item->setText(generateListDesc(i));
}
}
void UDSScanWindow::addNewScan()
{
ScanEntry newEntry;
newEntry.busToScan = 0;
newEntry.scanType = SCAN_TYPE::ST_TESTER_PRESENT;
newEntry.sessType = 0;
newEntry.bAdaptiveOffset = false;
newEntry.bShowNoReplies = false;
newEntry.idOffset = 8;
newEntry.startID = 0x7E0;
newEntry.endID = 0x7E7;
newEntry.maxWaitTime = 100;
newEntry.subfunctLen = 1;
newEntry.subfunctIncrement = 1;
newEntry.subfunctLower = 0;
newEntry.subfunctUpper = 0;
newEntry.serviceLower = 1;
newEntry.serviceUpper = 1;
scanEntries.append(newEntry);
displayScanEntry(scanEntries.length() - 1);
ui->listScansToRun->addItem(generateListDesc(scanEntries.length() - 1));
ui->listScansToRun->setCurrentRow(ui->listScansToRun->count() - 1);
}
void UDSScanWindow::loadScans()
{
QString filename;
QFileDialog dialog(qApp->activeWindow());
QSettings settings;
bool result = false;
QStringList filters;
filters.append(QString(tr("UDS Test Specification (*.uds *.UDS)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptOpen);
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
QFile inFile(filename);
inFile.open(QIODevice::ReadOnly);
QDataStream load(&inFile);
int fileVersion;
load >> fileVersion;
if (fileVersion != 1)
{
QMessageBox::warning(this, "Cannot Load File", "File is not a supported version.\nCannot load it!");
return;
}
inhibitUpdates = true;;
scanEntries.clear();
ui->listScansToRun->clear();
int numEntries;
load >> numEntries;
for (int i = 0; i < numEntries; i++)
{
ScanEntry entry;
load >> entry.startID >> entry.endID;
load >> entry.idOffset >> entry.bAdaptiveOffset >> entry.bShowNoReplies;
load >> entry.busToScan >> entry.maxWaitTime >> entry.scanType;
load >> entry.sessType >> entry.subfunctLen >> entry.subfunctLower;
load >> entry.subfunctUpper >> entry.subfunctIncrement;
load >> entry.serviceLower >> entry.serviceUpper;
scanEntries.append(entry);
ui->listScansToRun->addItem(generateListDesc(scanEntries.length() - 1));
}
inFile.close();
inhibitUpdates = false;
ui->listScansToRun->setCurrentRow(ui->listScansToRun->count() - 1);
displayScanEntry(scanEntries.length() - 1);
}
}
void UDSScanWindow::saveScans()
{
QString filename;
QFileDialog dialog(qApp->activeWindow());
QSettings settings;
bool result = false;
QStringList filters;
filters.append(QString(tr("UDS Test Specification (*.uds *.UDS)")));
dialog.setDirectory(settings.value("FileIO/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];
QFile outFile(filename);
outFile.open(QIODevice::WriteOnly);
QDataStream save(&outFile);
save << 1; //file version
save << scanEntries.count();
for (int i = 0; i < scanEntries.count(); i++)
{
save << scanEntries[i].startID;
save << scanEntries[i].endID;
save << scanEntries[i].idOffset;
save << scanEntries[i].bAdaptiveOffset;
save << scanEntries[i].bShowNoReplies;
save << scanEntries[i].busToScan;
save << scanEntries[i].maxWaitTime;
save << scanEntries[i].scanType;
save << scanEntries[i].sessType;
save << scanEntries[i].subfunctLen;
save << scanEntries[i].subfunctLower;
save << scanEntries[i].subfunctUpper;
save << scanEntries[i].subfunctIncrement;
save << scanEntries[i].serviceLower;
save << scanEntries[i].serviceUpper;
}
outFile.close();
}
}
QString UDSScanWindow::generateListDesc(int idx)
{
QString builder;
ScanEntry entry = scanEntries[idx];
builder = "(0x" + QString::number(entry.startID, 16) + " - 0x" + QString::number(entry.endID, 16) + ") ";
switch (entry.scanType)
{
case ST_TESTER_PRESENT:
builder += "TP";
break;
case ST_SESS_CTRL:
builder += "SESS";
break;
case ST_COMM_CTRL:
builder += "COMM";
break;
case ST_ECU_RESET:
builder += "ECU";
break;
case ST_CLEAR_DTC:
builder += "CDTC";
break;
case ST_READ_DTC:
builder += "RDTC";
break;
case ST_SEC_ACCESS:
builder += "SECU";
break;
case ST_READ_ID:
builder += "RID";
break;
case ST_READ_ADDR:
builder += "RADD";
break;
case ST_READ_SCALING:
builder += "RSCAL";
break;
case ST_IO_CTRL:
builder += "IO";
break;
case ST_ROUTINE_CTRL:
builder += "ROUT";
break;
case ST_CUSTOM:
builder += "CUST";
break;
}
return builder;
}
void UDSScanWindow::adaptiveToggled()
{
if (inhibitUpdates) return;
if (ui->cbAllowAdaptiveOffset->isChecked()) ui->spinReplyOffset->setEnabled(false);
else ui->spinReplyOffset->setEnabled(true);
if (currEditEntry) currEditEntry->bAdaptiveOffset = ui->cbAllowAdaptiveOffset->isChecked();
}
void UDSScanWindow::wildcardToggled()
void UDSScanWindow::setSessType()
{
bool state = false;
if (ui->ckWildcard->isChecked()) state = false;
else state = true;
ui->ckReset->setEnabled(state);
ui->ckSecurity->setEnabled(state);
ui->ckSession->setEnabled(state);
ui->ckTester->setEnabled(state);
ui->ckReadByAddr->setEnabled(state);
ui->ckReadByID->setEnabled(state);
ui->ckReset->setChecked(false);
ui->ckSecurity->setChecked(false);
ui->ckSession->setChecked(false);
ui->ckTester->setChecked(false);
ui->ckReadByAddr->setChecked(false);
ui->ckReadByID->setChecked(false);
ui->spinLowerService->setEnabled(!state);
ui->spinLowerSubfunc->setEnabled(!state);
ui->spinNumBytes->setEnabled(!state);
ui->spinUpperService->setEnabled(!state);
ui->spinUpperSubfunc->setEnabled(!state);
if (inhibitUpdates) return;
if (currEditEntry) currEditEntry->sessType = ui->cbSessType->currentIndex();
}
void UDSScanWindow::readByToggled()
void UDSScanWindow::setNoReplyVal()
{
bool state = false;
if (ui->ckReadByAddr->isChecked() || ui->ckReadByID->isChecked()) state = true;
else state = false;
if (inhibitUpdates) return;
if (currEditEntry) currEditEntry->bShowNoReplies = ui->ckShowNoReply->isChecked();
}
ui->spinLowerService->setEnabled(false);
ui->spinLowerSubfunc->setEnabled(state);
ui->spinNumBytes->setEnabled(state);
ui->spinUpperService->setEnabled(false);
ui->spinUpperSubfunc->setEnabled(state);
void UDSScanWindow::setMaxDelayVal()
{
if (inhibitUpdates) return;
if (currEditEntry) currEditEntry->maxWaitTime = ui->spinDelay->value();
}
void UDSScanWindow::setIncrementVal()
{
if (inhibitUpdates) return;
if (currEditEntry) currEditEntry->subfunctIncrement = ui->spinIncrement->value();
}
void UDSScanWindow::setReplyOffset()
{
if (inhibitUpdates) return;
if (currEditEntry) currEditEntry->idOffset = ui->spinReplyOffset->value();
}
void UDSScanWindow::changedScanType()
{
if (inhibitUpdates) return;
int idx = ui->cbScanType->currentIndex();
if (idx == -1)
{
ui->cbScanType->setCurrentIndex(0);
idx = 0;
}
if (currEditEntry) currEditEntry->scanType = (SCAN_TYPE)idx;
QListWidgetItem* item = ui->listScansToRun->currentItem();
item->setText(generateListDesc(ui->listScansToRun->currentRow()));
switch (idx)
{
case ST_TESTER_PRESENT:
case ST_SESS_CTRL:
ui->cbSessType->setEnabled(false);
ui->spinLowerService->setEnabled(false);
ui->spinLowerSubfunc->setEnabled(false);
ui->spinUpperService->setEnabled(false);
ui->spinUpperSubfunc->setEnabled(false);
ui->spinNumBytes->setEnabled(false);
ui->spinIncrement->setEnabled(false);
ui->cbSessType->setCurrentIndex(0);
break;
case ST_COMM_CTRL:
case ST_ECU_RESET:
case ST_CLEAR_DTC:
case ST_SEC_ACCESS:
case ST_READ_DTC:
ui->cbSessType->setEnabled(true);
ui->spinLowerService->setEnabled(false);
ui->spinUpperService->setEnabled(false);
ui->spinLowerSubfunc->setEnabled(false);
ui->spinUpperSubfunc->setEnabled(false);
ui->spinNumBytes->setEnabled(false);
ui->spinIncrement->setEnabled(false);
break;
case ST_IO_CTRL:
case ST_ROUTINE_CTRL:
case ST_READ_SCALING:
ui->cbSessType->setEnabled(true);
ui->spinLowerService->setEnabled(false);
ui->spinUpperService->setEnabled(false);
ui->spinLowerSubfunc->setEnabled(true);
ui->spinUpperSubfunc->setEnabled(true);
ui->spinNumBytes->setEnabled(false);
ui->spinNumBytes->setValue(2);
ui->spinIncrement->setEnabled(true);
break;
case ST_READ_ID:
case ST_READ_ADDR:
ui->cbSessType->setEnabled(true);
ui->spinLowerService->setEnabled(false);
ui->spinUpperService->setEnabled(false);
ui->spinLowerSubfunc->setEnabled(true);
ui->spinUpperSubfunc->setEnabled(true);
ui->spinNumBytes->setEnabled(true);
ui->spinIncrement->setEnabled(true);
break;
case ST_CUSTOM:
ui->cbSessType->setEnabled(true);
ui->spinLowerService->setEnabled(true);
ui->spinUpperService->setEnabled(true);
ui->spinLowerSubfunc->setEnabled(true);
ui->spinUpperSubfunc->setEnabled(true);
ui->spinNumBytes->setEnabled(true);
ui->spinIncrement->setEnabled(true);
break;
}
}
void UDSScanWindow::numBytesChanged()
{
if (inhibitUpdates) return;
uint64_t upperBound = (1ull << (8ull * ui->spinNumBytes->value())) - 1;
if (upperBound > 0x7FFFFFFF) upperBound = 0x7FFFFFFF;
ui->spinUpperSubfunc->setMaximum(upperBound);
if (currEditEntry) currEditEntry->subfunctLen = ui->spinNumBytes->value();
}
void UDSScanWindow::checkIDRange()
{
if (inhibitUpdates) return;
ui->spinStartID->setMaximum(ui->spinEndID->value());
ui->spinEndID->setMinimum(ui->spinStartID->value());
if (currEditEntry) currEditEntry->startID = ui->spinStartID->value();
if (currEditEntry) currEditEntry->endID = ui->spinEndID->value();
QListWidgetItem* item = ui->listScansToRun->currentItem();
item->setText(generateListDesc(ui->listScansToRun->currentRow()));
}
void UDSScanWindow::checkServiceRange()
{
if (inhibitUpdates) return;
ui->spinLowerService->setMaximum(ui->spinUpperService->value());
ui->spinUpperService->setMinimum(ui->spinLowerService->value());
if (currEditEntry) currEditEntry->serviceLower = ui->spinLowerService->value();
if (currEditEntry) currEditEntry->serviceUpper = ui->spinUpperService->value();
}
void UDSScanWindow::checkSubFuncRange()
{
if (inhibitUpdates) return;
ui->spinLowerSubfunc->setMaximum(ui->spinUpperSubfunc->value());
ui->spinUpperSubfunc->setMinimum(ui->spinLowerSubfunc->value());
if (currEditEntry) currEditEntry->subfunctLower = ui->spinLowerSubfunc->value();
if (currEditEntry) currEditEntry->subfunctUpper = ui->spinUpperSubfunc->value();
}
void UDSScanWindow::saveResults()
@@ -196,20 +528,27 @@ void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses)
sendingFrames.append(test);
}
void UDSScanWindow::scanUDS()
void UDSScanWindow::scanAll()
{
if (currentlyRunning)
sendingFrames.clear();
for (int i = 0; i < scanEntries.count(); i++)
{
waitTimer->stop();
sendingFrames.clear();
udsHandler->setReception(false);
udsHandler->setProcessAllIDs(false);
udsHandler->setFlowCtrl(false);
currentlyRunning = false;
ui->btnScan->setText("Start Scan");
return;
setupScan(i);
}
startScan();
}
void UDSScanWindow::scanSelected()
{
sendingFrames.clear();
int idx = ui->listScansToRun->currentRow();
if (idx < 0) return;
setupScan(idx);
startScan();
}
void UDSScanWindow::startScan()
{
udsHandler->setReception(true);
udsHandler->setProcessAllIDs(true);
udsHandler->setFlowCtrl(true);
@@ -217,121 +556,173 @@ void UDSScanWindow::scanUDS()
waitTimer->setInterval(ui->spinDelay->value());
ui->treeResults->clear();
sendingFrames.clear();
nodeService = nullptr;
nodeID = nullptr;
nodeSubFunc = nullptr;
UDS_MESSAGE test;
int typ, id;
int startID, endID;
startID = ui->spinStartID->value();
endID = ui->spinEndID->value();
if (endID < startID) {
int temp = startID;
startID = endID;
endID = temp;
}
int buses = ui->cbBuses->currentIndex();
for (id = startID; id <= endID; id++)
{
test.setFrameId( id );
test.payload().clear();
if (ui->ckTester->isChecked())
{
test.service = UDS_SERVICES::TESTER_PRESENT;
test.subFunc = 0;
sendOnBuses(test, buses);
}
if (ui->ckSession->isChecked())
{
for (typ = 1; typ < 4; typ++) //try each type of session access
{
test.service = UDS_SERVICES::DIAG_CONTROL;
test.subFunc = typ;
sendOnBuses(test, buses);
}
}
if (ui->ckReset->isChecked()) //try to command a reset of the ECU. You're likely to know if it works. ;)
{
for (typ = 1; typ < 4; typ++) //try each type of session access
{
test.service = UDS_SERVICES::ECU_RESET;
test.subFunc = typ;
sendOnBuses(test, buses);
}
}
if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists.
{
for (typ = 1; typ < 0x42; typ = typ + 2) //try each type of session access. In practice only the first 1-3 are likely to work
{
test.service = UDS_SERVICES::SECURITY_ACCESS;
test.subFunc = typ;
sendOnBuses(test, buses);
}
}
if (ui->ckReadByAddr->isChecked())
{
test.subFuncLen = ui->spinNumBytes->value();
test.service = UDS_SERVICES::READ_BY_ADDR;
for (int subf = ui->spinLowerSubfunc->value(); subf <= ui->spinUpperSubfunc->value(); subf++)
{
test.subFunc = subf;
sendOnBuses(test, buses);
}
}
if (ui->ckReadByID->isChecked())
{
test.subFuncLen = ui->spinNumBytes->value();
test.service = UDS_SERVICES::READ_BY_ID;
for (int subf = ui->spinLowerSubfunc->value(); subf <= ui->spinUpperSubfunc->value(); subf++)
{
test.subFunc = subf;
sendOnBuses(test, buses);
}
}
if (ui->ckWildcard->isChecked())
{
//preallocate the whole buffer so we don't have to keep updating the size and moving as we go.
//TODO: this shows a downside to the current method - it might potentially need to create a huge
//number of frames here. Of course, the rest of the system will do the same so I guess it's a bad idea
//any way you go to generate a 1 billion frame test.
int size = (endID - startID) * (ui->spinUpperService->value() - ui->spinLowerService->value());
size *= (ui->spinUpperSubfunc->value() - ui->spinLowerSubfunc->value());
sendingFrames.reserve(size);
test.subFuncLen = ui->spinNumBytes->value();
for (typ = ui->spinLowerService->value(); typ <= ui->spinUpperService->value(); typ++)
{
test.service = typ;
for (int subTyp = ui->spinLowerSubfunc->value(); subTyp <= ui->spinUpperSubfunc->value(); subTyp++)
{
test.subFunc = subTyp;
sendOnBuses(test, buses);
}
}
}
}
waitTimer->start();
currIdx = -1;
currentlyRunning = true;
ui->btnScan->setText("Abort Scan");
//ui->btnScan->setText("Abort Scan");
ui->progressBar->setValue(0);
ui->progressBar->setMaximum(sendingFrames.length());
qDebug() << "Number of operations: " << sendingFrames.length();
sendNextMsg();
}
void UDSScanWindow::stopScan()
{
waitTimer->stop();
sendingFrames.clear();
udsHandler->setReception(false);
udsHandler->setProcessAllIDs(false);
udsHandler->setFlowCtrl(false);
currentlyRunning = false;
//ui->btnScan->setText("Start Scan");
}
void UDSScanWindow::setupScan(int idx)
{
UDS_MESSAGE test;
qDebug() << "Generating scan id: " << idx;
for (uint32_t id = scanEntries[idx].startID; id <= scanEntries[idx].endID; id++)
{
test.setFrameId( id );
if (scanEntries[idx].sessType > 0)
{
test.payload().clear();
test.service = UDS_SERVICES::DIAG_CONTROL;
test.subFuncLen = 1;
test.subFunc = scanEntries[ idx].sessType;
sendOnBuses(test, scanEntries[idx].busToScan);
}
test.payload().clear();
qDebug() << "Generating scan on ID " << QString::number(id, 16) << " of type " << scanEntries[idx].scanType;
switch (scanEntries[idx].scanType)
{
case ST_TESTER_PRESENT:
test.service = UDS_SERVICES::TESTER_PRESENT;
test.subFuncLen = 1;
test.subFunc = 0;
sendOnBuses(test, scanEntries[idx].busToScan);
break;
case ST_SESS_CTRL:
for (int typ = 1; typ < 4; typ++) //try each type of session access
{
test.service = UDS_SERVICES::DIAG_CONTROL;
test.subFuncLen = 1;
test.subFunc = typ;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_COMM_CTRL:
test.service = UDS_SERVICES::COMM_CTRL;
test.subFuncLen = 2; //need two bytes for this one
test.subFunc = 0x100; //00 01 on the bus = enable Rx/Tx
sendOnBuses(test, scanEntries[idx].busToScan);
break;
case ST_ECU_RESET:
for (int typ = 1; typ < 4; typ++) //try each type of session access
{
test.service = UDS_SERVICES::ECU_RESET;
test.subFuncLen = 1;
test.subFunc = typ;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_CLEAR_DTC:
test.service = UDS_SERVICES::CLEAR_DIAG;
test.subFuncLen = 3; //DTC groups are sent as 3 bytes
test.subFunc = 0xFFFFFF; //clear everything!
sendOnBuses(test, scanEntries[idx].busToScan);
break;
case ST_READ_DTC:
test.service = UDS_SERVICES::READ_DTC;
test.subFuncLen = 2;
test.subFunc = 0x8702; //get DTCs by mask (87 is the mask)
sendOnBuses(test, scanEntries[idx].busToScan);
break;
case ST_SEC_ACCESS:
for (int typ = 1; typ < 0x42; typ = typ + 2) //try each type of session access. In practice only the first 1-3 are likely to work
{
test.service = UDS_SERVICES::SECURITY_ACCESS;
test.subFuncLen = 1;
test.subFunc = typ;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_READ_ID:
test.subFuncLen = scanEntries[idx].subfunctLen;
test.service = UDS_SERVICES::READ_BY_ID;
for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement)
{
test.subFunc = subf;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_READ_ADDR:
test.subFuncLen = scanEntries[idx].subfunctLen;
test.service = UDS_SERVICES::READ_BY_ADDR;
for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement)
{
test.subFunc = subf;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_READ_SCALING:
//sub function should always be a length of 2 though. Should conform to this in the GUI
test.subFuncLen = 2;
test.service = UDS_SERVICES::READ_SCALING_ID;
for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement)
{
test.subFunc = subf;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_IO_CTRL:
test.subFuncLen = 3;
test.service = UDS_SERVICES::IO_CTRL;
for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement)
{
test.subFunc = subf; //the upper byte will be 0 which is what we want. 0 = Return control to ECU
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_ROUTINE_CTRL:
test.subFuncLen = 3;
test.service = UDS_SERVICES::ROUTINE_CTRL;
for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement)
{
//request results of routine for all the addresses we're testing. This is the safest thing to do.
//starting or stopping arbitrary routines is super dangerous. Don't do that unless you really know
//what the hell you're doing or something really crazy might happen.
test.subFunc = (subf << 8) + 3;
sendOnBuses(test, scanEntries[idx].busToScan);
}
break;
case ST_CUSTOM:
test.subFuncLen = scanEntries[idx].subfunctLen;
for (uint32_t typ = scanEntries[idx].serviceLower; typ <= scanEntries[idx].serviceUpper; typ++)
{
test.service = typ;
for (int subTyp = scanEntries[idx].subfunctLower; subTyp <= scanEntries[idx].subfunctUpper; subTyp += scanEntries[idx].subfunctIncrement)
{
test.subFunc = subTyp;
sendOnBuses(test, scanEntries[idx].busToScan);
}
}
break;
}
}
}
//Updates here are sent about every 1/4 second. That's fine for most windows but not this one.
void UDSScanWindow::updatedFrames(int numFrames)
{
@@ -491,7 +882,7 @@ void UDSScanWindow::sendNextMsg()
udsHandler->setReception(false);
udsHandler->setProcessAllIDs(false);
udsHandler->setFlowCtrl(false);
ui->btnScan->setText("Start Scan");
//ui->btnScan->setText("Start Scan");
currentlyRunning = false;
}
ui->progressBar->setValue(currIdx);
+58 -3
View File
@@ -9,6 +9,44 @@
#include <QFile>
#include <QTreeWidget>
enum SCAN_TYPE
{
ST_TESTER_PRESENT,
ST_SESS_CTRL,
ST_COMM_CTRL,
ST_ECU_RESET,
ST_CLEAR_DTC,
ST_READ_DTC,
ST_SEC_ACCESS,
ST_READ_ID,
ST_READ_ADDR,
ST_READ_SCALING,
ST_IO_CTRL,
ST_ROUTINE_CTRL,
ST_CUSTOM,
};
//stores the parameters for one scan
class ScanEntry
{
public:
uint32_t startID, endID;
int32_t idOffset;
bool bAdaptiveOffset;
bool bShowNoReplies;
uint32_t busToScan;
uint32_t maxWaitTime; //in milliseconds
SCAN_TYPE scanType;
uint32_t sessType;
uint32_t subfunctLen;
qint64 subfunctLower;
qint64 subfunctUpper;
uint32_t subfunctIncrement;
uint32_t serviceLower;
uint32_t serviceUpper;
};
namespace Ui {
class UDSScanWindow;
}
@@ -24,16 +62,25 @@ public:
private slots:
void updatedFrames(int numFrames);
void gotUDSReply(UDS_MESSAGE msg);
void scanUDS();
void scanAll();
void scanSelected();
void saveResults();
void timeOut();
void adaptiveToggled();
void wildcardToggled();
void readByToggled();
void changedScanType();
void numBytesChanged();
void checkIDRange();
void checkServiceRange();
void checkSubFuncRange();
void deleteSelectedScan();
void addNewScan();
void loadScans();
void saveScans();
void setNoReplyVal();
void setMaxDelayVal();
void setIncrementVal();
void setReplyOffset();
void setSessType();
private:
Ui::UDSScanWindow *ui;
@@ -44,9 +91,17 @@ private:
QTreeWidgetItem *nodeID;
QTreeWidgetItem *nodeService;
QTreeWidgetItem *nodeSubFunc;
QVector<ScanEntry> scanEntries;
ScanEntry *currEditEntry;
int currIdx = 0;
bool currentlyRunning;
bool inhibitUpdates;
void displayScanEntry(int idx);
QString generateListDesc(int idx);
void setupScan(int idx);
void startScan();
void stopScan();
void sendNextMsg();
void sendOnBuses(UDS_MESSAGE frame, int buses);
void setupNodes(uint32_t replyID);
+7 -5
View File
@@ -351,16 +351,18 @@ void SignalViewerWindow::loadDefinitions(bool append)
QString msgName = QString(tokens[2]);
QString sigName = QString(tokens[3]);
DBC_MESSAGE *msg;;
if (msg = dbcHandler->findMessage(msgName))
if(msg = dbcHandler->findMessage(msgId))
{
sig = msg->sigHandler->findSignalByName(sigName);
loadedSignals.append(sig);
if(sig)
loadedSignals.append(sig);
}
else if(msg = dbcHandler->findMessage(msgId))
else if (msg = dbcHandler->findMessage(msgName))
{
//this is not a very safe way to match since messages names can be duplicated
sig = msg->sigHandler->findSignalByName(sigName);
//fix anything up about the name?
loadedSignals.append(sig);
if(sig)
loadedSignals.append(sig);
}
else
{
+88
View File
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DBCNodeDuplicateEditor</class>
<widget class="QDialog" name="DBCNodeDuplicateEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>314</width>
<height>144</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Duplicate Node</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>290</width>
<height>116</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>New Node Name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineNodeName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Current Base ID:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineOriginalBaseId">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>New Base ID:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineNewBaseId"/>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="btnDuplicate">
<property name="text">
<string>Duplicate Node</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="btnCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+95
View File
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DBCNodeRebaseEditor</class>
<widget class="QDialog" name="DBCNodeRebaseEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>303</width>
<height>148</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Rebase All Node Messages</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>283</width>
<height>116</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Node Name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineNodeName">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Current Base ID:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineOriginalBaseId">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>New Base ID:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineNewBaseId"/>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="btnDoRebase">
<property name="text">
<string>Rebase All Messages in Node</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="btnCancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+62 -22
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>356</width>
<height>282</height>
<width>426</width>
<height>540</height>
</rect>
</property>
<property name="windowTitle">
@@ -23,6 +23,30 @@
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QRadioButton" name="rbKayak">
<property name="text">
<string>socketcand (SocketCAN over Ethernet)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QRadioButton" name="rbSocketCAN">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>QT SerialBus Devices (SocketCAN, PeakCAN, etc)</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QRadioButton" name="rbMQTT">
<property name="text">
<string>MQTT Connection</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="rbGVRET">
<property name="text">
@@ -40,27 +64,10 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="rbSocketCAN">
<property name="enabled">
<bool>false</bool>
</property>
<item row="2" column="0">
<widget class="QRadioButton" name="rbLawicel">
<property name="text">
<string>QT SerialBus Devices (SocketCAN, PeakCAN, etc)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QRadioButton" name="rbKayak">
<property name="text">
<string>socketcand (SocketCAN over Ethernet)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QRadioButton" name="rbMQTT">
<property name="text">
<string>MQTT Connection</string>
<string>LAWICEL / SLCAN Serial</string>
</property>
</widget>
</item>
@@ -109,6 +116,39 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblSerialSpeed">
<property name="text">
<string>Serial Port Speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSerialSpeed"/>
</item>
<item>
<widget class="QLabel" name="lblCANSpeed">
<property name="text">
<string>CAN Bus Speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbCANSpeed"/>
</item>
<item>
<spacer name="verticalSpacer">
<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>
<widget class="QPushButton" name="btnOK">
<property name="text">
+411 -322
View File
@@ -6,61 +6,346 @@
<rect>
<x>0</x>
<y>0</y>
<width>742</width>
<height>628</height>
<width>1053</width>
<height>624</height>
</rect>
</property>
<property name="windowTitle">
<string>UDS Scanner</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_9" stretch="1,5">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Results</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="treeResults">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSaveResults">
<property name="text">
<string>Save Scan Results</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Scans To Run</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listScansToRun"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QLabel" name="label_4">
<widget class="QPushButton" name="btnAdd">
<property name="text">
<string>Starting ID</string>
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinStartID">
<widget class="QPushButton" name="btnDelete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QPushButton" name="btnLoad">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Starting ID</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinStartID">
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>536870911</number>
</property>
<property name="value">
<number>2016</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Ending ID</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinEndID">
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>536870911</number>
</property>
<property name="value">
<number>2023</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="ckShowNoReply">
<property name="text">
<string>Show &quot;No Reply&quot;</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbAllowAdaptiveOffset">
<property name="text">
<string>Allow adaptive reply offset</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Bus to scan</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbBuses"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maximum reply delay (ms)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinDelay">
<property name="minimum">
<number>50</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Reply Offset:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinReplyOffset">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>-128</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbScanType">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>Run test in session type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSessType">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Subfunct Len:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinNumBytes">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>4</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Lower Bound:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinLowerSubfunc">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>536870911</number>
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Upper Bound:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinUpperSubfunc">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>2016</number>
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Increment</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinIncrement">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>1024</number>
</property>
<property name="singleStep">
<number>8</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
@@ -70,24 +355,50 @@
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Ending ID</string>
<string>Lower Service:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinEndID">
<widget class="QSpinBox" name="spinLowerService">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>536870911</number>
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>Upper Service:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinUpperService">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>2023</number>
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
@@ -97,323 +408,101 @@
</layout>
</item>
<item>
<widget class="QCheckBox" name="ckShowNoReply">
<property name="text">
<string>Show Tests with no Replies</string>
<widget class="Line" name="line">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="checked">
<bool>true</bool>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Reply Offset:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinReplyOffset">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>-128</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbAllowAdaptiveOffset">
<property name="text">
<string>Allow adaptive reply offset</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Bus to scan</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbBuses"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maximum reply delay (ms)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinDelay">
<property name="minimum">
<number>50</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Scan Types:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckTester">
<property name="text">
<string>Tester Present</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckSession">
<property name="text">
<string>Session Ctrl</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckReset">
<property name="text">
<string>ECU Reset</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckSecurity">
<property name="text">
<string>Security Access</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QCheckBox" name="ckReadByID">
<property name="text">
<string>Read By ID</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckReadByAddr">
<property name="text">
<string>Read By Addr</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="ckWildcard">
<property name="text">
<string>Wildcard</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Lower Service:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinLowerService">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>Upper Service:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinUpperService">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Subfunction Bytes:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinNumBytes">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<property name="lineWidth">
<number>4</number>
</property>
<property name="value">
<number>1</number>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Lower Bound:</string>
<string>Results</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinLowerSubfunc">
<widget class="QTreeWidget" name="treeResults">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
<property name="value">
<number>0</number>
</property>
<property name="maximum">
<number>255</number>
<property name="textVisible">
<bool>true</bool>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Upper Bound:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinUpperSubfunc">
<property name="enabled">
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>255</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QPushButton" name="btnScanAll">
<property name="text">
<string>Run All Scans</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnScanSelected">
<property name="text">
<string>Run Selected Scan</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="btnSaveResults">
<property name="text">
<string>Save Scan Results</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnScan">
<property name="text">
<string>Start Scan</string>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>spinStartID</tabstop>
<tabstop>spinEndID</tabstop>
<tabstop>ckShowNoReply</tabstop>
<tabstop>spinReplyOffset</tabstop>
<tabstop>cbAllowAdaptiveOffset</tabstop>
<tabstop>cbBuses</tabstop>
<tabstop>spinDelay</tabstop>
<tabstop>ckTester</tabstop>
<tabstop>ckSession</tabstop>
<tabstop>ckReset</tabstop>
<tabstop>ckSecurity</tabstop>
<tabstop>ckReadByID</tabstop>
<tabstop>ckReadByAddr</tabstop>
<tabstop>ckWildcard</tabstop>
<tabstop>spinLowerService</tabstop>
<tabstop>spinUpperService</tabstop>
<tabstop>spinNumBytes</tabstop>
<tabstop>spinLowerSubfunc</tabstop>
<tabstop>spinUpperSubfunc</tabstop>
<tabstop>btnScan</tabstop>
<tabstop>treeResults</tabstop>
<tabstop>btnSaveResults</tabstop>
</tabstops>
<resources/>
<connections/>
+37 -3
View File
@@ -146,6 +146,11 @@ public:
return output;
}
static QString formatByteAsHex(uint8_t value)
{
return QString::number(value, 16).toUpper().rightJustified(2,'0');
}
static QVariant formatTimestamp(uint64_t timestamp)
{
if (!sysTimeMode) {
@@ -200,17 +205,44 @@ public:
return (value1 * (1.0 - samplePoint)) + (value2 * samplePoint);
}
/* A unified function that can extract a signal from the (up to) 64 bits of data bytes in a CAN frame
* handles both little and big endian signals (and floats too but that's untested).
*/
static int64_t processIntegerSignal(const QByteArray data, int startBit, int sigSize, bool littleEndian, bool isSigned)
{
int64_t result = 0;
int bit;
uint64_t result = 0;
int bit = 0;
int maxBytes = (startBit + sigSize) / 8;
if (data.size() < maxBytes) return 0;
if (data.size() < maxBytes) return 0; //if signal extends past the end of data then abort
if (littleEndian)
{
/*
int currByte = (startBit) / 8;
int currOffset = startBit - (currByte * 8);
int remainingBits = qMax(0, (sigSize - (8 - currOffset)) );
int prevBits = qMin((8 - currOffset), sigSize);
result = data[currByte] >> currOffset;
result &= ( (1 << sigSize) - 1); //doesn't hurt to do this even if sigSize is way larger than the # of bits we've got so far
while (remainingBits > 0)
{
currByte++;
if (remainingBits >= 8) //use this entire byte, its easy
{
result += data[currByte] << prevBits;
remainingBits -= 8;
prevBits += 8;
}
else //use only part of this byte. We're going to need to mask it
{
result += ((data[currByte] & ((1 << remainingBits) - 1) ) << prevBits);
remainingBits = 0;
}
}*/
bit = startBit;
for (int bitpos = 0; bitpos < sigSize; bitpos++)
{
@@ -222,6 +254,7 @@ public:
}
bit++;
}
}
else //motorola / big endian mode
{
@@ -266,6 +299,7 @@ public:
*/
uint64_t signedMask = ~((1ULL << sigSize) - 1);
result = (-1LL & signedMask) | result;
return (int64_t)(result);
}
}