summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/serialbus/can/connectdialog.cpp6
-rw-r--r--examples/serialbus/can/connectdialog.ui25
-rw-r--r--examples/serialbus/can/main.cpp3
-rw-r--r--src/plugins/canbus/canbus.pro2
-rw-r--r--src/plugins/canbus/passthrucan/j2534passthru.cpp222
-rw-r--r--src/plugins/canbus/passthrucan/j2534passthru.h332
-rw-r--r--src/plugins/canbus/passthrucan/main.cpp71
-rw-r--r--src/plugins/canbus/passthrucan/passthrucan.pro21
-rw-r--r--src/plugins/canbus/passthrucan/passthrucanbackend.cpp273
-rw-r--r--src/plugins/canbus/passthrucan/passthrucanbackend.h84
-rw-r--r--src/plugins/canbus/passthrucan/passthrucanio.cpp314
-rw-r--r--src/plugins/canbus/passthrucan/passthrucanio.h98
-rw-r--r--src/plugins/canbus/passthrucan/plugin.json3
-rw-r--r--src/plugins/canbus/peakcan/main.cpp6
-rw-r--r--src/plugins/canbus/peakcan/peakcan_symbols_p.h20
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.cpp61
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend_p.h4
-rw-r--r--src/plugins/canbus/socketcan/main.cpp4
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.cpp39
-rw-r--r--src/plugins/canbus/systeccan/main.cpp6
-rw-r--r--src/plugins/canbus/systeccan/systeccan_symbols_p.h2
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.cpp55
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.h6
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend_p.h2
-rw-r--r--src/plugins/canbus/tinycan/main.cpp6
-rw-r--r--src/plugins/canbus/tinycan/tinycan_symbols_p.h2
-rw-r--r--src/plugins/canbus/tinycan/tinycanbackend.cpp15
-rw-r--r--src/plugins/canbus/vectorcan/main.cpp6
-rw-r--r--src/plugins/canbus/vectorcan/vectorcan_symbols_p.h2
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.cpp20
-rw-r--r--src/serialbus/doc/src/passthrucan.qdoc155
-rw-r--r--src/serialbus/doc/src/qtcanbus-backends.qdoc4
-rw-r--r--src/serialbus/doc/src/qtserialbus-index.qdoc23
-rw-r--r--src/serialbus/qcanbusdevice.cpp40
-rw-r--r--src/serialbus/qcanbusdevice.h3
-rw-r--r--src/serialbus/qcanbusdeviceinfo.cpp32
-rw-r--r--src/serialbus/qcanbusdeviceinfo.h3
-rw-r--r--src/serialbus/qcanbusdeviceinfo_p.h2
-rw-r--r--src/serialbus/qcanbusframe.h11
-rw-r--r--src/tools/canbusutil/canbusutil.cpp96
-rw-r--r--src/tools/canbusutil/canbusutil.h16
-rw-r--r--src/tools/canbusutil/main.cpp26
-rw-r--r--src/tools/canbusutil/readtask.cpp19
-rw-r--r--src/tools/canbusutil/readtask.h8
-rw-r--r--tests/auto/plugins/genericcanbus/dummybackend.cpp27
-rw-r--r--tests/auto/plugins/genericcanbus/dummybackend.h5
-rw-r--r--tests/auto/plugins/genericcanbus/main.cpp1
-rw-r--r--tests/auto/plugins/genericcanbusv1/dummybackendv1.cpp6
-rw-r--r--tests/auto/plugins/genericcanbusv1/dummybackendv1.h2
-rw-r--r--tests/auto/qcanbus/tst_qcanbus.cpp12
-rw-r--r--tests/auto/qcanbusdevice/tst_qcanbusdevice.cpp152
-rw-r--r--tests/auto/qcanbusframe/tst_qcanbusframe.cpp54
53 files changed, 2106 insertions, 303 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 006073e..c9d5d20 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,4 +2,4 @@ load(qt_build_config)
CONFIG += warning_clean
DEFINES += QT_NO_FOREACH
-MODULE_VERSION = 5.10.1
+MODULE_VERSION = 5.11.0
diff --git a/examples/serialbus/can/connectdialog.cpp b/examples/serialbus/can/connectdialog.cpp
index 5a12592..601ef2c 100644
--- a/examples/serialbus/can/connectdialog.cpp
+++ b/examples/serialbus/can/connectdialog.cpp
@@ -115,6 +115,12 @@ void ConnectDialog::interfaceChanged(const QString &interface)
for (const QCanBusDeviceInfo &info : qAsConst(m_interfaces)) {
if (info.name() == interface) {
+ m_ui->descriptionLabel->setText(info.description());
+ QString serialNumber = info.serialNumber();
+ if (serialNumber.isEmpty())
+ serialNumber = tr("n/a");
+ m_ui->serialNumberLabel->setText(tr("Serial: %1").arg(serialNumber));
+ m_ui->channelLabel->setText(tr("Channel: %1").arg(info.channel()));
m_ui->isVirtual->setChecked(info.isVirtual());
m_ui->isFlexibleDataRateCapable->setChecked(info.hasFlexibleDataRate());
break;
diff --git a/examples/serialbus/can/connectdialog.ui b/examples/serialbus/can/connectdialog.ui
index def6e59..6d4f261 100644
--- a/examples/serialbus/can/connectdialog.ui
+++ b/examples/serialbus/can/connectdialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>441</width>
- <height>341</height>
+ <width>446</width>
+ <height>395</height>
</rect>
</property>
<property name="windowTitle">
@@ -192,6 +192,27 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="serialNumberLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="channelLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="isFlexibleDataRateCapable">
<property name="text">
<string>Flexible Data Rate</string>
diff --git a/examples/serialbus/can/main.cpp b/examples/serialbus/can/main.cpp
index 28cb478..757f3aa 100644
--- a/examples/serialbus/can/main.cpp
+++ b/examples/serialbus/can/main.cpp
@@ -49,10 +49,13 @@
****************************************************************************/
#include "mainwindow.h"
+
#include <QApplication>
+#include <QLoggingCategory>
int main(int argc, char *argv[])
{
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.canbus* = true"));
QApplication a(argc, argv);
MainWindow w;
w.show();
diff --git a/src/plugins/canbus/canbus.pro b/src/plugins/canbus/canbus.pro
index 37db8a3..0eddffc 100644
--- a/src/plugins/canbus/canbus.pro
+++ b/src/plugins/canbus/canbus.pro
@@ -7,6 +7,6 @@ qtConfig(socketcan) {
}
qtConfig(library) {
- SUBDIRS += peakcan tinycan
+ SUBDIRS += passthrucan peakcan tinycan
win32:SUBDIRS += systeccan vectorcan
}
diff --git a/src/plugins/canbus/passthrucan/j2534passthru.cpp b/src/plugins/canbus/passthrucan/j2534passthru.cpp
new file mode 100644
index 0000000..22bf996
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/j2534passthru.cpp
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 "j2534passthru.h"
+
+#include <QtEndian>
+
+#include <cstring>
+
+namespace {
+
+enum Ioctl {
+ GetConfig = 1,
+ SetConfig = 2
+};
+
+// Template to model the structs SCONFIG_LIST, SBYTE_ARRAY etc as defined
+// in the J2534 spec.
+template <typename T>
+struct SArray
+{
+ SArray(ulong n, T *p) : num(n), ptr(p) {}
+ // On Windows x64, ulong is 32 bit wide and thus the value would normally
+ // be padded so that the pointer begins on a 64-bit boundary. It is not
+ // clear from the J2534 spec whether structs should be packed or not on
+ // x64. Most vendors still only provide a 32-bit DLL, but there is at
+ // least one x64 implementation (from Hatteland Display) out there which
+ // does not pack this struct.
+ ulong num;
+ T *ptr;
+};
+
+// Fixed-length string buffers must be at least 80 bytes according to the spec.
+// The example code in the spec document uses 256 bytes though -- let's play it
+// safe and do so, too.
+const int StringBufferSize = 256;
+
+} // anonymous namespace
+
+Q_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_PASSTHRU, "qt.canbus.plugins.passthru", QtWarningMsg)
+
+namespace J2534 {
+
+Message::Message()
+{
+ std::memset(m_data, 0, sizeof(m_data));
+}
+
+Message::Message(Protocol proto)
+ : m_protocolId (ulong(proto))
+{
+ std::memset(m_data, 0, sizeof(m_data));
+}
+
+PassThru::PassThru(const QString &libraryPath, QObject *parent)
+ : QObject(parent)
+ , m_libJ2534 (libraryPath, this)
+{
+ if (!m_libJ2534.load()
+ || !resolveApiFunction(&m_ptOpen, "PassThruOpen")
+ || !resolveApiFunction(&m_ptClose, "PassThruClose")
+ || !resolveApiFunction(&m_ptConnect, "PassThruConnect")
+ || !resolveApiFunction(&m_ptDisconnect, "PassThruDisconnect")
+ || !resolveApiFunction(&m_ptReadMsgs, "PassThruReadMsgs")
+ || !resolveApiFunction(&m_ptWriteMsgs, "PassThruWriteMsgs")
+ || !resolveApiFunction(&m_ptStartMsgFilter, "PassThruStartMsgFilter")
+ || !resolveApiFunction(&m_ptGetLastError, "PassThruGetLastError")
+ || !resolveApiFunction(&m_ptIoctl, "PassThruIoctl")) {
+
+ m_lastError = LoadFailed;
+ m_lastErrorString = m_libJ2534.errorString();
+
+ qCWarning(QT_CANBUS_PLUGINS_PASSTHRU, "%ls", qUtf16Printable(m_lastErrorString));
+ }
+}
+
+PassThru::~PassThru()
+{
+ m_libJ2534.unload();
+}
+
+PassThru::Status PassThru::open(const QByteArray &name, Handle *deviceId)
+{
+ Q_ASSERT(m_ptOpen);
+
+ const char *const devName = (name.isEmpty()) ? nullptr : name.data();
+ const long status = (*m_ptOpen)(devName, deviceId);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::close(Handle deviceId)
+{
+ Q_ASSERT(m_ptClose);
+
+ const long status = (*m_ptClose)(deviceId);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::connect(Handle deviceId, Protocol protocolId,
+ ConnectFlags flags, uint baudRate, Handle *channelId)
+{
+ Q_ASSERT(m_ptConnect);
+
+ const long status = (*m_ptConnect)(deviceId, ulong(protocolId),
+ flags, baudRate, channelId);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::disconnect(Handle channelId)
+{
+ Q_ASSERT(m_ptDisconnect);
+
+ const long status = (*m_ptDisconnect)(channelId);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::readMsgs(Handle channelId, Message *msgs,
+ ulong *numMsgs, uint timeout)
+{
+ Q_ASSERT(m_ptReadMsgs);
+
+ const long status = (*m_ptReadMsgs)(channelId, msgs, numMsgs, timeout);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::writeMsgs(Handle channelId, const Message *msgs,
+ ulong *numMsgs, uint timeout)
+{
+ Q_ASSERT(m_ptWriteMsgs);
+
+ const long status = (*m_ptWriteMsgs)(channelId, msgs, numMsgs, timeout);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::startMsgFilter(Handle channelId, FilterType filterType,
+ const Message &maskMsg, const Message &patternMsg)
+{
+ Q_ASSERT(m_ptStartMsgFilter);
+
+ // The CAN pass-thru plugin implementation does not need the filter ID.
+ Handle filterId = 0;
+
+ const long status = (*m_ptStartMsgFilter)(channelId, filterType, &maskMsg,
+ &patternMsg, nullptr, &filterId);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::setConfig(Handle channelId, const Config *params, ulong numParams)
+{
+ Q_ASSERT(m_ptIoctl);
+
+ const SArray<const Config> configList {numParams, params};
+ const long status = (*m_ptIoctl)(channelId, SetConfig, &configList, nullptr);
+ return handleResult(status);
+}
+
+PassThru::Status PassThru::clear(Handle channelId, ClearTarget target)
+{
+ Q_ASSERT(m_ptIoctl);
+
+ const long status = (*m_ptIoctl)(channelId, target, nullptr, nullptr);
+ return handleResult(status);
+}
+
+QString PassThru::lastErrorString() const
+{
+ return m_lastErrorString;
+}
+
+PassThru::Status PassThru::handleResult(long statusCode)
+{
+ if (Q_UNLIKELY(statusCode != NoError)) {
+ m_lastError = Status(statusCode);
+
+ QByteArray description (StringBufferSize, 0);
+ Q_ASSERT(m_ptGetLastError);
+ const long descStatus = (*m_ptGetLastError)(description.data());
+
+ if (Q_LIKELY(descStatus == NoError)) {
+ m_lastErrorString = QString::fromLatin1(description);
+ } else {
+ m_lastErrorString = tr("Command failed with status code %1").arg(statusCode);
+ qCWarning(QT_CANBUS_PLUGINS_PASSTHRU, "GetLastError failed with code %ld", descStatus);
+ }
+ }
+ return Status(statusCode);
+}
+
+} // namespace J2534
diff --git a/src/plugins/canbus/passthrucan/j2534passthru.h b/src/plugins/canbus/passthrucan/j2534passthru.h
new file mode 100644
index 0000000..a9b88f4
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/j2534passthru.h
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 PASSTHRUCAN_J2534PASSTHRU_H
+#define PASSTHRUCAN_J2534PASSTHRU_H
+
+#include <QByteArray>
+#include <QLibrary>
+#include <QLoggingCategory>
+#include <QObject>
+#include <QString>
+
+#ifdef Q_OS_WIN32
+# define J2534_API __stdcall
+#else
+# define J2534_API
+#endif
+
+Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_PASSTHRU)
+
+namespace J2534 {
+
+class Message;
+
+extern "C" {
+
+typedef long (J2534_API *PassThruOpenFunc)(const void *pName, ulong *pDeviceId);
+typedef long (J2534_API *PassThruCloseFunc)(ulong deviceId);
+typedef long (J2534_API *PassThruConnectFunc)(ulong deviceId, ulong protocolId, ulong flags,
+ ulong baudRate, ulong *pChannelId);
+typedef long (J2534_API *PassThruDisconnectFunc)(ulong channelId);
+typedef long (J2534_API *PassThruReadMsgsFunc)(ulong channelId, Message *pMsg,
+ ulong *pNumMsgs, ulong timeout);
+typedef long (J2534_API *PassThruWriteMsgsFunc)(ulong channelId, const Message *pMsg,
+ ulong *pNumMsgs, ulong timeout);
+typedef long (J2534_API *PassThruStartMsgFilterFunc)(ulong channelID, ulong filterType,
+ const Message *pMaskMsg,
+ const Message *pPatternMsg,
+ const Message *pFlowControlMsg,
+ ulong *pFilterId);
+typedef long (J2534_API *PassThruGetLastErrorFunc)(char *pErrorDescription);
+typedef long (J2534_API *PassThruIoctlFunc)(ulong channelId, ulong ioctlId,
+ const void *pInput, void *pOutput);
+} // extern "C"
+
+enum class Protocol : uint {
+ J1850VPW = 1,
+ J1850PWM,
+ ISO9141,
+ ISO14230,
+ CAN,
+ ISO15765,
+ SCIAEngine,
+ SCIATrans,
+ SCIBEngine,
+ SCIBTrans
+};
+
+class Message
+{
+public:
+ static const ulong maxSize = 4128;
+
+ enum RxStatusBit {
+ InTxMsgType = 1 << 0,
+ InStartOfMessage = 1 << 1,
+ InRxBreak = 1 << 2,
+ InTxIndication = 1 << 3,
+ InISO15765PaddingError = 1 << 4,
+ InISO15765AddrType = 1 << 7,
+ InCAN29BitID = 1 << 8
+ };
+ Q_DECLARE_FLAGS(RxStatus, RxStatusBit)
+
+ enum TxFlag {
+ OutISO15765FramePad = 1 << 6,
+ OutISO15765AddrType = 1 << 7,
+ OutCAN29BitID = 1 << 8,
+ OutWaitP3MinOnly = 1 << 9
+ };
+ Q_DECLARE_FLAGS(TxFlags, TxFlag)
+
+ Message();
+ explicit Message(Protocol proto);
+
+ Protocol protocolId() const { return Protocol(m_protocolId); }
+ void setProtocolId(Protocol proto) { m_protocolId = uint(proto); }
+
+ RxStatus rxStatus() const { return RxStatus(uint(m_rxStatus)); }
+ void setRxStatus(RxStatus status) { m_rxStatus = uint(status); }
+
+ TxFlags txFlags() const { return TxFlags(uint(m_txFlags)); }
+ void setTxFlags(TxFlags flags) { m_txFlags = uint(flags); }
+
+ ulong timestamp() const { return m_timestamp; }
+ void setTimestamp(ulong stamp) { m_timestamp = stamp; }
+
+ ulong size() const { return m_dataSize; }
+ void setSize(ulong dataSize) { m_dataSize = dataSize; }
+
+ ulong extraDataIndex() const { return m_extraDataIndex; }
+ void setExtraDataIndex(ulong index) { m_extraDataIndex = index; }
+
+ char *data() { return m_data; }
+ const char *data() const { return m_data; }
+
+private:
+ ulong m_protocolId = 0;
+ ulong m_rxStatus = 0;
+ ulong m_txFlags = 0;
+ ulong m_timestamp = 0;
+ ulong m_dataSize = 0;
+ ulong m_extraDataIndex = 0;
+ char m_data[maxSize];
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Message::RxStatus)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Message::TxFlags)
+
+class Config
+{
+public:
+ enum Parameter {
+ DataRate = 1,
+
+ Loopback = 3,
+ NodeAddress,
+ NetworkLine,
+ P1Min,
+ P1Max,
+ P2Min,
+ P2Max,
+ P3Min,
+ P3Max,
+ P4Min,
+ P4Max,
+ W1,
+ W2,
+ W3,
+ W4,
+ W5,
+ Tidle,
+ Tinil,
+ Twup,
+ Parity,
+ BitSamplePoint,
+ SyncJumpWidth,
+ W0,
+ T1Max,
+ T2Max,
+ T4Max,
+ T5Max,
+ ISO15765BS,
+ ISO15765STmin,
+ DataBits,
+ FiveBaudMod,
+ BSTx,
+ STminTx,
+ T3Max,
+ ISO15765WFTMax,
+
+ CanMixedFormat = 0x8000,
+ J1962Pins,
+
+ SWCANHSDataRate = 0x8010,
+ SWCANSpeedchangeEnable,
+ SWCANResSwitch,
+
+ ActiveChannels = 0x8020,
+ SampleRate,
+ SamplesPerReading,
+ ReadingsPerMsg,
+ AveragingMethod,
+ SampleResolution,
+ InputRangeLow,
+ InputRangeHigh
+ };
+
+ Config() : m_parameter(0), m_value(0) {}
+ explicit Config(Parameter param, ulong val = 0) : m_parameter(param), m_value(val) {}
+
+ Parameter parameter() const { return Parameter(m_parameter); }
+ ulong value() const { return m_value; }
+
+private:
+ ulong m_parameter;
+ ulong m_value;
+};
+
+/**
+ * @brief J2534 pass-through interface, version 04.04.
+ * @internal
+ * @see http://www.drewtech.com/support/passthru.html
+ */
+class PassThru : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(PassThru)
+public:
+ typedef ulong Handle;
+
+ enum Status {
+ LoadFailed = -1,
+ NoError = 0,
+ NotSupported,
+ InvalidChannelID,
+ InvalidProtocolID,
+ NullParameter,
+ InvalidIoctlValue,
+ InvalidFlags,
+ Failed,
+ DeviceNotConnected,
+ Timeout,
+ InvalidMsg,
+ InvalidTimeInterval,
+ ExceededLimit,
+ InvalidMsgID,
+ DeviceInUse,
+ InvalidIoctlID,
+ BufferEmpty,
+ BufferFull,
+ BufferOverflow,
+ PinInvalid,
+ ChannelInUse,
+ MsgProtocolID,
+ InvalidFilterID,
+ NoFlowControl,
+ NotUnique,
+ InvalidBaudrate,
+ InvalidDeviceID
+ };
+
+ enum ConnectFlag {
+ CAN29BitID = 1 << 8,
+ ISO9141NoChecksum = 1 << 9,
+ CANIDBoth = 1 << 11,
+ ISO9141KLineOnly = 1 << 12
+ };
+ Q_DECLARE_FLAGS(ConnectFlags, ConnectFlag)
+
+ enum FilterType {
+ PassFilter = 1,
+ BlockFilter,
+ FlowControlFilter
+ };
+
+ enum ClearTarget {
+ TxBuffer = 7,
+ RxBuffer,
+ PeriodicMsgs,
+ MsgFilters
+ };
+
+ explicit PassThru(const QString &libraryPath, QObject *parent = nullptr);
+ virtual ~PassThru();
+
+ Status open(const QByteArray &name, Handle *deviceId);
+ Status close(Handle deviceId);
+ Status connect(Handle deviceId, Protocol protocolId, ConnectFlags flags,
+ uint baudRate, Handle *channelId);
+ Status disconnect(Handle channelId);
+ Status readMsgs(Handle channelId, Message *msgs, ulong *numMsgs, uint timeout = 0);
+ Status writeMsgs(Handle channelId, const Message *msgs, ulong *numMsgs, uint timeout = 0);
+ Status startMsgFilter(Handle channelId, FilterType filterType,
+ const Message &maskMsg, const Message &patternMsg);
+ Status setConfig(Handle channelId, const Config *params, ulong numParams = 1);
+ Status clear(Handle channelId, ClearTarget target);
+
+ Status lastError() const { return m_lastError; }
+ QString lastErrorString() const;
+
+private:
+ Status handleResult(long statusCode);
+
+ template <typename Func>
+ Func resolveApiFunction(Func *funcPtr, const char *name) {
+ *funcPtr = reinterpret_cast<Func>(m_libJ2534.resolve(name));
+ return *funcPtr;
+ }
+
+ QLibrary m_libJ2534;
+ PassThruOpenFunc m_ptOpen = nullptr;
+ PassThruCloseFunc m_ptClose = nullptr;
+ PassThruConnectFunc m_ptConnect = nullptr;
+ PassThruDisconnectFunc m_ptDisconnect = nullptr;
+ PassThruReadMsgsFunc m_ptReadMsgs = nullptr;
+ PassThruWriteMsgsFunc m_ptWriteMsgs = nullptr;
+ PassThruStartMsgFilterFunc m_ptStartMsgFilter = nullptr;
+ PassThruGetLastErrorFunc m_ptGetLastError = nullptr;
+ PassThruIoctlFunc m_ptIoctl = nullptr;
+ QString m_lastErrorString;
+ Status m_lastError = NoError;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(PassThru::ConnectFlags)
+
+} // namespace J2534
+
+#endif // PASSTHRUCAN_J2534PASSTHRU_H
diff --git a/src/plugins/canbus/passthrucan/main.cpp b/src/plugins/canbus/passthrucan/main.cpp
new file mode 100644
index 0000000..5017597
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 "passthrucanbackend.h"
+
+#include <QtSerialBus/qcanbus.h>
+#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusfactory.h>
+
+QT_BEGIN_NAMESPACE
+
+class PassThruCanBusPlugin : public QObject, public QCanBusFactoryV2
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QCanBusFactory" FILE "plugin.json")
+ Q_INTERFACES(QCanBusFactoryV2)
+
+public:
+ PassThruCanBusPlugin()
+ {
+ qRegisterMetaType<QCanBusDevice::CanBusError>();
+ qRegisterMetaType<QVector<QCanBusFrame>>();
+ }
+
+ QList<QCanBusDeviceInfo> availableDevices(QString *) const override
+ {
+ return PassThruCanBackend::interfaces();
+ }
+
+ QCanBusDevice *createDevice(const QString &interfaceName, QString *) const override
+ {
+ return new PassThruCanBackend(interfaceName);
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/canbus/passthrucan/passthrucan.pro b/src/plugins/canbus/passthrucan/passthrucan.pro
new file mode 100644
index 0000000..96ed090
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/passthrucan.pro
@@ -0,0 +1,21 @@
+QT = serialbus
+
+TARGET = qtpassthrucanbus
+
+SOURCES += \
+ j2534passthru.cpp \
+ main.cpp \
+ passthrucanio.cpp \
+ passthrucanbackend.cpp
+
+HEADERS += \
+ j2534passthru.h \
+ passthrucanio.h \
+ passthrucanbackend.h
+
+DISTFILES = plugin.json
+
+PLUGIN_TYPE = canbus
+PLUGIN_EXTENDS = serialbus
+PLUGIN_CLASS_NAME = PassThruCanBusPlugin
+load(qt_plugin)
diff --git a/src/plugins/canbus/passthrucan/passthrucanbackend.cpp b/src/plugins/canbus/passthrucan/passthrucanbackend.cpp
new file mode 100644
index 0000000..2c18160
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/passthrucanbackend.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 "passthrucanbackend.h"
+#include "passthrucanio.h"
+
+#include <QEventLoop>
+#include <QSettings>
+
+namespace {
+
+#ifdef Q_OS_WIN32
+
+static inline QString registryPath()
+{
+ return QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\PassThruSupport.04.04");
+}
+
+static QString canAdapterName(const QSettings &entries)
+{
+ const int supportsCan = entries.value(QStringLiteral("CAN")).toInt();
+ if (supportsCan)
+ return entries.value(QStringLiteral("Name")).toString();
+ return {};
+}
+
+static QString libraryForAdapter(const QString &adapterName)
+{
+ QString library;
+ QSettings entries (registryPath(), QSettings::NativeFormat);
+ const QStringList groups = entries.childGroups();
+
+ for (const auto &group : groups) {
+ entries.beginGroup(group);
+
+ const QString name = canAdapterName(entries);
+ if (!name.isEmpty() && (adapterName.isEmpty() ||
+ name.compare(adapterName, Qt::CaseInsensitive) == 0))
+ library = entries.value(QStringLiteral("FunctionLibrary")).toString();
+
+ entries.endGroup();
+
+ if (!library.isEmpty())
+ break;
+ }
+ return library;
+}
+
+#else // !Q_OS_WIN32
+
+static QString libraryForAdapter(const QString &adapterName)
+{
+ // Insert system-specific device name to J2534 library name mapping here.
+ // For now, allow the path to the J2534 library to be specified directly
+ // as the adapter name.
+ return adapterName;
+}
+
+#endif // !Q_OS_WIN32
+
+} // anonymous namespace
+
+PassThruCanBackend::PassThruCanBackend(const QString &name, QObject *parent)
+ : QCanBusDevice(parent)
+ , m_deviceName (name)
+ , m_canIO (new PassThruCanIO())
+{
+ m_canIO->moveToThread(&m_ioThread);
+
+ // Signals emitted by the I/O thread, to be queued.
+ connect(m_canIO, &PassThruCanIO::errorOccurred,
+ this, &PassThruCanBackend::setError);
+ connect(m_canIO, &PassThruCanIO::openFinished,
+ this, &PassThruCanBackend::ackOpenFinished);
+ connect(m_canIO, &PassThruCanIO::closeFinished,
+ this, &PassThruCanBackend::ackCloseFinished);
+ connect(m_canIO, &PassThruCanIO::messagesReceived,
+ this, &PassThruCanBackend::enqueueReceivedFrames);
+ connect(m_canIO, &PassThruCanIO::messagesSent,
+ this, &QCanBusDevice::framesWritten);
+}
+
+PassThruCanBackend::~PassThruCanBackend()
+{
+ if (state() != UnconnectedState) {
+ // If the I/O thread is still active at this point, we will have to
+ // wait for it to finish.
+ QEventLoop loop;
+ connect(&m_ioThread, &QThread::finished, &loop, &QEventLoop::quit);
+
+ if (state() != ClosingState)
+ disconnectDevice();
+
+ while (!m_ioThread.isFinished())
+ loop.exec(QEventLoop::ExcludeUserInputEvents);
+ }
+ m_canIO->deleteLater();
+}
+
+void PassThruCanBackend::setConfigurationParameter(int key, const QVariant &value)
+{
+ QCanBusDevice::setConfigurationParameter(key, value);
+
+ if (state() == ConnectedState)
+ applyConfig(key, value);
+}
+
+bool PassThruCanBackend::writeFrame(const QCanBusFrame &frame)
+{
+ if (state() != ConnectedState) {
+ setError(tr("Device is not connected"), WriteError);
+ return false;
+ }
+ if (!frame.isValid()) {
+ setError(tr("Invalid CAN bus frame"), WriteError);
+ return false;
+ }
+ if (frame.frameType() != QCanBusFrame::DataFrame) {
+ setError(tr("Unsupported CAN frame type"), WriteError);
+ return false;
+ }
+ // Push the frame directly to the write queue of the worker thread,
+ // bypassing the QCanBusDevice output queue. Despite the duplicated
+ // queue, things are cleaner this way as it avoids a reverse dependency
+ // from the worker object on the QCanBusDevice object.
+ return m_canIO->enqueueMessage(frame);
+}
+
+QString PassThruCanBackend::interpretErrorFrame(const QCanBusFrame &)
+{
+ // J2534 Pass-thru v04.04 does not seem to support error frames.
+ return {};
+}
+
+QList<QCanBusDeviceInfo> PassThruCanBackend::interfaces()
+{
+ QList<QCanBusDeviceInfo> list;
+#ifdef Q_OS_WIN32
+ QSettings entries (registryPath(), QSettings::NativeFormat);
+ const QStringList groups = entries.childGroups();
+
+ for (const auto &group : groups) {
+ entries.beginGroup(group);
+
+ const QString name = canAdapterName(entries);
+ if (!name.isEmpty())
+ list.append(createDeviceInfo(name));
+
+ entries.endGroup();
+ }
+#endif
+ return list;
+}
+
+bool PassThruCanBackend::open()
+{
+ if (Q_UNLIKELY(state() != ConnectingState)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Unexpected state on open");
+ return false;
+ }
+ // Support a special "adapter%subdevice" syntax to allow control of the
+ // device name passed to the J2534 library's PassThruOpen() function.
+ // If the "%subdevice" suffix is not used, the J2534 interface library
+ // will choose a default or ask the user.
+ const int splitPos = m_deviceName.indexOf(QChar::fromLatin1('%'));
+ const QString adapter = m_deviceName.left(splitPos);
+ QByteArray subDev;
+
+ if (splitPos >= 0)
+ subDev = m_deviceName.midRef(splitPos + 1).toLatin1();
+
+ const QString library = libraryForAdapter(adapter);
+ if (library.isEmpty()) {
+ setError(tr("Adapter not found: %1").arg(adapter), ConnectionError);
+ return false;
+ }
+ bool ok = false;
+ uint bitRate = configurationParameter(BitRateKey).toUInt(&ok);
+ if (!ok) {
+ bitRate = 500*1000; // default initial bit rate
+ setConfigurationParameter(BitRateKey, bitRate);
+ }
+ m_ioThread.start();
+
+ return QMetaObject::invokeMethod(m_canIO, "open", Qt::QueuedConnection,
+ Q_ARG(QString, library),
+ Q_ARG(QByteArray, subDev),
+ Q_ARG(uint, bitRate));
+}
+
+void PassThruCanBackend::close()
+{
+ if (Q_UNLIKELY(state() != ClosingState)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Unexpected state on close");
+ return;
+ }
+ QMetaObject::invokeMethod(m_canIO, "close", Qt::QueuedConnection);
+}
+
+void PassThruCanBackend::ackOpenFinished(bool success)
+{
+ // Do not transition to connected state if close() has been called
+ // in the meantime.
+ if (state() != ConnectingState)
+ return;
+
+ if (success) {
+ const QVariant loopback = configurationParameter(LoopbackKey);
+ if (loopback.toBool())
+ applyConfig(LoopbackKey, loopback);
+
+ QVariant filters = configurationParameter(RawFilterKey);
+ if (!filters.isValid()) {
+ // Configure default match-all filter.
+ filters = QVariant::fromValue(QList<Filter>{Filter{}});
+ setConfigurationParameter(RawFilterKey, filters);
+ }
+ applyConfig(RawFilterKey, filters);
+
+ QMetaObject::invokeMethod(m_canIO, "listen", Qt::QueuedConnection);
+
+ setState(ConnectedState);
+ } else {
+ setState(UnconnectedState);
+ }
+}
+
+void PassThruCanBackend::ackCloseFinished()
+{
+ m_ioThread.exit(0);
+ m_ioThread.wait();
+
+ setState(UnconnectedState);
+}
+
+void PassThruCanBackend::applyConfig(int key, const QVariant &value)
+{
+ QMetaObject::invokeMethod(m_canIO, "applyConfig", Qt::QueuedConnection,
+ Q_ARG(int, key), Q_ARG(QVariant, value));
+}
diff --git a/src/plugins/canbus/passthrucan/passthrucanbackend.h b/src/plugins/canbus/passthrucan/passthrucanbackend.h
new file mode 100644
index 0000000..864d1b4
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/passthrucanbackend.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 PASSTHRUCAN_PASSTHRUCANBACKEND_H
+#define PASSTHRUCAN_PASSTHRUCANBACKEND_H
+
+#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusframe.h>
+
+#include <QString>
+#include <QThread>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+class PassThruCanIO;
+
+class PassThruCanBackend : public QCanBusDevice
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(PassThruCanBackend)
+public:
+ explicit PassThruCanBackend(const QString &name, QObject *parent = nullptr);
+ virtual ~PassThruCanBackend();
+
+ void setConfigurationParameter(int key, const QVariant &value) override;
+ bool writeFrame(const QCanBusFrame &frame) override;
+ QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
+
+ static QList<QCanBusDeviceInfo> interfaces();
+
+protected:
+ bool open() override;
+ void close() override;
+
+private:
+ void ackOpenFinished(bool success);
+ void ackCloseFinished();
+ void applyConfig(int key, const QVariant &value);
+
+ QString m_deviceName;
+ QThread m_ioThread;
+ PassThruCanIO * m_canIO;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QCanBusDevice::CanBusError)
+Q_DECLARE_METATYPE(QVector<QCanBusFrame>)
+
+#endif // PASSTHRUCAN_PASSTHRUCANBACKEND_H
diff --git a/src/plugins/canbus/passthrucan/passthrucanio.cpp b/src/plugins/canbus/passthrucan/passthrucanio.cpp
new file mode 100644
index 0000000..dc3d2c7
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/passthrucanio.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 "passthrucanio.h"
+
+#include <QLoggingCategory>
+#include <QtEndian>
+
+#include <cstring>
+
+PassThruCanIO::PassThruCanIO(QObject *parent)
+ : QObject(parent)
+ , m_ioBuffer (8, J2534::Message(J2534::Protocol::CAN))
+{
+}
+
+PassThruCanIO::~PassThruCanIO()
+{
+}
+
+void PassThruCanIO::open(const QString &library, const QByteArray &subDev, uint bitRate)
+{
+ if (Q_UNLIKELY(m_passThru)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Pass-thru interface already open");
+ emit openFinished(false);
+ return;
+ }
+ qCDebug(QT_CANBUS_PLUGINS_PASSTHRU, "Loading interface library: %ls",
+ qUtf16Printable(library));
+
+ m_passThru = new J2534::PassThru(library, this);
+ J2534::PassThru::Status openStatus = m_passThru->lastError();
+
+ if (openStatus == J2534::PassThru::NoError)
+ openStatus = m_passThru->open(subDev, &m_deviceId);
+
+ if (openStatus == J2534::PassThru::NoError
+ && m_passThru->connect(m_deviceId, J2534::Protocol::CAN,
+ J2534::PassThru::CAN29BitID | J2534::PassThru::CANIDBoth,
+ bitRate, &m_channelId) == J2534::PassThru::NoError) {
+ emit openFinished(true);
+ return;
+ }
+ emit errorOccurred(m_passThru->lastErrorString(),
+ QCanBusDevice::ConnectionError);
+
+ if (openStatus == J2534::PassThru::NoError
+ && m_passThru->close(m_deviceId) != J2534::PassThru::NoError)
+ qCWarning(QT_CANBUS_PLUGINS_PASSTHRU, "Failed to close pass-thru device");
+
+ delete m_passThru;
+ m_passThru = nullptr;
+
+ emit openFinished(false);
+}
+
+void PassThruCanIO::close()
+{
+ if (Q_LIKELY(m_passThru)) {
+ delete m_idleNotifier;
+ m_idleNotifier = nullptr;
+
+ if (m_passThru->disconnect(m_channelId) != J2534::PassThru::NoError
+ || m_passThru->close(m_deviceId) != J2534::PassThru::NoError) {
+
+ qCWarning(QT_CANBUS_PLUGINS_PASSTHRU, "Failed to close pass-thru device");
+ emit errorOccurred(m_passThru->lastErrorString(),
+ QCanBusDevice::ConnectionError);
+ }
+ delete m_passThru;
+ m_passThru = nullptr;
+ }
+ emit closeFinished();
+}
+
+void PassThruCanIO::applyConfig(int key, const QVariant &value)
+{
+ if (Q_UNLIKELY(!m_passThru)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Pass-thru interface not open");
+ return;
+ }
+ bool success = true;
+
+ switch (key) {
+ case QCanBusDevice::RawFilterKey:
+ success = setMessageFilters(qvariant_cast<QList<QCanBusDevice::Filter>>(value));
+ break;
+ case QCanBusDevice::LoopbackKey:
+ success = setConfigValue(J2534::Config::Loopback, value.toBool());
+ break;
+ case QCanBusDevice::BitRateKey:
+ success = setConfigValue(J2534::Config::DataRate, value.toUInt());
+ break;
+ default:
+ emit errorOccurred(tr("Unsupported configuration key: %1").arg(key),
+ QCanBusDevice::ConfigurationError);
+ break;
+ }
+ if (!success) {
+ emit errorOccurred(tr("Configuration failed: %1").arg(m_passThru->lastErrorString()),
+ QCanBusDevice::ConfigurationError);
+ }
+}
+
+void PassThruCanIO::listen()
+{
+ if (Q_UNLIKELY(!m_passThru)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Pass-thru interface not open");
+ return;
+ }
+ if (Q_UNLIKELY(m_idleNotifier)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Idle notifier already created");
+ return;
+ }
+ m_idleNotifier = new QTimer(this);
+ connect(m_idleNotifier, &QTimer::timeout, this, &PassThruCanIO::pollForMessages);
+
+ m_idleNotifier->start(0);
+}
+
+bool PassThruCanIO::enqueueMessage(const QCanBusFrame &frame)
+{
+ const QMutexLocker lock (&m_writeGuard);
+ m_writeQueue.append(frame);
+ return true;
+}
+
+bool PassThruCanIO::setMessageFilters(const QList<QCanBusDevice::Filter> &filters)
+{
+ if (m_passThru->clear(m_channelId, J2534::PassThru::MsgFilters) != J2534::PassThru::NoError)
+ return false;
+
+ J2534::Message pattern {J2534::Protocol::CAN};
+ pattern.setSize(4);
+ J2534::Message mask {J2534::Protocol::CAN};
+ mask.setSize(4);
+
+ for (const auto &filter : filters) {
+ if (filter.type != QCanBusFrame::DataFrame
+ && filter.type != QCanBusFrame::InvalidFrame) {
+ emit errorOccurred(tr("Configuration failed: unsupported filter type"),
+ QCanBusDevice::ConfigurationError);
+ break;
+ }
+ if (filter.format & QCanBusDevice::Filter::MatchExtendedFormat)
+ pattern.setRxStatus(J2534::Message::InCAN29BitID);
+ else
+ pattern.setRxStatus({});
+
+ if (filter.format != QCanBusDevice::Filter::MatchBaseAndExtendedFormat)
+ mask.setRxStatus(J2534::Message::InCAN29BitID);
+ else
+ mask.setRxStatus({});
+
+ qToBigEndian<quint32>(filter.frameId & filter.frameIdMask, pattern.data());
+ qToBigEndian<quint32>(filter.frameIdMask, mask.data());
+
+ if (m_passThru->startMsgFilter(m_channelId, J2534::PassThru::PassFilter,
+ mask, pattern) != J2534::PassThru::NoError)
+ return false;
+ }
+ return true;
+}
+
+bool PassThruCanIO::setConfigValue(J2534::Config::Parameter param, ulong value)
+{
+ const J2534::Config config {param, value};
+
+ return (m_passThru->setConfig(m_channelId, &config) == J2534::PassThru::NoError);
+}
+
+void PassThruCanIO::pollForMessages()
+{
+ if (Q_UNLIKELY(!m_passThru)) {
+ qCCritical(QT_CANBUS_PLUGINS_PASSTHRU, "Pass-thru interface not open");
+ return;
+ }
+ const bool writePending = writeMessages();
+ readMessages(writePending);
+}
+
+bool PassThruCanIO::writeMessages()
+{
+ ulong numMsgs = m_ioBuffer.size();
+ {
+ const QMutexLocker lock (&m_writeGuard);
+ numMsgs = qMin<ulong>(m_writeQueue.size(), numMsgs);
+
+ for (ulong i = 0; i < numMsgs; ++i) {
+ const QCanBusFrame &frame = m_writeQueue.at(i);
+ J2534::Message &msg = m_ioBuffer[i];
+
+ const QByteArray payload = frame.payload();
+ const ulong payloadSize = qMin<ulong>(payload.size(),
+ J2534::Message::maxSize - 4);
+ msg.setRxStatus({});
+ msg.setTimestamp(0);
+ msg.setSize(4 + payloadSize);
+ msg.setExtraDataIndex(0);
+
+ if (frame.hasExtendedFrameFormat())
+ msg.setTxFlags(J2534::Message::OutCAN29BitID);
+ else
+ msg.setTxFlags({});
+
+ qToBigEndian<quint32>(frame.frameId(), msg.data());
+ std::memcpy(msg.data() + 4, payload.data(), payloadSize);
+ }
+ }
+ if (numMsgs == 0)
+ return false;
+
+ const auto status = m_passThru->writeMsgs(m_channelId, m_ioBuffer.constData(),
+ &numMsgs, pollTimeout);
+ if (status == J2534::PassThru::BufferFull)
+ return false;
+
+ if (status != J2534::PassThru::NoError && status != J2534::PassThru::Timeout) {
+ emit errorOccurred(tr("Message write failed: %1").arg(m_passThru->lastErrorString()),
+ QCanBusDevice::WriteError);
+ return false;
+ }
+ if (numMsgs == 0)
+ return false;
+
+ bool morePending;
+ {
+ const QMutexLocker lock (&m_writeGuard);
+ // De-queue successfully written frames.
+ m_writeQueue.erase(m_writeQueue.begin(), m_writeQueue.begin() + numMsgs);
+ morePending = !m_writeQueue.isEmpty();
+ }
+ emit messagesSent(numMsgs);
+
+ return morePending;
+}
+
+void PassThruCanIO::readMessages(bool writePending)
+{
+ // If there are outgoing messages waiting to be written, just check
+ // for already received messages but do not block waiting for more.
+ const uint timeout = (writePending) ? 0 : pollTimeout;
+
+ ulong numMsgs = m_ioBuffer.size();
+ const auto status = m_passThru->readMsgs(m_channelId, m_ioBuffer.data(),
+ &numMsgs, timeout);
+ if (status == J2534::PassThru::BufferEmpty)
+ return;
+
+ if (status != J2534::PassThru::NoError && status != J2534::PassThru::Timeout) {
+ emit errorOccurred(tr("Message read failed: %1").arg(m_passThru->lastErrorString()),
+ QCanBusDevice::ReadError);
+ if (status != J2534::PassThru::BufferOverflow)
+ return;
+ }
+ const int numFrames = qMin<ulong>(m_ioBuffer.size(), numMsgs);
+ QVector<QCanBusFrame> frames;
+ frames.reserve(numFrames);
+
+ for (int i = 0; i < numFrames; ++i) {
+ const J2534::Message &msg = m_ioBuffer.at(i);
+ if (Q_UNLIKELY(msg.size() < 4)
+ || Q_UNLIKELY(msg.size() > J2534::Message::maxSize)) {
+ // This normally shouldn't happen, so a log message is appropriate.
+ qCWarning(QT_CANBUS_PLUGINS_PASSTHRU,
+ "Message with invalid size %lu received", msg.size());
+ continue;
+ }
+ const quint32 msgId = qFromBigEndian<quint32>(msg.data());
+ const QByteArray payload (msg.data() + 4, msg.size() - 4);
+
+ QCanBusFrame frame (msgId, payload);
+ frame.setExtendedFrameFormat((msg.rxStatus() & J2534::Message::InCAN29BitID) != 0);
+ frame.setLocalEcho((msg.rxStatus() & J2534::Message::InTxMsgType) != 0);
+ frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(msg.timestamp()));
+
+ frames.append(std::move(frame));
+ }
+ if (!frames.isEmpty())
+ emit messagesReceived(std::move(frames));
+}
diff --git a/src/plugins/canbus/passthrucan/passthrucanio.h b/src/plugins/canbus/passthrucan/passthrucanio.h
new file mode 100644
index 0000000..071174c
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/passthrucanio.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** 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 PASSTHRUCAN_PASSTHRUCANIO_H
+#define PASSTHRUCAN_PASSTHRUCANIO_H
+
+#include "j2534passthru.h"
+
+#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusframe.h>
+#include <QByteArray>
+#include <QList>
+#include <QMutex>
+#include <QObject>
+#include <QString>
+#include <QTimer>
+#include <QVariant>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+class PassThruCanIO : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(PassThruCanIO)
+public:
+ static const uint pollTimeout = 100; // ms
+
+ explicit PassThruCanIO(QObject *parent = nullptr);
+ virtual ~PassThruCanIO();
+
+ Q_INVOKABLE void open(const QString &library, const QByteArray &subDev, uint bitRate);
+ Q_INVOKABLE void close();
+ Q_INVOKABLE void applyConfig(int key, const QVariant &value);
+ Q_INVOKABLE void listen();
+
+ // Internally locked; safe to call directly from any thread.
+ bool enqueueMessage(const QCanBusFrame &frame);
+
+Q_SIGNALS:
+ void errorOccurred(const QString &description, QCanBusDevice::CanBusError error);
+ void messagesReceived(QVector<QCanBusFrame> frames);
+ void messagesSent(qint64 count);
+ void openFinished(bool success);
+ void closeFinished();
+
+private:
+ bool setMessageFilters(const QList<QCanBusDevice::Filter> &filters);
+ bool setConfigValue(J2534::Config::Parameter param, ulong value);
+ void pollForMessages();
+ bool writeMessages();
+ void readMessages(bool writePending);
+
+ J2534::PassThru * m_passThru = nullptr;
+ J2534::PassThru::Handle m_deviceId = 0;
+ J2534::PassThru::Handle m_channelId = 0;
+ QTimer * m_idleNotifier = nullptr;
+ QVector<J2534::Message> m_ioBuffer;
+ QMutex m_writeGuard;
+ QList<QCanBusFrame> m_writeQueue;
+};
+
+QT_END_NAMESPACE
+
+#endif // PASSTHRUCAN_PASSTHRUCANIO_H
diff --git a/src/plugins/canbus/passthrucan/plugin.json b/src/plugins/canbus/passthrucan/plugin.json
new file mode 100644
index 0000000..2026547
--- /dev/null
+++ b/src/plugins/canbus/passthrucan/plugin.json
@@ -0,0 +1,3 @@
+{
+ "Key": "passthrucan"
+}
diff --git a/src/plugins/canbus/peakcan/main.cpp b/src/plugins/canbus/peakcan/main.cpp
index 7444f6d..8ab1b99 100644
--- a/src/plugins/canbus/peakcan/main.cpp
+++ b/src/plugins/canbus/peakcan/main.cpp
@@ -41,8 +41,12 @@
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusfactory.h>
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_PEAKCAN, "qt.canbus.plugins.peakcan")
+
class PeakCanBusPlugin : public QObject, public QCanBusFactoryV2
{
Q_OBJECT
@@ -62,7 +66,7 @@ public:
{
QString errorReason;
if (!PeakCanBackend::canCreate(&errorReason)) {
- qWarning("%ls", qUtf16Printable(errorReason));
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "%ls", qUtf16Printable(errorReason));
if (errorMessage)
*errorMessage = errorReason;
return nullptr;
diff --git a/src/plugins/canbus/peakcan/peakcan_symbols_p.h b/src/plugins/canbus/peakcan/peakcan_symbols_p.h
index 7c91750..d94a7ec 100644
--- a/src/plugins/canbus/peakcan/peakcan_symbols_p.h
+++ b/src/plugins/canbus/peakcan/peakcan_symbols_p.h
@@ -49,24 +49,15 @@
// We mean it.
//
-#ifdef LINK_LIBPCANBASIC
-
-extern "C"
-{
-#include <pcanbasic.h>
-}
-
-#else
-
#include <QtCore/qlibrary.h>
#include <QtCore/qstring.h>
#include <QtCore/qdebug.h>
#ifdef Q_OS_WIN32
-#include <windows.h>
-#define DRV_CALLBACK_TYPE WINAPI
+# include <windows.h>
+# define DRV_CALLBACK_TYPE WINAPI
#else
-#define DRV_CALLBACK_TYPE
+# define DRV_CALLBACK_TYPE
#endif
// Currently defined and supported PCAN channels
@@ -234,6 +225,7 @@ extern "C"
#define PCAN_BAUD_20K 0x532F // 20 kBit/s
#define PCAN_BAUD_10K 0x672F // 10 kBit/s
#define PCAN_BAUD_5K 0x7F7F // 5 kBit/s
+#define PCAN_BAUD_INVALID 0xFFFF // unknown or invalid baudrate
#define PCAN_TYPE_ISA 0x01 // PCAN-ISA 82C200
#define PCAN_TYPE_ISA_SJA 0x09 // PCAN-ISA SJA1000
@@ -277,7 +269,7 @@ typedef struct tagTPCANTimestamp
static fp_##symbolName symbolName;
#define RESOLVE_SYMBOL(symbolName) \
- symbolName = (fp_##symbolName)pcanLibrary->resolve(#symbolName); \
+ symbolName = reinterpret_cast<fp_##symbolName>(pcanLibrary->resolve(#symbolName)); \
if (!symbolName) \
return false;
@@ -314,6 +306,4 @@ inline bool resolveSymbols(QLibrary *pcanLibrary)
return true;
}
-#endif
-
#endif // PEAKCAN_SYMBOLS_P_H
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp
index 8f97f5d..7e6fe43 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.cpp
+++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp
@@ -43,17 +43,20 @@
#include <QtCore/qtimer.h>
#include <QtCore/qcoreevent.h>
+#include <QtCore/qloggingcategory.h>
#include <algorithm>
#ifdef Q_OS_WIN32
-#include <QtCore/qwineventnotifier.h>
+# include <QtCore/qwineventnotifier.h>
#else
-#include <QtCore/qsocketnotifier.h>
+# include <QtCore/qsocketnotifier.h>
#endif
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_PEAKCAN)
+
#ifndef LINK_LIBPCANBASIC
Q_GLOBAL_STATIC(QLibrary, pcanLibrary)
#endif
@@ -76,7 +79,7 @@ struct PcanChannel{
char name[6];
TPCANHandle index;
};
-PcanChannel pcanChannels[] = {
+static const PcanChannel pcanChannels[] = {
{ "usb0", PCAN_USBBUS1 },
{ "usb1", PCAN_USBBUS2 },
{ "usb2", PCAN_USBBUS3 },
@@ -117,14 +120,30 @@ 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,
+ int value = 0;
+ const TPCANHandle index = pcanChannels[i].index;
+ const TPCANStatus stat = ::CAN_GetValue(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,
+ const TPCANStatus fdStat = ::CAN_GetValue(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));
+
+ char description[256] = {0};
+ const TPCANStatus descStat = ::CAN_GetValue(index, PCAN_HARDWARE_NAME,
+ description, sizeof(description));
+ if (descStat != PCAN_ERROR_OK)
+ description[0] = 0;
+
+ int channel = 0;
+ const TPCANStatus chnStat = ::CAN_GetValue(index, PCAN_CONTROLLER_NUMBER,
+ &channel, sizeof(channel));
+ if (chnStat != PCAN_ERROR_OK)
+ channel = 0;
+
+ result.append(std::move(createDeviceInfo(QLatin1String(pcanChannels[i].name),
+ QString(), QLatin1String(description),
+ channel, false, isFd)));
}
}
@@ -154,7 +173,7 @@ protected:
}
private:
- PeakCanBackendPrivate *dptr;
+ PeakCanBackendPrivate * const dptr;
};
#else
class ReadNotifier : public QSocketNotifier
@@ -178,7 +197,7 @@ protected:
}
private:
- PeakCanBackendPrivate *dptr;
+ PeakCanBackendPrivate * const dptr;
};
#endif
@@ -203,7 +222,7 @@ protected:
}
private:
- PeakCanBackendPrivate *dptr;
+ PeakCanBackendPrivate * const dptr;
};
PeakCanBackendPrivate::PeakCanBackendPrivate(PeakCanBackend *q)
@@ -214,7 +233,7 @@ PeakCanBackendPrivate::PeakCanBackendPrivate(PeakCanBackend *q)
struct BitrateItem
{
int bitrate;
- int code;
+ TPCANBaudrate code;
};
struct BitrateLessFunctor
@@ -225,7 +244,7 @@ struct BitrateLessFunctor
}
};
-static int bitrateCodeFromBitrate(int bitrate)
+static TPCANBaudrate bitrateCodeFromBitrate(int bitrate)
{
static const BitrateItem bitratetable[] = {
{ 5000, PCAN_BAUD_5K },
@@ -248,7 +267,7 @@ static int bitrateCodeFromBitrate(int bitrate)
const BitrateItem item = { bitrate , 0 };
const BitrateItem *where = std::lower_bound(bitratetable, endtable, item, BitrateLessFunctor());
- return where != endtable ? where->code : -1;
+ return where != endtable ? where->code : PCAN_BAUD_INVALID;
}
bool PeakCanBackendPrivate::open()
@@ -256,7 +275,7 @@ bool PeakCanBackendPrivate::open()
Q_Q(PeakCanBackend);
const int bitrate = q->configurationParameter(QCanBusDevice::BitRateKey).toInt();
- const int bitrateCode = bitrateCodeFromBitrate(bitrate);
+ const TPCANBaudrate bitrateCode = bitrateCodeFromBitrate(bitrate);
const TPCANStatus st = ::CAN_Initialize(channelIndex, bitrateCode, 0, 0, 0);
if (Q_UNLIKELY(st != PCAN_ERROR_OK)) {
@@ -359,7 +378,7 @@ void PeakCanBackendPrivate::setupDefaultConfigurations()
q->setConfigurationParameter(QCanBusDevice::BitRateKey, 500000);
}
-QString PeakCanBackendPrivate::systemErrorString(int errorCode)
+QString PeakCanBackendPrivate::systemErrorString(TPCANStatus errorCode)
{
QByteArray buffer(256, 0);
if (Q_UNLIKELY(::CAN_GetErrorText(errorCode, 0, buffer.data()) != PCAN_ERROR_OK))
@@ -383,7 +402,7 @@ void PeakCanBackendPrivate::startWrite()
::memset(&message, 0, sizeof(message));
message.ID = frame.frameId();
- message.LEN = payload.size();
+ message.LEN = static_cast<quint8>(payload.size());
message.MSGTYPE = frame.hasExtendedFrameFormat() ? PCAN_MESSAGE_EXTENDED : PCAN_MESSAGE_STANDARD;
if (frame.frameType() == QCanBusFrame::RemoteRequestFrame)
@@ -428,7 +447,7 @@ void PeakCanBackendPrivate::startRead()
QCanBusFrame frame(message.ID, QByteArray(reinterpret_cast<const char *>(message.DATA), int(message.LEN)));
const quint64 millis = timestamp.millis + Q_UINT64_C(0xFFFFFFFF) * timestamp.millis_overflow;
const quint64 micros = Q_UINT64_C(1000) * millis + timestamp.micros;
- frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(micros));
+ frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(static_cast<qint64>(micros)));
frame.setExtendedFrameFormat(message.MSGTYPE & PCAN_MESSAGE_EXTENDED);
frame.setFrameType((message.MSGTYPE & PCAN_MESSAGE_RTR) ? QCanBusFrame::RemoteRequestFrame : QCanBusFrame::DataFrame);
@@ -448,7 +467,7 @@ bool PeakCanBackendPrivate::verifyBitRate(int bitrate)
return false;
}
- if (Q_UNLIKELY(bitrateCodeFromBitrate(bitrate) == -1)) {
+ if (Q_UNLIKELY(bitrateCodeFromBitrate(bitrate) == PCAN_BAUD_INVALID)) {
q->setError(PeakCanBackend::tr("Unsupported bitrate value"),
QCanBusDevice::ConfigurationError);
return false;
@@ -494,8 +513,8 @@ bool PeakCanBackend::open()
const QVariant param = configurationParameter(key);
const bool success = d->setConfigurationParameter(key, param);
if (Q_UNLIKELY(!success)) {
- qWarning("Cannot apply parameter: %d with value: %ls.",
- key, qUtf16Printable(param.toString()));
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot apply parameter: %d with value: %ls.",
+ key, qUtf16Printable(param.toString()));
}
}
}
@@ -541,7 +560,7 @@ bool PeakCanBackend::writeFrame(const QCanBusFrame &newData)
}
// CAN FD frame format not implemented at this stage
- if (Q_UNLIKELY(newData.payload().size() > 8)) {
+ if (Q_UNLIKELY(newData.hasFlexibleDataRateFormat())) {
setError(tr("CAN FD frame format not supported."), QCanBusDevice::WriteError);
return false;
}
diff --git a/src/plugins/canbus/peakcan/peakcanbackend_p.h b/src/plugins/canbus/peakcan/peakcanbackend_p.h
index a6c6458..2dc8197 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend_p.h
+++ b/src/plugins/canbus/peakcan/peakcanbackend_p.h
@@ -75,7 +75,7 @@ public:
bool setConfigurationParameter(int key, const QVariant &value);
void setupChannel(const QByteArray &interfaceName);
void setupDefaultConfigurations();
- QString systemErrorString(int errorCode);
+ QString systemErrorString(TPCANStatus errorCode);
void startWrite();
void startRead();
bool verifyBitRate(int bitrate);
@@ -83,7 +83,7 @@ public:
PeakCanBackend * const q_ptr;
bool isOpen = false;
- int channelIndex = PCAN_NONEBUS;
+ TPCANHandle channelIndex = PCAN_NONEBUS;
QTimer *writeNotifier = nullptr;
#if defined(Q_OS_WIN32)
diff --git a/src/plugins/canbus/socketcan/main.cpp b/src/plugins/canbus/socketcan/main.cpp
index 92e759b..328db97 100644
--- a/src/plugins/canbus/socketcan/main.cpp
+++ b/src/plugins/canbus/socketcan/main.cpp
@@ -40,10 +40,12 @@
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusfactory.h>
-#include <QtCore/qfile.h>
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN, "qt.canbus.plugins.socketcan")
+
//! [SocketCanFactory]
class SocketCanBusPlugin : public QObject, public QCanBusFactoryV2
{
diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp
index c890fff..74b0d1d 100644
--- a/src/plugins/canbus/socketcan/socketcanbackend.cpp
+++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp
@@ -40,6 +40,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qsocketnotifier.h>
#include <linux/can/error.h>
@@ -83,7 +84,11 @@ struct canfd_frame {
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN)
+
const char sysClassNetC[] = "/sys/class/net/";
+const char interfaceC[] = "/device/interface";
+const char devIdC[] = "/dev_id";
const char flagsC[] = "/flags";
const char mtuC[] = "/mtu";
const char typeC[] = "/type";
@@ -124,6 +129,23 @@ static quint32 flags(const QString &canDevice)
return result;
}
+static QString deviceDescription(const QString &canDevice)
+{
+ const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(interfaceC);
+ const QByteArray content = fileContent(path);
+ if (content.isEmpty() && isVirtual(canDevice))
+ return QStringLiteral("Virtual CAN");
+
+ return QString::fromUtf8(content);
+}
+
+static int deviceChannel(const QString &canDevice)
+{
+ const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(devIdC);
+ const QByteArray content = fileContent(path);
+ return content.toInt(nullptr, 0);
+}
+
QList<QCanBusDeviceInfo> SocketCanBackend::interfaces()
{
QList<QCanBusDeviceInfo> result;
@@ -140,9 +162,12 @@ QList<QCanBusDeviceInfo> SocketCanBackend::interfaces()
if (!(flags(deviceName) & DeviceIsActive))
continue;
- auto info = createDeviceInfo(deviceName, isVirtual(deviceName),
- isFlexibleDataRateCapable(deviceName));
- result.append(info);
+ const QString serial;
+ const QString description = deviceDescription(deviceName);
+ const int channel = deviceChannel(deviceName);
+ result.append(std::move(createDeviceInfo(deviceName, serial, description,
+ channel, isVirtual(deviceName),
+ isFlexibleDataRateCapable(deviceName))));
}
std::sort(result.begin(), result.end(),
@@ -249,7 +274,7 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu
socklen_t s = sizeof(can_filter);
if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER,
&filters, s) != 0)) {
- qWarning("Cannot unset socket filters");
+ qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Cannot unset socket filters.");
setError(qt_error_string(errno),
QCanBusDevice::CanBusError::ConfigurationError);
break;
@@ -373,8 +398,8 @@ bool SocketCanBackend::connectSocket()
const QVariant param = configurationParameter(key);
bool success = applyConfigurationParameter(key, param);
if (Q_UNLIKELY(!success)) {
- qWarning("Cannot apply parameter: %d with value: %ls",
- key, qUtf16Printable(param.toString()));
+ qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Cannot apply parameter: %d with value: %ls.",
+ key, qUtf16Printable(param.toString()));
}
}
@@ -443,7 +468,7 @@ bool SocketCanBackend::writeFrame(const QCanBusFrame &newData)
if (Q_UNLIKELY(!canFdOptionEnabled && newData.hasFlexibleDataRateFormat())) {
const QString error = tr("Cannot write CAN FD frame because CAN FD option is not enabled.");
- qDebug("%ls", qUtf16Printable(error));
+ qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(error));
setError(error, QCanBusDevice::WriteError);
return false;
}
diff --git a/src/plugins/canbus/systeccan/main.cpp b/src/plugins/canbus/systeccan/main.cpp
index fcb76a3..89377a0 100644
--- a/src/plugins/canbus/systeccan/main.cpp
+++ b/src/plugins/canbus/systeccan/main.cpp
@@ -40,8 +40,12 @@
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusfactory.h>
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SYSTECCAN, "qt.canbus.plugins.systeccan")
+
class SystecCanBusPlugin : public QObject, public QCanBusFactoryV2
{
Q_OBJECT
@@ -61,7 +65,7 @@ public:
{
QString errorReason;
if (Q_UNLIKELY(!SystecCanBackend::canCreate(&errorReason))) {
- qWarning("%ls", qUtf16Printable(errorReason));
+ qCWarning(QT_CANBUS_PLUGINS_SYSTECCAN, "%ls", qUtf16Printable(errorReason));
if (errorMessage)
*errorMessage = errorReason;
return nullptr;
diff --git a/src/plugins/canbus/systeccan/systeccan_symbols_p.h b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
index b69db83..102817c 100644
--- a/src/plugins/canbus/systeccan/systeccan_symbols_p.h
+++ b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
@@ -62,7 +62,7 @@ typedef quint8 tUcanHandle;
static fp_##symbolName symbolName;
#define RESOLVE_SYMBOL(symbolName) \
- symbolName = (fp_##symbolName)systecLibrary->resolve(#symbolName); \
+ symbolName = reinterpret_cast<fp_##symbolName>(systecLibrary->resolve(#symbolName)); \
if (!symbolName) \
return false;
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.cpp b/src/plugins/canbus/systeccan/systeccanbackend.cpp
index 996122d..7041af8 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.cpp
+++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp
@@ -43,11 +43,14 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qregularexpression.h>
#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SYSTECCAN)
+
Q_GLOBAL_STATIC(QLibrary, systecLibrary)
bool SystecCanBackend::canCreate(QString *errorReason)
@@ -60,19 +63,49 @@ bool SystecCanBackend::canCreate(QString *errorReason)
return true;
}
+QCanBusDeviceInfo SystecCanBackend::createDeviceInfo(const QString &serialNumber,
+ const QString &description,
+ uint deviceNumber,
+ int channelNumber)
+{
+ const QString name = QString::fromLatin1("can%1.%2").arg(deviceNumber).arg(channelNumber);
+ return QCanBusDevice::createDeviceInfo(name, serialNumber, description, channelNumber, false, false);
+}
+
+static QString descriptionString(uint productCode)
+{
+ switch (productCode & USBCAN_PRODCODE_MASK_PID) {
+ case USBCAN_PRODCODE_PID_GW001: return QStringLiteral("USB-CANmodul (G1)");
+ case USBCAN_PRODCODE_PID_GW002: return QStringLiteral("USB-CANmodul (G2)");
+ case USBCAN_PRODCODE_PID_MULTIPORT: return QStringLiteral("Multiport CAN-to-USB (G3)");
+ case USBCAN_PRODCODE_PID_BASIC: return QStringLiteral("USB-CANmodul1 (G3)");
+ case USBCAN_PRODCODE_PID_ADVANCED: return QStringLiteral("USB-CANmodul2 (G3)");
+ case USBCAN_PRODCODE_PID_USBCAN8: return QStringLiteral("USB-CANmodul8 (G3)");
+ case USBCAN_PRODCODE_PID_USBCAN16: return QStringLiteral("USB-CANmodul16 (G3)");
+ case USBCAN_PRODCODE_PID_ADVANCED_G4: return QStringLiteral("USB-CANmodul2 (G4)");
+ case USBCAN_PRODCODE_PID_BASIC_G4: return QStringLiteral("USB-CANmodul1 (G4)");
+ default: return QStringLiteral("Unknown");
+ }
+}
+
static void DRV_CALLBACK_TYPE ucanEnumCallback(DWORD index, BOOL isUsed,
tUcanHardwareInfoEx *hardwareInfo,
tUcanHardwareInitInfo *initInfo,
void *args)
{
- auto result = static_cast<QStringList *>(args);
+ auto result = static_cast<QList<QCanBusDeviceInfo> *>(args);
Q_UNUSED(index);
Q_UNUSED(isUsed);
- result->append(QString::fromLatin1("can%1.0").arg(hardwareInfo->m_bDeviceNr));
- if (USBCAN_CHECK_SUPPORT_TWO_CHANNEL(hardwareInfo))
- result->append(QString::fromLatin1("can%1.1").arg(hardwareInfo->m_bDeviceNr));
+ const QString serialNumber = QString::number(hardwareInfo->m_dwSerialNr);
+ const QString description = descriptionString(hardwareInfo->m_dwProductCode);
+ result->append(std::move(SystecCanBackend::createDeviceInfo(serialNumber, description,
+ hardwareInfo->m_bDeviceNr, 0)));
+ if (USBCAN_CHECK_SUPPORT_TWO_CHANNEL(hardwareInfo)) {
+ result->append(std::move(SystecCanBackend::createDeviceInfo(serialNumber, description,
+ hardwareInfo->m_bDeviceNr, 1)));
+ }
initInfo->m_fTryNext = true; // continue enumerating with next device
}
@@ -81,12 +114,8 @@ QList<QCanBusDeviceInfo> SystecCanBackend::interfaces()
{
QList<QCanBusDeviceInfo> result;
- QStringList devices;
- ::UcanEnumerateHardware(&ucanEnumCallback, &devices, false,
- 0, ~0, 0, ~0, 0, ~0);
+ ::UcanEnumerateHardware(&ucanEnumCallback, &result, false, 0, ~0, 0, ~0, 0, ~0);
- for (const QString &s : qAsConst(devices))
- result.append(createDeviceInfo(s, false, false));
return result;
}
@@ -110,7 +139,7 @@ protected:
}
private:
- SystecCanBackendPrivate *dptr;
+ SystecCanBackendPrivate * const dptr;
};
SystecCanBackendPrivate::SystecCanBackendPrivate(SystecCanBackend *q) :
@@ -459,8 +488,8 @@ bool SystecCanBackend::open()
const QVariant param = configurationParameter(key);
const bool success = d->setConfigurationParameter(key, param);
if (Q_UNLIKELY(!success)) {
- qWarning("Cannot apply parameter %d with value %ls.",
- key, qUtf16Printable(param.toString()));
+ qCWarning(QT_CANBUS_PLUGINS_SYSTECCAN, "Cannot apply parameter %d with value %ls.",
+ key, qUtf16Printable(param.toString()));
}
}
@@ -505,7 +534,7 @@ bool SystecCanBackend::writeFrame(const QCanBusFrame &newData)
}
// CAN FD frame format is not supported by the hardware yet
- if (Q_UNLIKELY(newData.payload().size() > 8)) {
+ if (Q_UNLIKELY(newData.hasFlexibleDataRateFormat())) {
setError(tr("CAN FD frame format not supported"), QCanBusDevice::WriteError);
return false;
}
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.h b/src/plugins/canbus/systeccan/systeccanbackend.h
index 7bf20f8..cb62808 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend.h
@@ -69,6 +69,12 @@ public:
static QList<QCanBusDeviceInfo> interfaces();
static bool canCreate(QString *errorReason);
+ // This function needs to be public as it is accessed by a callback
+ static QCanBusDeviceInfo createDeviceInfo(const QString &serialNumber,
+ const QString &description,
+ uint deviceNumber,
+ int channelNumber);
+
private:
SystecCanBackendPrivate * const d_ptr;
};
diff --git a/src/plugins/canbus/systeccan/systeccanbackend_p.h b/src/plugins/canbus/systeccan/systeccanbackend_p.h
index f180102..28eb7ff 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend_p.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend_p.h
@@ -73,7 +73,7 @@ public:
void customEvent(QEvent *event);
private:
- SystecCanBackendPrivate *dptr;
+ SystecCanBackendPrivate * const dptr;
};
class SystecCanBackendPrivate
diff --git a/src/plugins/canbus/tinycan/main.cpp b/src/plugins/canbus/tinycan/main.cpp
index c73d81e..36fb05d 100644
--- a/src/plugins/canbus/tinycan/main.cpp
+++ b/src/plugins/canbus/tinycan/main.cpp
@@ -41,8 +41,12 @@
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusfactory.h>
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_TINYCAN, "qt.canbus.plugins.tinycan")
+
class TinyCanBusPlugin : public QObject, public QCanBusFactoryV2
{
Q_OBJECT
@@ -60,7 +64,7 @@ public:
{
QString errorReason;
if (!TinyCanBackend::canCreate(&errorReason)) {
- qWarning("%ls", qUtf16Printable(errorReason));
+ qCWarning(QT_CANBUS_PLUGINS_TINYCAN, "%ls", qUtf16Printable(errorReason));
if (errorMessage)
*errorMessage = errorReason;
return nullptr;
diff --git a/src/plugins/canbus/tinycan/tinycan_symbols_p.h b/src/plugins/canbus/tinycan/tinycan_symbols_p.h
index 36580ed..44dffd6 100644
--- a/src/plugins/canbus/tinycan/tinycan_symbols_p.h
+++ b/src/plugins/canbus/tinycan/tinycan_symbols_p.h
@@ -285,7 +285,7 @@ typedef void (DRV_CALLBACK_TYPE *CanRxEventCallback)(
static fp_##symbolName symbolName;
#define RESOLVE_SYMBOL(symbolName) \
- symbolName = (fp_##symbolName)mhstcanLibrary->resolve(#symbolName); \
+ symbolName = reinterpret_cast<fp_##symbolName>(mhstcanLibrary->resolve(#symbolName)); \
if (!symbolName) \
return false;
diff --git a/src/plugins/canbus/tinycan/tinycanbackend.cpp b/src/plugins/canbus/tinycan/tinycanbackend.cpp
index 68e8bb2..3891186 100644
--- a/src/plugins/canbus/tinycan/tinycanbackend.cpp
+++ b/src/plugins/canbus/tinycan/tinycanbackend.cpp
@@ -45,11 +45,14 @@
#include <QtCore/qtimer.h>
#include <QtCore/qmutex.h>
#include <QtCore/qcoreevent.h>
+#include <QtCore/qloggingcategory.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_TINYCAN)
+
#ifndef LINK_LIBMHSTCAN
Q_GLOBAL_STATIC(QLibrary, mhstcanLibrary)
#endif
@@ -107,7 +110,7 @@ protected:
}
private:
- TinyCanBackendPrivate *dptr;
+ TinyCanBackendPrivate * const dptr;
};
static int driverRefCount = 0;
@@ -353,7 +356,7 @@ void TinyCanBackendPrivate::startWrite()
::memset(&message, 0, sizeof(message));
if (Q_UNLIKELY(payload.size() > int(sizeof(message.Data.Bytes)))) {
- qWarning("Can not write frame with payload size %d, ignored", payload.size());
+ qCWarning(QT_CANBUS_PLUGINS_TINYCAN, "Cannot write frame with payload size %d.", payload.size());
} else {
message.Id = frame.frameId();
message.Flags.Flag.Len = payload.size();
@@ -401,7 +404,7 @@ void TinyCanBackendPrivate::startRead()
q->setError(systemErrorString(ret), QCanBusDevice::CanBusError::ReadError);
} else {
if (status.CanStatus == CAN_STATUS_BUS_OFF) {
- qWarning("CAN bus is in off state, trying to reset the bus");
+ qCWarning(QT_CANBUS_PLUGINS_TINYCAN, "CAN bus is in off state, trying to reset the bus.");
if (::CanSetMode(channelIndex, OP_CAN_RESET, CAN_CMD_NONE) < 0)
q->setError(systemErrorString(ret), QCanBusDevice::CanBusError::ReadError);
}
@@ -517,8 +520,8 @@ bool TinyCanBackend::open()
const QVariant param = configurationParameter(key);
const bool success = d->setConfigurationParameter(key, param);
if (Q_UNLIKELY(!success)) {
- qWarning("Cannot apply parameter: %d with value: %ls",
- key, qUtf16Printable(param.toString()));
+ qCWarning(QT_CANBUS_PLUGINS_TINYCAN, "Cannot apply parameter: %d with value: %ls.",
+ key, qUtf16Printable(param.toString()));
}
}
}
@@ -565,7 +568,7 @@ bool TinyCanBackend::writeFrame(const QCanBusFrame &newData)
}
// CAN FD frame format not supported at this stage
- if (Q_UNLIKELY(newData.payload().size() > 8)) {
+ if (Q_UNLIKELY(newData.hasFlexibleDataRateFormat())) {
setError(tr("CAN FD frame format not supported."), QCanBusDevice::WriteError);
return false;
}
diff --git a/src/plugins/canbus/vectorcan/main.cpp b/src/plugins/canbus/vectorcan/main.cpp
index 07c30bc..bbfb851 100644
--- a/src/plugins/canbus/vectorcan/main.cpp
+++ b/src/plugins/canbus/vectorcan/main.cpp
@@ -40,8 +40,12 @@
#include <QtSerialBus/qcanbusdevice.h>
#include <QtSerialBus/qcanbusfactory.h>
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_VECTORCAN, "qt.canbus.plugins.vectorcan")
+
class VectorCanBusPlugin : public QObject, public QCanBusFactoryV2
{
Q_OBJECT
@@ -61,7 +65,7 @@ public:
{
QString errorReason;
if (Q_UNLIKELY(!VectorCanBackend::canCreate(&errorReason))) {
- qWarning("%ls", qUtf16Printable(errorReason));
+ qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "%ls", qUtf16Printable(errorReason));
if (errorMessage)
*errorMessage = errorReason;
return nullptr;
diff --git a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
index 7bfb3c6..3f2501f 100644
--- a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
+++ b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
@@ -441,7 +441,7 @@ typedef struct _XLacceptance {
static fp_##symbolName symbolName;
#define RESOLVE_SYMBOL(symbolName) \
- symbolName = (fp_##symbolName)vectorcanLibrary->resolve(#symbolName); \
+ symbolName = reinterpret_cast<fp_##symbolName>(vectorcanLibrary->resolve(#symbolName)); \
if (!symbolName) \
return false;
diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
index c84658b..dc28d7c 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
@@ -42,6 +42,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qcoreevent.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qwineventnotifier.h>
#include <QtCore/qcoreapplication.h>
@@ -49,6 +50,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_VECTORCAN)
+
#ifndef LINK_LIBVECTORCAN
Q_GLOBAL_STATIC(QLibrary, vectorcanLibrary)
#endif
@@ -86,7 +89,12 @@ QList<QCanBusDeviceInfo> VectorCanBackend::interfaces()
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));
+ const int channel = config.channel[i].hwChannel;
+ const QString name = QStringLiteral("can") + QString::number(i);
+ const QString serial = QString::number(config.channel[i].serialNumber);
+ const QString description = QLatin1String(config.channel[i].name);
+ result.append(std::move(createDeviceInfo(name, serial, description, channel,
+ isVirtual, isFd)));
}
VectorCanBackendPrivate::cleanupDriver();
@@ -117,7 +125,7 @@ protected:
}
private:
- VectorCanBackendPrivate *dptr;
+ VectorCanBackendPrivate * const dptr;
};
class WriteNotifier : public QTimer
@@ -142,7 +150,7 @@ protected:
}
private:
- VectorCanBackendPrivate *dptr;
+ VectorCanBackendPrivate * const dptr;
};
@@ -459,8 +467,8 @@ bool VectorCanBackend::open()
const QVariant param = configurationParameter(key);
const bool success = d->setConfigurationParameter(key, param);
if (!success) {
- qWarning("Cannot apply parameter: %d with value: %ls",
- key, qUtf16Printable(param.toString()));
+ qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Cannot apply parameter: %d with value: %ls.",
+ key, qUtf16Printable(param.toString()));
}
}
@@ -507,7 +515,7 @@ bool VectorCanBackend::writeFrame(const QCanBusFrame &newData)
}
// CAN FD frame format not implemented at this stage
- if (Q_UNLIKELY(newData.payload().size() > MAX_MSG_LEN)) {
+ if (Q_UNLIKELY(newData.hasFlexibleDataRateFormat())) {
setError(tr("CAN FD frame format not supported."),
QCanBusDevice::WriteError);
return false;
diff --git a/src/serialbus/doc/src/passthrucan.qdoc b/src/serialbus/doc/src/passthrucan.qdoc
new file mode 100644
index 0000000..740dbc4
--- /dev/null
+++ b/src/serialbus/doc/src/passthrucan.qdoc
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+ \page qtserialbus-passthrucan-overview.html
+ \title Using PassThruCAN Plugin
+
+ \brief Overview of how to use the J2534 Pass-Thru CAN plugin.
+
+ The Pass-Thru CAN plugin accesses CAN adapters via the SAE J2534 Pass-Thru API.
+ SAE J2534 is a standard for accessing vehicle busses from an x86 Windows PC.
+ Although the API is specified only for 32-bit Windows, some vendors also provide
+ implementations for 64-bit Windows and other operating systems such as Linux.
+
+ \section1 PassThruCAN usage
+
+ To use PassThruCAN, the corresponding vendor drivers for the CAN adapter must
+ be installed. The vendor must also provide an implementation of the J2534 API
+ by way of a shared library. Currently, only version 04.04 of the Pass-Thru API
+ is supported.
+
+ When using an x64 build of Qt, this plugin only works if the CAN device vendor
+ also provides a 64-bit version of the J2534 Pass-Thru interface library. If the
+ vendor provides only a 32-bit J2534 interface, a 32-bit build of Qt is required
+ to make use of it.
+
+ For automatic device discovery, the vendor software must also list and describe
+ the available adapters in the Windows registry. On systems other than Windows,
+ automatic discovery is currently not supported.
+
+ \section1 Creating CAN Bus Devices
+
+ At first it is necessary to check that QCanBus provides the desired plugin:
+
+ \code
+ if (QCanBus::instance()->plugins().contains(QStringLiteral("passthrucan"))) {
+ // plugin available
+ }
+ \endcode
+
+ Where \e passthrucan is the plugin name.
+
+ On Windows, automatic device discovery should be used to list the available
+ CAN adapters accessible via the Pass-Thru API:
+
+ \code
+ const auto adapters = QCanBus::instance()->
+ availableDevices(QStringLiteral("passthrucan"));
+ for (const QCanBusDeviceInfo &info : adapters) {
+ // List available adapter in the user interface.
+ uiListBox->addItem(info.name());
+ }
+ \endcode
+
+ On other operating systems, the list of discovered adapters will be empty.
+ Instead, the full path to the vendor-provided J2534 interface library
+ should be provided in lieu of the device name:
+
+ \code
+ QCanBusDevice *device = QCanBus::instance()->createDevice(
+ QStringLiteral("passthrucan"), QStringLiteral("/path/to/libj2534-vendor.so"));
+ \endcode
+
+ For special needs, it is also possible to pass a vendor-specific device
+ name argument when opening the Pass-Thru adapter:
+
+ \code
+ QCanBusDevice *device = QCanBus::instance()->createDevice(
+ QStringLiteral("passthrucan"), info.name() + QChar::fromLatin1('%') + deviceName);
+ \endcode
+
+ All operations on the Pass-Thru CAN bus device are executed asynchronously,
+ including connect and disconnect. In order to be notified when the device
+ is ready for reading and writing CAN frames, connect to the
+ \l {QCanBusDevice::}{stateChanged(QCanBusDevice::CanBusDeviceState state)}
+ signal:
+
+ \code
+ connect(device, &QCanBusDevice::stateChanged,
+ this, &MyClass::canStateChanged);
+ device->connectDevice();
+ \endcode
+
+ \l {QCanBusDevice::}{state()} will return \l {QCanBusDevice::}{ConnectedState}
+ once the CAN adapter has been successfully connected to. The device is then
+ open for writing and reading CAN frames:
+
+ \code
+ QCanBusFrame frame;
+ frame.setFrameId(8);
+ frame.setPayload(QByteArray("\xA3\x6E\x74\x9C", 4));
+ device->writeFrame(frame);
+ \endcode
+
+ The reading can be done using the \l {QCanBusDevice::}{readFrame()} method. The
+ \l {QCanBusDevice::}{framesReceived()} signal is emitted when at least one new frame
+ is available for reading:
+
+ \code
+ QCanBusFrame frame = device->readFrame();
+ \endcode
+
+ The Pass-Thru CAN plugin supports the following configuration options
+ controllable via \l {QCanBusDevice::}{setConfigurationParameter()}:
+
+ \table
+ \header
+ \li Configuration parameter key
+ \li Description
+ \row
+ \li QCanBusDevice::LoopbackKey
+ \li When enabled, if a CAN frame is transmitted on the CAN bus, a local
+ echo of this frame will be received by the CAN adapter. The echo
+ frames are marked with QCanBusFrame::hasLocalEcho(). By default,
+ loopback mode is disabled.
+ \row
+ \li QCanBusDevice::RawFilterKey
+ \li This option allows setting up filters for incoming CAN bus messages.
+ If provided, the value should be a \l {QList<QCanBusDevice::Filter>}.
+ Only data frame ID filters are supported. By default, data frames
+ with any ID are accepted.
+ \row
+ \li QCanBusDevice::BitRateKey
+ \li The bit rate of the CAN bus as an unsigned integer, in bit/s. The
+ default bit rate is 500000 (500 kbit/s). Setting the bit rate after
+ the device has already been connected may trigger an implicit
+ reinitialization of the CAN interface.
+ \endtable
+
+ The Pass-Thru CAN plugin supports extended frame format (29-bit IDs), but not
+ flexible data-rate (CAN FD).
+ */
diff --git a/src/serialbus/doc/src/qtcanbus-backends.qdoc b/src/serialbus/doc/src/qtcanbus-backends.qdoc
index e18adf6..1c4cd74 100644
--- a/src/serialbus/doc/src/qtcanbus-backends.qdoc
+++ b/src/serialbus/doc/src/qtcanbus-backends.qdoc
@@ -61,6 +61,10 @@
\li \l {Using SocketCAN Plugin}{SocketCAN} (\c socketcan)
\li CAN bus plugin using Linux sockets and open source drivers.
\row
+ \li CAN via SAE J2534 Pass-Thru
+ \li \l {Using PassThruCAN Plugin}{PassThruCAN} (\c passthrucan)
+ \li CAN bus plugin using the SAE J2534 Pass-Thru interface.
+ \row
\li SYS TEC electronic
\li \l {Using SystecCAN Backend}{SystecCAN} (\c systeccan)
\li CAN bus backend using the SYS TEC CAN adapters.
diff --git a/src/serialbus/doc/src/qtserialbus-index.qdoc b/src/serialbus/doc/src/qtserialbus-index.qdoc
index 6c91fbf..db9f241 100644
--- a/src/serialbus/doc/src/qtserialbus-index.qdoc
+++ b/src/serialbus/doc/src/qtserialbus-index.qdoc
@@ -73,14 +73,33 @@
\li Logging Category
\li Description
\row
+ \li qt.canbus
+ \li Enables standard logging inside the \l {Qt CAN Bus} classes
+ \row
+ \li qt.canbus.plugins
+ \li Enables low level logging inside the \l {Qt CAN Bus} plugin classes.
+ To set logging for a specific plugin, use "qt.canbus.plugins.pluginname".
+ e.g. "qt.canbus.plugins.socketcan". "qt.canbus.plugins*" affects all plugins.
+ \row
\li qt.modbus
- \li Enables standard logging inside the Modbus classes
+ \li Enables standard logging inside the \l {Qt Modbus} classes
\row
\li qt.modbus.lowlevel
\li Enables low level logging including individual packet content inside
- the Modbus classes
+ the \l {Qt Modbus} classes
\endtable
+ Logging categories can be used to enable additional warning and debug output
+ for \l QtSerialBus. More detailed information about logging can be found
+ in \l QLoggingCategory.
+
+ A quick way to enable all \l {Qt Modbus} logging is to add the following line
+ to the main() function:
+
+ \code
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));
+ \endcode
+
\section1 Examples
\list
diff --git a/src/serialbus/qcanbusdevice.cpp b/src/serialbus/qcanbusdevice.cpp
index 919c38a..b1c97a6 100644
--- a/src/serialbus/qcanbusdevice.cpp
+++ b/src/serialbus/qcanbusdevice.cpp
@@ -43,11 +43,14 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qeventloop.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qscopedvaluerollback.h>
#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(QT_CANBUS, "qt.canbus")
+
/*!
\class QCanBusDevice
\inmodule QtSerialBus
@@ -445,10 +448,10 @@ bool QCanBusDevice::waitForFramesWritten(int msecs)
{
// do not enter this function recursively
if (Q_UNLIKELY(d_func()->waitForWrittenEntered)) {
- qWarning("QCanBusDevice::waitForFramesWritten() must not be called "
- "recursively. Check that no slot containing waitForFramesReceived() "
- "is called in response to framesWritten(qint64) or errorOccurred(CanBusError)"
- "signals\n");
+ qCWarning(QT_CANBUS, "QCanBusDevice::waitForFramesWritten() must not be called "
+ "recursively. Check that no slot containing waitForFramesReceived() "
+ "is called in response to framesWritten(qint64) or "
+ "errorOccurred(CanBusError) signals.");
return false;
}
@@ -498,10 +501,10 @@ bool QCanBusDevice::waitForFramesReceived(int msecs)
{
// do not enter this function recursively
if (Q_UNLIKELY(d_func()->waitForReceivedEntered)) {
- qWarning("QCanBusDevice::waitForFramesReceived() must not be called "
- "recursively. Check that no slot containing waitForFramesReceived() "
- "is called in response to framesReceived() or errorOccurred(CanBusError) "
- "signals\n");
+ qCWarning(QT_CANBUS, "QCanBusDevice::waitForFramesReceived() must not be called "
+ "recursively. Check that no slot containing waitForFramesReceived() "
+ "is called in response to framesReceived() or "
+ "errorOccurred(CanBusError) signals.");
return false;
}
@@ -672,7 +675,7 @@ void QCanBusDevice::disconnectDevice()
if (Q_UNLIKELY(d->state == QCanBusDevice::UnconnectedState
|| d->state == QCanBusDevice::ClosingState)) {
- qWarning("Can not disconnect an unconnected device");
+ qCWarning(QT_CANBUS, "Can not disconnect an unconnected device.");
return;
}
@@ -724,10 +727,27 @@ void QCanBusDevice::setState(QCanBusDevice::CanBusDeviceState newState)
QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, bool isVirtual,
bool isFlexibleDataRateCapable)
{
+ return createDeviceInfo(name, QString(), QString(), 0, isVirtual, isFlexibleDataRateCapable);
+}
+
+/*!
+ \since 5.11
+ Returns a QCanBusDeviceInfo created from the given parameters \a name,
+ \a serialNumber, \a description, \a channel, \a isVirtual, and \a
+ isFlexibleDataRateCapable.
+ \internal
+ */
+QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, const QString &serialNumber,
+ const QString &description, int channel,
+ bool isVirtual, bool isFlexibleDataRateCapable)
+{
QScopedPointer<QCanBusDeviceInfoPrivate> info(new QCanBusDeviceInfoPrivate);
info->name = name;
- info->isVirtual = isVirtual;
+ info->serialNumber = serialNumber;
+ info->description = description;
+ info->channel = channel;
info->hasFlexibleDataRate = isFlexibleDataRateCapable;
+ info->isVirtual = isVirtual;
return QCanBusDeviceInfo(*info.take());
}
diff --git a/src/serialbus/qcanbusdevice.h b/src/serialbus/qcanbusdevice.h
index 3a644c6..482e9d0 100644
--- a/src/serialbus/qcanbusdevice.h
+++ b/src/serialbus/qcanbusdevice.h
@@ -146,6 +146,9 @@ protected:
static QCanBusDeviceInfo createDeviceInfo(const QString &name,
bool isVirtual = false,
bool isFlexibleDataRateCapable = false);
+ static QCanBusDeviceInfo createDeviceInfo(const QString &name, const QString &serialNumber,
+ const QString &description, int channel,
+ bool isVirtual, bool isFlexibleDataRateCapable);
};
Q_DECLARE_TYPEINFO(QCanBusDevice::CanBusError, Q_PRIMITIVE_TYPE);
diff --git a/src/serialbus/qcanbusdeviceinfo.cpp b/src/serialbus/qcanbusdeviceinfo.cpp
index 30b0e12..25c02e1 100644
--- a/src/serialbus/qcanbusdeviceinfo.cpp
+++ b/src/serialbus/qcanbusdeviceinfo.cpp
@@ -96,6 +96,38 @@ QString QCanBusDeviceInfo::name() const
}
/*!
+ \since 5.11
+ Returns a textual description of the CAN bus interface, if available.
+ Example output: "PCAN USB Pro FD". If no description is available,
+ an empty string is returned.
+*/
+QString QCanBusDeviceInfo::description() const
+{
+ return d_ptr->description;
+}
+
+/*!
+ \since 5.11
+ Returns the serial number of the CAN bus interface as string, if available.
+ Otherwise, an empty string is returned.
+*/
+QString QCanBusDeviceInfo::serialNumber() const
+{
+ return d_ptr->serialNumber;
+}
+
+/*!
+ \since 5.11
+ Returns the sequential channel number of the CAN bus interface, starting
+ with zero. If the interface has only one channel or if no information about
+ the channel is available, zero is returned.
+*/
+int QCanBusDeviceInfo::channel() const
+{
+ return d_ptr->channel;
+}
+
+/*!
Returns true, if the CAN bus interface is CAN FD (flexible data rate) capable.
If this information is not available, false is returned.
diff --git a/src/serialbus/qcanbusdeviceinfo.h b/src/serialbus/qcanbusdeviceinfo.h
index 68b68a3..fbe2c71 100644
--- a/src/serialbus/qcanbusdeviceinfo.h
+++ b/src/serialbus/qcanbusdeviceinfo.h
@@ -65,6 +65,9 @@ public:
}
QString name() const;
+ QString description() const;
+ QString serialNumber() const;
+ int channel() const;
bool hasFlexibleDataRate() const;
bool isVirtual() const;
diff --git a/src/serialbus/qcanbusdeviceinfo_p.h b/src/serialbus/qcanbusdeviceinfo_p.h
index ae6d71d..78c9e1c 100644
--- a/src/serialbus/qcanbusdeviceinfo_p.h
+++ b/src/serialbus/qcanbusdeviceinfo_p.h
@@ -62,7 +62,9 @@ public:
}
QString name;
+ QString description;
QString serialNumber;
+ int channel = 0;
bool hasFlexibleDataRate = false;
bool isVirtual = false;
};
diff --git a/src/serialbus/qcanbusframe.h b/src/serialbus/qcanbusframe.h
index 0300a9c..d1f8857 100644
--- a/src/serialbus/qcanbusframe.h
+++ b/src/serialbus/qcanbusframe.h
@@ -133,17 +133,16 @@ public:
return false;
// maximum permitted payload size in CAN or CAN FD
+ const int length = load.length();
if (isFlexibleDataRate) {
- if (load.length() > 64)
- return false;
if (format == RemoteRequestFrame)
return false;
- } else {
- if (load.length() > 8)
- return false;
+
+ return length <= 8 || length == 12 || length == 16 || length == 20
+ || length == 24 || length == 32 || length == 48 || length == 64;
}
- return true;
+ return length <= 8;
}
FrameType frameType() const Q_DECL_NOTHROW
diff --git a/src/tools/canbusutil/canbusutil.cpp b/src/tools/canbusutil/canbusutil.cpp
index c553c52..38433bb 100644
--- a/src/tools/canbusutil/canbusutil.cpp
+++ b/src/tools/canbusutil/canbusutil.cpp
@@ -36,8 +36,11 @@
#include "canbusutil.h"
-CanBusUtil::CanBusUtil(QTextStream &output, QCoreApplication &app, QObject *parent)
- : QObject(parent),
+#include <QCoreApplication>
+#include <QTextStream>
+
+CanBusUtil::CanBusUtil(QTextStream &output, QCoreApplication &app, QObject *parent) :
+ QObject(parent),
m_canBus(QCanBus::instance()),
m_output(output),
m_app(app),
@@ -58,7 +61,7 @@ void CanBusUtil::setShowFdFlags(bool showFdFlags)
bool CanBusUtil::start(const QString &pluginName, const QString &deviceName, const QString &data)
{
if (!m_canBus) {
- m_output << "Unable to create QCanBus" << endl;
+ m_output << tr("Error: Cannot create QCanBus.") << endl;
return false;
}
@@ -73,29 +76,41 @@ bool CanBusUtil::start(const QString &pluginName, const QString &deviceName, con
if (m_listening) {
if (m_readTask->isShowFdFlags())
m_canDevice->setConfigurationParameter(QCanBusDevice::CanFdKey, true);
- connect(m_canDevice.data(), &QCanBusDevice::framesReceived, m_readTask, &ReadTask::checkMessages);
+ connect(m_canDevice.data(), &QCanBusDevice::framesReceived,
+ m_readTask, &ReadTask::handleFrames);
} else {
if (!sendData())
return false;
- QTimer::singleShot(0, &m_app, SLOT(quit()));
+ QTimer::singleShot(0, &m_app, QCoreApplication::quit);
}
return true;
}
-void CanBusUtil::printPlugins()
+int CanBusUtil::printPlugins()
{
+ if (!m_canBus) {
+ m_output << tr("Error: Cannot create QCanBus.") << endl;
+ return 1;
+ }
+
const QStringList plugins = m_canBus->plugins();
- for (int i = 0; i < plugins.size(); i++)
- m_output << plugins.at(i) << endl;
+ for (const QString &plugin : plugins)
+ m_output << plugin << endl;
+ return 0;
}
int CanBusUtil::printDevices(const QString &pluginName)
{
+ if (!m_canBus) {
+ m_output << tr("Error: Cannot create QCanBus.") << endl;
+ return 1;
+ }
+
QString errorMessage;
const QList<QCanBusDeviceInfo> devices = m_canBus->availableDevices(pluginName, &errorMessage);
if (!errorMessage.isEmpty()) {
- m_output << "Error: " << errorMessage << endl;
+ m_output << tr("Error gathering available devices: '%1'").arg(errorMessage) << endl;
return 1;
}
@@ -108,12 +123,12 @@ bool CanBusUtil::parseDataField(quint32 &id, QString &payload)
{
int hashMarkPos = m_data.indexOf('#');
if (hashMarkPos < 0) {
- m_output << "Data field invalid: No hash mark found!" << endl;
+ m_output << tr("Data field invalid: No hash mark found!") << endl;
return false;
}
id = m_data.leftRef(hashMarkPos).toUInt(nullptr, 16);
- payload = m_data.right(m_data.length() - hashMarkPos - 1);
+ payload = m_data.right(m_data.size() - hashMarkPos - 1);
return true;
}
@@ -121,37 +136,30 @@ bool CanBusUtil::parseDataField(quint32 &id, QString &payload)
bool CanBusUtil::setFrameFromPayload(QString payload, QCanBusFrame *frame)
{
if (!payload.isEmpty() && payload.at(0).toUpper() == 'R') {
- bool validPayloadLength = false;
-
frame->setFrameType(QCanBusFrame::RemoteRequestFrame);
- if (payload.size() == 1) { // payload = "R"
- validPayloadLength = true;
- } else if (payload.size() > 1) { // payload = "R8"
- payload = payload.mid(1);
- int rtrFrameLength = payload.toInt(&validPayloadLength);
-
- if (validPayloadLength && rtrFrameLength >= 0 && rtrFrameLength <= 8) {
- frame->setPayload(QByteArray(rtrFrameLength, 0));
- } else if (validPayloadLength) {
- m_output << "The length must be between 0 and 8 (including)." << endl;
- validPayloadLength = false;
- }
- }
+ if (payload.size() == 1) // payload = "R"
+ return true;
- if (!validPayloadLength) {
- m_output << "Data field invalid: RTR data frame length not specified/valid." << endl;
+ bool ok = false;
+ int rtrFrameLength = payload.midRef(1).toInt(&ok);
+ if (ok && rtrFrameLength >= 0 && rtrFrameLength <= 8) { // payload = "R8"
+ frame->setPayload(QByteArray(rtrFrameLength, 0));
+ return true;
}
- return validPayloadLength;
- } else if (!payload.isEmpty() && payload.at(0) == '#') {
+ m_output << tr("Error: RTR frame length must be between 0 and 8 (including).") << endl;
+ return false;
+ }
+
+ if (!payload.isEmpty() && payload.at(0) == '#') {
frame->setFlexibleDataRateFormat(true);
- payload = payload.mid(1);
+ payload.remove(0, 1);
}
const QRegularExpression re(QStringLiteral("^[0-9A-Fa-f]*$"));
if (!re.match(payload).hasMatch()) {
- m_output << "Data field invalid: Only hex numbers allowed." << endl;
+ m_output << tr("Data field invalid: Only hex numbers allowed.") << endl;
return false;
}
@@ -163,7 +171,7 @@ bool CanBusUtil::setFrameFromPayload(QString payload, QCanBusFrame *frame)
frame->setErrorStateIndicator(flags & ErrorStateIndicatorFlag);
payload.remove(0, 1);
} else {
- m_output << "Data field invalid: Size is not multiple of two." << endl;
+ m_output << tr("Data field invalid: Size is not multiple of two.") << endl;
return false;
}
}
@@ -172,8 +180,8 @@ bool CanBusUtil::setFrameFromPayload(QString payload, QCanBusFrame *frame)
const int maxSize = frame->hasFlexibleDataRateFormat() ? 64 : 8;
if (bytes.size() > maxSize) {
- m_output << "Warning: Truncating payload at max. size of " << maxSize << " bytes." << endl;
- bytes.truncate(maxSize);
+ m_output << tr("Data field invalid: Size is longer than %1 bytes.").arg(maxSize) << endl;
+ return false;
}
frame->setPayload(bytes);
@@ -184,20 +192,18 @@ bool CanBusUtil::setFrameFromPayload(QString payload, QCanBusFrame *frame)
bool CanBusUtil::connectCanDevice()
{
if (!m_canBus->plugins().contains(m_pluginName)) {
- m_output << "Could not find suitable plugin." << endl;
- m_output << "Available plugins:" << endl;
- printPlugins();
+ m_output << tr("Cannot find CAN bus plugin '%1'.").arg(m_pluginName) << endl;
return false;
}
m_canDevice.reset(m_canBus->createDevice(m_pluginName, m_deviceName));
if (!m_canDevice) {
- m_output << "Unable to create QCanBusDevice with device name: " << m_deviceName << endl;
+ m_output << tr("Cannot create CAN bus device: '%1'").arg(m_deviceName) << endl;
return false;
}
- connect(m_canDevice.data(), &QCanBusDevice::errorOccurred, m_readTask, &ReadTask::receiveError);
+ connect(m_canDevice.data(), &QCanBusDevice::errorOccurred, m_readTask, &ReadTask::handleError);
if (!m_canDevice->connectDevice()) {
- m_output << "Unable to connect QCanBusDevice with device name: " << m_deviceName << endl;
+ m_output << tr("Cannot create CAN bus device: '%1'").arg(m_deviceName) << endl;
return false;
}
@@ -210,15 +216,15 @@ bool CanBusUtil::sendData()
QString payload;
QCanBusFrame frame;
- if (parseDataField(id, payload) == false)
+ if (!parseDataField(id, payload))
return false;
- if (setFrameFromPayload(payload, &frame) == false)
+ if (!setFrameFromPayload(payload, &frame))
return false;
if (id > 0x1FFFFFFF) { // 29 bits
- id = 0x1FFFFFFF;
- m_output << "Warning! Id does not fit into Extended Frame Format, setting id to: " << id << endl;
+ m_output << tr("Cannot send invalid frame ID: '%1'").arg(id, 0, 16) << endl;
+ return false;
}
frame.setFrameId(id);
diff --git a/src/tools/canbusutil/canbusutil.h b/src/tools/canbusutil/canbusutil.h
index 356b3df..e6432a3 100644
--- a/src/tools/canbusutil/canbusutil.h
+++ b/src/tools/canbusutil/canbusutil.h
@@ -37,16 +37,16 @@
#ifndef CANBUSUTIL_H
#define CANBUSUTIL_H
+#include "readtask.h"
+
#include <QObject>
-#include <QTextStream>
-#include <QCoreApplication>
#include <QScopedPointer>
-#include "readtask.h"
-
QT_BEGIN_NAMESPACE
class QCanBusFrame;
+class QCoreApplication;
+class QTextStream;
QT_END_NAMESPACE
@@ -59,7 +59,7 @@ public:
void setShowTimeStamp(bool showTimeStamp);
void setShowFdFlags(bool showFdFlags);
bool start(const QString &pluginName, const QString &deviceName, const QString &data = QString());
- void printPlugins();
+ int printPlugins();
int printDevices(const QString &pluginName);
private:
@@ -69,15 +69,15 @@ private:
bool sendData();
private:
- QCanBus *m_canBus;
+ QCanBus *m_canBus = nullptr;
QTextStream &m_output;
QCoreApplication &m_app;
- bool m_listening;
+ bool m_listening = false;
QString m_pluginName;
QString m_deviceName;
QString m_data;
QScopedPointer<QCanBusDevice> m_canDevice;
- ReadTask *m_readTask;
+ ReadTask *m_readTask = nullptr;
};
#endif // CANBUSUTIL_H
diff --git a/src/tools/canbusutil/main.cpp b/src/tools/canbusutil/main.cpp
index 1304f22..6744f19 100644
--- a/src/tools/canbusutil/main.cpp
+++ b/src/tools/canbusutil/main.cpp
@@ -34,6 +34,9 @@
**
****************************************************************************/
+#include "canbusutil.h"
+#include "sigtermhandler.h"
+
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QTextStream>
@@ -41,15 +44,10 @@
#include <signal.h>
-#include "canbusutil.h"
-#include "sigtermhandler.h"
-
-#define PROGRAMNAME "canbusutil"
-
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- QCoreApplication::setApplicationName(QStringLiteral(PROGRAMNAME));
+ QCoreApplication::setApplicationName(QStringLiteral("canbusutil"));
QCoreApplication::setApplicationVersion(QStringLiteral(QT_VERSION_STR));
QScopedPointer<SigTermHandler> s(SigTermHandler::instance());
@@ -106,10 +104,8 @@ int main(int argc, char *argv[])
parser.process(app);
- if (parser.isSet(listOption)) {
- util.printPlugins();
- return 0;
- }
+ if (parser.isSet(listOption))
+ return util.printPlugins();
QString data;
const QStringList args = parser.positionalArguments();
@@ -117,16 +113,16 @@ int main(int argc, char *argv[])
util.setShowTimeStamp(parser.isSet(showTimeStampOption));
util.setShowFdFlags(parser.isSet(showFdFlagsOption));
} else if (args.size() == 3) {
- data = args[2];
+ data = args.at(2);
} else if (args.size() == 1 && parser.isSet(listDevicesOption)) {
- return util.printDevices(args[0]);
+ return util.printDevices(args.at(0));
} else if (args.size() != 2) {
- fprintf(stderr, "Invalid number of arguments (%d given).\n\n%s",
- args.size(), qPrintable(parser.helpText()));
+ output << CanBusUtil::tr("Invalid number of arguments (%1 given).").arg(args.size());
+ output << endl << endl << parser.helpText();
return 1;
}
- if (!util.start(args[0], args[1], data))
+ if (!util.start(args.at(0), args.at(1), data))
return -1;
return app.exec();
diff --git a/src/tools/canbusutil/readtask.cpp b/src/tools/canbusutil/readtask.cpp
index fb159b7..2bde509 100644
--- a/src/tools/canbusutil/readtask.cpp
+++ b/src/tools/canbusutil/readtask.cpp
@@ -36,9 +36,9 @@
#include "readtask.h"
-ReadTask::ReadTask(QTextStream &output, QObject *parent)
- : QObject(parent),
- output(output) { }
+ReadTask::ReadTask(QTextStream &output, QObject *parent) :
+ QObject(parent),
+ m_output(output) { }
void ReadTask::setShowTimeStamp(bool showTimeStamp)
{
@@ -55,10 +55,10 @@ void ReadTask::setShowFdFlags(bool showFlags)
m_showFdFlags = showFlags;
}
-void ReadTask::checkMessages() {
+void ReadTask::handleFrames() {
auto canDevice = qobject_cast<QCanBusDevice *>(QObject::sender());
if (canDevice == nullptr) {
- qWarning("ReadTask::checkMessages: Unknown sender");
+ qWarning("ReadTask::handleFrames: Unknown sender.");
return;
}
@@ -87,16 +87,17 @@ void ReadTask::checkMessages() {
else
view += frame.toString();
- output << view << endl;
+ m_output << view << endl;
}
}
-void ReadTask::receiveError(QCanBusDevice::CanBusError /*error*/) {
+void ReadTask::handleError(QCanBusDevice::CanBusError /*error*/)
+{
auto canDevice = qobject_cast<QCanBusDevice *>(QObject::sender());
if (canDevice == nullptr) {
- qWarning("ReadTask::receiveError: Unknown sender");
+ qWarning("ReadTask::handleError: Unknown sender.");
return;
}
- output << "Read error: " << canDevice->errorString() << endl;
+ m_output << tr("Read error: '%1'").arg(canDevice->errorString()) << endl;
}
diff --git a/src/tools/canbusutil/readtask.h b/src/tools/canbusutil/readtask.h
index e00440a..a866d3d 100644
--- a/src/tools/canbusutil/readtask.h
+++ b/src/tools/canbusutil/readtask.h
@@ -45,17 +45,17 @@ class ReadTask : public QObject
{
Q_OBJECT
public:
- explicit ReadTask(QTextStream &output, QObject *parent = nullptr);
+ explicit ReadTask(QTextStream &m_output, QObject *parent = nullptr);
void setShowTimeStamp(bool showStamp);
bool isShowFdFlags() const;
void setShowFdFlags(bool isShowFdFlags);
public slots:
- void checkMessages();
- void receiveError(QCanBusDevice::CanBusError /*error*/);
+ void handleFrames();
+ void handleError(QCanBusDevice::CanBusError /*error*/);
private:
- QTextStream &output;
+ QTextStream &m_output;
bool m_showTimeStamp = false;
bool m_showFdFlags = false;
};
diff --git a/tests/auto/plugins/genericcanbus/dummybackend.cpp b/tests/auto/plugins/genericcanbus/dummybackend.cpp
index 4c3173a..83d2480 100644
--- a/tests/auto/plugins/genericcanbus/dummybackend.cpp
+++ b/tests/auto/plugins/genericcanbus/dummybackend.cpp
@@ -43,12 +43,16 @@
QT_BEGIN_NAMESPACE
DummyBackend::DummyBackend() :
- sendTimer(new QTimer(this))
+ simulateReceivingTimer(new QTimer(this))
{
- sendTimer->setInterval(1000);
- sendTimer->setSingleShot(false);
- connect(sendTimer, &QTimer::timeout, this, &DummyBackend::sendMessage);
- sendTimer->start();
+ connect(simulateReceivingTimer, &QTimer::timeout, [this]() {
+ const quint64 timeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
+ QCanBusFrame dummyFrame(12, "def");
+ dummyFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(timeStamp * 1000));
+
+ enqueueReceivedFrames({dummyFrame});
+ });
+ simulateReceivingTimer->start(1000);
}
bool DummyBackend::open()
@@ -62,20 +66,9 @@ void DummyBackend::close()
setState(QCanBusDevice::UnconnectedState);
}
-void DummyBackend::sendMessage()
-{
- quint64 timeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
- QCanBusFrame dummyFrame;
- dummyFrame.setFrameId(12);
- dummyFrame.setPayload(QByteArray("def"));
- dummyFrame.setTimeStamp(QCanBusFrame::TimeStamp(timeStamp / 1000, (timeStamp % 1000) * 1000));
-
- enqueueReceivedFrames(QVector<QCanBusFrame>() << dummyFrame);
-}
-
bool DummyBackend::writeFrame(const QCanBusFrame &data)
{
- qDebug() << "DummyBackend::writeFrame: " << data.toString();
+ qDebug("DummyBackend::writeFrame: %ls", qUtf16Printable(data.toString()));
return true;
}
diff --git a/tests/auto/plugins/genericcanbus/dummybackend.h b/tests/auto/plugins/genericcanbus/dummybackend.h
index 22bbc80..d9727be 100644
--- a/tests/auto/plugins/genericcanbus/dummybackend.h
+++ b/tests/auto/plugins/genericcanbus/dummybackend.h
@@ -58,11 +58,8 @@ public:
static QList<QCanBusDeviceInfo> interfaces();
-public Q_SLOTS:
- void sendMessage();
-
private:
- QTimer *sendTimer;
+ QTimer *simulateReceivingTimer = nullptr;
};
QT_END_NAMESPACE
diff --git a/tests/auto/plugins/genericcanbus/main.cpp b/tests/auto/plugins/genericcanbus/main.cpp
index 8e14fee..89103a4 100644
--- a/tests/auto/plugins/genericcanbus/main.cpp
+++ b/tests/auto/plugins/genericcanbus/main.cpp
@@ -38,7 +38,6 @@
#include <QtSerialBus/qcanbus.h>
#include <QtSerialBus/qcanbusfactory.h>
-#include "../../../../src/serialbus/qcanbusdeviceinfo_p.h"
QT_BEGIN_NAMESPACE
diff --git a/tests/auto/plugins/genericcanbusv1/dummybackendv1.cpp b/tests/auto/plugins/genericcanbusv1/dummybackendv1.cpp
index 117aeec..4d7d9c0 100644
--- a/tests/auto/plugins/genericcanbusv1/dummybackendv1.cpp
+++ b/tests/auto/plugins/genericcanbusv1/dummybackendv1.cpp
@@ -43,16 +43,16 @@
QT_BEGIN_NAMESPACE
DummyBackendV1::DummyBackendV1() :
- sendTimer(new QTimer(this))
+ simulateReceivingTimer(new QTimer(this))
{
- connect(sendTimer, &QTimer::timeout, [this]() {
+ connect(simulateReceivingTimer, &QTimer::timeout, [this]() {
const quint64 timeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
QCanBusFrame dummyFrame(11, "abc");
dummyFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(timeStamp * 1000));
enqueueReceivedFrames({dummyFrame});
});
- sendTimer->start(1000);
+ simulateReceivingTimer->start(1000);
}
bool DummyBackendV1::open()
diff --git a/tests/auto/plugins/genericcanbusv1/dummybackendv1.h b/tests/auto/plugins/genericcanbusv1/dummybackendv1.h
index 4c3fc64..6892b4f 100644
--- a/tests/auto/plugins/genericcanbusv1/dummybackendv1.h
+++ b/tests/auto/plugins/genericcanbusv1/dummybackendv1.h
@@ -57,7 +57,7 @@ public:
QString interpretErrorFrame(const QCanBusFrame &) override;
private:
- QTimer *sendTimer;
+ QTimer *simulateReceivingTimer = nullptr;
};
QT_END_NAMESPACE
diff --git a/tests/auto/qcanbus/tst_qcanbus.cpp b/tests/auto/qcanbus/tst_qcanbus.cpp
index 9e6a647..475adc4 100644
--- a/tests/auto/qcanbus/tst_qcanbus.cpp
+++ b/tests/auto/qcanbus/tst_qcanbus.cpp
@@ -37,7 +37,7 @@
#include <QtSerialBus/qcanbus.h>
#include <QtSerialBus/qcanbusfactory.h>
-#include <QtTest/QtTest>
+#include <QtTest/qtest.h>
class tst_QCanBus : public QObject
{
@@ -52,7 +52,7 @@ private slots:
void createDevice();
private:
- QCanBus *bus;
+ QCanBus *bus = nullptr;
};
tst_QCanBus::tst_QCanBus()
@@ -89,12 +89,12 @@ void tst_QCanBus::plugins()
void tst_QCanBus::interfaces()
{
// Plugins derived from QCanBusFactory(V1) don't have availableDevices()
- const QList<QCanBusDeviceInfo> pluginListV1 = bus->availableDevices("genericV1");
- QVERIFY(pluginListV1.isEmpty());
+ const QList<QCanBusDeviceInfo> deviceListV1 = bus->availableDevices("genericV1");
+ QVERIFY(deviceListV1.isEmpty());
const QList<QCanBusDeviceInfo> pluginList = bus->availableDevices("generic");
- QCOMPARE(1, pluginList.size());
- QCOMPARE(QString("can0"), pluginList.at(0).name());
+ QCOMPARE(pluginList.size(), 1);
+ QCOMPARE(pluginList.at(0).name(), QStringLiteral("can0"));
QVERIFY(pluginList.at(0).isVirtual());
QVERIFY(pluginList.at(0).hasFlexibleDataRate());
}
diff --git a/tests/auto/qcanbusdevice/tst_qcanbusdevice.cpp b/tests/auto/qcanbusdevice/tst_qcanbusdevice.cpp
index 3fce8d5..cf18c4a 100644
--- a/tests/auto/qcanbusdevice/tst_qcanbusdevice.cpp
+++ b/tests/auto/qcanbusdevice/tst_qcanbusdevice.cpp
@@ -34,12 +34,13 @@
**
****************************************************************************/
-#include <QtSerialBus/QCanBusDevice>
-#include <QtSerialBus/QCanBusFrame>
+#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusframe.h>
-#include <QtTest/QtTest>
-#include <QSignalSpy>
-#include <QScopedPointer>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qtimer.h>
+#include <QtTest/qsignalspy.h>
+#include <QtTest/qtest.h>
#include <memory>
@@ -47,8 +48,7 @@ class tst_Backend : public QCanBusDevice
{
Q_OBJECT
public:
- tst_Backend() :
- firstOpen(true), writeBufferUsed(true)
+ tst_Backend()
{
referenceFrame.setFrameId(5);
referenceFrame.setPayload(QByteArray("FOOBAR"));
@@ -61,8 +61,8 @@ public:
if (state() != QCanBusDevice::ConnectedState)
return false;
- // line below triggers framesReceived() signal
- enqueueReceivedFrames(QVector<QCanBusFrame>() << referenceFrame);
+ // the line below triggers the framesReceived() signal
+ enqueueReceivedFrames({referenceFrame});
return true;
}
@@ -109,7 +109,7 @@ public:
bool isWriteBuffered() const { return writeBufferUsed; }
void setWriteBuffered(bool isBuffered)
{
- // permits switching between buffered and unbuffered write mode
+ // allows switching between buffered and unbuffered write mode
writeBufferUsed = isBuffered;
}
@@ -128,8 +128,8 @@ public slots:
private:
QCanBusFrame referenceFrame;
- bool firstOpen;
- bool writeBufferUsed;
+ bool firstOpen = true;
+ bool writeBufferUsed = true;
};
class tst_QCanBusDevice : public QObject
@@ -165,21 +165,19 @@ void tst_QCanBusDevice::initTestCase()
device.reset(new tst_Backend());
QVERIFY(device);
- QSignalSpy stateSpy(device.data(),
- SIGNAL(stateChanged(QCanBusDevice::CanBusDeviceState)));
+ QSignalSpy stateSpy(device.data(), &QCanBusDevice::stateChanged);
- QVERIFY(!device->connectDevice()); //first connect triggered to fail
+ QVERIFY(!device->connectDevice()); // first connect triggered to fail
QVERIFY(device->connectDevice());
- QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState,
- 5000);
+ QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState, 5000);
QCOMPARE(stateSpy.count(), 4);
- QCOMPARE(stateSpy[0].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(0).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ConnectingState);
- QCOMPARE(stateSpy[1].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(1).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::UnconnectedState);
- QCOMPARE(stateSpy[2].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(2).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ConnectingState);
- QCOMPARE(stateSpy[3].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(3).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ConnectedState);
}
@@ -214,22 +212,20 @@ void tst_QCanBusDevice::write()
{
// we assume unbuffered writing in this function
device->setWriteBuffered(false);
- QCOMPARE(device->isWriteBuffered(), false);
+ QVERIFY(!device->isWriteBuffered());
- QSignalSpy spy(device.data(), SIGNAL(framesWritten(qint64)));
- QSignalSpy stateSpy(device.data(),
- SIGNAL(stateChanged(QCanBusDevice::CanBusDeviceState)));
+ QSignalSpy spy(device.data(), &QCanBusDevice::framesWritten);
+ QSignalSpy stateSpy(device.data(), &QCanBusDevice::stateChanged);
QCanBusFrame frame;
frame.setPayload(QByteArray("testData"));
device->disconnectDevice();
- QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::UnconnectedState,
- 5000);
+ QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::UnconnectedState, 5000);
QCOMPARE(stateSpy.count(), 2);
- QCOMPARE(stateSpy[0].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(0).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ClosingState);
- QCOMPARE(stateSpy[1].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(1).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::UnconnectedState);
stateSpy.clear();
QVERIFY(stateSpy.isEmpty());
@@ -237,14 +233,12 @@ void tst_QCanBusDevice::write()
device->writeFrame(frame);
QCOMPARE(spy.count(), 0);
-
device->connectDevice();
- QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState,
- 5000);
+ QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState, 5000);
QCOMPARE(stateSpy.count(), 2);
- QCOMPARE(stateSpy[0].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(0).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ConnectingState);
- QCOMPARE(stateSpy[1].at(0).value<QCanBusDevice::CanBusDeviceState>(),
+ QCOMPARE(stateSpy.at(1).at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ConnectedState);
device->writeFrame(frame);
@@ -253,8 +247,7 @@ void tst_QCanBusDevice::write()
void tst_QCanBusDevice::read()
{
- QSignalSpy stateSpy(device.data(),
- SIGNAL(stateChanged(QCanBusDevice::CanBusDeviceState)));
+ QSignalSpy stateSpy(device.data(), &QCanBusDevice::stateChanged);
device->disconnectDevice();
QCOMPARE(device->state(), QCanBusDevice::UnconnectedState);
@@ -263,8 +256,7 @@ void tst_QCanBusDevice::read()
const QCanBusFrame frame1 = device->readFrame();
QVERIFY(device->connectDevice());
- QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState,
- 5000);
+ QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState, 5000);
QCOMPARE(stateSpy.count(), 2);
QCOMPARE(stateSpy[0].at(0).value<QCanBusDevice::CanBusDeviceState>(),
QCanBusDevice::ConnectingState);
@@ -281,48 +273,43 @@ void tst_QCanBusDevice::read()
void tst_QCanBusDevice::error()
{
- QSignalSpy spy(device.data(), SIGNAL(errorOccurred(QCanBusDevice::CanBusError)));
+ QSignalSpy spy(device.data(), &QCanBusDevice::errorOccurred);
QString testString(QStringLiteral("testString"));
auto backend = qobject_cast<tst_Backend *>(device.data());
QVERIFY(backend);
- //NoError
+ // NoError
QVERIFY(device->errorString().isEmpty());
- //ReadError
- backend->emulateError(testString+QString::fromLatin1("a"),
- QCanBusDevice::ReadError);
- QCOMPARE(testString+QString::fromLatin1("a"), device->errorString());
- QVERIFY(device->error() == 1);
+ // ReadError
+ backend->emulateError(testString + QStringLiteral("a"), QCanBusDevice::ReadError);
+ QCOMPARE(testString + QStringLiteral("a"), device->errorString());
+ QCOMPARE(device->error(), 1);
QCOMPARE(spy.count(), 1);
- //WriteError
- backend->emulateError(testString+QString::fromLatin1("b"),
- QCanBusDevice::WriteError);
- QCOMPARE(testString+QString::fromLatin1("b"), device->errorString());
- QVERIFY(device->error() == 2);
+ // WriteError
+ backend->emulateError(testString + QStringLiteral("b"), QCanBusDevice::WriteError);
+ QCOMPARE(testString + QStringLiteral("b"), device->errorString());
+ QCOMPARE(device->error(), 2);
QCOMPARE(spy.count(), 2);
- //ConnectionError
- backend->emulateError(testString+QString::fromLatin1("c"),
- QCanBusDevice::ConnectionError);
- QCOMPARE(testString+QString::fromLatin1("c"), device->errorString());
- QVERIFY(device->error() == 3);
+ // ConnectionError
+ backend->emulateError(testString + QStringLiteral("c"), QCanBusDevice::ConnectionError);
+ QCOMPARE(testString + QStringLiteral("c"), device->errorString());
+ QCOMPARE(device->error(), 3);
QCOMPARE(spy.count(), 3);
- //ConfigurationError
- backend->emulateError(testString+QString::fromLatin1("d"),
- QCanBusDevice::ConfigurationError);
- QCOMPARE(testString+QString::fromLatin1("d"), device->errorString());
- QVERIFY(device->error() == 4);
+ // ConfigurationError
+ backend->emulateError(testString + QStringLiteral("d"), QCanBusDevice::ConfigurationError);
+ QCOMPARE(testString + QStringLiteral("d"), device->errorString());
+ QCOMPARE(device->error(), 4);
QCOMPARE(spy.count(), 4);
- //UnknownError
- backend->emulateError(testString+QString::fromLatin1("e"),
- QCanBusDevice::UnknownError);
- QCOMPARE(testString+QString::fromLatin1("e"), device->errorString());
- QVERIFY(device->error() == 5);
+ // UnknownError
+ backend->emulateError(testString + QStringLiteral("e"), QCanBusDevice::UnknownError);
+ QCOMPARE(testString + QStringLiteral("e"), device->errorString());
+ QCOMPARE(device->error(), 5);
QCOMPARE(spy.count(), 5);
}
@@ -356,9 +343,8 @@ void tst_QCanBusDevice::tst_filtering()
f.format = QCanBusDevice::Filter::MatchBaseFormat;
filters.append(f);
- QVariant wrapper = QVariant::fromValue(filters);
- QList<QCanBusDevice::Filter> newFilter
- = wrapper.value<QList<QCanBusDevice::Filter> >();
+ const QVariant wrapper = QVariant::fromValue(filters);
+ const auto newFilter = wrapper.value<QList<QCanBusDevice::Filter> >();
QCOMPARE(newFilter.count(), 2);
QCOMPARE(newFilter.at(0).type, QCanBusFrame::DataFrame);
@@ -380,22 +366,21 @@ void tst_QCanBusDevice::tst_filtering()
void tst_QCanBusDevice::tst_bufferingAttribute()
{
std::unique_ptr<tst_Backend> canDevice(new tst_Backend);
- QVERIFY((bool)canDevice);
+ QVERIFY(canDevice != nullptr);
// by default buffered set to true
- QCOMPARE(canDevice->isWriteBuffered(), true);
+ QVERIFY(canDevice->isWriteBuffered());
canDevice->setWriteBuffered(false);
- QCOMPARE(canDevice->isWriteBuffered(), false);
+ QVERIFY(!canDevice->isWriteBuffered());
canDevice->setWriteBuffered(true);
- QCOMPARE(canDevice->isWriteBuffered(), true);
+ QVERIFY(canDevice->isWriteBuffered());
}
void tst_QCanBusDevice::tst_waitForFramesReceived()
{
if (device->state() != QCanBusDevice::ConnectedState) {
QVERIFY(device->connectDevice());
- QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState,
- 5000);
+ QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState, 5000);
}
QVERIFY(!device->framesAvailable());
@@ -431,14 +416,14 @@ void tst_QCanBusDevice::tst_waitForFramesReceived()
QVERIFY(!device->framesAvailable());
QTimer::singleShot(2000, [&]() {
- device->emulateError(QString("TriggerError"), QCanBusDevice::ReadError);
+ device->emulateError(QStringLiteral("TriggerError"), QCanBusDevice::ReadError);
});
elapsed.restart();
// error will be inserted after 2s
result = device->waitForFramesReceived(8000);
QVERIFY(!elapsed.hasExpired(8000));
QVERIFY(!result);
- QCOMPARE(device->errorString(), QString("TriggerError"));
+ QCOMPARE(device->errorString(), QStringLiteral("TriggerError"));
QCOMPARE(device->error(), QCanBusDevice::ReadError);
// test recursive calling of waitForFramesReceived() behavior
@@ -450,7 +435,7 @@ void tst_QCanBusDevice::tst_waitForFramesReceived()
QTimer::singleShot(2000, [&]() { device->triggerNewFrame(); });
QObject::connect(device.data(), &QCanBusDevice::framesReceived, [this, &handleCounter]() {
handleCounter++;
- //this should trigger a recursion which we want to catch
+ // this should trigger a recursion which we want to catch
device->waitForFramesReceived(5000);
});
result = device->waitForFramesReceived(8000);
@@ -462,26 +447,25 @@ void tst_QCanBusDevice::tst_waitForFramesWritten()
{
if (device->state() != QCanBusDevice::ConnectedState) {
QVERIFY(device->connectDevice());
- QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState,
- 5000);
+ QTRY_VERIFY_WITH_TIMEOUT(device->state() == QCanBusDevice::ConnectedState, 5000);
}
device->setWriteBuffered(false);
bool result = device->waitForFramesWritten(1000);
- QVERIFY(!result); //no buffer, wait not possible
+ QVERIFY(!result); // no buffer, waiting not possible
device->setWriteBuffered(true);
QVERIFY(device->framesToWrite() == 0);
result = device->waitForFramesWritten(1000);
- QVERIFY(!result); //nothing in buffer, nothing to wait for
+ QVERIFY(!result); // nothing in buffer, nothing to wait for
QCanBusFrame frame;
frame.setPayload(QByteArray("testData"));
// test error case
QTimer::singleShot(500, [&]() {
- device->emulateError(QString("TriggerWriteError"), QCanBusDevice::ReadError);
+ device->emulateError(QStringLiteral("TriggerWriteError"), QCanBusDevice::ReadError);
});
device->writeFrame(frame);
QElapsedTimer elapsed;
@@ -491,7 +475,7 @@ void tst_QCanBusDevice::tst_waitForFramesWritten()
result = device->waitForFramesWritten(8000);
QVERIFY(!elapsed.hasExpired(8000));
QVERIFY(!result);
- QCOMPARE(device->errorString(), QString("TriggerWriteError"));
+ QCOMPARE(device->errorString(), QStringLiteral("TriggerWriteError"));
QCOMPARE(device->error(), QCanBusDevice::ReadError);
// flush remaining frames out to reset the test
@@ -523,7 +507,7 @@ void tst_QCanBusDevice::tst_waitForFramesWritten()
QTimer::singleShot(2000, [&]() { device->writeFrame(frame); });
QObject::connect(device.data(), &QCanBusDevice::framesWritten, [this, &handleCounter]() {
handleCounter++;
- //this should trigger a recursion which we want to catch
+ // this should trigger a recursion which we want to catch
device->waitForFramesWritten(5000);
});
result = device->waitForFramesWritten(8000);
diff --git a/tests/auto/qcanbusframe/tst_qcanbusframe.cpp b/tests/auto/qcanbusframe/tst_qcanbusframe.cpp
index 38c3784..96ebee1 100644
--- a/tests/auto/qcanbusframe/tst_qcanbusframe.cpp
+++ b/tests/auto/qcanbusframe/tst_qcanbusframe.cpp
@@ -34,8 +34,10 @@
**
****************************************************************************/
-#include <QtTest/QtTest>
-#include <QtSerialBus/QCanBusFrame>
+#include <QtSerialBus/qcanbusframe.h>
+
+#include <QtCore/qdatastream.h>
+#include <QtTest/qtest.h>
class tst_QCanBusFrame : public QObject
{
@@ -54,6 +56,8 @@ private slots:
void tst_isValid_data();
void tst_isValid();
+ void tst_isValidSize_data();
+ void tst_isValidSize();
void tst_toString_data();
void tst_toString();
@@ -330,7 +334,7 @@ void tst_QCanBusFrame::tst_isValid_data()
<< QByteArray(9, 0) << 512u << false << false;
QTest::newRow("data frame CAN FD long payload")
<< QCanBusFrame::DataFrame << true
- << QByteArray(9, 0) << 512u << false << true;
+ << QByteArray(12, 0) << 512u << false << true;
QTest::newRow("data frame CAN FD too long payload")
<< QCanBusFrame::DataFrame << false
<< QByteArray(65, 0) << 512u << false << true;
@@ -362,6 +366,46 @@ void tst_QCanBusFrame::tst_isValid()
QCOMPARE(QCanBusFrame::InvalidFrame, frame.frameType());
}
+void tst_QCanBusFrame::tst_isValidSize_data()
+{
+ QTest::addColumn<int>("payloadLength");
+ QTest::addColumn<bool>("isFlexibleDataRate");
+ QTest::addColumn<bool>("isValid");
+
+ QTest::newRow("2.0-0") << 0 << false << true;
+ QTest::newRow("2.0-8") << 8 << false << true;
+ QTest::newRow("2.0-9") << 9 << false << false;
+
+ QTest::newRow("FD-0") << 0 << true << true;
+ QTest::newRow("FD-8") << 8 << true << true;
+ QTest::newRow("FD-9") << 9 << true << false;
+ QTest::newRow("FD-11") << 11 << true << false;
+ QTest::newRow("FD-12") << 12 << true << true;
+ QTest::newRow("FD-13") << 13 << true << false;
+ QTest::newRow("FD-16") << 16 << true << true;
+
+ QTest::newRow("FD-20") << 20 << true << true;
+ QTest::newRow("FD-24") << 24 << true << true;
+ QTest::newRow("FD-32") << 32 << true << true;
+ QTest::newRow("FD-48") << 48 << true << true;
+
+ QTest::newRow("FD-63") << 63 << true << false;
+ QTest::newRow("FD-64") << 64 << true << true;
+ QTest::newRow("FD-65") << 65 << true << false;
+}
+
+void tst_QCanBusFrame::tst_isValidSize()
+{
+ QFETCH(int, payloadLength);
+ QFETCH(bool, isFlexibleDataRate);
+ QFETCH(bool, isValid);
+
+ QCanBusFrame frame(0, QByteArray(payloadLength, ' '));
+ frame.setFlexibleDataRateFormat(isFlexibleDataRate);
+
+ QCOMPARE(frame.isValid(), isValid);
+}
+
void tst_QCanBusFrame::tst_toString_data()
{
QTest::addColumn<QCanBusFrame::FrameType>("frameType");
@@ -568,7 +612,7 @@ void tst_QCanBusFrame::tst_error()
QCOMPARE(frame.frameId(), 0u); //id of Error frame always 0
QCOMPARE(frame.error(), QCanBusFrame::TransmissionTimeoutError);
- frame.setError(QCanBusFrame::FrameErrors(QCanBusFrame::ControllerError|QCanBusFrame::ProtocolViolationError));
+ frame.setError(QCanBusFrame::FrameErrors(QCanBusFrame::ControllerError | QCanBusFrame::ProtocolViolationError));
QCOMPARE(frame.frameType(), QCanBusFrame::ErrorFrame);
QCOMPARE(frame.frameId(), 0u); //id of Error frame always 0
QCOMPARE(frame.error(),
@@ -576,7 +620,7 @@ void tst_QCanBusFrame::tst_error()
frame.setFrameType(QCanBusFrame::RemoteRequestFrame);
QCOMPARE(frame.frameType(), QCanBusFrame::RemoteRequestFrame);
- QCOMPARE(frame.frameId(), (uint)(QCanBusFrame::ControllerError|QCanBusFrame::ProtocolViolationError));
+ QCOMPARE(frame.frameId(), uint(QCanBusFrame::ControllerError | QCanBusFrame::ProtocolViolationError));
QCOMPARE(frame.error(), QCanBusFrame::NoError);
}