summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndre Hartmann <aha_1980@gmx.de>2016-07-31 20:43:13 +0200
committerAndré Hartmann <aha_1980@gmx.de>2017-01-10 15:18:02 +0000
commit55d405697c79c4ca23535140e60915e89b4054e3 (patch)
tree8144ae742df62f6d362a71d160a2e3e93484fd96 /src
parent66fd2b9655d5f34f880b8daf8b2f422a27789517 (diff)
CAN: Add QCanBusDeviceInfo
Returns: * a list of available devices for the chosen plugin * if the device is virtual * if the device is CAN FD capable Use this list in the CAN Example for interface selection. If information about virtual channels or CAN FD capabability is not available, false is returned. For SocketCAN, PeakCAN, VectorCAN and SystecCAN, the implementation is completed. TinyCAN only return the list of possible interfaces for now. This is can be changed later, but needs quite some refactoring of the TinyCAN plugin. [ChangeLog][QtCanBus] Added the new class QCanBusDeviceInfo for enumeration of available CAN interfaces and more information about them. Task-number: QTBUG-54298 Change-Id: I851bcc3b9ee41aaaf1164c6b4a5aaf6503cd8746 Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com> Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/canbus/peakcan/main.cpp8
-rw-r--r--src/plugins/canbus/peakcan/peakcan_symbols_p.h3
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.cpp19
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.h2
-rw-r--r--src/plugins/canbus/socketcan/main.cpp6
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.cpp69
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.h3
-rw-r--r--src/plugins/canbus/systeccan/main.cpp8
-rw-r--r--src/plugins/canbus/systeccan/systeccan_symbols_p.h35
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.cpp29
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.h2
-rw-r--r--src/plugins/canbus/tinycan/main.cpp6
-rw-r--r--src/plugins/canbus/tinycan/tinycanbackend.cpp5
-rw-r--r--src/plugins/canbus/tinycan/tinycanbackend.h2
-rw-r--r--src/plugins/canbus/vectorcan/main.cpp8
-rw-r--r--src/plugins/canbus/vectorcan/vectorcan_symbols_p.h3
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.cpp54
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.h2
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend_p.h4
-rw-r--r--src/serialbus/qcanbus.cpp69
-rw-r--r--src/serialbus/qcanbus.h3
-rw-r--r--src/serialbus/qcanbusdevice.cpp16
-rw-r--r--src/serialbus/qcanbusdevice.h5
-rw-r--r--src/serialbus/qcanbusdeviceinfo.cpp134
-rw-r--r--src/serialbus/qcanbusdeviceinfo.h75
-rw-r--r--src/serialbus/qcanbusdeviceinfo_p.h72
-rw-r--r--src/serialbus/qcanbusfactory.cpp11
-rw-r--r--src/serialbus/qcanbusfactory.h2
-rw-r--r--src/serialbus/serialbus.pro3
29 files changed, 625 insertions, 33 deletions
diff --git a/src/plugins/canbus/peakcan/main.cpp b/src/plugins/canbus/peakcan/main.cpp
index 00b4d36..453124b 100644
--- a/src/plugins/canbus/peakcan/main.cpp
+++ b/src/plugins/canbus/peakcan/main.cpp
@@ -51,6 +51,14 @@ class PeakCanBusPlugin : public QObject, public QCanBusFactory
public:
+ QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const override
+ {
+ if (Q_UNLIKELY(!PeakCanBackend::canCreate(errorMessage)))
+ return QList<QCanBusDeviceInfo>();
+
+ return PeakCanBackend::interfaces();
+ }
+
QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override
{
QString errorReason;
diff --git a/src/plugins/canbus/peakcan/peakcan_symbols_p.h b/src/plugins/canbus/peakcan/peakcan_symbols_p.h
index dbbf6b2..a265383 100644
--- a/src/plugins/canbus/peakcan/peakcan_symbols_p.h
+++ b/src/plugins/canbus/peakcan/peakcan_symbols_p.h
@@ -178,6 +178,9 @@ extern "C"
#define PCAN_TRACE_SIZE 0x13 // Configuration of the maximum file size of a CAN trace
#define PCAN_TRACE_CONFIGURE 0x14 // Configuration of the trace file storing mode (TRACE_FILE_***)
#define PCAN_CHANNEL_IDENTIFYING 0x15 // Phisical identification of a USB based PCAN-Channel by blinking its associated LED
+#define PCAN_CHANNEL_FEATURES 0x16 // Capabilities of a PCAN device (FEATURE_***)
+
+#define FEATURE_FD_CAPABLE 0x01 // Device supports flexible data-rate (CAN-FD)
// PCAN parameter values
#define PCAN_PARAMETER_OFF 0x00 // The PCAN parameter is not set (inactive)
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp
index 68091e1..dd7e4cb 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.cpp
+++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp
@@ -112,6 +112,25 @@ PcanChannel pcanChannels[] = {
{ "none", PCAN_NONEBUS }
};
+QList<QCanBusDeviceInfo> PeakCanBackend::interfaces()
+{
+ QList<QCanBusDeviceInfo> result;
+
+ for (int i = 0; pcanChannels[i].index != PCAN_NONEBUS; ++i) {
+ int value;
+ const TPCANStatus stat = ::CAN_GetValue(pcanChannels[i].index, PCAN_CHANNEL_CONDITION,
+ &value, sizeof(value));
+ if ((stat == PCAN_ERROR_OK) && (value & PCAN_CHANNEL_AVAILABLE)) {
+ const TPCANStatus fdStat = ::CAN_GetValue(pcanChannels[i].index, PCAN_CHANNEL_FEATURES,
+ &value, sizeof(value));
+ const bool isFd = (fdStat == PCAN_ERROR_OK) && (value & FEATURE_FD_CAPABLE);
+ result.append(createDeviceInfo(QLatin1String(pcanChannels[i].name), false, isFd));
+ }
+ }
+
+ return result;
+}
+
#if defined(Q_OS_WIN32)
class ReadNotifier : public QWinEventNotifier
{
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.h b/src/plugins/canbus/peakcan/peakcanbackend.h
index d44ba58..f806d05 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.h
+++ b/src/plugins/canbus/peakcan/peakcanbackend.h
@@ -40,6 +40,7 @@
#include <QtSerialBus/qcanbusframe.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
#include <QtCore/qvariant.h>
#include <QtCore/qvector.h>
@@ -68,6 +69,7 @@ public:
QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
static bool canCreate(QString *errorReason);
+ static QList<QCanBusDeviceInfo> interfaces();
private:
PeakCanBackendPrivate * const d_ptr;
diff --git a/src/plugins/canbus/socketcan/main.cpp b/src/plugins/canbus/socketcan/main.cpp
index eb13cea..d1e9115 100644
--- a/src/plugins/canbus/socketcan/main.cpp
+++ b/src/plugins/canbus/socketcan/main.cpp
@@ -53,6 +53,12 @@ class SocketCanBusPlugin : public QObject, public QCanBusFactory
public:
+ QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const override
+ {
+ Q_UNUSED(errorMessage);
+ return SocketCanBackend::interfaces();
+ }
+
QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override
{
Q_UNUSED(errorMessage);
diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp
index 8974279..c506706 100644
--- a/src/plugins/canbus/socketcan/socketcanbackend.cpp
+++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp
@@ -36,8 +36,10 @@
#include "socketcanbackend.h"
-#include <QtCore/qdebug.h>
#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qfile.h>
#include <QtCore/qsocketnotifier.h>
#include <linux/can/error.h>
@@ -74,6 +76,71 @@ struct canfd_frame {
QT_BEGIN_NAMESPACE
+const char sysClassNetC[] = "/sys/class/net/";
+const char flagsC[] = "/flags";
+const char mtuC[] = "/mtu";
+const char typeC[] = "/type";
+const char virtualC[] = "virtual";
+
+enum {
+ CanFlexibleDataRateMtu = 72,
+ TypeSocketCan = 280,
+ DeviceIsActive = 1
+};
+
+static QByteArray fileContent(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly))
+ return QByteArray();
+
+ return file.readAll().trimmed();
+}
+
+static bool isFlexibleDataRateCapable(const QString &canDevice)
+{
+ const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(mtuC);
+ const int mtu = fileContent(path).toInt();
+ return mtu == CanFlexibleDataRateMtu;
+}
+
+static bool isVirtual(const QString &canDevice)
+{
+ const QFileInfo fi(QLatin1String(sysClassNetC) + canDevice);
+ return fi.canonicalPath().contains(QLatin1String(virtualC));
+}
+
+static quint32 flags(const QString &canDevice)
+{
+ const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(flagsC);
+ const quint32 result = fileContent(path).toUInt(nullptr, 0);
+ return result;
+}
+
+QList<QCanBusDeviceInfo> SocketCanBackend::interfaces()
+{
+ QList<QCanBusDeviceInfo> result;
+ QDirIterator it(sysClassNetC,
+ QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
+ QDirIterator::Subdirectories);
+
+ while (it.hasNext()) {
+ const QString dirEntry = it.next();
+ if (fileContent(dirEntry + QLatin1String(typeC)).toInt() != TypeSocketCan)
+ continue;
+
+ const QString deviceName = dirEntry.mid(strlen(sysClassNetC));
+ if (!(flags(deviceName) & DeviceIsActive))
+ continue;
+
+ auto info = createDeviceInfo(deviceName, isVirtual(deviceName),
+ isFlexibleDataRateCapable(deviceName));
+ result.append(info);
+ }
+
+ return result;
+}
+
SocketCanBackend::SocketCanBackend(const QString &name) :
canSocket(-1),
notifier(nullptr),
diff --git a/src/plugins/canbus/socketcan/socketcanbackend.h b/src/plugins/canbus/socketcan/socketcanbackend.h
index 06e7f84..940588a 100644
--- a/src/plugins/canbus/socketcan/socketcanbackend.h
+++ b/src/plugins/canbus/socketcan/socketcanbackend.h
@@ -39,6 +39,7 @@
#include <QtSerialBus/qcanbusframe.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
#include <QtCore/qsocketnotifier.h>
#include <QtCore/qstring.h>
@@ -62,6 +63,8 @@ public:
QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
+ static QList<QCanBusDeviceInfo> interfaces();
+
private Q_SLOTS:
void readSocket();
diff --git a/src/plugins/canbus/systeccan/main.cpp b/src/plugins/canbus/systeccan/main.cpp
index 1302e71..d81072d 100644
--- a/src/plugins/canbus/systeccan/main.cpp
+++ b/src/plugins/canbus/systeccan/main.cpp
@@ -49,6 +49,14 @@ class SystecCanBusPlugin : public QObject, public QCanBusFactory
Q_INTERFACES(QCanBusFactory)
public:
+ QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const override
+ {
+ if (Q_UNLIKELY(!SystecCanBackend::canCreate(errorMessage)))
+ return QList<QCanBusDeviceInfo>();
+
+ return SystecCanBackend::interfaces();
+ }
+
QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override
{
QString errorReason;
diff --git a/src/plugins/canbus/systeccan/systeccan_symbols_p.h b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
index 3b4429e..b69db83 100644
--- a/src/plugins/canbus/systeccan/systeccan_symbols_p.h
+++ b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
@@ -220,6 +220,37 @@ typedef struct _tUcanHardwareInfoEx {
#define USBCAN_HWINFO_SIZE_V2 0x22 // size with m_adwDeviceId[]
#define USBCAN_HWINFO_SIZE_V3 0x26 // size with m_adwDeviceId[] and m_dwFlags
+// definitions for product code in structure tUcanHardwareInfoEx
+#define USBCAN_PRODCODE_MASK_DID 0xFFFF0000L
+#define USBCAN_PRODCODE_MASK_MFU 0x00008000L
+#define USBCAN_PRODCODE_PID_TWO_CHA 0x00000001L
+#define USBCAN_PRODCODE_PID_TERM 0x00000001L
+#define USBCAN_PRODCODE_PID_RBUSER 0x00000001L
+#define USBCAN_PRODCODE_PID_RBCAN 0x00000001L
+#define USBCAN_PRODCODE_PID_G4 0x00000020L
+#define USBCAN_PRODCODE_PID_RESVD 0x00000040L
+#define USBCAN_PRODCODE_MASK_PID 0x00007FFFL
+#define USBCAN_PRODCODE_MASK_PIDG3 (USBCAN_PRODCODE_MASK_PID & ~USBCAN_PRODCODE_PID_RESVD)
+
+#define USBCAN_PRODCODE_PID_GW001 0x00001100L // order code GW-001 "USB-CANmodul" outdated
+#define USBCAN_PRODCODE_PID_GW002 0x00001102L // order code GW-002 "USB-CANmodul" outdated
+#define USBCAN_PRODCODE_PID_MULTIPORT 0x00001103L // order code 3004006/3404000/3404001 "Multiport CAN-to-USB"
+#define USBCAN_PRODCODE_PID_BASIC 0x00001104L // order code 3204000/3204001 "USB-CANmodul1"
+#define USBCAN_PRODCODE_PID_ADVANCED 0x00001105L // order code 3204002/3204003 "USB-CANmodul2"
+#define USBCAN_PRODCODE_PID_USBCAN8 0x00001107L // order code 3404000 "USB-CANmodul8"
+#define USBCAN_PRODCODE_PID_USBCAN16 0x00001109L // order code 3404001 "USB-CANmodul16"
+#define USBCAN_PRODCODE_PID_RESERVED3 0x00001110L
+#define USBCAN_PRODCODE_PID_ADVANCED_G4 0x00001121L // order code ------- "USB-CANmodul2" 4th generation
+#define USBCAN_PRODCODE_PID_BASIC_G4 0x00001122L // order code 3204000 "USB-CANmodul1" 4th generation
+#define USBCAN_PRODCODE_PID_RESERVED1 0x00001144L
+#define USBCAN_PRODCODE_PID_RESERVED2 0x00001145L
+#define USBCAN_PRODCODE_PID_RESERVED4 0x00001162L
+
+// checks if the module supports two CAN channels (at logical device)
+#define USBCAN_CHECK_SUPPORT_TWO_CHANNEL(pHwInfoEx) \
+ ((((pHwInfoEx)->m_dwProductCode & USBCAN_PRODCODE_MASK_PID) >= USBCAN_PRODCODE_PID_MULTIPORT) && \
+ (((pHwInfoEx)->m_dwProductCode & USBCAN_PRODCODE_PID_TWO_CHA) != 0) )
+
typedef struct _tUcanHardwareInitInfo {
DWORD m_dwSize; // [IN] size of this structure
BOOL m_fDoInitialize; // [IN] specifies if the found module should be initialized by the DLL
@@ -239,8 +270,7 @@ typedef void (DRV_CALLBACK_TYPE *tUcanEnumCallback) (
#pragma pack(pop)
GENERATE_SYMBOL_VARIABLE(quint32, UcanEnumerateHardware,
- tUcanEnumCallback /* callback */, void * /* args */,
- BOOL /* used */,
+ tUcanEnumCallback /* callback */, void * /* args */, BOOL /* used */,
quint8, quint8 /* device number low and high */,
quint32, quint32, /* serial low and high */
quint32, quint32 /* product code low and high */)
@@ -264,6 +294,7 @@ inline bool resolveSymbols(QLibrary *systecLibrary)
return false;
}
+ RESOLVE_SYMBOL(UcanEnumerateHardware);
RESOLVE_SYMBOL(UcanInitHardwareEx);
RESOLVE_SYMBOL(UcanDeinitHardware);
RESOLVE_SYMBOL(UcanInitCanEx2);
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.cpp b/src/plugins/canbus/systeccan/systeccanbackend.cpp
index a947cd3..652c8cb 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.cpp
+++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp
@@ -60,6 +60,35 @@ bool SystecCanBackend::canCreate(QString *errorReason)
return true;
}
+static void DRV_CALLBACK_TYPE ucanEnumCallback(DWORD index, BOOL isUsed,
+ tUcanHardwareInfoEx *hardwareInfo,
+ tUcanHardwareInitInfo *initInfo,
+ void *args)
+{
+ auto result = static_cast<QStringList *>(args);
+
+ Q_UNUSED(isUsed);
+ Q_UNUSED(hardwareInfo);
+ Q_UNUSED(initInfo);
+
+ result->append(QString::fromLatin1("can%1.0").arg(index));
+ if (USBCAN_CHECK_SUPPORT_TWO_CHANNEL(hardwareInfo))
+ result->append(QString::fromLatin1("can%1.1").arg(index));
+}
+
+QList<QCanBusDeviceInfo> SystecCanBackend::interfaces()
+{
+ QList<QCanBusDeviceInfo> result;
+
+ QStringList devices;
+ ::UcanEnumerateHardware(&ucanEnumCallback, &devices, false,
+ 0, ~0, 0, ~0, 0, ~0);
+
+ for (const QString &s : qAsConst(devices))
+ result.append(createDeviceInfo(s, false, false));
+ return result;
+}
+
class OutgoingEventNotifier : public QTimer
{
public:
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.h b/src/plugins/canbus/systeccan/systeccanbackend.h
index 11df787..7bf20f8 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend.h
@@ -39,6 +39,7 @@
#include <QtSerialBus/qcanbusframe.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
#include <QtCore/qvariant.h>
#include <QtCore/qlist.h>
@@ -65,6 +66,7 @@ public:
QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
+ static QList<QCanBusDeviceInfo> interfaces();
static bool canCreate(QString *errorReason);
private:
diff --git a/src/plugins/canbus/tinycan/main.cpp b/src/plugins/canbus/tinycan/main.cpp
index fe988ba..55c5590 100644
--- a/src/plugins/canbus/tinycan/main.cpp
+++ b/src/plugins/canbus/tinycan/main.cpp
@@ -51,6 +51,12 @@ class TinyCanBusPlugin : public QObject, public QCanBusFactory
public:
+ QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const override
+ {
+ Q_UNUSED(errorMessage);
+ return TinyCanBackend::interfaces();
+ }
+
QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override
{
QString errorReason;
diff --git a/src/plugins/canbus/tinycan/tinycanbackend.cpp b/src/plugins/canbus/tinycan/tinycanbackend.cpp
index 0961813..390adee 100644
--- a/src/plugins/canbus/tinycan/tinycanbackend.cpp
+++ b/src/plugins/canbus/tinycan/tinycanbackend.cpp
@@ -68,6 +68,11 @@ bool TinyCanBackend::canCreate(QString *errorReason)
#endif
}
+QList<QCanBusDeviceInfo> TinyCanBackend::interfaces()
+{
+ return { createDeviceInfo(QStringLiteral("can0.0")), createDeviceInfo(QStringLiteral("can0.1")) };
+}
+
Q_GLOBAL_STATIC(QList<TinyCanBackendPrivate *>, qChannels)
static QMutex channelsGuard(QMutex::NonRecursive);
diff --git a/src/plugins/canbus/tinycan/tinycanbackend.h b/src/plugins/canbus/tinycan/tinycanbackend.h
index bd3aca0..3726a71 100644
--- a/src/plugins/canbus/tinycan/tinycanbackend.h
+++ b/src/plugins/canbus/tinycan/tinycanbackend.h
@@ -40,6 +40,7 @@
#include <QtSerialBus/qcanbusframe.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
#include <QtCore/qvariant.h>
#include <QtCore/qvector.h>
@@ -68,6 +69,7 @@ public:
QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
static bool canCreate(QString *errorReason);
+ static QList<QCanBusDeviceInfo> interfaces();
private:
TinyCanBackendPrivate * const d_ptr;
diff --git a/src/plugins/canbus/vectorcan/main.cpp b/src/plugins/canbus/vectorcan/main.cpp
index 7be88b9..a606ae7 100644
--- a/src/plugins/canbus/vectorcan/main.cpp
+++ b/src/plugins/canbus/vectorcan/main.cpp
@@ -49,6 +49,14 @@ class VectorCanBusPlugin : public QObject, public QCanBusFactory
Q_INTERFACES(QCanBusFactory)
public:
+ QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const override
+ {
+ if (Q_UNLIKELY(!VectorCanBackend::canCreate(errorMessage)))
+ return QList<QCanBusDeviceInfo>();
+
+ return VectorCanBackend::interfaces();
+ }
+
QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override
{
QString errorReason;
diff --git a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
index 429f50e..4238fae 100644
--- a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
+++ b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
@@ -362,6 +362,9 @@ typedef long XLportHandle, *pXLportHandle;
// defines for special DeviceStatus
#define XL_SPECIAL_DEVICE_STAT_FPGA_UPDATE_DONE 0x01 // automatic driver FPGA flashing done
+#define XL_HWTYPE_NONE 0
+#define XL_HWTYPE_VIRTUAL 1
+
typedef struct s_xl_channel_config {
char name[XL_MAX_LENGTH + 1];
quint8 hwType; // HWTYPE_xxxx (see above)
diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
index 005b726..50ede55 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
@@ -67,6 +67,32 @@ bool VectorCanBackend::canCreate(QString *errorReason)
#endif
}
+QList<QCanBusDeviceInfo> VectorCanBackend::interfaces()
+{
+ QList<QCanBusDeviceInfo> result;
+
+ if (Q_UNLIKELY(VectorCanBackendPrivate::loadDriver() != XL_SUCCESS))
+ return result;
+
+ XLdriverConfig config;
+ if (Q_UNLIKELY(::xlGetDriverConfig(&config) != XL_SUCCESS)) {
+ VectorCanBackendPrivate::cleanupDriver();
+ return result;
+ }
+
+ for (uint i = 0; i < config.channelCount; ++i) {
+ if (config.channel[i].hwType == XL_HWTYPE_NONE)
+ continue;
+
+ const bool isVirtual = config.channel[i].hwType == XL_HWTYPE_VIRTUAL;
+ const bool isFd = config.channel[i].channelCapabilities & XL_CHANNEL_FLAG_CANFD_SUPPORT;
+ result.append(createDeviceInfo(QStringLiteral("can") + QString::number(i), isVirtual, isFd));
+ }
+
+ VectorCanBackendPrivate::cleanupDriver();
+ return result;
+}
+
static int driverRefCount = 0;
class ReadNotifier : public QWinEventNotifier
@@ -338,23 +364,31 @@ void VectorCanBackendPrivate::startRead()
q->enqueueReceivedFrames(newFrames);
}
-void VectorCanBackendPrivate::startupDriver()
+XLstatus VectorCanBackendPrivate::loadDriver()
{
- Q_Q(VectorCanBackend);
-
if (driverRefCount == 0) {
const XLstatus status = ::xlOpenDriver();
- if (status != XL_SUCCESS) {
- q->setError(systemErrorString(status),
- QCanBusDevice::CanBusError::ConnectionError);
- return;
- }
- } else if (driverRefCount < 0) {
+ if (Q_UNLIKELY(status != XL_SUCCESS))
+ return status;
+
+ } else if (Q_UNLIKELY(driverRefCount < 0)) {
qCritical("Wrong reference counter: %d", driverRefCount);
- return;
+ return XL_ERR_CANNOT_OPEN_DRIVER;
}
++driverRefCount;
+ return XL_SUCCESS;
+}
+
+void VectorCanBackendPrivate::startupDriver()
+{
+ Q_Q(VectorCanBackend);
+
+ const XLstatus status = loadDriver();
+ if (Q_UNLIKELY(status != XL_SUCCESS)) {
+ q->setError(systemErrorString(status),
+ QCanBusDevice::CanBusError::ConnectionError);
+ }
}
void VectorCanBackendPrivate::cleanupDriver()
diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.h b/src/plugins/canbus/vectorcan/vectorcanbackend.h
index 89966ed..d956634 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend.h
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend.h
@@ -39,6 +39,7 @@
#include <QtSerialBus/qcanbusframe.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
#include <QtCore/qvariant.h>
#include <QtCore/qvector.h>
@@ -67,6 +68,7 @@ public:
QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
static bool canCreate(QString *errorReason);
+ static QList<QCanBusDeviceInfo> interfaces();
private:
VectorCanBackendPrivate * const d_ptr;
diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend_p.h b/src/plugins/canbus/vectorcan/vectorcanbackend_p.h
index dbb3903..dff90d8 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend_p.h
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend_p.h
@@ -37,6 +37,7 @@
#ifndef VECTORCANBACKEND_P_H
#define VECTORCANBACKEND_P_H
+#include "vectorcan_symbols_p.h"
#include "vectorcanbackend.h"
#if defined(Q_OS_WIN32)
@@ -76,8 +77,9 @@ public:
QString systemErrorString(int errorCode) const;
void startWrite();
void startRead();
+ static XLstatus loadDriver();
void startupDriver();
- void cleanupDriver();
+ static void cleanupDriver();
bool setBitRate(quint32 bitrate);
VectorCanBackend * const q_ptr;
diff --git a/src/serialbus/qcanbus.cpp b/src/serialbus/qcanbus.cpp
index 3e1704c..a16b230 100644
--- a/src/serialbus/qcanbus.cpp
+++ b/src/serialbus/qcanbus.cpp
@@ -122,6 +122,50 @@ static void setErrorMessage(QString *result, const QString &message)
*result = message;
}
+static QCanBusFactory *canBusFactory(const QString &plugin, QString *errorMessage)
+{
+ if (Q_UNLIKELY(!qCanBusPlugins()->contains(plugin))) {
+ setErrorMessage(errorMessage, QCanBus::tr("No such plugin: '%1'").arg(plugin));
+ return nullptr;
+ }
+
+ QCanBusPrivate d = qCanBusPlugins()->value(plugin);
+ if (!d.factory) {
+ d.factory = qobject_cast<QCanBusFactory *>(qFactoryLoader->instance(d.index));
+
+ if (d.factory)
+ qCanBusPlugins()->insert(plugin, d);
+ }
+
+ if (Q_UNLIKELY(!d.factory))
+ setErrorMessage(errorMessage, QCanBus::tr("No factory for plugin: '%1'").arg(plugin));
+
+ return d.factory;
+}
+
+/*!
+ \since 5.9
+
+ Returns the available interfaces for \a plugin. In case of failure, the optional
+ parameter \a errorMessage returns a textual error description.
+
+ \note Some plugins might not or only partially support this function.
+
+ \sa createDevice()
+*/
+QList<QCanBusDeviceInfo> QCanBus::availableDevices(const QString &plugin, QString *errorMessage) const
+{
+ const QCanBusFactory *factory = canBusFactory(plugin, errorMessage);
+ if (Q_UNLIKELY(!factory))
+ return QList<QCanBusDeviceInfo>();
+
+ QString errorString;
+ QList<QCanBusDeviceInfo> result = factory->availableDevices(&errorString);
+
+ setErrorMessage(errorMessage, errorString);
+ return result;
+}
+
/*!
Creates a CAN bus device. \a plugin is the name of the plugin as returned by the \l plugins()
method. \a interfaceName is the CAN bus interface name. In case of failure, the optional
@@ -139,30 +183,19 @@ static void setErrorMessage(QString *result, const QString &message)
\endcode
\note The \a interfaceName is plugin-dependent. See the corresponding plugin documentation
- for more information: \l {CAN Bus Plugins}.
+ for more information: \l {CAN Bus Plugins}. To get a list of available interfaces,
+ \l availableDevices() can be used.
+
+ \sa availableDevices()
*/
QCanBusDevice *QCanBus::createDevice(const QString &plugin, const QString &interfaceName,
QString *errorMessage) const
{
- if (!qCanBusPlugins()->contains(plugin)) {
- setErrorMessage(errorMessage, tr("No such plugin: '%1'").arg(plugin));
- return nullptr;
- }
-
- QCanBusPrivate d = qCanBusPlugins()->value(plugin);
- if (!d.factory) {
- d.factory
- = qobject_cast<QCanBusFactory *>(qFactoryLoader->instance(d.index));
-
- if (d.factory)
- qCanBusPlugins()->insert(plugin, d);
- }
- if (!d.factory) {
- setErrorMessage(errorMessage, tr("No factory for plugin: '%1'").arg(plugin));
+ const QCanBusFactory *factory = canBusFactory(plugin, errorMessage);
+ if (Q_UNLIKELY(!factory))
return nullptr;
- }
- return d.factory->createDevice(interfaceName, errorMessage);
+ return factory->createDevice(interfaceName, errorMessage);
}
QCanBus::QCanBus(QObject *parent) :
diff --git a/src/serialbus/qcanbus.h b/src/serialbus/qcanbus.h
index 3f03400..2ed1877 100644
--- a/src/serialbus/qcanbus.h
+++ b/src/serialbus/qcanbus.h
@@ -40,6 +40,7 @@
#include <QtCore/qobject.h>
#include <QtSerialBus/qserialbusglobal.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
QT_BEGIN_NAMESPACE
@@ -53,6 +54,8 @@ public:
static QCanBus *instance();
QStringList plugins() const;
+ QList<QCanBusDeviceInfo> availableDevices(const QString &plugin, QString *errorMessage = nullptr) const;
+
QCanBusDevice *createDevice(const QString &plugin,
const QString &interfaceName,
QString *errorMessage = nullptr) const;
diff --git a/src/serialbus/qcanbusdevice.cpp b/src/serialbus/qcanbusdevice.cpp
index c80753a..f094469 100644
--- a/src/serialbus/qcanbusdevice.cpp
+++ b/src/serialbus/qcanbusdevice.cpp
@@ -36,6 +36,7 @@
#include "qcanbusdevice.h"
#include "qcanbusdevice_p.h"
+#include "qcanbusdeviceinfo_p.h"
#include "qcanbusframe.h"
@@ -694,4 +695,19 @@ void QCanBusDevice::setState(QCanBusDevice::CanBusDeviceState newState)
emit stateChanged(newState);
}
+/*!
+ * Returns a QCanBusDeviceInfo created from the given parameters \a name,
+ * \a isVirtual, and \a isFlexibleDataRateCapable.
+ * \internal
+ */
+QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, bool isVirtual,
+ bool isFlexibleDataRateCapable)
+{
+ QCanBusDeviceInfoPrivate info;
+ info.name = name;
+ info.isVirtual = isVirtual;
+ info.hasFlexibleDataRate = isFlexibleDataRateCapable;
+ return QCanBusDeviceInfo(info);
+}
+
QT_END_NAMESPACE
diff --git a/src/serialbus/qcanbusdevice.h b/src/serialbus/qcanbusdevice.h
index 6a015af..607fa25 100644
--- a/src/serialbus/qcanbusdevice.h
+++ b/src/serialbus/qcanbusdevice.h
@@ -39,6 +39,7 @@
#include <QtCore/qobject.h>
#include <QtSerialBus/qcanbusframe.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
QT_BEGIN_NAMESPACE
@@ -140,6 +141,10 @@ protected:
// Can be folded into one call to connectDevice() & disconnectDevice()
virtual bool open() = 0;
virtual void close() = 0;
+
+ static QCanBusDeviceInfo createDeviceInfo(const QString &name,
+ bool isVirtual = false,
+ bool isFlexibleDataRateCapable = false);
};
Q_DECLARE_TYPEINFO(QCanBusDevice::CanBusError, Q_PRIMITIVE_TYPE);
diff --git a/src/serialbus/qcanbusdeviceinfo.cpp b/src/serialbus/qcanbusdeviceinfo.cpp
new file mode 100644
index 0000000..418e4f0
--- /dev/null
+++ b/src/serialbus/qcanbusdeviceinfo.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcanbusdeviceinfo.h"
+#include "qcanbusdeviceinfo_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QCanBusDeviceInfo
+ \inmodule QtSerialBus
+ \since 5.9
+
+ \brief The QCanBusDeviceInfo provides information about CAN interfaces.
+
+ Each plugin may support one or more interfaces with different
+ capabilities. This class provides information about available functions.
+*/
+
+/*!
+ Constructs a new empty QCanBusDeviceInfo.
+*/
+QCanBusDeviceInfo::QCanBusDeviceInfo() :
+ d_ptr(new QCanBusDeviceInfoPrivate)
+{
+}
+
+/*!
+ Constructs a new QCanBusDeviceInfo from \a other.
+*/
+QCanBusDeviceInfo::QCanBusDeviceInfo(const QCanBusDeviceInfo &other) :
+ d_ptr(other.d_ptr)
+{
+}
+
+/*!
+ Constructs a new QCanBusDeviceInfo from the QCanBusDeviceInfoPrivate \a dd.
+ \internal
+*/
+QCanBusDeviceInfo::QCanBusDeviceInfo(QCanBusDeviceInfoPrivate &dd) :
+ d_ptr(new QCanBusDeviceInfoPrivate(dd))
+{
+}
+
+/*!
+ Destroys the QCanBusDeviceInfo object. References to the values in the
+ object become invalid.
+*/
+QCanBusDeviceInfo::~QCanBusDeviceInfo()
+{
+}
+
+/*!
+ Swap this instance's shared data pointer with the shared data pointer in
+ \a other.
+ \internal
+*/
+void QCanBusDeviceInfo::swap(QCanBusDeviceInfo other)
+{
+ d_ptr.swap(other.d_ptr);
+}
+
+/*!
+ Sets the QCanBusDeviceInfo object to be equal to \a other.
+*/
+QCanBusDeviceInfo &QCanBusDeviceInfo::operator=(const QCanBusDeviceInfo &other)
+{
+ QCanBusDeviceInfo(other).swap(*this);
+ return *this;
+}
+
+/*!
+ Returns the interface name of this CAN bus interface, e.g. can0.
+*/
+QString QCanBusDeviceInfo::name() const
+{
+ return d_ptr->name;
+}
+
+/*!
+ Returns true, if the CAN bus interface is CAN FD (flexible data rate) capable.
+
+ If this information is not available, false is returned.
+*/
+bool QCanBusDeviceInfo::hasFlexibleDataRate() const
+{
+ return d_ptr->hasFlexibleDataRate;
+}
+
+/*!
+ Returns true, if the CAN bus interface is virtual (i.e. not connected to real
+ CAN hardware).
+
+ If this information is not available, false is returned.
+*/
+bool QCanBusDeviceInfo::isVirtual() const
+{
+ return d_ptr->isVirtual;
+}
+
+QT_END_NAMESPACE
diff --git a/src/serialbus/qcanbusdeviceinfo.h b/src/serialbus/qcanbusdeviceinfo.h
new file mode 100644
index 0000000..33bf1c8
--- /dev/null
+++ b/src/serialbus/qcanbusdeviceinfo.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCANBUSDEVICEINFO_H
+#define QCANBUSDEVICEINFO_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qstring.h>
+#include <QtSerialBus/qserialbusglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCanBusDeviceInfoPrivate;
+class QCanBusDeviceInfoPrivateDeleter;
+
+class Q_SERIALBUS_EXPORT QCanBusDeviceInfo
+{
+public:
+ QCanBusDeviceInfo();
+ QCanBusDeviceInfo(const QCanBusDeviceInfo &other);
+ ~QCanBusDeviceInfo();
+
+ void swap(QCanBusDeviceInfo other);
+ QCanBusDeviceInfo &operator=(const QCanBusDeviceInfo &other);
+
+ QString name() const;
+
+ bool hasFlexibleDataRate() const;
+ bool isVirtual() const;
+
+private:
+ friend class QCanBusDevice;
+ friend class GenericBusPlugin;
+
+ QCanBusDeviceInfo(QCanBusDeviceInfoPrivate &dd);
+
+ QSharedDataPointer<QCanBusDeviceInfoPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QCANBUSDEVICEINFO_H
diff --git a/src/serialbus/qcanbusdeviceinfo_p.h b/src/serialbus/qcanbusdeviceinfo_p.h
new file mode 100644
index 0000000..ae6d71d
--- /dev/null
+++ b/src/serialbus/qcanbusdeviceinfo_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCANBUSDEVICEINFO_P_H
+#define QCANBUSDEVICEINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCanBusDeviceInfoPrivate : public QSharedData {
+public:
+ QCanBusDeviceInfoPrivate() { }
+
+ ~QCanBusDeviceInfoPrivate()
+ {
+ }
+
+ QString name;
+ QString serialNumber;
+ bool hasFlexibleDataRate = false;
+ bool isVirtual = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QCANBUSDEVICEINFO_P_H
diff --git a/src/serialbus/qcanbusfactory.cpp b/src/serialbus/qcanbusfactory.cpp
index b3df416..db6c294 100644
--- a/src/serialbus/qcanbusfactory.cpp
+++ b/src/serialbus/qcanbusfactory.cpp
@@ -50,6 +50,16 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn QList<QCanBusDeviceInfo> QCanBusFactory::availableDevices(QString *errorMessage) const
+
+ Returns the list of available devices and their capabilities for the QCanBusDevice.
+
+ \a errorMessage contains an error description in case of failure.
+
+ \since 5.9
+*/
+
+/*!
\fn QCanBusDevice *QCanBusFactory::createDevice(const QString &interfaceName,
QString *errorMessage) const
@@ -67,5 +77,4 @@ QT_BEGIN_NAMESPACE
\fn QCanBusFactory::~QCanBusFactory()
*/
-
QT_END_NAMESPACE
diff --git a/src/serialbus/qcanbusfactory.h b/src/serialbus/qcanbusfactory.h
index 4d391c1..2ab9862 100644
--- a/src/serialbus/qcanbusfactory.h
+++ b/src/serialbus/qcanbusfactory.h
@@ -40,12 +40,14 @@
#include <QtCore/qstringlist.h>
#include <QtSerialBus/qserialbusglobal.h>
#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusdeviceinfo.h>
QT_BEGIN_NAMESPACE
class Q_SERIALBUS_EXPORT QCanBusFactory
{
public:
+ virtual QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const = 0;
virtual QCanBusDevice *createDevice(const QString &interfaceName,
QString *errorMessage) const = 0;
protected:
diff --git a/src/serialbus/serialbus.pro b/src/serialbus/serialbus.pro
index 02348da..14583bc 100644
--- a/src/serialbus/serialbus.pro
+++ b/src/serialbus/serialbus.pro
@@ -8,6 +8,7 @@ QMAKE_DOCS = $$PWD/doc/qtserialbus.qdocconf
PUBLIC_HEADERS += \
qcanbusdevice.h \
+ qcanbusdeviceinfo.h \
qcanbusfactory.h \
qcanbusframe.h \
qcanbus.h \
@@ -26,6 +27,7 @@ PUBLIC_HEADERS += \
PRIVATE_HEADERS += \
qcanbusdevice_p.h \
+ qcanbusdeviceinfo_p.h \
qmodbusserver_p.h \
qmodbusclient_p.h \
qmodbusdevice_p.h \
@@ -39,6 +41,7 @@ PRIVATE_HEADERS += \
SOURCES += \
qcanbusdevice.cpp \
+ qcanbusdeviceinfo.cpp \
qcanbus.cpp \
qcanbusfactory.cpp \
qcanbusframe.cpp \