Files
giesCANne/connections/canserver.cpp
2025-03-29 17:10:50 +01:00

239 lines
6.4 KiB
C++

//
// 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, false, 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::fromMicroSeconds(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;
}