adding socketcand support

This commit is contained in:
Bertrand
2021-02-23 09:38:19 +01:00
parent 40553ca980
commit c49783a55b
12 changed files with 599 additions and 27 deletions
+3 -1
View File
@@ -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 \
+1
View File
@@ -18,6 +18,7 @@ namespace CANCon {
KVASER, KVASER,
SERIALBUS, SERIALBUS,
REMOTE, REMOTE,
KAYAK,
MQTT, MQTT,
NONE NONE
}; };
+3
View File
@@ -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: {}
+2
View File
@@ -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);
+1
View File
@@ -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";
+58 -9
View File
@@ -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;
+4 -2
View File
@@ -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);
+33 -5
View File
@@ -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";
+4 -2
View File
@@ -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);
+393
View File
@@ -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;
}
}
+82
View File
@@ -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
+15 -8
View File
@@ -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>