adding socketcand support
This commit is contained in:
+3
-1
@@ -51,6 +51,7 @@ SOURCES += main.cpp\
|
|||||||
connections/serialbusconnection.cpp \
|
connections/serialbusconnection.cpp \
|
||||||
connections/canconfactory.cpp \
|
connections/canconfactory.cpp \
|
||||||
connections/gvretserial.cpp \
|
connections/gvretserial.cpp \
|
||||||
|
connections/socketcand.cpp \
|
||||||
connections/canconmanager.cpp \
|
connections/canconmanager.cpp \
|
||||||
re/sniffer/snifferitem.cpp \
|
re/sniffer/snifferitem.cpp \
|
||||||
re/sniffer/sniffermodel.cpp \
|
re/sniffer/sniffermodel.cpp \
|
||||||
@@ -91,7 +92,8 @@ SOURCES += main.cpp\
|
|||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
can_structs.h \
|
can_structs.h \
|
||||||
canframemodel.h \ \
|
canframemodel.h \
|
||||||
|
connections/socketcand.h \
|
||||||
connections/mqtt_bus.h \
|
connections/mqtt_bus.h \
|
||||||
mqtt/qmqtt.h \
|
mqtt/qmqtt.h \
|
||||||
mqtt/qmqtt_client.h \
|
mqtt/qmqtt_client.h \
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace CANCon {
|
|||||||
KVASER,
|
KVASER,
|
||||||
SERIALBUS,
|
SERIALBUS,
|
||||||
REMOTE,
|
REMOTE,
|
||||||
|
KAYAK,
|
||||||
MQTT,
|
MQTT,
|
||||||
NONE
|
NONE
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "serialbusconnection.h"
|
#include "serialbusconnection.h"
|
||||||
#include "gvretserial.h"
|
#include "gvretserial.h"
|
||||||
#include "mqtt_bus.h"
|
#include "mqtt_bus.h"
|
||||||
|
#include "socketcand.h"
|
||||||
|
|
||||||
using namespace CANCon;
|
using namespace CANCon;
|
||||||
|
|
||||||
@@ -15,6 +16,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 KAYAK:
|
||||||
|
return new SocketCANd(pPortName);
|
||||||
case MQTT:
|
case MQTT:
|
||||||
return new MQTT_BUS(pPortName);
|
return new MQTT_BUS(pPortName);
|
||||||
default: {}
|
default: {}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
#include "canconmanager.h"
|
#include "canconmanager.h"
|
||||||
#include "canconfactory.h"
|
#include "canconfactory.h"
|
||||||
@@ -228,6 +229,7 @@ bool CANConManager::sendFrame(const CANFrame& pFrame)
|
|||||||
//workingFrame.timestamp -= mTimestampBasis;
|
//workingFrame.timestamp -= mTimestampBasis;
|
||||||
}
|
}
|
||||||
txFrame = conn->getQueue().get();
|
txFrame = conn->getQueue().get();
|
||||||
|
QCoreApplication::processEvents();
|
||||||
*txFrame = workingFrame;
|
*txFrame = workingFrame;
|
||||||
conn->getQueue().queue();
|
conn->getQueue().queue();
|
||||||
return conn->sendFrame(workingFrame);
|
return conn->sendFrame(workingFrame);
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
|
|||||||
case CANCon::KVASER: return "KVASER";
|
case CANCon::KVASER: return "KVASER";
|
||||||
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";
|
||||||
default: {}
|
default: {}
|
||||||
}
|
}
|
||||||
else qDebug() << "Tried to show connection type but connection was nullptr";
|
else qDebug() << "Tried to show connection type but connection was nullptr";
|
||||||
|
|||||||
@@ -69,12 +69,17 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
|||||||
ui->cbBusSpeed->addItem("500000");
|
ui->cbBusSpeed->addItem("500000");
|
||||||
ui->cbBusSpeed->addItem("1000000");
|
ui->cbBusSpeed->addItem("1000000");
|
||||||
|
|
||||||
rxBroadcast = new QUdpSocket(this);
|
rxBroadcastGVRET = new QUdpSocket(this);
|
||||||
//Need to make sure it tries to share the address in case there are
|
//Need to make sure it tries to share the address in case there are
|
||||||
//multiple instances of SavvyCAN running.
|
//multiple instances of SavvyCAN running.
|
||||||
rxBroadcast->bind(QHostAddress::Any, 17222, QAbstractSocket::ShareAddress);
|
rxBroadcastGVRET->bind(QHostAddress::AnyIPv4, 17222, QAbstractSocket::ShareAddress);
|
||||||
|
|
||||||
connect(rxBroadcast, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
connect(rxBroadcastGVRET, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
||||||
|
|
||||||
|
//Doing the same for socketcand/kayak hosts:
|
||||||
|
rxBroadcastKayak = new QUdpSocket(this);
|
||||||
|
rxBroadcastKayak->bind(QHostAddress::AnyIPv4, 42000, QAbstractSocket::ShareAddress);
|
||||||
|
connect(rxBroadcastKayak, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,12 +87,56 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
|||||||
void ConnectionWindow::readPendingDatagrams()
|
void ConnectionWindow::readPendingDatagrams()
|
||||||
{
|
{
|
||||||
//qDebug() << "Got a UDP frame!";
|
//qDebug() << "Got a UDP frame!";
|
||||||
while (rxBroadcast->hasPendingDatagrams()) {
|
while (rxBroadcastGVRET->hasPendingDatagrams()) {
|
||||||
QNetworkDatagram datagram = rxBroadcast->receiveDatagram();
|
QNetworkDatagram datagram = rxBroadcastGVRET->receiveDatagram();
|
||||||
if (!remoteDeviceIP.contains(datagram.senderAddress().toString()))
|
if (!remoteDeviceIPGVRET.contains(datagram.senderAddress().toString()))
|
||||||
{
|
{
|
||||||
remoteDeviceIP.append(datagram.senderAddress().toString());
|
remoteDeviceIPGVRET.append(datagram.senderAddress().toString());
|
||||||
qDebug() << "Add new remote IP " << datagram.senderAddress().toString();
|
//qDebug() << "Add new remote IP " << datagram.senderAddress().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (rxBroadcastKayak->hasPendingDatagrams()) {
|
||||||
|
QNetworkDatagram datagram = rxBroadcastKayak->receiveDatagram();
|
||||||
|
//qDebug() << "Broadcast Datagram: " << QString::fromUtf8(datagram.data());
|
||||||
|
QXmlStreamReader CANBeaconXml(QString::fromUtf8(datagram.data()));
|
||||||
|
QString KayakHost;
|
||||||
|
QString KayakBus;
|
||||||
|
while(!CANBeaconXml.atEnd() && !CANBeaconXml.hasError())
|
||||||
|
{
|
||||||
|
CANBeaconXml.readNext();
|
||||||
|
if(CANBeaconXml.name() == "CANBeacon" && !CANBeaconXml.isEndElement())
|
||||||
|
KayakHost.append(CANBeaconXml.attributes().value("name"));
|
||||||
|
|
||||||
|
if(CANBeaconXml.name() == "URL")
|
||||||
|
KayakHost.append(" (" + CANBeaconXml.readElementText() + ')');
|
||||||
|
|
||||||
|
//Kayak can theoretically send multiple busses over one ports
|
||||||
|
//TODO: implement this case in socketcand.cpp
|
||||||
|
if(CANBeaconXml.name() == "Bus" && !CANBeaconXml.isEndElement())
|
||||||
|
KayakBus.append(CANBeaconXml.attributes().value("name") + ",");
|
||||||
|
|
||||||
|
}
|
||||||
|
KayakHost = KayakBus.left(KayakBus.length() - 1) + "@" + KayakHost;
|
||||||
|
|
||||||
|
QVector<QString> connectedPorts;
|
||||||
|
if (connModel->rowCount() > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < connModel->rowCount(); i++)
|
||||||
|
{
|
||||||
|
CANConnection *var_conn = connModel->getAtIdx(i);
|
||||||
|
connectedPorts.append(var_conn->getPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectedPorts.contains(KayakHost))
|
||||||
|
{
|
||||||
|
remoteDeviceKayak.removeOne(KayakHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!remoteDeviceKayak.contains(KayakHost) && !connectedPorts.contains(KayakHost))
|
||||||
|
{
|
||||||
|
remoteDeviceKayak.append(KayakHost);
|
||||||
|
//qDebug() << "Add new remote IP " << datagram.senderAddress().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +242,7 @@ void ConnectionWindow::consoleEnableChanged(bool checked) {
|
|||||||
|
|
||||||
void ConnectionWindow::handleNewConn()
|
void ConnectionWindow::handleNewConn()
|
||||||
{
|
{
|
||||||
NewConnectionDialog *thisDialog = new NewConnectionDialog(&remoteDeviceIP);
|
NewConnectionDialog *thisDialog = new NewConnectionDialog(&remoteDeviceIPGVRET, &remoteDeviceKayak);
|
||||||
CANCon::type newType;
|
CANCon::type newType;
|
||||||
QString newPort;
|
QString newPort;
|
||||||
QString newDriver;
|
QString newDriver;
|
||||||
|
|||||||
@@ -60,8 +60,10 @@ private:
|
|||||||
Ui::ConnectionWindow *ui;
|
Ui::ConnectionWindow *ui;
|
||||||
QSettings *settings;
|
QSettings *settings;
|
||||||
CANConnectionModel *connModel;
|
CANConnectionModel *connModel;
|
||||||
QUdpSocket *rxBroadcast;
|
QUdpSocket *rxBroadcastGVRET;
|
||||||
QVector<QString> remoteDeviceIP;
|
QUdpSocket *rxBroadcastKayak;
|
||||||
|
QVector<QString> remoteDeviceIPGVRET;
|
||||||
|
QVector<QString> remoteDeviceKayak;
|
||||||
|
|
||||||
CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver);
|
CANConnection* create(CANCon::type pTye, QString pPortName, QString pDriver);
|
||||||
void populateBusDetails(int offset);
|
void populateBusDetails(int offset);
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
#include "newconnectiondialog.h"
|
#include "newconnectiondialog.h"
|
||||||
#include "ui_newconnectiondialog.h"
|
#include "ui_newconnectiondialog.h"
|
||||||
|
|
||||||
NewConnectionDialog::NewConnectionDialog(QVector<QString>* ips, QWidget *parent) :
|
NewConnectionDialog::NewConnectionDialog(QVector<QString>* gvretips, QVector<QString>* kayakhosts, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::NewConnectionDialog),
|
ui(new Ui::NewConnectionDialog),
|
||||||
remoteDeviceIP(ips)
|
remoteDeviceIPGVRET(gvretips),
|
||||||
|
remoteBusKayak(kayakhosts)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
if (isSerialBusAvailable())
|
if (isSerialBusAvailable())
|
||||||
{
|
{
|
||||||
ui->rbSocketCAN->setEnabled(true);
|
ui->rbSocketCAN->setEnabled(true);
|
||||||
@@ -25,6 +25,7 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* ips, QWidget *parent)
|
|||||||
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
|
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
|
||||||
connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
|
connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
|
||||||
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->rbMQTT, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
|
connect(ui->rbMQTT, &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);
|
||||||
@@ -34,7 +35,8 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* ips, QWidget *parent)
|
|||||||
ui->cbDeviceType->setHidden(true);
|
ui->cbDeviceType->setHidden(true);
|
||||||
selectSerial();
|
selectSerial();
|
||||||
|
|
||||||
qDebug() << "Was passed " << remoteDeviceIP->count() << " remote IPs";
|
qDebug() << "Was passed " << remoteDeviceIPGVRET->count() << " remote GVRET IPs";
|
||||||
|
qDebug() << "Was passed " << remoteBusKayak->count() << " remote Kayak Busses";
|
||||||
}
|
}
|
||||||
|
|
||||||
NewConnectionDialog::~NewConnectionDialog()
|
NewConnectionDialog::~NewConnectionDialog()
|
||||||
@@ -52,6 +54,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->rbRemote->isChecked()) selectRemote();
|
if (ui->rbRemote->isChecked()) selectRemote();
|
||||||
|
if (ui->rbKayak->isChecked()) selectKayak();
|
||||||
if (ui->rbMQTT->isChecked()) selectMQTT();
|
if (ui->rbMQTT->isChecked()) selectMQTT();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +102,19 @@ void NewConnectionDialog::selectRemote()
|
|||||||
ui->lblDeviceType->setHidden(true);
|
ui->lblDeviceType->setHidden(true);
|
||||||
ui->cbDeviceType->setHidden(true);
|
ui->cbDeviceType->setHidden(true);
|
||||||
ui->cbPort->clear();
|
ui->cbPort->clear();
|
||||||
foreach(QString pName, *remoteDeviceIP)
|
foreach(QString pName, *remoteDeviceIPGVRET)
|
||||||
|
{
|
||||||
|
ui->cbPort->addItem(pName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewConnectionDialog::selectKayak()
|
||||||
|
{
|
||||||
|
ui->lPort->setText("Available Bus(ses):");
|
||||||
|
ui->lblDeviceType->setHidden(true);
|
||||||
|
ui->cbDeviceType->setHidden(true);
|
||||||
|
ui->cbPort->clear();
|
||||||
|
foreach(QString pName, *remoteBusKayak)
|
||||||
{
|
{
|
||||||
ui->cbPort->addItem(pName);
|
ui->cbPort->addItem(pName);
|
||||||
}
|
}
|
||||||
@@ -127,6 +142,9 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
|
|||||||
case CANCon::REMOTE:
|
case CANCon::REMOTE:
|
||||||
ui->rbRemote->setChecked(true);
|
ui->rbRemote->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
case CANCon::KAYAK:
|
||||||
|
ui->rbKayak->setChecked(true);
|
||||||
|
break;
|
||||||
case CANCon::MQTT:
|
case CANCon::MQTT:
|
||||||
ui->rbMQTT->setChecked(true);
|
ui->rbMQTT->setChecked(true);
|
||||||
break;
|
break;
|
||||||
@@ -162,6 +180,13 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
|
|||||||
else ui->cbPort->addItem(pPortName);
|
else ui->cbPort->addItem(pPortName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CANCon::KAYAK:
|
||||||
|
{
|
||||||
|
int idx = ui->cbPort->findText(pPortName);
|
||||||
|
if (idx > -1) ui->cbPort->setCurrentIndex(idx);
|
||||||
|
else ui->cbPort->addItem(pPortName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CANCon::MQTT:
|
case CANCon::MQTT:
|
||||||
ui->cbPort->setCurrentText(pPortName);
|
ui->cbPort->setCurrentText(pPortName);
|
||||||
break;
|
break;
|
||||||
@@ -177,6 +202,8 @@ QString NewConnectionDialog::getPortName()
|
|||||||
case CANCon::REMOTE:
|
case CANCon::REMOTE:
|
||||||
case CANCon::MQTT:
|
case CANCon::MQTT:
|
||||||
return ui->cbPort->currentText();
|
return ui->cbPort->currentText();
|
||||||
|
case CANCon::KAYAK:
|
||||||
|
return ui->cbPort->currentText();
|
||||||
default:
|
default:
|
||||||
qDebug() << "getPortName: can't get port";
|
qDebug() << "getPortName: can't get port";
|
||||||
}
|
}
|
||||||
@@ -198,6 +225,7 @@ CANCon::type NewConnectionDialog::getConnectionType()
|
|||||||
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
|
if (ui->rbGVRET->isChecked()) return CANCon::GVRET_SERIAL;
|
||||||
if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS;
|
if (ui->rbSocketCAN->isChecked()) return CANCon::SERIALBUS;
|
||||||
if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
|
if (ui->rbRemote->isChecked()) return CANCon::REMOTE;
|
||||||
|
if (ui->rbKayak->isChecked()) return CANCon::KAYAK;
|
||||||
if (ui->rbMQTT->isChecked()) return CANCon::MQTT;
|
if (ui->rbMQTT->isChecked()) return CANCon::MQTT;
|
||||||
qDebug() << "getConnectionType: error";
|
qDebug() << "getConnectionType: error";
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class NewConnectionDialog : public QDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit NewConnectionDialog(QVector<QString>* ips, QWidget *parent = nullptr);
|
explicit NewConnectionDialog(QVector<QString>* gvretips, QVector<QString>* kayakips, QWidget *parent = nullptr);
|
||||||
~NewConnectionDialog();
|
~NewConnectionDialog();
|
||||||
|
|
||||||
CANCon::type getConnectionType();
|
CANCon::type getConnectionType();
|
||||||
@@ -34,12 +34,14 @@ private:
|
|||||||
Ui::NewConnectionDialog *ui;
|
Ui::NewConnectionDialog *ui;
|
||||||
QList<QSerialPortInfo> ports;
|
QList<QSerialPortInfo> ports;
|
||||||
QList<QCanBusDeviceInfo> canDevices;
|
QList<QCanBusDeviceInfo> canDevices;
|
||||||
QVector<QString>* remoteDeviceIP;
|
QVector<QString>* remoteDeviceIPGVRET;
|
||||||
|
QVector<QString>* remoteBusKayak;
|
||||||
|
|
||||||
void selectSerial();
|
void selectSerial();
|
||||||
void selectKvaser();
|
void selectKvaser();
|
||||||
void selectSocketCan();
|
void selectSocketCan();
|
||||||
void selectRemote();
|
void selectRemote();
|
||||||
|
void selectKayak();
|
||||||
void selectMQTT();
|
void selectMQTT();
|
||||||
bool isSerialBusAvailable();
|
bool isSerialBusAvailable();
|
||||||
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
|
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
|
||||||
|
|||||||
@@ -0,0 +1,393 @@
|
|||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QCanBusFrame>
|
||||||
|
#include <QSerialPortInfo>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
#include <QtNetwork>
|
||||||
|
#include <QMetaObject>
|
||||||
|
|
||||||
|
#include "socketcand.h"
|
||||||
|
|
||||||
|
SocketCANd::SocketCANd(QString portName) :
|
||||||
|
CANConnection(portName, "kayak", CANCon::KAYAK, 1, 4000, true),
|
||||||
|
mTimer(this) /*NB: set this as parent of timer to manage it from working thread */
|
||||||
|
{
|
||||||
|
|
||||||
|
mTimer.setInterval(10000); //tick every 10 seconds
|
||||||
|
mTimer.setSingleShot(false); //keep ticking
|
||||||
|
connect(&mTimer, SIGNAL(timeout()), this, SLOT(checkConnection()));
|
||||||
|
|
||||||
|
sendDebug("SocketCANd()");
|
||||||
|
//tcpClient = nullptr;
|
||||||
|
hostCanIDs = portName.left(portName.indexOf("@")).split(',');
|
||||||
|
QString hostIPandPort = portName.mid(portName.indexOf("can://")+6, portName.length() - portName.indexOf("can://") - 7); //7 is lenght of 'can://' and ')'
|
||||||
|
hostIP = QHostAddress(hostIPandPort.left(hostIPandPort.indexOf(":")));
|
||||||
|
hostPort = (hostIPandPort.right(hostIPandPort.length() - hostIPandPort.lastIndexOf(":") -1)).toInt();
|
||||||
|
QVarLengthArray<QTcpSocket*> tcpClient(0);
|
||||||
|
mNumBuses = hostCanIDs.length();
|
||||||
|
mBusData.resize(mNumBuses);
|
||||||
|
reconnecting = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < mNumBuses; i++)
|
||||||
|
{
|
||||||
|
rx_state.append(IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SocketCANd::~SocketCANd()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
sendDebug("~SocketCANd()");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::sendDebug(const QString debugText)
|
||||||
|
{
|
||||||
|
qDebug() << debugText;
|
||||||
|
debugOutput(debugText);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::sendBytesToTCP(const QByteArray &bytes, int busNum)
|
||||||
|
{
|
||||||
|
if (tcpClient[busNum] && !tcpClient[busNum]->isOpen())
|
||||||
|
{
|
||||||
|
sendDebug("Attempt to write to TCP/IP port when it is not open!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString buildDebug;
|
||||||
|
buildDebug = "Send data to " + hostIP.toString() + ":" + QString::number(hostPort) + " -> ";
|
||||||
|
foreach (int byt, bytes) {
|
||||||
|
byt = (unsigned char)byt;
|
||||||
|
buildDebug = buildDebug % QString::number(byt, 16) % " ";
|
||||||
|
}
|
||||||
|
sendDebug(buildDebug);
|
||||||
|
|
||||||
|
if (tcpClient[busNum]) tcpClient[busNum]->write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::sendStringToTCP(const char* data, int busNum)
|
||||||
|
{
|
||||||
|
if (tcpClient[busNum] && !tcpClient[busNum]->isOpen())
|
||||||
|
{
|
||||||
|
sendDebug("Attempt to write to TCP/IP port when it is not open!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString buildDebug;
|
||||||
|
buildDebug = "Send data to " + hostIP.toString() + ":" + QString::number(hostPort) + " -> " + data;
|
||||||
|
sendDebug(buildDebug);
|
||||||
|
//qInfo() << buildDebug;
|
||||||
|
|
||||||
|
if (tcpClient[busNum]) tcpClient[busNum]->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::piStarted()
|
||||||
|
{
|
||||||
|
connectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketCANd::piSuspend(bool pSuspend)
|
||||||
|
{
|
||||||
|
/* update capSuspended */
|
||||||
|
setCapSuspended(pSuspend);
|
||||||
|
|
||||||
|
/* flush queue if we are suspended */
|
||||||
|
if(isCapSuspended())
|
||||||
|
getQueue().flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketCANd::piStop()
|
||||||
|
{
|
||||||
|
mTimer.stop();
|
||||||
|
disconnectDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SocketCANd::piGetBusSettings(int pBusIdx, CANBus& pBus)
|
||||||
|
{
|
||||||
|
return getBusConfig(pBusIdx, pBus);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketCANd::piSetBusSettings(int pBusIdx, CANBus bus)
|
||||||
|
{
|
||||||
|
setBusConfig(pBusIdx, bus);
|
||||||
|
bus.setSpeed(250000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SocketCANd::piSendFrame(const CANFrame& frame)
|
||||||
|
{
|
||||||
|
QByteArray buffer;
|
||||||
|
int c;
|
||||||
|
int ID;
|
||||||
|
|
||||||
|
// //calculate bus number offset (in case of multiple connections)
|
||||||
|
// //useless since SavvyCAN already delivers the right index in frame.bus
|
||||||
|
// QList<CANConnection*> connList = CANConManager::getInstance()->getConnections();
|
||||||
|
// int currentConnPos = connList.indexOf(this);
|
||||||
|
// int busOffset = 0;
|
||||||
|
// for (int i = 0; i < currentConnPos; i++)
|
||||||
|
// {
|
||||||
|
// busOffset += connList[i]->getNumBuses();
|
||||||
|
// }
|
||||||
|
// int busNum = frame.bus - busOffset;
|
||||||
|
|
||||||
|
int busNum = frame.bus;
|
||||||
|
|
||||||
|
framesRapid++;
|
||||||
|
|
||||||
|
if (tcpClient[busNum] && !tcpClient[busNum]->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 |= 1 << 31;
|
||||||
|
|
||||||
|
QString sendStr = "< send " + QString::number(ID, 16) + " " + QString::number(frame.payload().length()) + " ";
|
||||||
|
for (c = 0; c < frame.payload().length(); c++)
|
||||||
|
{
|
||||||
|
sendStr.append(QString::number(frame.payload()[c], 16) + " ");
|
||||||
|
}
|
||||||
|
sendStr.append(">");
|
||||||
|
std::string str = sendStr.toStdString();
|
||||||
|
const char* sendCmd = str.c_str();
|
||||||
|
sendStringToTCP(sendCmd, busNum);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
void SocketCANd::connectDevice()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
|
/* disconnect device */
|
||||||
|
/* avoiding this solution since it removes connection selection in case of connection check */
|
||||||
|
//if(tcpClient)
|
||||||
|
// disconnectDevice();
|
||||||
|
|
||||||
|
// only resetting tcpClient
|
||||||
|
for (int i = 0; i < tcpClient.length(); i++)
|
||||||
|
{
|
||||||
|
if (tcpClient[i])
|
||||||
|
{
|
||||||
|
if (tcpClient[i]->isOpen())
|
||||||
|
{
|
||||||
|
tcpClient[i]->close();
|
||||||
|
}
|
||||||
|
tcpClient[i]->disconnect();
|
||||||
|
delete tcpClient[i];
|
||||||
|
tcpClient[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcpClient.clear();
|
||||||
|
|
||||||
|
mTimer.start();
|
||||||
|
|
||||||
|
//sendDebug("TCP Connection to a Kayak device");
|
||||||
|
for (int i = 0; i < mNumBuses; i++)
|
||||||
|
{
|
||||||
|
rx_state[i] = IDLE;
|
||||||
|
tcpClient.append(new QTcpSocket());
|
||||||
|
tcpClient[i]->connectToHost(hostIP, hostPort);
|
||||||
|
//connect(tcpClient[i], SIGNAL(readyRead()), this, SLOT(readTCPData()));
|
||||||
|
connect(tcpClient[i], SIGNAL(readyRead()), this, SLOT(invokeReadTCPData()));
|
||||||
|
sendDebug("Created TCP Socket to Kayak device " + hostCanIDs.at(i));
|
||||||
|
}
|
||||||
|
setStatus(CANCon::CONNECTED);
|
||||||
|
CANConStatus stats;
|
||||||
|
stats.conStatus = getStatus();
|
||||||
|
stats.numHardwareBuses = mNumBuses;
|
||||||
|
//signalSender = qobject_cast<QTcpSocket*>(QObject::sender());
|
||||||
|
if (!reconnecting) emit status(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::deviceConnected(int busNum)
|
||||||
|
{
|
||||||
|
sendDebug("Opening CAN on Kayak Device!");
|
||||||
|
const char* openCanCmd = ("< open " + hostCanIDs[busNum] + " >").toStdString().c_str();
|
||||||
|
sendStringToTCP(openCanCmd, busNum);
|
||||||
|
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::checkConnection()
|
||||||
|
{
|
||||||
|
int bufSize = 0;
|
||||||
|
for (int i = 0; i < tcpClient.length(); i++)
|
||||||
|
{
|
||||||
|
bufSize += tcpClient[i]->readBufferSize();
|
||||||
|
//sendDebug("Buffer size: " + QString::number(bufSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufSize == 0)
|
||||||
|
{
|
||||||
|
reconnecting = true;
|
||||||
|
connectDevice();
|
||||||
|
sendDebug("Reconnecting to TCP Host " + hostIP.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::switchToRawMode(int busNum)
|
||||||
|
{
|
||||||
|
sendDebug("Switching to rawmode...");
|
||||||
|
const char* rawmodeCmd = "< rawmode >";
|
||||||
|
sendStringToTCP(rawmodeCmd, busNum);
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::decodeFrames(QString data, int busNum)
|
||||||
|
{
|
||||||
|
if (data.indexOf("< frame ") == -1)
|
||||||
|
{
|
||||||
|
qDebug() << "Received datagramm doesn't contain any frame: " << data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString framePart = data.mid(data.indexOf("< frame "), data.length()); //remove starting beginning of payload if not < frame >
|
||||||
|
const QString frameStrConst = framePart.left(framePart.indexOf(">")+1);
|
||||||
|
QString frameStr = frameStrConst;
|
||||||
|
QStringList frameParsed = (frameStr.remove(QRegExp("^<")).remove(QRegExp(">$"))).simplified().split(' ');
|
||||||
|
|
||||||
|
buildFrame.setFrameId(frameParsed[1].toUInt(nullptr, 16));
|
||||||
|
buildFrame.bus = busNum;
|
||||||
|
|
||||||
|
if (buildFrame.frameId() > 0x7FF) buildFrame.setExtendedFrameFormat(true);
|
||||||
|
else buildFrame.setExtendedFrameFormat(false);
|
||||||
|
|
||||||
|
buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, frameParsed[2].toDouble() * 1000000l));
|
||||||
|
//buildFrame.len = frameParsed[3].length() * 0.5;
|
||||||
|
int framelength = frameParsed[3].length() * 0.5;
|
||||||
|
|
||||||
|
buildData.resize(framelength);
|
||||||
|
|
||||||
|
int c;
|
||||||
|
for (c = 0; c < framelength; c++)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
unsigned char byteVal = frameParsed[3].mid(c*2, 2).toUInt(&ok, 16);
|
||||||
|
buildData[c] = byteVal;
|
||||||
|
}
|
||||||
|
buildFrame.setPayload(buildData);
|
||||||
|
// buildFrame.isReceived = true;
|
||||||
|
|
||||||
|
if (!isCapSuspended())
|
||||||
|
{
|
||||||
|
/* get frame from queue */
|
||||||
|
CANFrame* frame_p = getQueue().get();
|
||||||
|
if(frame_p) {
|
||||||
|
/* copy frame */
|
||||||
|
*frame_p = buildFrame;
|
||||||
|
//frame_p->remote = false;
|
||||||
|
frame_p->setFrameType(QCanBusFrame::DataFrame);
|
||||||
|
checkTargettedFrame(buildFrame);
|
||||||
|
/* enqueue frame */
|
||||||
|
getQueue().queue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
qDebug() << "can't get a frame, capture suspended";
|
||||||
|
|
||||||
|
if (framePart.length() > frameStrConst.length())
|
||||||
|
decodeFrames(framePart.right(framePart.length() - frameStrConst.length()), busNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::disconnectDevice() {
|
||||||
|
for (int i = 0; i < tcpClient.length(); i++)
|
||||||
|
{
|
||||||
|
if (tcpClient[i])
|
||||||
|
{
|
||||||
|
if (tcpClient[i]->isOpen())
|
||||||
|
{
|
||||||
|
tcpClient[i]->close();
|
||||||
|
}
|
||||||
|
tcpClient[i]->disconnect();
|
||||||
|
delete tcpClient[i];
|
||||||
|
tcpClient[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcpClient.clear();
|
||||||
|
|
||||||
|
setStatus(CANCon::NOT_CONNECTED);
|
||||||
|
CANConStatus stats;
|
||||||
|
stats.conStatus = getStatus();
|
||||||
|
stats.numHardwareBuses = mNumBuses;
|
||||||
|
emit status(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::invokeReadTCPData()
|
||||||
|
{
|
||||||
|
QTcpSocket* signalSender = qobject_cast<QTcpSocket*>(QObject::sender());
|
||||||
|
int busNum = tcpClient.indexOf(signalSender);
|
||||||
|
QMetaObject::invokeMethod(this, "readTCPData", Qt::QueuedConnection, Q_ARG(int, busNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketCANd::readTCPData(int busNum)
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
|
||||||
|
if (tcpClient[busNum]) data = tcpClient[busNum]->readAll();
|
||||||
|
//sendDebug("Got data from TCP. Len = " % QString::number(data.length()));
|
||||||
|
//qDebug() << "Received datagramm: " << data;
|
||||||
|
procRXData(data, busNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketCANd::procRXData(QString data, int busNum)
|
||||||
|
{
|
||||||
|
if (data != "")
|
||||||
|
{
|
||||||
|
mTimer.stop();
|
||||||
|
mTimer.start();
|
||||||
|
}
|
||||||
|
QByteArray output;
|
||||||
|
|
||||||
|
switch (rx_state.at(busNum))
|
||||||
|
{
|
||||||
|
case IDLE:
|
||||||
|
qDebug() << "Received datagramm: " << data;
|
||||||
|
if (data == "< hi >")
|
||||||
|
{
|
||||||
|
deviceConnected(busNum);
|
||||||
|
rx_state[busNum] = BCM;
|
||||||
|
}
|
||||||
|
else qInfo() << hostCanIDs[busNum] << ": Could not open bus. Host did not greet with ""< hi >"": " << data;
|
||||||
|
break;
|
||||||
|
case BCM:
|
||||||
|
qDebug() << "Received datagramm: " << data;
|
||||||
|
if (data == "< ok >")
|
||||||
|
{
|
||||||
|
switchToRawMode(busNum);
|
||||||
|
rx_state[busNum] = SWITCHING2RAW;
|
||||||
|
}
|
||||||
|
else qInfo() << hostCanIDs[busNum] << ": Could not open bus. Host did not respond with ""< ok >"": " << data;
|
||||||
|
break;
|
||||||
|
case SWITCHING2RAW:
|
||||||
|
qDebug() << "Received datagramm: " << data;
|
||||||
|
if (data == "< ok >")
|
||||||
|
{
|
||||||
|
rx_state[busNum] = RAWMODE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAWMODE:
|
||||||
|
decodeFrames(data, busNum);
|
||||||
|
break;
|
||||||
|
case ISOTP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#ifndef SOCKETCAND_H
|
||||||
|
#define SOCKETCAND_H
|
||||||
|
|
||||||
|
//#include <QSerialPort>
|
||||||
|
//#include <QCanBusDevice>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
//#include <QUdpSocket>
|
||||||
|
|
||||||
|
/*************/
|
||||||
|
#include <QDateTime>
|
||||||
|
/*************/
|
||||||
|
|
||||||
|
#include "canframemodel.h"
|
||||||
|
#include "canconnection.h"
|
||||||
|
#include "canconmanager.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace KAYAKSTATE {
|
||||||
|
|
||||||
|
enum MODE
|
||||||
|
{
|
||||||
|
IDLE, //NO_BUS in socketcand doc
|
||||||
|
BCM,
|
||||||
|
SWITCHING2RAW,
|
||||||
|
RAWMODE,
|
||||||
|
ISOTP
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace KAYAKSTATE;
|
||||||
|
class SocketCANd : public CANConnection
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SocketCANd(QString portName);
|
||||||
|
virtual ~SocketCANd();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void connectDevice();
|
||||||
|
void checkConnection();
|
||||||
|
void readTCPData(int busNum);
|
||||||
|
void invokeReadTCPData();
|
||||||
|
void deviceConnected(int busNum);
|
||||||
|
void switchToRawMode(int busNum);
|
||||||
|
void decodeFrames(QString, int busNum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void procRXData(QString, int busNum);
|
||||||
|
void sendBytesToTCP(const QByteArray &bytes, int busNum);
|
||||||
|
void sendStringToTCP(const char* data, int busNum);
|
||||||
|
void sendDebug(const QString debugText);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QTimer mTimer;
|
||||||
|
bool reconnecting;
|
||||||
|
QVarLengthArray<QTcpSocket*> tcpClient;
|
||||||
|
QHostAddress hostIP;
|
||||||
|
int hostPort;
|
||||||
|
QList<QString> hostCanIDs;
|
||||||
|
int framesRapid;
|
||||||
|
QByteArray buildData;
|
||||||
|
QVarLengthArray<MODE> rx_state;
|
||||||
|
CANFrame buildFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SOCKETCAND_H
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>359</width>
|
<width>356</width>
|
||||||
<height>291</height>
|
<height>282</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -26,14 +26,21 @@
|
|||||||
<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">
|
||||||
<string>Serial Connection</string>
|
<string>Serial Connection (GVRET)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="1" column="0">
|
||||||
|
<widget class="QRadioButton" name="rbRemote">
|
||||||
|
<property name="text">
|
||||||
|
<string>Network connection (GVRET)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
<widget class="QRadioButton" name="rbSocketCAN">
|
<widget class="QRadioButton" name="rbSocketCAN">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@@ -43,14 +50,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QRadioButton" name="rbRemote">
|
<widget class="QRadioButton" name="rbKayak">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Network Connection</string>
|
<string>socketcand (SocketCAN over Ethernet)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QRadioButton" name="rbMQTT">
|
<widget class="QRadioButton" name="rbMQTT">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>MQTT Connection</string>
|
<string>MQTT Connection</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user