Merge branch 'fix_socketcandpartialframedrop' of github.com:qurrent-llc/SavvyCAN into fix_socketcandpartialframedrop
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace CANCon {
|
||||
REMOTE,
|
||||
KAYAK,
|
||||
MQTT,
|
||||
LAWICEL,
|
||||
NONE
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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!";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
{
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -84,7 +84,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
|
||||
break;
|
||||
case 4:
|
||||
currentSignal->valType = STRING;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
dbcFile->setDirtyFlag();
|
||||
fillSignalForm(currentSignal);
|
||||
|
||||
+103
-83
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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 "No Reply"</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/>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user