summaryrefslogtreecommitdiffstats
path: root/src/plugins/canbus
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/canbus')
-rw-r--r--src/plugins/canbus/peakcan/peakcan_symbols_p.h51
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.cpp99
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.h3
-rw-r--r--src/plugins/canbus/socketcan/libsocketcan.cpp238
-rw-r--r--src/plugins/canbus/socketcan/libsocketcan.h76
-rw-r--r--src/plugins/canbus/socketcan/socketcan.pro2
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.cpp45
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.h8
-rw-r--r--src/plugins/canbus/systeccan/systeccan_symbols_p.h27
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.cpp61
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.h3
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend_p.h2
-rw-r--r--src/plugins/canbus/tinycan/tinycanbackend.cpp30
-rw-r--r--src/plugins/canbus/tinycan/tinycanbackend.h2
-rw-r--r--src/plugins/canbus/tinycan/tinycanbackend_p.h1
-rw-r--r--src/plugins/canbus/vectorcan/vectorcan_symbols_p.h20
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.cpp56
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.h2
18 files changed, 673 insertions, 53 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..b1a991d 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.cpp
+++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp
@@ -68,6 +68,8 @@ bool PeakCanBackend::canCreate(QString *errorReason)
#else
static bool symbolsResolved = resolveSymbols(pcanLibrary());
if (Q_UNLIKELY(!symbolsResolved)) {
+ qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot load library: %ls",
+ qUtf16Printable(pcanLibrary()->errorString()));
*errorReason = pcanLibrary()->errorString();
return false;
}
@@ -331,15 +333,21 @@ bool PeakCanBackendPrivate::open()
}
if (Q_UNLIKELY(st != PCAN_ERROR_OK)) {
- q->setError(systemErrorString(st), QCanBusDevice::ConnectionError);
+ const QString errorString = systemErrorString(st);
+ qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot initialize hardware: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::ConnectionError);
return false;
}
#if defined(Q_OS_WIN32)
if (readHandle == INVALID_HANDLE_VALUE) {
readHandle = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
- if (!readHandle) {
- q->setError(qt_error_string(::GetLastError()), QCanBusDevice::ConnectionError);
+ if (Q_UNLIKELY(!readHandle)) {
+ const QString errorString = qt_error_string(::GetLastError());
+ qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot create receive event handler: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::ConnectionError);
return false;
}
}
@@ -353,7 +361,10 @@ bool PeakCanBackendPrivate::open()
#else
const TPCANStatus err = ::CAN_GetValue(channelIndex, PCAN_RECEIVE_EVENT, &readHandle, sizeof(readHandle));
if (Q_UNLIKELY(err != PCAN_ERROR_OK)) {
- q->setError(systemErrorString(err), QCanBusDevice::ConnectionError);
+ const QString errorString = systemErrorString(err);
+ qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot create receive event handler: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::ConnectionError);
return false;
}
#endif
@@ -380,8 +391,12 @@ void PeakCanBackendPrivate::close()
quint32 value = 0;
const TPCANStatus err = ::CAN_SetValue(channelIndex, PCAN_RECEIVE_EVENT, &value, sizeof(value));
- if (Q_UNLIKELY(err != PCAN_ERROR_OK))
- q->setError(systemErrorString(err), QCanBusDevice::ConnectionError);
+ if (Q_UNLIKELY(err != PCAN_ERROR_OK)) {
+ const QString errorString = systemErrorString(err);
+ qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot unregister receive event handler: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::ConnectionError);
+ }
const TPCANStatus st = ::CAN_Uninitialize(channelIndex);
if (Q_UNLIKELY(st != PCAN_ERROR_OK))
@@ -389,8 +404,12 @@ void PeakCanBackendPrivate::close()
#if defined(Q_OS_WIN32)
if (readHandle && (readHandle != INVALID_HANDLE_VALUE)) {
- if (Q_UNLIKELY(!::CloseHandle(readHandle)))
- q->setError(qt_error_string(::GetLastError()), QCanBusDevice::ConnectionError);
+ const QString errorString = qt_error_string(::GetLastError());
+ if (Q_UNLIKELY(!::CloseHandle(readHandle))) {
+ qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot close read handle: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::ConnectionError);
+ }
readHandle = INVALID_HANDLE_VALUE;
}
#else
@@ -413,6 +432,7 @@ bool PeakCanBackendPrivate::setConfigurationParameter(int key, const QVariant &v
case QCanBusDevice::DataBitRateKey: {
const int dataBitrate = value.toInt();
if (Q_UNLIKELY(dataBitrateString(dataBitrate).isEmpty())) {
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unsupported data bitrate value: %d", dataBitrate);
q->setError(PeakCanBackend::tr("Unsupported data bitrate value: %1.").arg(dataBitrate),
QCanBusDevice::ConfigurationError);
return false;
@@ -420,6 +440,7 @@ bool PeakCanBackendPrivate::setConfigurationParameter(int key, const QVariant &v
return true;
}
default:
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unsupported configuration key: %d", key);
q->setError(PeakCanBackend::tr("Unsupported configuration key: %1").arg(key),
QCanBusDevice::ConfigurationError);
return false;
@@ -558,8 +579,9 @@ void PeakCanBackendPrivate::startWrite()
::memcpy(message.DATA, payload.constData(), sizeof(message.DATA));
st = ::CAN_WriteFD(channelIndex, &message);
} else if (frame.hasFlexibleDataRateFormat()) {
- q->setError(PeakCanBackend::tr("Cannot send CAN FD frame format as CAN FD is not enabled."),
- QCanBusDevice::WriteError);
+ const char errorString[] = "Cannot send CAN FD frame format as CAN FD is not enabled.";
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN(), errorString);
+ q->setError(PeakCanBackend::tr(errorString), QCanBusDevice::WriteError);
} else {
TPCANMsg message;
::memset(&message, 0, sizeof(message));
@@ -576,10 +598,14 @@ void PeakCanBackendPrivate::startWrite()
st = ::CAN_Write(channelIndex, &message);
}
- if (Q_UNLIKELY(st != PCAN_ERROR_OK))
- q->setError(systemErrorString(st), QCanBusDevice::WriteError);
- else
+ if (Q_UNLIKELY(st != PCAN_ERROR_OK)) {
+ const QString errorString = systemErrorString(st);
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot write frame: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::WriteError);
+ } else {
emit q->framesWritten(qint64(1));
+ }
if (q->hasOutgoingFrames() && !writeNotifier->isActive())
writeNotifier->start();
@@ -611,7 +637,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 +667,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;
@@ -662,8 +688,9 @@ bool PeakCanBackendPrivate::verifyBitRate(int bitrate)
Q_Q(PeakCanBackend);
if (Q_UNLIKELY(isOpen)) {
- q->setError(PeakCanBackend::tr("Cannot change bitrate for already opened device."),
- QCanBusDevice::ConfigurationError);
+ const char errorString[] = "Cannot change bitrate for already opened device.";
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, errorString);
+ q->setError(PeakCanBackend::tr(errorString), QCanBusDevice::ConfigurationError);
return false;
}
@@ -674,6 +701,7 @@ bool PeakCanBackendPrivate::verifyBitRate(int bitrate)
isValidBitrate = bitrateCodeFromBitrate(bitrate) != PCAN_BAUD_INVALID;
if (Q_UNLIKELY(!isValidBitrate)) {
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unsupported bitrate value: %d.", bitrate);
q->setError(PeakCanBackend::tr("Unsupported bitrate value: %1.").arg(bitrate),
QCanBusDevice::ConfigurationError);
}
@@ -689,6 +717,12 @@ PeakCanBackend::PeakCanBackend(const QString &name, QObject *parent)
d->setupChannel(name.toLatin1());
d->setupDefaultConfigurations();
+
+ std::function<void()> f = std::bind(&PeakCanBackend::resetController, this);
+ setResetControllerFunction(f);
+
+ std::function<CanBusStatus()> g = std::bind(&PeakCanBackend::busStatus, this);
+ setCanBusStatusGetter(g);
}
PeakCanBackend::~PeakCanBackend()
@@ -709,11 +743,11 @@ bool PeakCanBackend::open()
if (Q_UNLIKELY(!d->open()))
return false;
- // apply all stored configurations except bitrate, because
- // the bitrate can not be applied after opening of device
+ // Apply all stored configurations except bitrate, because
+ // the bitrate cannot be changed after opening the device
const auto keys = configurationKeys();
for (int key : keys) {
- if (key == QCanBusDevice::BitRateKey)
+ if (key == QCanBusDevice::BitRateKey || key == QCanBusDevice::DataBitRateKey)
continue;
const QVariant param = configurationParameter(key);
const bool success = d->setConfigurationParameter(key, param);
@@ -780,4 +814,29 @@ QString PeakCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
return QString();
}
+void PeakCanBackend::resetController()
+{
+ close();
+ open();
+}
+
+QCanBusDevice::CanBusStatus PeakCanBackend::busStatus() const
+{
+ const TPCANStatus status = ::CAN_GetStatus(d_ptr->channelIndex);
+
+ switch (status & PCAN_ERROR_ANYBUSERR) {
+ case PCAN_ERROR_OK:
+ return QCanBusDevice::CanBusStatus::Good;
+ case PCAN_ERROR_BUSWARNING:
+ return QCanBusDevice::CanBusStatus::Warning;
+ case PCAN_ERROR_BUSPASSIVE:
+ return QCanBusDevice::CanBusStatus::Error;
+ case PCAN_ERROR_BUSOFF:
+ return QCanBusDevice::CanBusStatus::BusOff;
+ default:
+ qCWarning(QT_CANBUS_PLUGINS_PEAKCAN, "Unknown CAN bus status: %lu.", ulong(status));
+ return QCanBusDevice::CanBusStatus::Unknown;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.h b/src/plugins/canbus/peakcan/peakcanbackend.h
index 7f7083e..a9e108e 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.h
+++ b/src/plugins/canbus/peakcan/peakcanbackend.h
@@ -72,6 +72,9 @@ public:
static QList<QCanBusDeviceInfo> interfaces();
private:
+ void resetController();
+ CanBusStatus busStatus() const;
+
PeakCanBackendPrivate * const d_ptr;
};
diff --git a/src/plugins/canbus/socketcan/libsocketcan.cpp b/src/plugins/canbus/socketcan/libsocketcan.cpp
new file mode 100644
index 0000000..c6144db
--- /dev/null
+++ b/src/plugins/canbus/socketcan/libsocketcan.cpp
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** 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 */
+};
+
+enum can_state {
+ CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */
+ CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */
+ CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */
+ CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */
+ CAN_STATE_STOPPED, /* Device is stopped */
+ CAN_STATE_SLEEPING, /* Device is sleeping */
+ CAN_STATE_MAX
+};
+
+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 */)
+GENERATE_SYMBOL(int, can_get_state, const char * /* name */, int * /* state */)
+
+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);
+ RESOLVE_SYMBOL(can_get_state);
+
+ 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;
+}
+
+bool LibSocketCan::hasBusStatus() const
+{
+ return ::can_get_state != nullptr;
+}
+
+QCanBusDevice::CanBusStatus LibSocketCan::busStatus(const QString &interface) const
+{
+ if (!::can_get_state) {
+ qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_get_state() is not available.");
+ return QCanBusDevice::CanBusStatus::Unknown;
+ }
+
+ int status = 0;
+ int result = ::can_get_state(interface.toLatin1().constData(), &status);
+
+ if (result < 0)
+ return QCanBusDevice::CanBusStatus::Unknown;
+
+ switch (status) {
+ case CAN_STATE_ERROR_ACTIVE:
+ return QCanBusDevice::CanBusStatus::Good;
+ case CAN_STATE_ERROR_WARNING:
+ return QCanBusDevice::CanBusStatus::Warning;
+ case CAN_STATE_ERROR_PASSIVE:
+ return QCanBusDevice::CanBusStatus::Error;
+ case CAN_STATE_BUS_OFF:
+ return QCanBusDevice::CanBusStatus::BusOff;
+ default:
+ // Device is stopped or sleeping, so status is unknown
+ return QCanBusDevice::CanBusStatus::Unknown;
+ }
+}
+
+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..b77afa1
--- /dev/null
+++ b/src/plugins/canbus/socketcan/libsocketcan.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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>
+#include <QtSerialBus/qcanbusdevice.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);
+
+ bool hasBusStatus() const;
+ QCanBusDevice::CanBusStatus busStatus(const QString &interface) const;
+};
+
+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 a2da146..27fa326 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>
@@ -182,7 +186,25 @@ 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();
+
+ std::function<void()> f = std::bind(&SocketCanBackend::resetController, this);
+ setResetControllerFunction(f);
+
+ if (hasBusStatus()) {
+ // Only register busStatus when libsocketcan is available
+ // QCanBusDevice::hasBusStatus() will return false otherwise
+ std::function<CanBusStatus()> g = std::bind(&SocketCanBackend::busStatus, this);
+ setCanBusStatusGetter(g);
+ }
}
SocketCanBackend::~SocketCanBackend()
@@ -201,6 +223,8 @@ void SocketCanBackend::resetConfigurations()
QVariant::fromValue(QCanBusFrame::FrameErrors(QCanBusFrame::AnyError)));
QCanBusDevice::setConfigurationParameter(
QCanBusDevice::CanFdKey, false);
+ QCanBusDevice::setConfigurationParameter(
+ QCanBusDevice::BitRateKey, 500000);
}
bool SocketCanBackend::open()
@@ -346,6 +370,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);
@@ -731,4 +761,19 @@ void SocketCanBackend::readSocket()
enqueueReceivedFrames(newFrames);
}
+void SocketCanBackend::resetController()
+{
+ libSocketCan->restart(canSocketName);
+}
+
+bool SocketCanBackend::hasBusStatus() const
+{
+ return libSocketCan->hasBusStatus();
+}
+
+QCanBusDevice::CanBusStatus SocketCanBackend::busStatus() const
+{
+ return libSocketCan->busStatus(canSocketName);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/canbus/socketcan/socketcanbackend.h b/src/plugins/canbus/socketcan/socketcanbackend.h
index b49d267..199401e 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
@@ -79,6 +83,9 @@ private:
void resetConfigurations();
bool connectSocket();
bool applyConfigurationParameter(int key, const QVariant &value);
+ void resetController();
+ bool hasBusStatus() const;
+ QCanBusDevice::CanBusStatus busStatus() const;
canfd_frame m_frame;
sockaddr_can m_address;
@@ -89,6 +96,7 @@ private:
qint64 canSocket = -1;
QSocketNotifier *notifier = nullptr;
+ std::unique_ptr<LibSocketCan> libSocketCan;
QString canSocketName;
bool canFdOptionEnabled = false;
};
diff --git a/src/plugins/canbus/systeccan/systeccan_symbols_p.h b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
index 102817c..ce32422 100644
--- a/src/plugins/canbus/systeccan/systeccan_symbols_p.h
+++ b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
@@ -81,6 +81,20 @@ typedef void (DRV_CALLBACK_TYPE *tCallbackFktEx) (tUcanHandle handle, quint32 ev
#define USBCAN_EVENT_FATALDISCON 8 // a USB-CANmodul has been disconnected during operation
#define USBCAN_EVENT_RESERVED1 0x80
+// CAN status flags (is returned with function UcanGetStatus() or UcanGetStatusEx() )
+#define USBCAN_CANERR_OK 0x0000 // no error
+#define USBCAN_CANERR_XMTFULL 0x0001 // Tx-buffer of the CAN controller is full
+#define USBCAN_CANERR_OVERRUN 0x0002 // Rx-buffer of the CAN controller is full
+#define USBCAN_CANERR_BUSLIGHT 0x0004 // Bus error: Error Limit 1 exceeded (refer to SJA1000 manual)
+#define USBCAN_CANERR_BUSHEAVY 0x0008 // Bus error: Error Limit 2 exceeded (refer to SJA1000 manual)
+#define USBCAN_CANERR_BUSOFF 0x0010 // Bus error: CAN controller has gone into Bus-Off state
+#define USBCAN_CANERR_QRCVEMPTY 0x0020 // RcvQueue is empty
+#define USBCAN_CANERR_QOVERRUN 0x0040 // RcvQueue overrun
+#define USBCAN_CANERR_QXMTFULL 0x0080 // transmit queue is full
+#define USBCAN_CANERR_REGTEST 0x0100 // Register test of the SJA1000 failed
+#define USBCAN_CANERR_MEMTEST 0x0200 // Memory test failed
+#define USBCAN_CANERR_TXMSGLOST 0x0400 // transmit CAN message was automatically deleted by firmware
+
#define kUcanModeNormal 0x00 // normal mode (send and receive)
#define kUcanModeListenOnly 0x01 // listen only mode (only receive)
#define kUcanModeTxEcho 0x02 // CAN messages which was sent will be received at UcanReadCanMsg..
@@ -88,8 +102,8 @@ typedef void (DRV_CALLBACK_TYPE *tCallbackFktEx) (tUcanHandle handle, quint32 ev
#define kUcanModeHighResTimer 0x08 // high resolution time stamps in received CAN messages (only available with STM derivates)
// ABR and ACR for mode "receive all CAN messages"
-#define USBCAN_AMR_ALL (quint32) 0xffffffff
-#define USBCAN_ACR_ALL (quint32) 0x00000000
+#define USBCAN_AMR_ALL 0xffffffffU
+#define USBCAN_ACR_ALL 0x00000000U
#define USBCAN_OCR_DEFAULT 0x1A // default OCR for standard GW-002
#define USBCAN_OCR_RS485_ISOLATED 0x1E // OCR for RS485 interface and galvanic isolation
@@ -143,6 +157,11 @@ typedef struct _tCanMsgStruct {
quint32 m_dwTime; // Time in ms
} tCanMsgStruct;
+typedef struct _tStatusStruct {
+ quint16 m_wCanStatus; // current CAN status
+ quint16 m_wUsbStatus; // current USB status
+} tStatusStruct;
+
// Function return codes (encoding)
#define USBCAN_SUCCESSFUL 0x00 // no error
#define USBCAN_ERR 0x01 // error in library; function has not been executed
@@ -280,7 +299,9 @@ GENERATE_SYMBOL_VARIABLE(UCANRET, UcanDeinitHardware, tUcanHandle)
GENERATE_SYMBOL_VARIABLE(UCANRET, UcanInitCanEx2, tUcanHandle, quint8 /* channel */, tUcanInitCanParam *)
GENERATE_SYMBOL_VARIABLE(UCANRET, UcanDeinitCanEx, tUcanHandle, quint8 /* channel */)
GENERATE_SYMBOL_VARIABLE(UCANRET, UcanReadCanMsgEx, tUcanHandle, quint8 *, tCanMsgStruct *, quint32 *)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanResetCan, tUcanHandle)
GENERATE_SYMBOL_VARIABLE(UCANRET, UcanWriteCanMsgEx, tUcanHandle, quint8, tCanMsgStruct *, quint32 *)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanGetStatus, tUcanHandle, tStatusStruct *)
inline bool resolveSymbols(QLibrary *systecLibrary)
{
@@ -300,7 +321,9 @@ inline bool resolveSymbols(QLibrary *systecLibrary)
RESOLVE_SYMBOL(UcanInitCanEx2);
RESOLVE_SYMBOL(UcanDeinitCanEx);
RESOLVE_SYMBOL(UcanReadCanMsgEx);
+ RESOLVE_SYMBOL(UcanResetCan);
RESOLVE_SYMBOL(UcanWriteCanMsgEx);
+ RESOLVE_SYMBOL(UcanGetStatus);
return true;
}
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.cpp b/src/plugins/canbus/systeccan/systeccanbackend.cpp
index 3fdd135..0663f39 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.cpp
+++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp
@@ -114,7 +114,7 @@ QList<QCanBusDeviceInfo> SystecCanBackend::interfaces()
{
QList<QCanBusDeviceInfo> result;
- ::UcanEnumerateHardware(&ucanEnumCallback, &result, false, 0, ~0, 0, ~0, 0, ~0);
+ ::UcanEnumerateHardware(&ucanEnumCallback, &result, false, 0, quint8(~0), 0, quint32(~0), 0, quint32(~0));
return result;
}
@@ -281,8 +281,8 @@ bool SystecCanBackendPrivate::setupChannel(const QString &interfaceName)
const QRegularExpressionMatch match = re.match(interfaceName);
if (Q_LIKELY(match.hasMatch())) {
- device = match.captured(1).toInt();
- channel = match.captured(2).toInt();
+ device = quint8(match.captured(1).toUShort());
+ channel = quint8(match.captured(2).toUShort());
} else {
q->setError(SystecCanBackend::tr("Invalid interface '%1'.")
.arg(interfaceName), QCanBusDevice::ConnectionError);
@@ -377,7 +377,7 @@ void SystecCanBackendPrivate::startWrite()
::memset(&message, 0, sizeof(message));
message.m_dwID = frame.frameId();
- message.m_bDLC = payload.size();
+ message.m_bDLC = quint8(payload.size());
message.m_bFF = frame.hasExtendedFrameFormat() ? USBCAN_MSG_FF_EXT : USBCAN_MSG_FF_STD;
@@ -454,6 +454,40 @@ bool SystecCanBackendPrivate::verifyBitRate(int bitrate)
return true;
}
+void SystecCanBackendPrivate::resetController()
+{
+ ::UcanResetCan(handle);
+}
+
+QCanBusDevice::CanBusStatus SystecCanBackendPrivate::busStatus()
+{
+ Q_Q(SystecCanBackend);
+
+ tStatusStruct status;
+ ::memset(&status, 0, sizeof(status));
+ const UCANRET result = ::UcanGetStatus(handle, &status);
+
+ if (Q_UNLIKELY(result != USBCAN_SUCCESSFUL)) {
+ qCWarning(QT_CANBUS_PLUGINS_SYSTECCAN, "Can not query CAN bus status.");
+ q->setError(SystecCanBackend::tr("Can not query CAN bus status."), QCanBusDevice::ConfigurationError);
+ return QCanBusDevice::CanBusStatus::Unknown;
+ }
+
+ if (status.m_wCanStatus & USBCAN_CANERR_BUSOFF)
+ return QCanBusDevice::CanBusStatus::BusOff;
+
+ if (status.m_wCanStatus & USBCAN_CANERR_BUSHEAVY)
+ return QCanBusDevice::CanBusStatus::Error;
+
+ if (status.m_wCanStatus & USBCAN_CANERR_BUSLIGHT)
+ return QCanBusDevice::CanBusStatus::Warning;
+
+ if (status.m_wCanStatus == USBCAN_CANERR_OK)
+ return QCanBusDevice::CanBusStatus::Good;
+
+ return QCanBusDevice::CanBusStatus::Unknown;
+}
+
SystecCanBackend::SystecCanBackend(const QString &name, QObject *parent) :
QCanBusDevice(parent),
d_ptr(new SystecCanBackendPrivate(this))
@@ -462,6 +496,12 @@ SystecCanBackend::SystecCanBackend(const QString &name, QObject *parent) :
d->setupChannel(name);
d->setupDefaultConfigurations();
+
+ std::function<void()> f = std::bind(&SystecCanBackend::resetController, this);
+ setResetControllerFunction(f);
+
+ std::function<CanBusStatus()> g = std::bind(&SystecCanBackend::busStatus, this);
+ setCanBusStatusGetter(g);
}
SystecCanBackend::~SystecCanBackend()
@@ -553,4 +593,17 @@ QString SystecCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
return QString();
}
+void SystecCanBackend::resetController()
+{
+ Q_D(SystecCanBackend);
+ d->resetController();
+}
+
+QCanBusDevice::CanBusStatus SystecCanBackend::busStatus()
+{
+ Q_D(SystecCanBackend);
+
+ return d->busStatus();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.h b/src/plugins/canbus/systeccan/systeccanbackend.h
index cb62808..22c1193 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend.h
@@ -76,6 +76,9 @@ public:
int channelNumber);
private:
+ void resetController();
+ QCanBusDevice::CanBusStatus busStatus();
+
SystecCanBackendPrivate * const d_ptr;
};
diff --git a/src/plugins/canbus/systeccan/systeccanbackend_p.h b/src/plugins/canbus/systeccan/systeccanbackend_p.h
index 28eb7ff..b2da322 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend_p.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend_p.h
@@ -94,6 +94,8 @@ public:
void startWrite();
void readAllReceivedMessages();
bool verifyBitRate(int bitrate);
+ void resetController();
+ QCanBusDevice::CanBusStatus busStatus();
SystecCanBackend * const q_ptr;
diff --git a/src/plugins/canbus/tinycan/tinycanbackend.cpp b/src/plugins/canbus/tinycan/tinycanbackend.cpp
index 3891186..411b917 100644
--- a/src/plugins/canbus/tinycan/tinycanbackend.cpp
+++ b/src/plugins/canbus/tinycan/tinycanbackend.cpp
@@ -405,8 +405,7 @@ void TinyCanBackendPrivate::startRead()
} else {
if (status.CanStatus == CAN_STATUS_BUS_OFF) {
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);
+ resetController();
}
}
@@ -446,7 +445,8 @@ void TinyCanBackendPrivate::startupDriver()
::CanSetEvents(EVENT_ENABLE_RX_MESSAGES);
} else if (Q_UNLIKELY(driverRefCount < 0)) {
- qCritical("Wrong reference counter: %d", driverRefCount);
+ qCCritical(QT_CANBUS_PLUGINS_TINYCAN, "Wrong driver reference counter: %d",
+ driverRefCount);
return;
}
@@ -458,7 +458,8 @@ void TinyCanBackendPrivate::cleanupDriver()
--driverRefCount;
if (Q_UNLIKELY(driverRefCount < 0)) {
- qCritical("Wrong reference counter: %d", driverRefCount);
+ qCCritical(QT_CANBUS_PLUGINS_TINYCAN, "Wrong driver reference counter: %d",
+ driverRefCount);
driverRefCount = 0;
} else if (driverRefCount == 0) {
::CanSetEvents(EVENT_DISABLE_ALL);
@@ -466,6 +467,18 @@ void TinyCanBackendPrivate::cleanupDriver()
}
}
+void TinyCanBackendPrivate::resetController()
+{
+ Q_Q(TinyCanBackend);
+ qint32 ret = ::CanSetMode(channelIndex, OP_CAN_RESET, CAN_CMD_NONE);
+ if (Q_UNLIKELY(ret < 0)) {
+ const QString errorString = systemErrorString(ret);
+ qCWarning(QT_CANBUS_PLUGINS_TINYCAN, "Cannot perform hardware reset: %ls",
+ qUtf16Printable(errorString));
+ q->setError(errorString, QCanBusDevice::CanBusError::ConfigurationError);
+ }
+}
+
bool TinyCanBackendPrivate::setBitRate(int bitrate)
{
Q_Q(TinyCanBackend);
@@ -496,6 +509,9 @@ TinyCanBackend::TinyCanBackend(const QString &name, QObject *parent)
d->setupChannel(name);
d->setupDefaultConfigurations();
+
+ std::function<void()> f = std::bind(&TinyCanBackend::resetController, this);
+ setResetControllerFunction(f);
}
TinyCanBackend::~TinyCanBackend()
@@ -589,4 +605,10 @@ QString TinyCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
return QString();
}
+void TinyCanBackend::resetController()
+{
+ Q_D(TinyCanBackend);
+ d->resetController();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/canbus/tinycan/tinycanbackend.h b/src/plugins/canbus/tinycan/tinycanbackend.h
index 5f504ca..428e9bc 100644
--- a/src/plugins/canbus/tinycan/tinycanbackend.h
+++ b/src/plugins/canbus/tinycan/tinycanbackend.h
@@ -72,6 +72,8 @@ public:
static QList<QCanBusDeviceInfo> interfaces();
private:
+ void resetController();
+
TinyCanBackendPrivate * const d_ptr;
};
diff --git a/src/plugins/canbus/tinycan/tinycanbackend_p.h b/src/plugins/canbus/tinycan/tinycanbackend_p.h
index 905175c..25316a2 100644
--- a/src/plugins/canbus/tinycan/tinycanbackend_p.h
+++ b/src/plugins/canbus/tinycan/tinycanbackend_p.h
@@ -75,6 +75,7 @@ public:
void startRead();
void startupDriver();
void cleanupDriver();
+ void resetController();
bool setBitRate(int bitrate);
diff --git a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
index 3f2501f..8c1ad52 100644
--- a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
+++ b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h
@@ -249,9 +249,27 @@ static_assert(sizeof(s_xl_can_msg) == 32, "Invalid size of s_xl_can_msg structur
#define XL_TRANSCEIVER_EVENT_ERROR 1
#define XL_TRANSCEIVER_EVENT_CHANGED 2
+#define XL_CHIPSTAT_BUSOFF 0x01
+#define XL_CHIPSTAT_ERROR_PASSIVE 0x02
+#define XL_CHIPSTAT_ERROR_WARNING 0x04
+#define XL_CHIPSTAT_ERROR_ACTIVE 0x08
+
+#define XL_CAN_STATE_FLAG_SJA_MODE 0x00000001
+
+// CAN Chip status
+struct s_xl_chip_state {
+ unsigned char busStatus;
+ unsigned char txErrorCounter;
+ unsigned char rxErrorCounter;
+ unsigned char chipState; // raw Status Register Value
+ unsigned int flags;
+};
+static_assert(sizeof(s_xl_chip_state) == 8, "Invalid size of s_xl_chip_state structure");
+
// basic bus message structure
union s_xl_tag_data {
struct s_xl_can_msg msg;
+ struct s_xl_chip_state chipState;
};
// event type definition (48 bytes)
@@ -456,6 +474,7 @@ GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanSetChannelBitrate, XLportHandle, XLacces
GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanTransmit, XLportHandle, XLaccess, quint32 *, void *)
GENERATE_SYMBOL_VARIABLE(XLstatus, xlReceive, XLportHandle, quint32 *, XLevent *)
GENERATE_SYMBOL_VARIABLE(XLstatus, xlSetNotification, XLportHandle, XLhandle *, int)
+GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanRequestChipState, XLportHandle, XLaccess)
GENERATE_SYMBOL_VARIABLE(char *, xlGetErrorString, XLstatus)
inline bool resolveSymbols(QLibrary *vectorcanLibrary)
@@ -481,6 +500,7 @@ inline bool resolveSymbols(QLibrary *vectorcanLibrary)
RESOLVE_SYMBOL(xlCanTransmit)
RESOLVE_SYMBOL(xlReceive)
RESOLVE_SYMBOL(xlSetNotification)
+ RESOLVE_SYMBOL(xlCanRequestChipState)
RESOLVE_SYMBOL(xlGetErrorString)
return true;
diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
index 9026888..9d3bdef 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
@@ -271,7 +271,8 @@ void VectorCanBackendPrivate::setupChannel(const QString &interfaceName)
}
}
- qCritical("Unable to parse the channel %ls", qUtf16Printable(interfaceName));
+ qCCritical(QT_CANBUS_PLUGINS_VECTORCAN, "Unable to parse the channel %ls",
+ qUtf16Printable(interfaceName));
}
void VectorCanBackendPrivate::setupDefaultConfigurations()
@@ -388,7 +389,8 @@ XLstatus VectorCanBackendPrivate::loadDriver()
return status;
} else if (Q_UNLIKELY(driverRefCount < 0)) {
- qCritical("Wrong reference counter: %d", driverRefCount);
+ qCCritical(QT_CANBUS_PLUGINS_VECTORCAN, "Wrong driver reference counter: %d",
+ driverRefCount);
return XL_ERR_CANNOT_OPEN_DRIVER;
}
@@ -412,7 +414,8 @@ void VectorCanBackendPrivate::cleanupDriver()
--driverRefCount;
if (Q_UNLIKELY(driverRefCount < 0)) {
- qCritical("Wrong reference counter: %d", driverRefCount);
+ qCCritical(QT_CANBUS_PLUGINS_VECTORCAN, "Wrong driver reference counter: %d",
+ driverRefCount);
driverRefCount = 0;
} else if (driverRefCount == 0) {
::xlCloseDriver();
@@ -443,6 +446,9 @@ VectorCanBackend::VectorCanBackend(const QString &name, QObject *parent)
d->setupChannel(name);
d->setupDefaultConfigurations();
+
+ std::function<CanBusStatus()> g = std::bind(&VectorCanBackend::busStatus, this);
+ setCanBusStatusGetter(g);
}
VectorCanBackend::~VectorCanBackend()
@@ -537,4 +543,48 @@ QString VectorCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
return QString();
}
+QCanBusDevice::CanBusStatus VectorCanBackend::busStatus()
+{
+ Q_D(VectorCanBackend);
+
+ const XLstatus requestStatus = ::xlCanRequestChipState(d->portHandle, d->channelMask);
+ if (Q_UNLIKELY(requestStatus != XL_SUCCESS)) {
+ const QString errorString = d->systemErrorString(requestStatus);
+ qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Can not query CAN bus status: %ls.",
+ qUtf16Printable(errorString));
+ setError(errorString, QCanBusDevice::CanBusError::ReadError);
+ return QCanBusDevice::CanBusStatus::Unknown;
+ }
+
+ quint32 eventCount = 1;
+ XLevent event;
+ ::memset(&event, 0, sizeof(event));
+
+ const XLstatus receiveStatus = ::xlReceive(d->portHandle, &eventCount, &event);
+ if (Q_UNLIKELY(receiveStatus != XL_SUCCESS)) {
+ const QString errorString = d->systemErrorString(receiveStatus);
+ qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Can not query CAN bus status: %ls.",
+ qUtf16Printable(errorString));
+ setError(errorString, QCanBusDevice::CanBusError::ReadError);
+ return QCanBusDevice::CanBusStatus::Unknown;
+ }
+
+ if (Q_LIKELY(event.tag == XL_CHIP_STATE)) {
+ switch (event.tagData.chipState.busStatus) {
+ case XL_CHIPSTAT_BUSOFF:
+ return QCanBusDevice::CanBusStatus::BusOff;
+ case XL_CHIPSTAT_ERROR_PASSIVE:
+ return QCanBusDevice::CanBusStatus::Error;
+ case XL_CHIPSTAT_ERROR_WARNING:
+ return QCanBusDevice::CanBusStatus::Warning;
+ case XL_CHIPSTAT_ERROR_ACTIVE:
+ return QCanBusDevice::CanBusStatus::Good;
+ }
+ }
+
+ qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Unknown CAN bus status: %u",
+ uint(event.tagData.chipState.busStatus));
+ return QCanBusDevice::CanBusStatus::Unknown;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.h b/src/plugins/canbus/vectorcan/vectorcanbackend.h
index 165d369..89b9da6 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend.h
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend.h
@@ -71,6 +71,8 @@ public:
static QList<QCanBusDeviceInfo> interfaces();
private:
+ QCanBusDevice::CanBusStatus busStatus();
+
VectorCanBackendPrivate * const d_ptr;
};