Merge pull request #5 from collin80/master

Getting latest from upstream
This commit is contained in:
Andy Huska
2022-10-09 08:48:21 -07:00
committed by GitHub
23 changed files with 1913 additions and 596 deletions
+2
View File
@@ -20,6 +20,7 @@ QMAKE_INFO_PLIST = Info.plist.template
ICON = icons/SavvyIcon.icns ICON = icons/SavvyIcon.icns
SOURCES += main.cpp\ SOURCES += main.cpp\
connections/lawicel_serial.cpp \
connections/mqtt_bus.cpp \ connections/mqtt_bus.cpp \
dbc/dbcnodeduplicateeditor.cpp \ dbc/dbcnodeduplicateeditor.cpp \
mqtt/qmqtt_client.cpp \ mqtt/qmqtt_client.cpp \
@@ -100,6 +101,7 @@ SOURCES += main.cpp\
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
can_structs.h \ can_structs.h \
canframemodel.h \ canframemodel.h \
connections/lawicel_serial.h \
connections/socketcand.h \ connections/socketcand.h \
connections/mqtt_bus.h \ connections/mqtt_bus.h \
dbc/dbcnodeduplicateeditor.h \ dbc/dbcnodeduplicateeditor.h \
+1
View File
@@ -20,6 +20,7 @@ namespace CANCon {
REMOTE, REMOTE,
KAYAK, KAYAK,
MQTT, MQTT,
LAWICEL,
NONE NONE
}; };
} }
+4 -1
View File
@@ -4,10 +4,11 @@
#include "gvretserial.h" #include "gvretserial.h"
#include "mqtt_bus.h" #include "mqtt_bus.h"
#include "socketcand.h" #include "socketcand.h"
#include "lawicel_serial.h"
using namespace CANCon; 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) { switch(pType) {
case SERIALBUS: case SERIALBUS:
@@ -19,6 +20,8 @@ CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDri
return new GVRetSerial(pPortName, false); return new GVRetSerial(pPortName, false);
case REMOTE: case REMOTE:
return new GVRetSerial(pPortName, true); //it's a special case of GVRET connected over TCP/IP so it uses the same class 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: case KAYAK:
return new SocketCANd(pPortName); return new SocketCANd(pPortName);
case MQTT: case MQTT:
+1 -1
View File
@@ -7,7 +7,7 @@
class CanConFactory class CanConFactory
{ {
public: 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 #endif // CANCONFACTORY_H
+5
View File
@@ -5,6 +5,8 @@
CANConnection::CANConnection(QString pPort, CANConnection::CANConnection(QString pPort,
QString pDriver, QString pDriver,
CANCon::type pType, CANCon::type pType,
int pSerialSpeed,
int pBusSpeed,
int pNumBuses, int pNumBuses,
int pQueueLen, int pQueueLen,
bool pUseThread) : bool pUseThread) :
@@ -13,6 +15,7 @@ CANConnection::CANConnection(QString pPort,
mPort(pPort), mPort(pPort),
mDriver(pDriver), mDriver(pDriver),
mType(pType), mType(pType),
mSerialSpeed(pSerialSpeed),
mIsCapSuspended(false), mIsCapSuspended(false),
mStatus(CANCon::NOT_CONNECTED), mStatus(CANCon::NOT_CONNECTED),
mStarted(false), mStarted(false),
@@ -34,6 +37,8 @@ CANConnection::CANConnection(QString pPort,
mBusData[i].mConfigured = false; mBusData[i].mConfigured = false;
} }
if (pBusSpeed > 0) mBusData[0].mBus.setSpeed(pBusSpeed);
/* if needed, create a thread and move ourself into it */ /* if needed, create a thread and move ourself into it */
if(pUseThread) { if(pUseThread) {
mThread_p = new QThread(); mThread_p = new QThread();
+6 -1
View File
@@ -21,13 +21,17 @@ protected:
* @param pPort: string containing port name * @param pPort: string containing port name
* @param pDriver: string containing driver name - Really only used for SerialBus connections * @param pDriver: string containing driver name - Really only used for SerialBus connections
* @param pType: the type of connection @ref CANCon::type * @param pType: the type of connection @ref CANCon::type
* @param 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 pNumBuses: the number of buses the device has
* @param pQueueLen: the length of the lock free queue to use * @param pQueueLen: the length of the lock free queue to use
* @param pUseThread: if set to true, object will be execute in a dedicated thread * @param pUseThread: if set to true, object will be execute in a dedicated thread
*/ */
CANConnection(QString pPort, CANConnection(QString pPort,
QString pDriver, QString pDriver,
CANCon::type pType, CANCon::type pType,
int pSerialSpeed,
int pBusSpeed,
int pNumBuses, int pNumBuses,
int pQueueLen, int pQueueLen,
bool pUseThread); bool pUseThread);
@@ -201,6 +205,7 @@ protected:
int mNumBuses; //protected to allow connected device to figure out how many buses are available int mNumBuses; //protected to allow connected device to figure out how many buses are available
QVector<BusData> mBusData; QVector<BusData> mBusData;
bool mConsoleOutput; //send debugging info to the console? bool mConsoleOutput; //send debugging info to the console?
int mSerialSpeed;
//determine if the passed frame is part of a filter or not. //determine if the passed frame is part of a filter or not.
void checkTargettedFrame(CANFrame &frame); void checkTargettedFrame(CANFrame &frame);
+1
View File
@@ -86,6 +86,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
case CANCon::SERIALBUS: return "SerialBus"; case CANCon::SERIALBUS: return "SerialBus";
case CANCon::GVRET_SERIAL: return "GVRET"; case CANCon::GVRET_SERIAL: return "GVRET";
case CANCon::KAYAK: return "socketcand"; case CANCon::KAYAK: return "socketcand";
case CANCon::LAWICEL: return "LAWICEL";
default: {} default: {}
} }
else qDebug() << "Tried to show connection type but connection was nullptr"; else qDebug() << "Tried to show connection type but connection was nullptr";
+15 -5
View File
@@ -250,6 +250,8 @@ void ConnectionWindow::handleNewConn()
CANCon::type newType; CANCon::type newType;
QString newPort; QString newPort;
QString newDriver; QString newDriver;
int newSerialSpeed;
int newBusSpeed;
CANConnection *conn; CANConnection *conn;
if (thisDialog->exec() == QDialog::Accepted) if (thisDialog->exec() == QDialog::Accepted)
@@ -257,7 +259,9 @@ void ConnectionWindow::handleNewConn()
newType = thisDialog->getConnectionType(); newType = thisDialog->getConnectionType();
newPort = thisDialog->getPortName(); newPort = thisDialog->getPortName();
newDriver = thisDialog->getDriverName(); newDriver = thisDialog->getDriverName();
conn = create(newType, newPort, newDriver); newSerialSpeed = thisDialog->getSerialSpeed();
newBusSpeed = thisDialog->getBusSpeed();
conn = create(newType, newPort, newDriver, newSerialSpeed, newBusSpeed);
if (conn) if (conn)
{ {
connModel->add(conn); connModel->add(conn);
@@ -292,6 +296,7 @@ void ConnectionWindow::handleResetConn()
{ {
QString port, driver; QString port, driver;
CANCon::type type; CANCon::type type;
int serSpeed, busSpeed;
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row(); int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
if (selIdx <0) return; if (selIdx <0) return;
@@ -304,13 +309,15 @@ void ConnectionWindow::handleResetConn()
type = conn_p->getType(); type = conn_p->getType();
port = conn_p->getPort(); port = conn_p->getPort();
driver = conn_p->getDriver(); driver = conn_p->getDriver();
serSpeed = 0; //TODO: implement these
busSpeed = 0;
/* stop and delete connection */ /* stop and delete connection */
conn_p->stop(); conn_p->stop();
conn_p = nullptr; 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); if (conn_p) connModel->replace(selIdx, conn_p);
} }
@@ -476,12 +483,12 @@ void ConnectionWindow::handleSendText() {
emit sendDebugData(bytes); 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; CANConnection* conn_p;
/* create connection */ /* create connection */
conn_p = CanConFactory::create(pTye, pPortName, pDriver); conn_p = CanConFactory::create(pTye, pPortName, pDriver, pSerialSpeed, pBusSpeed);
if(conn_p) if(conn_p)
{ {
/* connect signal */ /* connect signal */
@@ -518,7 +525,8 @@ void ConnectionWindow::loadConnections()
for(int i = 0 ; i < portNames.count() ; i++) for(int i = 0 ; i < portNames.count() ; i++)
{ {
CANConnection* conn_p = create((CANCon::type)devTypes[i], portNames[i], 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 */ /* add connection to model */
connModel->add(conn_p); connModel->add(conn_p);
} }
@@ -536,6 +544,8 @@ void ConnectionWindow::saveConnections()
QVector<QString> portNames; QVector<QString> portNames;
QVector<int> devTypes; QVector<int> devTypes;
QVector<QString> driverNames; QVector<QString> driverNames;
QVector<int> serialSpeeds;
QVector<int> busSpeeds;
/* save connections */ /* save connections */
foreach(CANConnection* conn_p, conns) foreach(CANConnection* conn_p, conns)
+1 -1
View File
@@ -65,7 +65,7 @@ private:
QVector<QString> remoteDeviceIPGVRET; QVector<QString> remoteDeviceIPGVRET;
QVector<QString> remoteDeviceKayak; 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 populateBusDetails(int offset);
void loadConnections(); void loadConnections();
void saveConnections(); void saveConnections();
+1 -1
View File
@@ -9,7 +9,7 @@
#include "gvretserial.h" #include "gvretserial.h"
GVRetSerial::GVRetSerial(QString portName, bool useTcp) : 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 */ mTimer(this), /*NB: set this as parent of timer to manage it from working thread */
useTcp(useTcp) useTcp(useTcp)
{ {
+496
View File
@@ -0,0 +1,496 @@
#include <QObject>
#include <QDebug>
#include <QCanBusFrame>
#include <QSerialPortInfo>
#include <QSettings>
#include <QStringBuilder>
#include <QtNetwork>
#include "lawicel_serial.h"
#include "utility.h"
LAWICELSerial::LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed) :
CANConnection(portName, "LAWICEL", CANCon::LAWICEL,serialSpeed, lawicelSpeed, 3, 4000, true),
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{
sendDebug("LAWICELSerial()");
serial = nullptr;
isAutoRestart = false;
readSettings();
}
LAWICELSerial::~LAWICELSerial()
{
stop();
sendDebug("~LAWICELSerial()");
}
void LAWICELSerial::sendDebug(const QString debugText)
{
qDebug() << debugText;
debugOutput(debugText);
}
void LAWICELSerial::sendToSerial(const QByteArray &bytes)
{
if (serial == nullptr)
{
sendDebug("Attempt to write to serial port when it has not been initialized!");
return;
}
if (serial && !serial->isOpen())
{
sendDebug("Attempt to write to serial port when it is not open!");
return;
}
QString buildDebug;
buildDebug = "Write to serial -> ";
foreach (int byt, bytes) {
byt = (unsigned char)byt;
buildDebug = buildDebug % QString::number(byt, 16) % " ";
}
sendDebug(buildDebug);
if (serial) serial->write(bytes);
}
void LAWICELSerial::piStarted()
{
connectDevice();
}
void LAWICELSerial::piSuspend(bool pSuspend)
{
/* update capSuspended */
setCapSuspended(pSuspend);
/* flush queue if we are suspended */
if(isCapSuspended())
getQueue().flush();
}
void LAWICELSerial::piStop()
{
mTimer.stop();
disconnectDevice();
}
bool LAWICELSerial::piGetBusSettings(int pBusIdx, CANBus& pBus)
{
return getBusConfig(pBusIdx, pBus);
}
void LAWICELSerial::piSetBusSettings(int pBusIdx, CANBus bus)
{
/* sanity checks */
if( (pBusIdx < 0) || pBusIdx >= getNumBuses())
return;
/* copy bus config */
setBusConfig(pBusIdx, bus);
/*
qDebug() << "About to update bus " << pBusIdx << " on GVRET";
if (pBusIdx == 0)
{
can0Baud = bus.getSpeed();
can0Baud |= 0x80000000;
if (bus.isActive())
{
can0Baud |= 0x40000000;
can0Enabled = true;
}
else can0Enabled = false;
if (bus.isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
else can0ListenOnly = false;
}
*/
if (pBusIdx < 2) {
/* update baud rates */
QByteArray buffer;
//sendDebug("Got signal to update bauds. 1: " + QString::number((can0Baud & 0xFFFFFFF)));
buffer[0] = (char)0xF1; //start of a command over serial
//sendToSerial(buffer);
}
}
bool LAWICELSerial::piSendFrame(const CANFrame& frame)
{
QByteArray buffer;
int c;
quint32 ID;
//qDebug() << "Sending out lawicel frame with id " << frame.ID << " on bus " << frame.bus;
framesRapid++;
if (serial == nullptr) return false;
if (serial && !serial->isOpen()) return false;
//if (!isConnected) return false;
// Doesn't make sense to send an error frame
// to an adapter
if (frame.frameId() & 0x20000000) {
return true;
}
ID = frame.frameId();
if (frame.hasExtendedFrameFormat()) ID |= 1u << 31;
int idx = 0;
QString buildStr;
if (frame.hasExtendedFrameFormat())
{
buildStr = QString::asprintf("T%08X%u", ID, frame.payload().length());
}
else
{
buildStr = QString::asprintf("t%03X%u", ID, frame.payload().length());
}
foreach (QChar chr, buildStr)
{
buffer[idx] = chr.toLatin1();
idx++;
}
for (c = 0; c < frame.payload().length(); c++)
{
QString byt = Utility::formatByteAsHex(frame.payload()[c]);
buffer[idx + (c * 2)] = byt[0].toLatin1();
buffer[idx + (c * 2) + 1] = byt[1].toLatin1();
}
buffer[idx + (frame.payload().length() * 2)] = 13; //CR
sendToSerial(buffer);
return true;
}
/****************************************************************/
void LAWICELSerial::readSettings()
{
QSettings settings;
}
void LAWICELSerial::connectDevice()
{
QSettings settings;
/* disconnect device */
if(serial)
disconnectDevice();
/* open new device */
qDebug() << "Serial port: " << getPort();
serial = new QSerialPort(QSerialPortInfo(getPort()));
if(!serial) {
sendDebug("can't open serial port " + getPort());
return;
}
sendDebug("Created Serial Port Object");
/* connect reading event */
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(serialError(QSerialPort::SerialPortError)));
/* configure */
serial->setBaudRate(mSerialSpeed);
serial->setDataBits(serial->Data8);
serial->setFlowControl(serial->HardwareControl);
//serial->setFlowControl(serial->NoFlowControl);
if (!serial->open(QIODevice::ReadWrite))
{
//sendDebug("Error returned during port opening: " + serial->errorString());
}
else
{
//serial->setDataTerminalReady(true); //Seemingly these two lines used to be needed
//serial->setRequestToSend(true); //But, really both ends should automatically handle these
deviceConnected();
}
}
void LAWICELSerial::deviceConnected()
{
sendDebug("Connecting to LAWICEL Device!");
QByteArray output;
output.clear();
output.append('C'); //close the bus in case it was already up
output.append(13);
sendToSerial(output);
output.clear();
output.append('S'); //configure speed of bus
switch (this->mBusData[0].mBus.getSpeed())
{
case 10000:
output.append('0');
break;
case 20000:
output.append('1');
break;
case 50000:
output.append('2');
break;
case 100000:
output.append('3');
break;
case 125000:
output.append('4');
break;
case 250000:
output.append('5');
break;
case 500000:
output.append('6');
break;
case 800000:
output.append('7');
break;
case 1000000:
output.append('8');
break;
default:
output.append('6');
break;
}
output.append('\x0D');
sendToSerial(output);
output.clear();
output.append('O'); //open bus now that we set the speed
output.append(13);
sendToSerial(output);
mNumBuses = 1;
setStatus(CANCon::CONNECTED);
CANConStatus stats;
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
mBusData[0].mConfigured = true;
mBusData[0].mBus.setActive(true);
//mBusData[0].mBus.setSpeed();
emit status(stats);
}
void LAWICELSerial::disconnectDevice() {
if (serial != nullptr)
{
if (serial->isOpen())
{
//serial->clear();
serial->close();
}
serial->disconnect(); //disconnect all signals
delete serial;
serial = nullptr;
}
setStatus(CANCon::NOT_CONNECTED);
CANConStatus stats;
stats.conStatus = getStatus();
stats.numHardwareBuses = mNumBuses;
emit status(stats);
}
void LAWICELSerial::serialError(QSerialPort::SerialPortError err)
{
QString errMessage;
bool killConnection = false;
switch (err)
{
case QSerialPort::NoError:
return;
case QSerialPort::DeviceNotFoundError:
errMessage = "Device not found error on serial";
killConnection = true;
piStop();
break;
case QSerialPort::PermissionError:
errMessage = "Permission error on serial port";
killConnection = true;
piStop();
break;
case QSerialPort::OpenError:
errMessage = "Open error on serial port";
killConnection = true;
piStop();
break;
case QSerialPort::ParityError:
errMessage = "Parity error on serial port";
break;
case QSerialPort::FramingError:
errMessage = "Framing error on serial port";
break;
case QSerialPort::BreakConditionError:
errMessage = "Break error on serial port";
break;
case QSerialPort::WriteError:
errMessage = "Write error on serial port";
piStop();
break;
case QSerialPort::ReadError:
errMessage = "Read error on serial port";
piStop();
break;
case QSerialPort::ResourceError:
errMessage = "Serial port seems to have disappeared.";
killConnection = true;
piStop();
break;
case QSerialPort::UnsupportedOperationError:
errMessage = "Unsupported operation on serial port";
killConnection = true;
break;
case QSerialPort::UnknownError:
errMessage = "Beats me what happened to the serial port.";
killConnection = true;
piStop();
break;
case QSerialPort::TimeoutError:
errMessage = "Timeout error on serial port";
killConnection = true;
break;
case QSerialPort::NotOpenError:
errMessage = "The serial port isn't open";
killConnection = true;
piStop();
break;
}
/*
if (serial)
{
serial->clearError();
serial->flush();
serial->close();
}*/
if (errMessage.length() > 1)
{
sendDebug(errMessage);
}
if (killConnection)
{
qDebug() << "Shooting the serial object in the head. It deserves it.";
disconnectDevice();
}
}
void LAWICELSerial::connectionTimeout()
{
//one second after trying to connect are we actually connected?
if (CANCon::NOT_CONNECTED==getStatus()) //no?
{
//then emit the the failure signal and see if anyone cares
sendDebug("Failed to connect to LAWICEL at that com port");
disconnectDevice();
connectDevice();
}
else
{
/* start timer */
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
mTimer.setInterval(250); //tick four times per second
mTimer.setSingleShot(false); //keep ticking
mTimer.start();
}
}
void LAWICELSerial::readSerialData()
{
QByteArray data;
unsigned char c;
QString debugBuild;
CANFrame buildFrame;
QByteArray buildData;
if (serial) data = serial->readAll();
sendDebug("Got data from serial. Len = " % QString::number(data.length()));
for (int i = 0; i < data.length(); i++)
{
c = data.at(i);
//qDebug() << c << " " << QString::number(c, 16) << " " << QString(c);
debugBuild = debugBuild % QString::number(c, 16).rightJustified(2,'0') % " ";
//procRXChar(c);
mBuildLine.append(c);
if (c == 13) //all lawicel commands end in CR
{
qDebug() << "Got CR!";
switch (mBuildLine[0].toLatin1())
{
case 't': //standard frame
//tIIILDD
buildFrame.setFrameId(mBuildLine.mid(1, 3).toInt(nullptr, 16));
buildFrame.isReceived = true;
buildFrame.setFrameType(QCanBusFrame::FrameType::DataFrame);
buildData.resize(mBuildLine.mid(4, 1).toInt());
for (int c = 0; c < buildData.size(); c++)
{
buildData[c] = mBuildLine.mid(5 + (c*2), 2).toInt(nullptr, 16);
}
buildFrame.setPayload(buildData);
if (!isCapSuspended())
{
/* get frame from queue */
CANFrame* frame_p = getQueue().get();
if(frame_p) {
//qDebug() << "Lawicel got frame on bus " << frame_p->bus;
/* copy frame */
*frame_p = buildFrame;
checkTargettedFrame(buildFrame);
/* enqueue frame */
getQueue().queue();
}
else
qDebug() << "can't get a frame, ERROR";
}
break;
case 'T': //extended frame
break;
}
mBuildLine.clear();
}
}
debugOutput(debugBuild);
//qDebug() << debugBuild;
}
//Debugging data sent from connection window. Inject it into Comm traffic.
void LAWICELSerial::debugInput(QByteArray bytes) {
sendToSerial(bytes);
}
void LAWICELSerial::handleTick()
{
//qDebug() << "Tick!";
}
+66
View File
@@ -0,0 +1,66 @@
#ifndef LAWICELSERIAL_H
#define LAWICELSERIAL_H
#include <QSerialPort>
#include <QCanBusDevice>
#include <QThread>
#include <QTimer>
/*************/
#include <QDateTime>
/*************/
#include "canframemodel.h"
#include "canconnection.h"
#include "canconmanager.h"
class LAWICELSerial : public CANConnection
{
Q_OBJECT
public:
LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed);
virtual ~LAWICELSerial();
protected:
virtual void piStarted();
virtual void piStop();
virtual void piSetBusSettings(int pBusIdx, CANBus pBus);
virtual bool piGetBusSettings(int pBusIdx, CANBus& pBus);
virtual void piSuspend(bool pSuspend);
virtual bool piSendFrame(const CANFrame&) ;
void disconnectDevice();
public slots:
void debugInput(QByteArray bytes);
private slots:
void connectDevice();
void connectionTimeout();
void readSerialData();
void serialError(QSerialPort::SerialPortError err);
void deviceConnected();
void handleTick();
private:
void readSettings();
void rebuildLocalTimeBasis();
void sendToSerial(const QByteArray &bytes);
void sendDebug(const QString debugText);
protected:
QTimer mTimer;
QThread mThread;
QString mBuildLine;
bool isAutoRestart;
QSerialPort *serial;
int framesRapid;
CANFrame buildFrame;
bool can0Enabled;
bool can0ListenOnly;
};
#endif // LAWICELSERIAL_H
+1 -1
View File
@@ -9,7 +9,7 @@
#include "mqtt_bus.h" #include "mqtt_bus.h"
MQTT_BUS::MQTT_BUS(QString topicName) : 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 */ mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{ {
+96
View File
@@ -27,12 +27,17 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* gvretips, QVector<QSt
connect(ui->rbRemote, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); connect(ui->rbRemote, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbKayak, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged); connect(ui->rbKayak, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbMQTT, &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->cbDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NewConnectionDialog::handleDeviceTypeChanged);
connect(ui->btnOK, &QPushButton::clicked, this, &NewConnectionDialog::handleCreateButton); connect(ui->btnOK, &QPushButton::clicked, this, &NewConnectionDialog::handleCreateButton);
ui->lblDeviceType->setHidden(true); ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true); ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
selectSerial(); selectSerial();
qDebug() << "Was passed " << remoteDeviceIPGVRET->count() << " remote GVRET IPs"; qDebug() << "Was passed " << remoteDeviceIPGVRET->count() << " remote GVRET IPs";
@@ -53,6 +58,7 @@ void NewConnectionDialog::handleConnTypeChanged()
{ {
if (ui->rbGVRET->isChecked()) selectSerial(); if (ui->rbGVRET->isChecked()) selectSerial();
if (ui->rbSocketCAN->isChecked()) selectSocketCan(); if (ui->rbSocketCAN->isChecked()) selectSocketCan();
if (ui->rbLawicel->isChecked()) selectLawicel();
if (ui->rbRemote->isChecked()) selectRemote(); if (ui->rbRemote->isChecked()) selectRemote();
if (ui->rbKayak->isChecked()) selectKayak(); if (ui->rbKayak->isChecked()) selectKayak();
if (ui->rbMQTT->isChecked()) selectMQTT(); if (ui->rbMQTT->isChecked()) selectMQTT();
@@ -68,12 +74,57 @@ void NewConnectionDialog::handleDeviceTypeChanged()
ui->cbPort->addItem(canDevices[i].name()); 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("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() void NewConnectionDialog::selectSerial()
{ {
ui->lPort->setText("Serial Port:"); ui->lPort->setText("Serial Port:");
ui->lblDeviceType->setHidden(true); ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->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(); ui->cbPort->clear();
ports = QSerialPortInfo::availablePorts(); ports = QSerialPortInfo::availablePorts();
@@ -87,6 +138,10 @@ void NewConnectionDialog::selectSocketCan()
ui->lPort->setText("Port:"); ui->lPort->setText("Port:");
ui->lblDeviceType->setHidden(false); ui->lblDeviceType->setHidden(false);
ui->cbDeviceType->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(); ui->cbDeviceType->clear();
QStringList plugins; QStringList plugins;
@@ -99,8 +154,14 @@ void NewConnectionDialog::selectSocketCan()
void NewConnectionDialog::selectRemote() void NewConnectionDialog::selectRemote()
{ {
ui->lPort->setText("IP Address:"); ui->lPort->setText("IP Address:");
ui->lblDeviceType->setHidden(true); ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->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(); ui->cbPort->clear();
foreach(QString pName, *remoteDeviceIPGVRET) foreach(QString pName, *remoteDeviceIPGVRET)
{ {
@@ -111,8 +172,14 @@ void NewConnectionDialog::selectRemote()
void NewConnectionDialog::selectKayak() void NewConnectionDialog::selectKayak()
{ {
ui->lPort->setText("Available Bus(ses):"); ui->lPort->setText("Available Bus(ses):");
ui->lblDeviceType->setHidden(true); ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->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(); ui->cbPort->clear();
foreach(QString pName, *remoteBusKayak) foreach(QString pName, *remoteBusKayak)
{ {
@@ -123,8 +190,14 @@ void NewConnectionDialog::selectKayak()
void NewConnectionDialog::selectMQTT() void NewConnectionDialog::selectMQTT()
{ {
ui->lPort->setText("Topic Name:"); ui->lPort->setText("Topic Name:");
ui->lblDeviceType->setHidden(true); ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->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(); ui->cbPort->clear();
} }
@@ -148,6 +221,8 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
case CANCon::MQTT: case CANCon::MQTT:
ui->rbMQTT->setChecked(true); ui->rbMQTT->setChecked(true);
break; break;
case CANCon::LAWICEL:
ui->rbLawicel->setChecked(true);
default: {} default: {}
} }
@@ -157,6 +232,7 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
switch(pType) switch(pType)
{ {
case CANCon::GVRET_SERIAL: case CANCon::GVRET_SERIAL:
case CANCon::LAWICEL:
{ {
int idx = ui->cbPort->findText(pPortName); int idx = ui->cbPort->findText(pPortName);
if( idx<0 ) idx=0; if( idx<0 ) idx=0;
@@ -201,6 +277,7 @@ QString NewConnectionDialog::getPortName()
case CANCon::SERIALBUS: case CANCon::SERIALBUS:
case CANCon::REMOTE: case CANCon::REMOTE:
case CANCon::MQTT: case CANCon::MQTT:
case CANCon::LAWICEL:
return ui->cbPort->currentText(); return ui->cbPort->currentText();
case CANCon::KAYAK: case CANCon::KAYAK:
return ui->cbPort->currentText(); return ui->cbPort->currentText();
@@ -220,6 +297,24 @@ QString NewConnectionDialog::getDriverName()
return "N/A"; 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() CANCon::type NewConnectionDialog::getConnectionType()
{ {
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL; if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
@@ -227,6 +322,7 @@ CANCon::type NewConnectionDialog::getConnectionType()
if (ui->rbRemote->isChecked()) return CANCon::REMOTE; if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
if (ui->rbKayak->isChecked()) return CANCon::KAYAK; if (ui->rbKayak->isChecked()) return CANCon::KAYAK;
if (ui->rbMQTT->isChecked()) return CANCon::MQTT; if (ui->rbMQTT->isChecked()) return CANCon::MQTT;
if (ui->rbLawicel->isChecked()) return CANCon::LAWICEL;
qDebug() << "getConnectionType: error"; qDebug() << "getConnectionType: error";
return CANCon::NONE; return CANCon::NONE;
+3
View File
@@ -24,6 +24,8 @@ public:
CANCon::type getConnectionType(); CANCon::type getConnectionType();
QString getPortName(); QString getPortName();
QString getDriverName(); QString getDriverName();
int getSerialSpeed();
int getBusSpeed();
public slots: public slots:
void handleConnTypeChanged(); void handleConnTypeChanged();
@@ -43,6 +45,7 @@ private:
void selectRemote(); void selectRemote();
void selectKayak(); void selectKayak();
void selectMQTT(); void selectMQTT();
void selectLawicel();
bool isSerialBusAvailable(); bool isSerialBusAvailable();
void setPortName(CANCon::type pType, QString pPortName, QString pDriver); void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
}; };
+1 -1
View File
@@ -12,7 +12,7 @@
/***********************************/ /***********************************/
SerialBusConnection::SerialBusConnection(QString portName, QString driverName) : 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 */ mTimer(this) /*NB: set connection as parent of timer to manage it from working thread */
{ {
} }
+1 -1
View File
@@ -10,7 +10,7 @@
#include "socketcand.h" #include "socketcand.h"
SocketCANd::SocketCANd(QString portName) : 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 */ mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
{ {
+103 -83
View File
@@ -1599,10 +1599,13 @@ bool FrameFileIO::isCanalyzerASC(QString filename)
//47.971842 2 248 Rx d 8 FF FF FF FF FF FF FF FF //47.971842 2 248 Rx d 8 FF FF FF FF FF FF FF FF
//version 8.1 //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 //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 //Version 16.0.0
//0.008600 1 358 Rx d 8 04 03 50 01 F0 40 54 2C Length = 233910 BitCount = 121 ID = 856 //0.008600 1 358 Rx d 8 04 03 50 01 F0 40 54 2C Length = 233910 BitCount = 121 ID = 856
//Time bus id dir ? len databytes (Ver 8.0) //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 ? ? 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) //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 //So it seems the file format is not entirely different based on version but rather on some other
//settings... Fun! //settings... Fun!
@@ -1660,104 +1663,74 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
{ {
tokens = line.simplified().split(' '); 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... //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.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(); if (tokens[4].endsWith('x'))
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
{ {
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<uint64_t>(tokens[0].toDouble() * 1000000.0))); QByteArray copied_id = tokens[4];
if (tokens[4].endsWith('x')) copied_id.chop(1);
{ thisFrame.setFrameId(copied_id.toUInt(nullptr, 16));
QByteArray copied_id = tokens[4]; thisFrame.setExtendedFrameFormat(true);
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);
} }
else else
{ {
if (tokens[2].endsWith('x')) thisFrame.setFrameId(tokens[4].toUInt(nullptr, 16));
{ thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without '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) int payloadLen = tokens[8].toInt();
{ qDebug() << "PayloadLen: " << payloadLen << " Tokens: " << tokens;
qDebug() << "Payload length too long. Original line: " << line; QByteArray bytes(payloadLen, 0);
return false; if (payloadLen > 8)
} {
if (payloadLen < 0) qDebug() << "Payload length too long. Original line: " << line;
{ return false;
qDebug() << "Payload length negative! Original line: " << line; }
return false; if (payloadLen < 0)
} {
thisFrame.isReceived = tokens[3].toUpper().contains("RX"); qDebug() << "Payload length negative! Original line: " << line;
thisFrame.bus = tokens[1].toInt(); return false;
if (tokens[4] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame); }
for (int d = 6; d < (6 + payloadLen); d++) 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) 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 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; foundErrors = true;
qDebug() << "D:" << d << " Count:" << tokens.count(); qDebug() << "D:" << d << " Count:" << tokens.count();
qDebug() << "Expected byte missing! Original line: " << line; qDebug() << "Expected byte missing! Original line: " << line;
@@ -1765,8 +1738,55 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
} }
thisFrame.setPayload(bytes); thisFrame.setPayload(bytes);
} }
frames->append(thisFrame);
} }
else
{
int payloadLen = tokens[5].toInt();
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, static_cast<uint64_t>(tokens[0].toDouble() * 1000000.0)));
if (tokens[2].endsWith('x'))
{
QByteArray copied_id = tokens[2];
copied_id.chop(1);
thisFrame.setFrameId(copied_id.toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(true);
}
else
{
thisFrame.setFrameId(tokens[2].toUInt(nullptr, 16));
thisFrame.setExtendedFrameFormat(thisFrame.frameId() > 0x7FF); //some .asc files have extended IDs without 'x'
}
QByteArray bytes(payloadLen, 0);
if (payloadLen > 8)
{
qDebug() << "Payload length too long. Original line: " << line;
return false;
}
if (payloadLen < 0)
{
qDebug() << "Payload length negative! Original line: " << line;
return false;
}
thisFrame.isReceived = tokens[3].toUpper().contains("RX");
thisFrame.bus = tokens[1].toInt();
if (tokens[4] == "r") thisFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
for (int d = 6; d < (6 + payloadLen); d++)
{
if (tokens.count() > d)
{
bytes[d - 6] = static_cast<char>(tokens[d].toInt(nullptr, 16));
}
else //expected byte wasn't there to read. Set it zero and set error flag
{
bytes[d - 6] = 0;
foundErrors = true;
qDebug() << "D:" << d << " Count:" << tokens.count();
qDebug() << "Expected byte missing! Original line: " << line;
}
}
thisFrame.setPayload(bytes);
}
frames->append(thisFrame);
} }
} }
} }
+541 -150
View File
@@ -6,6 +6,23 @@
#include "utility.h" #include "utility.h"
#include "helpwindow.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) : UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::UDSScanWindow) ui(new Ui::UDSScanWindow)
@@ -21,15 +38,23 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
waitTimer->setInterval(100); waitTimer->setInterval(100);
udsHandler = new UDS_HANDLER; 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(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
connect(udsHandler, &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply); 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(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut);
connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults); connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults);
connect(ui->ckWildcard, &QCheckBox::toggled, this, &UDSScanWindow::wildcardToggled); connect(ui->cbScanType, &QComboBox::currentTextChanged, this, &UDSScanWindow::changedScanType);
connect(ui->ckReadByAddr, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled);
connect(ui->ckReadByID, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled);
connect(ui->cbAllowAdaptiveOffset, &QCheckBox::toggled, this, &UDSScanWindow::adaptiveToggled); connect(ui->cbAllowAdaptiveOffset, &QCheckBox::toggled, this, &UDSScanWindow::adaptiveToggled);
connect(ui->spinNumBytes, SIGNAL(valueChanged(int)), this, SLOT(numBytesChanged())); connect(ui->spinNumBytes, SIGNAL(valueChanged(int)), this, SLOT(numBytesChanged()));
connect(ui->spinLowerService, SIGNAL(valueChanged(int)), this, SLOT(checkServiceRange())); 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->spinUpperSubfunc, SIGNAL(valueChanged(int)), this, SLOT(checkSubFuncRange()));
connect(ui->spinStartID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange())); connect(ui->spinStartID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange()));
connect(ui->spinEndID, 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(); int numBuses = CANConManager::getInstance()->getNumBuses();
for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n));
installEventFilter(this); installEventFilter(this);
addNewScan();
} }
UDSScanWindow::~UDSScanWindow() UDSScanWindow::~UDSScanWindow()
@@ -71,74 +109,368 @@ bool UDSScanWindow::eventFilter(QObject *obj, QEvent *event)
return false; 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() void UDSScanWindow::adaptiveToggled()
{ {
if (inhibitUpdates) return;
if (ui->cbAllowAdaptiveOffset->isChecked()) ui->spinReplyOffset->setEnabled(false); if (ui->cbAllowAdaptiveOffset->isChecked()) ui->spinReplyOffset->setEnabled(false);
else ui->spinReplyOffset->setEnabled(true); else ui->spinReplyOffset->setEnabled(true);
if (currEditEntry) currEditEntry->bAdaptiveOffset = ui->cbAllowAdaptiveOffset->isChecked();
} }
void UDSScanWindow::wildcardToggled() void UDSScanWindow::setSessType()
{ {
bool state = false; if (inhibitUpdates) return;
if (ui->ckWildcard->isChecked()) state = false; if (currEditEntry) currEditEntry->sessType = ui->cbSessType->currentIndex();
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);
} }
void UDSScanWindow::readByToggled() void UDSScanWindow::setNoReplyVal()
{ {
bool state = false; if (inhibitUpdates) return;
if (ui->ckReadByAddr->isChecked() || ui->ckReadByID->isChecked()) state = true; if (currEditEntry) currEditEntry->bShowNoReplies = ui->ckShowNoReply->isChecked();
else state = false; }
ui->spinLowerService->setEnabled(false); void UDSScanWindow::setMaxDelayVal()
ui->spinLowerSubfunc->setEnabled(state); {
ui->spinNumBytes->setEnabled(state); if (inhibitUpdates) return;
ui->spinUpperService->setEnabled(false); if (currEditEntry) currEditEntry->maxWaitTime = ui->spinDelay->value();
ui->spinUpperSubfunc->setEnabled(state); }
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() void UDSScanWindow::numBytesChanged()
{ {
if (inhibitUpdates) return;
uint64_t upperBound = (1ull << (8ull * ui->spinNumBytes->value())) - 1; uint64_t upperBound = (1ull << (8ull * ui->spinNumBytes->value())) - 1;
if (upperBound > 0x7FFFFFFF) upperBound = 0x7FFFFFFF; if (upperBound > 0x7FFFFFFF) upperBound = 0x7FFFFFFF;
ui->spinUpperSubfunc->setMaximum(upperBound); ui->spinUpperSubfunc->setMaximum(upperBound);
if (currEditEntry) currEditEntry->subfunctLen = ui->spinNumBytes->value();
} }
void UDSScanWindow::checkIDRange() void UDSScanWindow::checkIDRange()
{ {
if (inhibitUpdates) return;
ui->spinStartID->setMaximum(ui->spinEndID->value()); ui->spinStartID->setMaximum(ui->spinEndID->value());
ui->spinEndID->setMinimum(ui->spinStartID->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() void UDSScanWindow::checkServiceRange()
{ {
if (inhibitUpdates) return;
ui->spinLowerService->setMaximum(ui->spinUpperService->value()); ui->spinLowerService->setMaximum(ui->spinUpperService->value());
ui->spinUpperService->setMinimum(ui->spinLowerService->value()); ui->spinUpperService->setMinimum(ui->spinLowerService->value());
if (currEditEntry) currEditEntry->serviceLower = ui->spinLowerService->value();
if (currEditEntry) currEditEntry->serviceUpper = ui->spinUpperService->value();
} }
void UDSScanWindow::checkSubFuncRange() void UDSScanWindow::checkSubFuncRange()
{ {
if (inhibitUpdates) return;
ui->spinLowerSubfunc->setMaximum(ui->spinUpperSubfunc->value()); ui->spinLowerSubfunc->setMaximum(ui->spinUpperSubfunc->value());
ui->spinUpperSubfunc->setMinimum(ui->spinLowerSubfunc->value()); ui->spinUpperSubfunc->setMinimum(ui->spinLowerSubfunc->value());
if (currEditEntry) currEditEntry->subfunctLower = ui->spinLowerSubfunc->value();
if (currEditEntry) currEditEntry->subfunctUpper = ui->spinUpperSubfunc->value();
} }
void UDSScanWindow::saveResults() void UDSScanWindow::saveResults()
@@ -196,20 +528,27 @@ void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses)
sendingFrames.append(test); sendingFrames.append(test);
} }
void UDSScanWindow::scanUDS() void UDSScanWindow::scanAll()
{ {
if (currentlyRunning) sendingFrames.clear();
for (int i = 0; i < scanEntries.count(); i++)
{ {
waitTimer->stop(); setupScan(i);
sendingFrames.clear();
udsHandler->setReception(false);
udsHandler->setProcessAllIDs(false);
udsHandler->setFlowCtrl(false);
currentlyRunning = false;
ui->btnScan->setText("Start Scan");
return;
} }
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->setReception(true);
udsHandler->setProcessAllIDs(true); udsHandler->setProcessAllIDs(true);
udsHandler->setFlowCtrl(true); udsHandler->setFlowCtrl(true);
@@ -217,121 +556,173 @@ void UDSScanWindow::scanUDS()
waitTimer->setInterval(ui->spinDelay->value()); waitTimer->setInterval(ui->spinDelay->value());
ui->treeResults->clear(); ui->treeResults->clear();
sendingFrames.clear();
nodeService = nullptr; nodeService = nullptr;
nodeID = nullptr; nodeID = nullptr;
nodeSubFunc = 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(); waitTimer->start();
currIdx = -1; currIdx = -1;
currentlyRunning = true; currentlyRunning = true;
ui->btnScan->setText("Abort Scan"); //ui->btnScan->setText("Abort Scan");
ui->progressBar->setValue(0); ui->progressBar->setValue(0);
ui->progressBar->setMaximum(sendingFrames.length()); ui->progressBar->setMaximum(sendingFrames.length());
qDebug() << "Number of operations: " << sendingFrames.length();
sendNextMsg(); 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. //Updates here are sent about every 1/4 second. That's fine for most windows but not this one.
void UDSScanWindow::updatedFrames(int numFrames) void UDSScanWindow::updatedFrames(int numFrames)
{ {
@@ -491,7 +882,7 @@ void UDSScanWindow::sendNextMsg()
udsHandler->setReception(false); udsHandler->setReception(false);
udsHandler->setProcessAllIDs(false); udsHandler->setProcessAllIDs(false);
udsHandler->setFlowCtrl(false); udsHandler->setFlowCtrl(false);
ui->btnScan->setText("Start Scan"); //ui->btnScan->setText("Start Scan");
currentlyRunning = false; currentlyRunning = false;
} }
ui->progressBar->setValue(currIdx); ui->progressBar->setValue(currIdx);
+58 -3
View File
@@ -9,6 +9,44 @@
#include <QFile> #include <QFile>
#include <QTreeWidget> #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 { namespace Ui {
class UDSScanWindow; class UDSScanWindow;
} }
@@ -24,16 +62,25 @@ public:
private slots: private slots:
void updatedFrames(int numFrames); void updatedFrames(int numFrames);
void gotUDSReply(UDS_MESSAGE msg); void gotUDSReply(UDS_MESSAGE msg);
void scanUDS(); void scanAll();
void scanSelected();
void saveResults(); void saveResults();
void timeOut(); void timeOut();
void adaptiveToggled(); void adaptiveToggled();
void wildcardToggled(); void changedScanType();
void readByToggled();
void numBytesChanged(); void numBytesChanged();
void checkIDRange(); void checkIDRange();
void checkServiceRange(); void checkServiceRange();
void checkSubFuncRange(); void checkSubFuncRange();
void deleteSelectedScan();
void addNewScan();
void loadScans();
void saveScans();
void setNoReplyVal();
void setMaxDelayVal();
void setIncrementVal();
void setReplyOffset();
void setSessType();
private: private:
Ui::UDSScanWindow *ui; Ui::UDSScanWindow *ui;
@@ -44,9 +91,17 @@ private:
QTreeWidgetItem *nodeID; QTreeWidgetItem *nodeID;
QTreeWidgetItem *nodeService; QTreeWidgetItem *nodeService;
QTreeWidgetItem *nodeSubFunc; QTreeWidgetItem *nodeSubFunc;
QVector<ScanEntry> scanEntries;
ScanEntry *currEditEntry;
int currIdx = 0; int currIdx = 0;
bool currentlyRunning; bool currentlyRunning;
bool inhibitUpdates;
void displayScanEntry(int idx);
QString generateListDesc(int idx);
void setupScan(int idx);
void startScan();
void stopScan();
void sendNextMsg(); void sendNextMsg();
void sendOnBuses(UDS_MESSAGE frame, int buses); void sendOnBuses(UDS_MESSAGE frame, int buses);
void setupNodes(uint32_t replyID); void setupNodes(uint32_t replyID);
+62 -22
View File
@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>356</width> <width>426</width>
<height>282</height> <height>540</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -23,6 +23,30 @@
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="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"> <item row="0" column="0">
<widget class="QRadioButton" name="rbGVRET"> <widget class="QRadioButton" name="rbGVRET">
<property name="text"> <property name="text">
@@ -40,27 +64,10 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QRadioButton" name="rbSocketCAN"> <widget class="QRadioButton" name="rbLawicel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>QT SerialBus Devices (SocketCAN, PeakCAN, etc)</string> <string>LAWICEL / SLCAN Serial</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>
</property> </property>
</widget> </widget>
</item> </item>
@@ -109,6 +116,39 @@
</property> </property>
</widget> </widget>
</item> </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> <item>
<widget class="QPushButton" name="btnOK"> <widget class="QPushButton" name="btnOK">
<property name="text"> <property name="text">
+411 -322
View File
@@ -6,61 +6,346 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>742</width> <width>1053</width>
<height>628</height> <height>624</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>UDS Scanner</string> <string>UDS Scanner</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="1,5">
<item> <item>
<widget class="QLabel" name="label_2"> <layout class="QVBoxLayout" name="verticalLayout">
<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">
<item> <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> <item>
<widget class="QLabel" name="label_4"> <widget class="QPushButton" name="btnAdd">
<property name="text"> <property name="text">
<string>Starting ID</string> <string>Add</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QSpinBox" name="spinStartID"> <widget class="QPushButton" name="btnDelete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QPushButton" name="btnLoad">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Starting ID</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinStartID">
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>536870911</number>
</property>
<property name="value">
<number>2016</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Ending ID</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinEndID">
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>536870911</number>
</property>
<property name="value">
<number>2023</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="ckShowNoReply">
<property name="text">
<string>Show &quot;No Reply&quot;</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbAllowAdaptiveOffset">
<property name="text">
<string>Allow adaptive reply offset</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Bus to scan</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbBuses"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Maximum reply delay (ms)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinDelay">
<property name="minimum">
<number>50</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Reply Offset:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinReplyOffset">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>-128</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbScanType">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>Run test in session type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSessType">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Subfunct Len:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinNumBytes">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>4</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Lower Bound:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinLowerSubfunc">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix"> <property name="prefix">
<string>0x</string> <string>0x</string>
</property> </property>
<property name="maximum"> <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>
<property name="value"> <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>
<property name="displayIntegerBase"> <property name="displayIntegerBase">
<number>16</number> <number>16</number>
@@ -70,24 +355,50 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_6">
<item> <item>
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_11">
<property name="text"> <property name="text">
<string>Ending ID</string> <string>Lower Service:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QSpinBox" name="spinEndID"> <widget class="QSpinBox" name="spinLowerService">
<property name="enabled">
<bool>false</bool>
</property>
<property name="prefix"> <property name="prefix">
<string>0x</string> <string>0x</string>
</property> </property>
<property name="maximum"> <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>
<property name="value"> <property name="value">
<number>2023</number> <number>255</number>
</property> </property>
<property name="displayIntegerBase"> <property name="displayIntegerBase">
<number>16</number> <number>16</number>
@@ -97,323 +408,101 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="ckShowNoReply"> <widget class="Line" name="line">
<property name="text"> <property name="minimumSize">
<string>Show Tests with no Replies</string> <size>
<width>0</width>
<height>20</height>
</size>
</property> </property>
<property name="checked"> <property name="frameShadow">
<bool>true</bool> <enum>QFrame::Plain</enum>
</property> </property>
</widget> <property name="lineWidth">
</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">
<number>4</number> <number>4</number>
</property> </property>
<property name="value"> <property name="orientation">
<number>1</number> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Lower Bound:</string> <string>Results</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<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"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="prefix"> <property name="value">
<string>0x</string> <number>0</number>
</property> </property>
<property name="maximum"> <property name="textVisible">
<number>255</number> <bool>true</bool>
</property> </property>
<property name="displayIntegerBase"> <property name="invertedAppearance">
<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> <bool>false</bool>
</property> </property>
<property name="prefix"> </widget>
<string>0x</string> </item>
</property> <item>
<property name="maximum"> <layout class="QHBoxLayout" name="horizontalLayout_8">
<number>255</number> <item>
</property> <widget class="QPushButton" name="btnScanAll">
<property name="value"> <property name="text">
<number>255</number> <string>Run All Scans</string>
</property> </property>
<property name="displayIntegerBase"> </widget>
<number>16</number> </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> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</item> </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> </layout>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>spinStartID</tabstop> <tabstop>spinStartID</tabstop>
<tabstop>spinEndID</tabstop> <tabstop>spinEndID</tabstop>
<tabstop>ckShowNoReply</tabstop>
<tabstop>spinReplyOffset</tabstop>
<tabstop>cbAllowAdaptiveOffset</tabstop>
<tabstop>cbBuses</tabstop> <tabstop>cbBuses</tabstop>
<tabstop>spinDelay</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>spinLowerService</tabstop>
<tabstop>spinUpperService</tabstop> <tabstop>spinUpperService</tabstop>
<tabstop>spinNumBytes</tabstop> <tabstop>spinNumBytes</tabstop>
<tabstop>spinLowerSubfunc</tabstop> <tabstop>spinLowerSubfunc</tabstop>
<tabstop>spinUpperSubfunc</tabstop> <tabstop>spinUpperSubfunc</tabstop>
<tabstop>btnScan</tabstop>
<tabstop>treeResults</tabstop>
<tabstop>btnSaveResults</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections/> <connections/>
+37 -3
View File
@@ -146,6 +146,11 @@ public:
return output; return output;
} }
static QString formatByteAsHex(uint8_t value)
{
return QString::number(value, 16).toUpper().rightJustified(2,'0');
}
static QVariant formatTimestamp(uint64_t timestamp) static QVariant formatTimestamp(uint64_t timestamp)
{ {
if (!sysTimeMode) { if (!sysTimeMode) {
@@ -200,17 +205,44 @@ public:
return (value1 * (1.0 - samplePoint)) + (value2 * samplePoint); 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) static int64_t processIntegerSignal(const QByteArray data, int startBit, int sigSize, bool littleEndian, bool isSigned)
{ {
int64_t result = 0; uint64_t result = 0;
int bit; int bit = 0;
int maxBytes = (startBit + sigSize) / 8; 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) 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; bit = startBit;
for (int bitpos = 0; bitpos < sigSize; bitpos++) for (int bitpos = 0; bitpos < sigSize; bitpos++)
{ {
@@ -222,6 +254,7 @@ public:
} }
bit++; bit++;
} }
} }
else //motorola / big endian mode else //motorola / big endian mode
{ {
@@ -266,6 +299,7 @@ public:
*/ */
uint64_t signedMask = ~((1ULL << sigSize) - 1); uint64_t signedMask = ~((1ULL << sigSize) - 1);
result = (-1LL & signedMask) | result; result = (-1LL & signedMask) | result;
return (int64_t)(result);
} }
} }