summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Hartmann <aha_1980@gmx.de>2020-02-19 13:46:36 +0100
committerAndre Hartmann <aha_1980@gmx.de>2020-02-27 10:12:27 +0100
commit99a3d35350c8c474524805de34e432e086204b8a (patch)
treeda7e15bea94aaa257c58b1972faad73f0337a1b3
parentd7514af334022b7eee5b8f3b181b1fda8e218016 (diff)
PeakCAN: Use new device enumeration method from PCAN-Basic 4.4.0
So far only available for Windows, where the new code is much faster. On my system, it takes 115 ms to enumerate both channels of a PCAN USB Pro FD, instead of 901 ms withthe old method. If no PCAN device is connected at all, it returns in 10 ms. (Measured on Windows 7 Pro x64 in VirtualBox with Linux host). On Linux, it has already been blazing fast with the old enumeration code. [ChangeLog][PeakCAN] QCanBusDevice::availableDevices() uses PCAN_ATTACHED_CHANNELS on Windows now and gained a massive speedup. The required PCAN-Basic-API is now 4.4.0 therefore. Fixes: QTBUG-82115 Change-Id: Ic95b2f632110b0b1374b6eaa402cd228f278cdf2 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/plugins/canbus/peakcan/peakcan_symbols_p.h19
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.cpp64
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.h2
-rw-r--r--src/serialbus/doc/src/peakcan.qdoc4
4 files changed, 86 insertions, 3 deletions
diff --git a/src/plugins/canbus/peakcan/peakcan_symbols_p.h b/src/plugins/canbus/peakcan/peakcan_symbols_p.h
index 3618365..9031592 100644
--- a/src/plugins/canbus/peakcan/peakcan_symbols_p.h
+++ b/src/plugins/canbus/peakcan/peakcan_symbols_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2017 Denis Shienkov <denis.shienkov@gmail.com>
+** Copyright (c) 2020 Andre Hartmann <aha_1980@gmx.de>
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
@@ -197,6 +198,8 @@
#define PCAN_BUSSPEED_DATA 0x1BU // Configured CAN data speed as Bits per seconds
#define PCAN_IP_ADDRESS 0x1CU // Remote address of a LAN channel as string in IPv4 format
#define PCAN_LAN_SERVICE_STATUS 0x1DU // Status of the Virtual PCAN-Gateway Service
+#define PCAN_ATTACHED_CHANNELS_COUNT 0x2AU // Get the amount of PCAN channels attached to a system
+#define PCAN_ATTACHED_CHANNELS 0x2BU // Get information about PCAN channels attached to a system
#define FEATURE_FD_CAPABLE 0x01U // Device supports flexible data-rate (CAN-FD)
@@ -225,6 +228,10 @@
#define TRACE_FILE_TIME 0x04U // Includes the start time into the name of the trace file
#define TRACE_FILE_OVERWRITE 0x80U // Causes the overwriting of available traces (same name)
+// Other constants
+#define MAX_LENGTH_HARDWARE_NAME 33 // Maximum length of the name of a device: 32 characters + terminator
+#define MAX_LENGTH_VERSION_STRING 18 // Maximum length of a version string: 17 characters + terminator
+
// PCAN message types
#define PCAN_MESSAGE_STANDARD 0x00U // The PCAN message is a CAN Standard Frame (11-bit identifier)
#define PCAN_MESSAGE_RTR 0x01U // The PCAN message is a CAN Remote-Transfer-Request Frame
@@ -312,6 +319,18 @@ typedef struct tagTPCANMsgFD
quint8 DATA[64]; // Data of the message (DATA[0]..DATA[63])
} TPCANMsgFD;
+// Describes an available PCAN channel
+typedef struct tagTPCANChannelInformation
+{
+ TPCANHandle channel_handle; // PCAN channel handle
+ TPCANDevice device_type; // Kind of PCAN device
+ quint8 controller_number; // CAN-Controller number
+ quint32 device_features; // Device capabilities flag (see FEATURE_*)
+ char device_name[MAX_LENGTH_HARDWARE_NAME]; // Device name
+ quint32 device_id; // Device number
+ quint32 channel_condition; // Availability status of a PCAN-Channel
+} TPCANChannelInformation;
+
#define GENERATE_SYMBOL_VARIABLE(returnType, symbolName, ...) \
typedef returnType (DRV_CALLBACK_TYPE *fp_##symbolName)(__VA_ARGS__); \
static fp_##symbolName symbolName;
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp
index 8154157..82177af 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.cpp
+++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2017 Denis Shienkov <denis.shienkov@gmail.com>
+** Copyright (c) 2020 Andre Hartmann <aha_1980@gmx.de>
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
@@ -44,8 +45,10 @@
#include <QtCore/qtimer.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qscopeguard.h>
#include <algorithm>
+#include <vector>
#ifdef Q_OS_WIN32
# include <QtCore/qwineventnotifier.h>
@@ -126,7 +129,7 @@ static const PcanChannel pcanChannels[] = {
{ "none", PCAN_NONEBUS }
};
-QList<QCanBusDeviceInfo> PeakCanBackend::interfaces()
+QList<QCanBusDeviceInfo> PeakCanBackend::interfacesByChannelCondition()
{
QList<QCanBusDeviceInfo> result;
@@ -168,6 +171,65 @@ QList<QCanBusDeviceInfo> PeakCanBackend::interfaces()
return result;
}
+QList<QCanBusDeviceInfo> PeakCanBackend::interfacesByAttachedChannels(bool *ok)
+{
+ *ok = true;
+ quint32 count = 0;
+ const TPCANStatus countStat = ::CAN_GetValue(0, PCAN_ATTACHED_CHANNELS_COUNT,
+ &count, sizeof(count));
+ if (Q_UNLIKELY(countStat != PCAN_ERROR_OK)) {
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot query PCAN_ATTACHED_CHANNELS_COUNT.");
+ *ok = false;
+ return {};
+ }
+ if (count == 0)
+ return {};
+
+ std::vector<TPCANChannelInformation> infos(count);
+ const TPCANStatus infosStat = ::CAN_GetValue(0, PCAN_ATTACHED_CHANNELS, infos.data(),
+ infos.size() * sizeof(TPCANChannelInformation));
+ if (Q_UNLIKELY(infosStat != PCAN_ERROR_OK)) {
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot query PCAN_ATTACHED_CHANNELS.");
+ *ok = false;
+ return {};
+ }
+
+ QList<QCanBusDeviceInfo> result;
+ for (quint32 i = 0; i < count; ++i) {
+ auto info = infos[i];
+ if (info.channel_condition & PCAN_CHANNEL_AVAILABLE) {
+ const quint32 deviceId = info.channel_handle;
+ const auto pcanChannel = std::find_if(std::begin(pcanChannels), std::end(pcanChannels),
+ [deviceId](PcanChannel channel) {
+ return channel.index == deviceId;
+ });
+ const QString name = pcanChannel->name;
+ const QString description = info.device_name;
+ const QString alias = QString::number(info.device_id);
+ const int channel = info.controller_number;
+ const bool isCanFd = (info.device_features & FEATURE_FD_CAPABLE);
+
+ result.append(std::move(createDeviceInfo(name, QString(), description, alias,
+ channel, false, isCanFd)));
+ }
+ }
+
+ return result;
+}
+
+QList<QCanBusDeviceInfo> PeakCanBackend::interfaces()
+{
+#ifdef Q_OS_WIN
+ bool ok = false;
+ const QList<QCanBusDeviceInfo> attachedChannelsResult = interfacesByAttachedChannels(&ok);
+ if (ok)
+ return attachedChannelsResult;
+#endif
+
+ const QList<QCanBusDeviceInfo> result = interfacesByChannelCondition();
+ return result;
+}
+
#if defined(Q_OS_WIN32)
class PeakCanReadNotifier : public QWinEventNotifier
{
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.h b/src/plugins/canbus/peakcan/peakcanbackend.h
index a9e108e..0ee74c3 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.h
+++ b/src/plugins/canbus/peakcan/peakcanbackend.h
@@ -69,6 +69,8 @@ public:
QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
static bool canCreate(QString *errorReason);
+ static QList<QCanBusDeviceInfo> interfacesByChannelCondition();
+ static QList<QCanBusDeviceInfo> interfacesByAttachedChannels(bool *ok);
static QList<QCanBusDeviceInfo> interfaces();
private:
diff --git a/src/serialbus/doc/src/peakcan.qdoc b/src/serialbus/doc/src/peakcan.qdoc
index 8189c90..c10263b 100644
--- a/src/serialbus/doc/src/peakcan.qdoc
+++ b/src/serialbus/doc/src/peakcan.qdoc
@@ -34,8 +34,8 @@
\l{http://www.peak-system.com/}{PEAK-System} CAN adapters.
This plugin requires the PCAN device drivers and the PCAN-Basic library
- version 4.0.0 or higher on Windows (pcanbasic.dll) and Linux (libpcanbasic.so).
- On macOS the plugin requires the PCBUSB library from
+ version 4.4.0 or higher on Windows (pcanbasic.dll) resp. 4.0.0 on Linux
+ (libpcanbasic.so). On macOS the plugin requires the PCBUSB library from
\l{http://www.mac-can.com}{UV Software}.
\note QCanBusDeviceInfo::alias() is only supported on Windows and with