diff options
Diffstat (limited to 'src/plugins/canbus')
-rw-r--r-- | src/plugins/canbus/peakcan/peakcan_symbols_p.h | 51 | ||||
-rw-r--r-- | src/plugins/canbus/peakcan/peakcanbackend.cpp | 4 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/libsocketcan.cpp | 193 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/libsocketcan.h | 72 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcan.pro | 2 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcanbackend.cpp | 20 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcanbackend.h | 5 |
7 files changed, 325 insertions, 22 deletions
diff --git a/src/plugins/canbus/peakcan/peakcan_symbols_p.h b/src/plugins/canbus/peakcan/peakcan_symbols_p.h index 9ab2e67..3470df2 100644 --- a/src/plugins/canbus/peakcan/peakcan_symbols_p.h +++ b/src/plugins/canbus/peakcan/peakcan_symbols_p.h @@ -267,21 +267,28 @@ #define PCAN_TYPE_DNG_SJA_EPP 0x06U // PCAN-Dongle EPP SJA1000 // Type definitions -#define TPCANHandle quint16 // Represents a PCAN hardware channel handle -#define TPCANStatus quint32 // Represents a PCAN status/error code -#define TPCANParameter quint8 // Represents a PCAN parameter to be read or set -#define TPCANDevice quint8 // Represents a PCAN device -#define TPCANMessageType quint8 // Represents the type of a PCAN message -#define TPCANType quint8 // Represents the type of PCAN hardware to be initialized -#define TPCANMode quint8 // Represents a PCAN filter mode -#define TPCANBaudrate quint16 // Represents a PCAN Baud rate register value -#define TPCANBitrateFD char * // Represents a PCAN-FD bit rate string -#define TPCANTimestampFD quint64 // Represents a timestamp of a received PCAN FD message +#ifdef Q_OS_MACOS +#define TPCANLong quint64 +#define TPCANLongToFrameID(a) static_cast<quint32>(a) +#else +#define TPCANLong quint32 +#define TPCANLongToFrameID(a) a +#endif +#define TPCANHandle quint16 // Represents a PCAN hardware channel handle +#define TPCANStatus TPCANLong // Represents a PCAN status/error code +#define TPCANParameter quint8 // Represents a PCAN parameter to be read or set +#define TPCANDevice quint8 // Represents a PCAN device +#define TPCANMessageType quint8 // Represents the type of a PCAN message +#define TPCANType quint8 // Represents the type of PCAN hardware to be initialized +#define TPCANMode quint8 // Represents a PCAN filter mode +#define TPCANBaudrate quint16 // Represents a PCAN Baud rate register value +#define TPCANBitrateFD char * // Represents a PCAN-FD bit rate string +#define TPCANTimestampFD quint64 // Represents a timestamp of a received PCAN FD message // Represents a PCAN message typedef struct tagTPCANMsg { - quint32 ID; // 11/29-bit message identifier + TPCANLong ID; // 11/29-bit message identifier TPCANMessageType MSGTYPE; // Type of the message quint8 LEN; // Data Length Code of the message (0..8) quint8 DATA[8]; // Data of the message (DATA[0]..DATA[7]) @@ -291,15 +298,15 @@ typedef struct tagTPCANMsg // Total Microseconds = micros + 1000 * millis + 0xFFFFFFFF * 1000 * millis_overflow typedef struct tagTPCANTimestamp { - quint32 millis; // Base-value: milliseconds: 0.. 2^32-1 - quint16 millis_overflow; // Roll-arounds of millis - quint16 micros; // Microseconds: 0..999 + TPCANLong millis; // Base-value: milliseconds: 0.. 2^32-1 + quint16 millis_overflow; // Roll-arounds of millis + quint16 micros; // Microseconds: 0..999 } TPCANTimestamp; // Represents a PCAN message from a FD capable hardware typedef struct tagTPCANMsgFD { - quint32 ID; // 11/29-bit message identifier + TPCANLong ID; // 11/29-bit message identifier TPCANMessageType MSGTYPE; // Type of the message quint8 DLC; // Data Length Code of the message (0..15) quint8 DATA[64]; // Data of the message (DATA[0]..DATA[63]) @@ -314,7 +321,7 @@ typedef struct tagTPCANMsgFD if (!symbolName) \ return false; -GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_Initialize, TPCANHandle, TPCANBaudrate, TPCANType, quint32, quint16) +GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_Initialize, TPCANHandle, TPCANBaudrate, TPCANType, TPCANLong, quint16) GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_InitializeFD, TPCANHandle, TPCANBitrateFD) GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_Uninitialize, TPCANHandle) GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_Reset, TPCANHandle) @@ -323,15 +330,19 @@ GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_Read, TPCANHandle, TPCANMsg *, TPCANTi GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_ReadFD, TPCANHandle, TPCANMsgFD *, TPCANTimestampFD *) GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_Write, TPCANHandle, TPCANMsg *) GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_WriteFD, TPCANHandle, TPCANMsgFD *) -GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_FilterMessages, TPCANHandle, quint32, quint32, TPCANMode) -GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_GetValue, TPCANHandle, TPCANParameter, void *, quint32) -GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_SetValue, TPCANHandle, TPCANParameter, void *, quint32) +GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_FilterMessages, TPCANHandle, TPCANLong, TPCANLong, TPCANMode) +GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_GetValue, TPCANHandle, TPCANParameter, void *, TPCANLong) +GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_SetValue, TPCANHandle, TPCANParameter, void *, TPCANLong) GENERATE_SYMBOL_VARIABLE(TPCANStatus, CAN_GetErrorText, TPCANStatus, quint16, char *) inline bool resolveSymbols(QLibrary *pcanLibrary) { if (!pcanLibrary->isLoaded()) { - pcanLibrary->setFileName(QStringLiteral("pcanbasic")); + #ifdef Q_OS_MACOS + pcanLibrary->setFileName(QStringLiteral("PCBUSB")); + #else + pcanLibrary->setFileName(QStringLiteral("pcanbasic")); + #endif if (!pcanLibrary->load()) return false; } diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp index f8932e9..2f5e2d0 100644 --- a/src/plugins/canbus/peakcan/peakcanbackend.cpp +++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp @@ -611,7 +611,7 @@ void PeakCanBackendPrivate::startRead() continue; const int size = dlcToSize(static_cast<CanFrameDlc>(message.DLC)); - QCanBusFrame frame(message.ID, + QCanBusFrame frame(TPCANLongToFrameID(message.ID), QByteArray(reinterpret_cast<const char *>(message.DATA), size)); frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(static_cast<qint64>(timestamp))); frame.setExtendedFrameFormat(message.MSGTYPE & PCAN_MESSAGE_EXTENDED); @@ -641,7 +641,7 @@ void PeakCanBackendPrivate::startRead() continue; const int size = static_cast<int>(message.LEN); - QCanBusFrame frame(message.ID, + QCanBusFrame frame(TPCANLongToFrameID(message.ID), QByteArray(reinterpret_cast<const char *>(message.DATA), size)); const quint64 millis = timestamp.millis + Q_UINT64_C(0xFFFFFFFF) * timestamp.millis_overflow; const quint64 micros = Q_UINT64_C(1000) * millis + timestamp.micros; diff --git a/src/plugins/canbus/socketcan/libsocketcan.cpp b/src/plugins/canbus/socketcan/libsocketcan.cpp new file mode 100644 index 0000000..ca63391 --- /dev/null +++ b/src/plugins/canbus/socketcan/libsocketcan.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Andre Hartmann <aha_1980@gmx.de> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtSerialBus module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "libsocketcan.h" + +#include <QtCore/qloggingcategory.h> + +#if QT_CONFIG(library) +# include <QtCore/qlibrary.h> +#endif + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN) + +#define GENERATE_SYMBOL(returnType, symbolName, ...) \ + typedef returnType (*fp_##symbolName)(__VA_ARGS__); \ + static fp_##symbolName symbolName = nullptr; + +#define RESOLVE_SYMBOL(symbolName) \ + symbolName = reinterpret_cast<fp_##symbolName>(library->resolve(#symbolName)); \ + if (!symbolName) \ + return false; + +struct can_bittiming { + quint32 bitrate = 0; /* Bit-rate in bits/second */ + quint32 sample_point = 0; /* Sample point in one-tenth of a percent */ + quint32 tq = 0; /* Time quanta (TQ) in nanoseconds */ + quint32 prop_seg = 0; /* Propagation segment in TQs */ + quint32 phase_seg1 = 0; /* Phase buffer segment 1 in TQs */ + quint32 phase_seg2 = 0; /* Phase buffer segment 2 in TQs */ + quint32 sjw = 0; /* Synchronization jump width in TQs */ + quint32 brp = 0; /* Bit-rate prescaler */ +}; + +GENERATE_SYMBOL(int, can_do_restart, const char * /* name */) +GENERATE_SYMBOL(int, can_do_stop, const char * /* name */) +GENERATE_SYMBOL(int, can_do_start, const char * /* name */) +GENERATE_SYMBOL(int, can_set_bitrate, const char * /* name */, quint32 /* bitrate */) +GENERATE_SYMBOL(int, can_get_bittiming, const char * /* name */, struct can_bittiming * /* bt */) + +LibSocketCan::LibSocketCan(QString *errorString) +{ +#if QT_CONFIG(library) + auto resolveSymbols = [](QLibrary *library) { + if (!library->isLoaded()) { + library->setFileName(QStringLiteral("socketcan")); + if (!library->load()) + return false; + } + + RESOLVE_SYMBOL(can_do_start); + RESOLVE_SYMBOL(can_do_stop); + RESOLVE_SYMBOL(can_do_restart); + RESOLVE_SYMBOL(can_set_bitrate); + RESOLVE_SYMBOL(can_get_bittiming); + + return true; + }; + + QLibrary lib; + if (Q_UNLIKELY(!resolveSymbols(&lib))) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(lib.errorString())); + if (errorString) + *errorString = lib.errorString(); + } +#else + const QString error = + QObject::tr("Cannot load library libsocketcan as Qt was built without QLibrary."); + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(error)); + if (errorString) + *errorString = error; +#endif +} + +/*! + Brings the CAN \a interface up. + + \internal + \note Requires appropriate permissions. +*/ +bool LibSocketCan::start(const QString &interface) +{ + if (!::can_do_start) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_start() is not available."); + return false; + } + + return ::can_do_start(interface.toLatin1().constData()) == 0; +} + +/*! + Brings the CAN \a interface down. + + \internal + \note Requires appropriate permissions. +*/ +bool LibSocketCan::stop(const QString &interface) +{ + if (!::can_do_stop) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_stop() is not available."); + return false; + } + + return ::can_do_stop(interface.toLatin1().constData()) == 0; +} + +/*! + Performs a CAN controller reset on the CAN \a interface. + + \internal + \note Reset can only be triggerd if the controller is in bus off + and the auto restart not turned on. + \note Requires appropriate permissions. + */ +bool LibSocketCan::restart(const QString &interface) +{ + if (!::can_do_restart) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_restart() is not available."); + return false; + } + + return ::can_do_restart(interface.toLatin1().constData()) == 0; +} + +/*! + Returns the configured bitrate for \a interface. + \internal +*/ +quint32 LibSocketCan::bitrate(const QString &interface) const +{ + if (!::can_get_bittiming) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_get_bittiming() is not available."); + return 0; + } + + struct can_bittiming bt; + if (::can_get_bittiming(interface.toLatin1().constData(), &bt) == 0) + return bt.bitrate; + + return 0; +} + +/*! + Sets the bitrate for the CAN \a interface. + + \internal + \note Requires appropriate permissions. + */ +bool LibSocketCan::setBitrate(const QString &interface, quint32 bitrate) +{ + if (!::can_set_bitrate) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_set_bitrate() is not available."); + return false; + } + + return ::can_set_bitrate(interface.toLatin1().constData(), bitrate) == 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/canbus/socketcan/libsocketcan.h b/src/plugins/canbus/socketcan/libsocketcan.h new file mode 100644 index 0000000..91229ee --- /dev/null +++ b/src/plugins/canbus/socketcan/libsocketcan.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Andre Hartmann <aha_1980@gmx.de> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtSerialBus module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LIBSOCKETCAN_H +#define LIBSOCKETCAN_H + +#include <QtCore/qglobal.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QString; + +class LibSocketCan final +{ +public: + explicit LibSocketCan(QString *errorString = nullptr); + + bool start(const QString &interface); + bool stop(const QString &interface); + bool restart(const QString &interface); + + quint32 bitrate(const QString &interface) const; + bool setBitrate(const QString &interface, quint32 bitrate); +}; + +QT_END_NAMESPACE + +#endif // LIBSOCKETCAN_H diff --git a/src/plugins/canbus/socketcan/socketcan.pro b/src/plugins/canbus/socketcan/socketcan.pro index 20a2c5d..cd731fd 100644 --- a/src/plugins/canbus/socketcan/socketcan.pro +++ b/src/plugins/canbus/socketcan/socketcan.pro @@ -3,9 +3,11 @@ TARGET = qtsocketcanbus QT = core serialbus HEADERS += \ + libsocketcan.h \ socketcanbackend.h SOURCES += \ + libsocketcan.cpp \ main.cpp \ socketcanbackend.cpp diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp index 74b0d1d..cac1db5 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.cpp +++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp @@ -36,6 +36,10 @@ #include "socketcanbackend.h" +#include "libsocketcan.h" + +#include <QtSerialBus/qcanbusdevice.h> + #include <QtCore/qdatastream.h> #include <QtCore/qdebug.h> #include <QtCore/qdiriterator.h> @@ -181,6 +185,14 @@ QList<QCanBusDeviceInfo> SocketCanBackend::interfaces() SocketCanBackend::SocketCanBackend(const QString &name) : canSocketName(name) { + QString errorString; + libSocketCan.reset(new LibSocketCan(&errorString)); + if (Q_UNLIKELY(!errorString.isEmpty())) { + qCInfo(QT_CANBUS_PLUGINS_SOCKETCAN, + "Cannot load library libsocketcan, some functionality will not be available.\n%ls", + qUtf16Printable(errorString)); + } + resetConfigurations(); } @@ -200,6 +212,8 @@ void SocketCanBackend::resetConfigurations() QVariant::fromValue(QCanBusFrame::FrameErrors(QCanBusFrame::AnyError))); QCanBusDevice::setConfigurationParameter( QCanBusDevice::CanFdKey, false); + QCanBusDevice::setConfigurationParameter( + QCanBusDevice::BitRateKey, 500000); } bool SocketCanBackend::open() @@ -345,6 +359,12 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu success = true; break; } + case QCanBusDevice::BitRateKey: + { + const quint32 bitRate = value.toUInt(); + libSocketCan->setBitrate(canSocketName, bitRate); + break; + } default: setError(tr("SocketCanBackend: No such configuration as %1 in SocketCanBackend").arg(key), QCanBusDevice::CanBusError::ConfigurationError); diff --git a/src/plugins/canbus/socketcan/socketcanbackend.h b/src/plugins/canbus/socketcan/socketcanbackend.h index b49d267..1392251 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.h +++ b/src/plugins/canbus/socketcan/socketcanbackend.h @@ -52,8 +52,12 @@ #include <linux/can.h> #include <sys/time.h> +#include <memory> + QT_BEGIN_NAMESPACE +class LibSocketCan; + class SocketCanBackend : public QCanBusDevice { Q_OBJECT @@ -89,6 +93,7 @@ private: qint64 canSocket = -1; QSocketNotifier *notifier = nullptr; + std::unique_ptr<LibSocketCan> libSocketCan; QString canSocketName; bool canFdOptionEnabled = false; }; |