Support for getting live data from a CANserver

This commit is contained in:
Chris Whiteford
2023-01-22 11:31:41 -05:00
parent 55becb0d58
commit c6c2869124
10 changed files with 348 additions and 0 deletions
+1
View File
@@ -21,6 +21,7 @@ namespace CANCon {
KAYAK,
MQTT,
LAWICEL,
CANSERVER,
NONE
};
}
+3
View File
@@ -5,6 +5,7 @@
#include "mqtt_bus.h"
#include "socketcand.h"
#include "lawicel_serial.h"
#include "canserver.h"
using namespace CANCon;
@@ -26,6 +27,8 @@ CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDri
return new SocketCANd(pPortName);
case MQTT:
return new MQTT_BUS(pPortName);
case CANSERVER:
return new CANserver(pPortName);
default: {}
}
+1
View File
@@ -87,6 +87,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
case CANCon::GVRET_SERIAL: return "GVRET";
case CANCon::KAYAK: return "socketcand";
case CANCon::LAWICEL: return "LAWICEL";
case CANCon::CANSERVER: return "CANserver";
default: {}
}
else qDebug() << "Tried to show connection type but connection was nullptr";
+238
View File
@@ -0,0 +1,238 @@
//
// canserver.cpp
// SavvyCAN
//
// Created by Chris Whiteford on 2022-01-21.
//
#include <QObject>
#include <QDebug>
#include <QCanBusFrame>
#include <QSettings>
#include <QStringBuilder>
#include <QtNetwork>
#include "utility.h"
#include "canserver.h"
CANserver::CANserver(QString serverAddressString) :
CANConnection(serverAddressString, "CANserver", CANCon::CANSERVER, 0, 0, 3, 4000, true),
_udpClient(new QUdpSocket(this)),
_heartbeatTimer(new QTimer(this))
{
qDebug() << "CANserver: " << "Constructing new Connection...";
CANBus bus_info;
bus_info.setActive(true);
bus_info.setListenOnly(true);
bus_info.setSpeed(500000);
setBusConfig(0, bus_info);
setBusConfig(1, bus_info);
setBusConfig(2, bus_info);
// setup udp client
this->_canserverAddress = QHostAddress(serverAddressString);
connect(_udpClient, SIGNAL(readyRead()), this, SLOT(readNetworkData()));
// setup signal and slot
connect(_heartbeatTimer, SIGNAL(timeout()), this, SLOT(heartbeatTimerSlot()));
_heartbeatTimer->stop();
}
CANserver::~CANserver()
{
qDebug() << "CANserver: " << "Deconstructing Connection...";
stop();
delete _heartbeatTimer; _heartbeatTimer = NULL;
delete _udpClient; _udpClient = NULL;
}
void CANserver::piStarted()
{
this->connectToDevice();
}
void CANserver::piSuspend(bool pSuspend)
{
/* update capSuspended */
setCapSuspended(pSuspend);
/* flush queue if we are suspended */
if(isCapSuspended())
getQueue().flush();
}
void CANserver::piStop()
{
this->disconnectFromDevice();
}
bool CANserver::piGetBusSettings(int pBusIdx, CANBus& pBus)
{
return getBusConfig(pBusIdx, pBus);
}
void CANserver::piSetBusSettings(int pBusIdx, CANBus bus)
{
/* sanity checks */
if( (pBusIdx < 0) || pBusIdx >= getNumBuses())
return;
/* copy bus config */
setBusConfig(pBusIdx, bus);
}
bool CANserver::piSendFrame(const CANFrame& )
{
//We don't support sending frames right now
return true;
}
void CANserver::connectToDevice()
{
qDebug() << "CANserver: " << "Establishing UDP connection to a CANserver device...";
bool bindResult = _udpClient->bind(1338);
qDebug() << "CANserver: " << "UDP Bind result: " << bindResult;
heartbeat();
qDebug() << "CANserver: " << "Scheduling additional heartbeats...";
_heartbeatTimer->start(3500);
setStatus(CANCon::CONNECTED);
CANConStatus stats;
stats.conStatus = getStatus();
stats.numHardwareBuses = 3;
emit status(stats);
}
void CANserver::disconnectFromDevice()
{
_heartbeatTimer->stop();
QByteArray Data;
Data.append("bye");
QNetworkDatagram datagram(Data, _canserverAddress, 1338);
qDebug() << "CANserver: " << "Sending bye...";
_udpClient->writeDatagram(datagram);
_udpClient->close();
}
void CANserver::heartbeat()
{
//Send the PANDA hello packet (in this case we are using the v1 version of the protocol because we just want to get ALL the data)
QByteArray Data;
Data.append("hello");
QNetworkDatagram datagram(Data, _canserverAddress, 1338);
qDebug() << "CANserver: " << "Sending a heartbeat...";
_udpClient->writeDatagram(datagram);
}
void CANserver::readNetworkData()
{
QByteArray datagram;
do {
datagram.resize(_udpClient->pendingDatagramSize());
_udpClient->readDatagram(datagram.data(), datagram.size());
} while (_udpClient->hasPendingDatagrams());
// If capture is suspended bail out after reading the bytes from the network. No need to parse them
if(isCapSuspended())
return;
uint16_t packetCount = datagram.length() / 16;
//qDebug() << "Processing " << packetCount << " packets";
//Process this chunk of data
for (int i = 0 ; i < packetCount; i++)
{
uint16_t headerByteLocation = (i*16);
uint16_t dataByteLocation = (i*16) + 8;
uint32_t headerData1Byte1 = datagram.at(headerByteLocation + 0) & 0xFF;
uint32_t headerData1Byte2 = datagram.at(headerByteLocation + 1) & 0xFF;
uint32_t headerData1Byte3 = datagram.at(headerByteLocation + 2) & 0xFF;
uint32_t headerData1Byte4 = datagram.at(headerByteLocation + 3) & 0xFF;
uint32_t headerData2Byte1 = datagram.at(headerByteLocation + 4) & 0xFF;
uint32_t headerData2Byte2 = datagram.at(headerByteLocation + 5) & 0xFF;
uint32_t headerData2Byte3 = datagram.at(headerByteLocation + 6) & 0xFF;
uint32_t headerData2Byte4 = datagram.at(headerByteLocation + 7) & 0xFF;
//printf("HB1: %02X, %02X, %02X, %02X\n", headerData1Byte1, headerData1Byte2, headerData1Byte3, headerData1Byte4);
//printf("HB2: %02X, %02X, %02X, %02X\n", headerData2Byte1, headerData2Byte2, headerData2Byte3, headerData2Byte4);
uint32_t headerData1 = headerData1Byte1;
headerData1 += headerData1Byte2 << 8;
headerData1 += headerData1Byte3 << 16;
headerData1 += headerData1Byte4 << 24;
uint32_t headerData2 = headerData2Byte1;
headerData2 += headerData2Byte2 << 8;
headerData2 += headerData2Byte3 << 16;
headerData2 += headerData2Byte4 << 24;
uint32_t frameId = headerData1 >> 21;
uint32_t length = (headerData2 & 0x0F);
uint32_t busId = (headerData2 >> 4);
//printf("frameId: %02X, busId: %d, length: %d\n", frameId, busId, length);
CANFrame* frame_p = getQueue().get();
if(frame_p)
{
frame_p->setFrameId(frameId);
frame_p->setExtendedFrameFormat(0);
// We need to change the bus id if it is the special CANserver bus id.
// This keeps us from needing to define 15 busses just to get access to our special one
if (busId == 15)
{
busId = 2;
}
frame_p->bus = busId;
frame_p->setFrameType(QCanBusFrame::DataFrame);
frame_p->isReceived = true;
frame_p->setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ul));
frame_p->setPayload(datagram.mid(dataByteLocation, length));
checkTargettedFrame(*frame_p);
/* enqueue frame */
getQueue().queue();
}
}
}
void CANserver::heartbeatTimerSlot()
{
heartbeat();
}
void CANserver::readSettings()
{
QSettings settings;
}
+64
View File
@@ -0,0 +1,64 @@
//
// canserver.h
// SavvyCAN
//
// Created by Chris Whiteford on 2022-01-21.
//
#ifndef canserver_h
#define canserver_h
#include <stdio.h>
#include <QCanBusDevice>
#include <QThread>
#include <QTimer>
#include <QUdpSocket>
/*************/
#include <QDateTime>
/*************/
#include "canframemodel.h"
#include "canconnection.h"
#include "canconmanager.h"
class CANserver : public CANConnection
{
Q_OBJECT
public:
CANserver(QString serverAddress);
virtual ~CANserver();
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&);
private slots:
void readNetworkData();
void heartbeatTimerSlot();
private:
void readSettings();
void connectToDevice();
void disconnectFromDevice();
void heartbeat();
protected:
QHostAddress _canserverAddress;
QUdpSocket *_udpClient;
QTimer *_heartbeatTimer;
};
#endif /* canserver_h */
+29
View File
@@ -28,6 +28,7 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* gvretips, QVector<QSt
connect(ui->rbKayak, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbMQTT, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbLawicel, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbCANserver, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->cbDeviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NewConnectionDialog::handleDeviceTypeChanged);
connect(ui->btnOK, &QPushButton::clicked, this, &NewConnectionDialog::handleCreateButton);
@@ -62,6 +63,7 @@ void NewConnectionDialog::handleConnTypeChanged()
if (ui->rbRemote->isChecked()) selectRemote();
if (ui->rbKayak->isChecked()) selectKayak();
if (ui->rbMQTT->isChecked()) selectMQTT();
if (ui->rbCANserver->isChecked()) selectCANserver();
}
void NewConnectionDialog::handleDeviceTypeChanged()
@@ -202,6 +204,20 @@ void NewConnectionDialog::selectMQTT()
ui->cbPort->clear();
}
void NewConnectionDialog::selectCANserver()
{
ui->lPort->setText("CANserver IP Address:");
ui->lblDeviceType->setHidden(true);
ui->cbDeviceType->setHidden(true);
ui->cbCANSpeed->setHidden(true);
ui->cbSerialSpeed->setHidden(true);
ui->lblCANSpeed->setHidden(true);
ui->lblSerialSpeed->setHidden(true);
ui->cbPort->clear();
}
void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QString pDriver)
{
@@ -224,6 +240,10 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
break;
case CANCon::LAWICEL:
ui->rbLawicel->setChecked(true);
break;
case CANCon::CANSERVER:
ui->rbCANserver->setChecked(true);
break;
default: {}
}
@@ -267,6 +287,11 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
case CANCon::MQTT:
ui->cbPort->setCurrentText(pPortName);
break;
case CANCon::CANSERVER:
{
ui->cbPort->setCurrentText(pPortName);
break;
}
default: {}
}
}
@@ -282,6 +307,9 @@ QString NewConnectionDialog::getPortName()
return ui->cbPort->currentText();
case CANCon::KAYAK:
return ui->cbPort->currentText();
case CANCon::CANSERVER:
return ui->cbPort->currentText();
default:
qDebug() << "getPortName: can't get port";
}
@@ -324,6 +352,7 @@ CANCon::type NewConnectionDialog::getConnectionType()
if (ui->rbKayak->isChecked()) return CANCon::KAYAK;
if (ui->rbMQTT->isChecked()) return CANCon::MQTT;
if (ui->rbLawicel->isChecked()) return CANCon::LAWICEL;
if (ui->rbCANserver->isChecked()) return CANCon::CANSERVER;
qDebug() << "getConnectionType: error";
return CANCon::NONE;
+1
View File
@@ -46,6 +46,7 @@ private:
void selectKayak();
void selectMQTT();
void selectLawicel();
void selectCANserver();
bool isSerialBusAvailable();
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
};