Support for getting live data from a CANserver
This commit is contained in:
@@ -43,3 +43,5 @@ Makefile
|
|||||||
# Editor files
|
# Editor files
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
SavvyCAN.pro.qtds
|
SavvyCAN.pro.qtds
|
||||||
|
.xcode
|
||||||
|
SavvyCAN.xcodeproj
|
||||||
|
|||||||
@@ -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/canserver.cpp \
|
||||||
connections/lawicel_serial.cpp \
|
connections/lawicel_serial.cpp \
|
||||||
connections/mqtt_bus.cpp \
|
connections/mqtt_bus.cpp \
|
||||||
dbc/dbcnodeduplicateeditor.cpp \
|
dbc/dbcnodeduplicateeditor.cpp \
|
||||||
@@ -101,6 +102,7 @@ SOURCES += main.cpp\
|
|||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
can_structs.h \
|
can_structs.h \
|
||||||
canframemodel.h \
|
canframemodel.h \
|
||||||
|
connections/canserver.h \
|
||||||
connections/lawicel_serial.h \
|
connections/lawicel_serial.h \
|
||||||
connections/socketcand.h \
|
connections/socketcand.h \
|
||||||
connections/mqtt_bus.h \
|
connections/mqtt_bus.h \
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace CANCon {
|
|||||||
KAYAK,
|
KAYAK,
|
||||||
MQTT,
|
MQTT,
|
||||||
LAWICEL,
|
LAWICEL,
|
||||||
|
CANSERVER,
|
||||||
NONE
|
NONE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "mqtt_bus.h"
|
#include "mqtt_bus.h"
|
||||||
#include "socketcand.h"
|
#include "socketcand.h"
|
||||||
#include "lawicel_serial.h"
|
#include "lawicel_serial.h"
|
||||||
|
#include "canserver.h"
|
||||||
|
|
||||||
using namespace CANCon;
|
using namespace CANCon;
|
||||||
|
|
||||||
@@ -26,6 +27,8 @@ CANConnection* CanConFactory::create(type pType, QString pPortName, QString pDri
|
|||||||
return new SocketCANd(pPortName);
|
return new SocketCANd(pPortName);
|
||||||
case MQTT:
|
case MQTT:
|
||||||
return new MQTT_BUS(pPortName);
|
return new MQTT_BUS(pPortName);
|
||||||
|
case CANSERVER:
|
||||||
|
return new CANserver(pPortName);
|
||||||
default: {}
|
default: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ QVariant CANConnectionModel::data(const QModelIndex &index, int role) const
|
|||||||
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";
|
case CANCon::LAWICEL: return "LAWICEL";
|
||||||
|
case CANCon::CANSERVER: return "CANserver";
|
||||||
default: {}
|
default: {}
|
||||||
}
|
}
|
||||||
else qDebug() << "Tried to show connection type but connection was nullptr";
|
else qDebug() << "Tried to show connection type but connection was nullptr";
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
@@ -28,6 +28,7 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* gvretips, QVector<QSt
|
|||||||
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->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->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);
|
||||||
@@ -62,6 +63,7 @@ void NewConnectionDialog::handleConnTypeChanged()
|
|||||||
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();
|
||||||
|
if (ui->rbCANserver->isChecked()) selectCANserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewConnectionDialog::handleDeviceTypeChanged()
|
void NewConnectionDialog::handleDeviceTypeChanged()
|
||||||
@@ -202,6 +204,20 @@ void NewConnectionDialog::selectMQTT()
|
|||||||
ui->cbPort->clear();
|
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)
|
void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QString pDriver)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -224,6 +240,10 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
|
|||||||
break;
|
break;
|
||||||
case CANCon::LAWICEL:
|
case CANCon::LAWICEL:
|
||||||
ui->rbLawicel->setChecked(true);
|
ui->rbLawicel->setChecked(true);
|
||||||
|
break;
|
||||||
|
case CANCon::CANSERVER:
|
||||||
|
ui->rbCANserver->setChecked(true);
|
||||||
|
break;
|
||||||
default: {}
|
default: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +287,11 @@ void NewConnectionDialog::setPortName(CANCon::type pType, QString pPortName, QSt
|
|||||||
case CANCon::MQTT:
|
case CANCon::MQTT:
|
||||||
ui->cbPort->setCurrentText(pPortName);
|
ui->cbPort->setCurrentText(pPortName);
|
||||||
break;
|
break;
|
||||||
|
case CANCon::CANSERVER:
|
||||||
|
{
|
||||||
|
ui->cbPort->setCurrentText(pPortName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {}
|
default: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +307,9 @@ QString NewConnectionDialog::getPortName()
|
|||||||
return ui->cbPort->currentText();
|
return ui->cbPort->currentText();
|
||||||
case CANCon::KAYAK:
|
case CANCon::KAYAK:
|
||||||
return ui->cbPort->currentText();
|
return ui->cbPort->currentText();
|
||||||
|
case CANCon::CANSERVER:
|
||||||
|
return ui->cbPort->currentText();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
qDebug() << "getPortName: can't get port";
|
qDebug() << "getPortName: can't get port";
|
||||||
}
|
}
|
||||||
@@ -324,6 +352,7 @@ CANCon::type NewConnectionDialog::getConnectionType()
|
|||||||
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;
|
if (ui->rbLawicel->isChecked()) return CANCon::LAWICEL;
|
||||||
|
if (ui->rbCANserver->isChecked()) return CANCon::CANSERVER;
|
||||||
qDebug() << "getConnectionType: error";
|
qDebug() << "getConnectionType: error";
|
||||||
|
|
||||||
return CANCon::NONE;
|
return CANCon::NONE;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ private:
|
|||||||
void selectKayak();
|
void selectKayak();
|
||||||
void selectMQTT();
|
void selectMQTT();
|
||||||
void selectLawicel();
|
void selectLawicel();
|
||||||
|
void selectCANserver();
|
||||||
bool isSerialBusAvailable();
|
bool isSerialBusAvailable();
|
||||||
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
|
void setPortName(CANCon::type pType, QString pPortName, QString pDriver);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -71,6 +71,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QRadioButton" name="rbCANserver">
|
||||||
|
<property name="text">
|
||||||
|
<string>CANserver</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user