diff options
author | Andre Hartmann <aha_1980@gmx.de> | 2020-02-19 13:46:36 +0100 |
---|---|---|
committer | Andre Hartmann <aha_1980@gmx.de> | 2020-02-27 10:12:27 +0100 |
commit | 99a3d35350c8c474524805de34e432e086204b8a (patch) | |
tree | da7e15bea94aaa257c58b1972faad73f0337a1b3 | |
parent | d7514af334022b7eee5b8f3b181b1fda8e218016 (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.h | 19 | ||||
-rw-r--r-- | src/plugins/canbus/peakcan/peakcanbackend.cpp | 64 | ||||
-rw-r--r-- | src/plugins/canbus/peakcan/peakcanbackend.h | 2 | ||||
-rw-r--r-- | src/serialbus/doc/src/peakcan.qdoc | 4 |
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 |