summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Hartmann <aha_1980@gmx.de>2019-02-23 11:18:22 +0100
committerAndre Hartmann <aha_1980@gmx.de>2019-07-17 14:21:24 +0200
commitf83587a9978bd212d7cd64a8d68330a8b97572db (patch)
treed6f3421d7dbaf6b5b732f975dde4b2903d2e3454
parent30df8839a1d0e81580fa570b9fa7d6c4217d8b25 (diff)
Add QCanBusDevice::busStatus()
The original terminology is Error active, Error warning, Error Passive and Bus Off. We map them to GoodStatus, WarningStatus, ErrorStatus and BusOffStatus here. [ChangeLog][QCanBusDevice] Added the function busStatus() to query the CAN bus status from the CAN bus device. Fixes: QTBUG-70766 Change-Id: I22b99e2a02a6b22509005dd177796b861d536281 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--examples/serialbus/can/mainwindow.cpp30
-rw-r--r--examples/serialbus/can/mainwindow.h2
-rw-r--r--examples/serialbus/can/mainwindow.ui9
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.cpp22
-rw-r--r--src/plugins/canbus/peakcan/peakcanbackend.h1
-rw-r--r--src/plugins/canbus/socketcan/libsocketcan.cpp45
-rw-r--r--src/plugins/canbus/socketcan/libsocketcan.h4
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.cpp17
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.h2
-rw-r--r--src/plugins/canbus/systeccan/systeccan_symbols_p.h21
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.cpp39
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.h1
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend_p.h1
-rw-r--r--src/plugins/canbus/vectorcan/vectorcan_symbols_p.h20
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.cpp47
-rw-r--r--src/plugins/canbus/vectorcan/vectorcanbackend.h2
-rw-r--r--src/serialbus/doc/src/peakcan.qdoc1
-rw-r--r--src/serialbus/doc/src/socketcan.qdoc1
-rw-r--r--src/serialbus/doc/src/systeccan.qdoc1
-rw-r--r--src/serialbus/doc/src/vectorcan.qdoc7
-rw-r--r--src/serialbus/qcanbusdevice.cpp62
-rw-r--r--src/serialbus/qcanbusdevice.h12
-rw-r--r--src/serialbus/qcanbusdevice_p.h1
23 files changed, 346 insertions, 2 deletions
diff --git a/examples/serialbus/can/mainwindow.cpp b/examples/serialbus/can/mainwindow.cpp
index b2bae6d..29c5f1f 100644
--- a/examples/serialbus/can/mainwindow.cpp
+++ b/examples/serialbus/can/mainwindow.cpp
@@ -60,7 +60,8 @@
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
- m_ui(new Ui::MainWindow)
+ m_ui(new Ui::MainWindow),
+ m_busStatusTimer(new QTimer(this))
{
m_ui->setupUi(this);
@@ -174,6 +175,31 @@ void MainWindow::connectDevice()
.arg(p.pluginName).arg(p.deviceInterfaceName));
}
}
+
+ connect(m_busStatusTimer, &QTimer::timeout, this, [this]() {
+ switch (m_canDevice->busStatus()) {
+ case QCanBusDevice::CanBusStatus::Good:
+ m_ui->busStatus->setText("CAN bus status: Good.");
+ break;
+ case QCanBusDevice::CanBusStatus::Warning:
+ m_ui->busStatus->setText("CAN bus status: Warning.");
+ break;
+ case QCanBusDevice::CanBusStatus::Error:
+ m_ui->busStatus->setText("CAN bus status: Error.");
+ break;
+ case QCanBusDevice::CanBusStatus::BusOff:
+ m_ui->busStatus->setText("CAN bus status: Bus Off.");
+ break;
+ default:
+ m_ui->busStatus->setText("CAN bus status: Unknown.");
+ break;
+ }
+ });
+
+ if (m_canDevice->hasBusStatus())
+ m_busStatusTimer->start(2000);
+ else
+ m_ui->busStatus->setText(tr("No CAN bus status available."));
}
void MainWindow::disconnectDevice()
@@ -181,6 +207,8 @@ void MainWindow::disconnectDevice()
if (!m_canDevice)
return;
+ m_busStatusTimer->stop();
+
m_canDevice->disconnectDevice();
delete m_canDevice;
m_canDevice = nullptr;
diff --git a/examples/serialbus/can/mainwindow.h b/examples/serialbus/can/mainwindow.h
index 40b2e4a..673e87a 100644
--- a/examples/serialbus/can/mainwindow.h
+++ b/examples/serialbus/can/mainwindow.h
@@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE
class QCanBusFrame;
class QLabel;
+class QTimer;
namespace Ui {
class MainWindow;
@@ -96,6 +97,7 @@ private:
QLabel *m_written = nullptr;
ConnectDialog *m_connectDialog = nullptr;
QCanBusDevice *m_canDevice = nullptr;
+ QTimer *m_busStatusTimer = nullptr;
};
#endif // MAINWINDOW_H
diff --git a/examples/serialbus/can/mainwindow.ui b/examples/serialbus/can/mainwindow.ui
index 2f61336..f773ffb 100644
--- a/examples/serialbus/can/mainwindow.ui
+++ b/examples/serialbus/can/mainwindow.ui
@@ -66,6 +66,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QLabel" name="busStatus">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -77,7 +84,7 @@
<x>0</x>
<y>0</y>
<width>551</width>
- <height>19</height>
+ <height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuCalls">
diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp
index 30d3b8c..b1a991d 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.cpp
+++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp
@@ -720,6 +720,9 @@ PeakCanBackend::PeakCanBackend(const QString &name, QObject *parent)
std::function<void()> f = std::bind(&PeakCanBackend::resetController, this);
setResetControllerFunction(f);
+
+ std::function<CanBusStatus()> g = std::bind(&PeakCanBackend::busStatus, this);
+ setCanBusStatusGetter(g);
}
PeakCanBackend::~PeakCanBackend()
@@ -817,4 +820,23 @@ void PeakCanBackend::resetController()
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 6a9cda2..a9e108e 100644
--- a/src/plugins/canbus/peakcan/peakcanbackend.h
+++ b/src/plugins/canbus/peakcan/peakcanbackend.h
@@ -73,6 +73,7 @@ public:
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
index ca63391..c6144db 100644
--- a/src/plugins/canbus/socketcan/libsocketcan.cpp
+++ b/src/plugins/canbus/socketcan/libsocketcan.cpp
@@ -66,11 +66,22 @@ struct can_bittiming {
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)
{
@@ -87,6 +98,7 @@ LibSocketCan::LibSocketCan(QString *errorString)
RESOLVE_SYMBOL(can_do_restart);
RESOLVE_SYMBOL(can_set_bitrate);
RESOLVE_SYMBOL(can_get_bittiming);
+ RESOLVE_SYMBOL(can_get_state);
return true;
};
@@ -190,4 +202,37 @@ bool LibSocketCan::setBitrate(const QString &interface, quint32 bitrate)
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
index 91229ee..b77afa1 100644
--- a/src/plugins/canbus/socketcan/libsocketcan.h
+++ b/src/plugins/canbus/socketcan/libsocketcan.h
@@ -38,6 +38,7 @@
#define LIBSOCKETCAN_H
#include <QtCore/qglobal.h>
+#include <QtSerialBus/qcanbusdevice.h>
//
// W A R N I N G
@@ -65,6 +66,9 @@ public:
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
diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp
index 9e99a57..7d0fc52 100644
--- a/src/plugins/canbus/socketcan/socketcanbackend.cpp
+++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp
@@ -197,6 +197,13 @@ SocketCanBackend::SocketCanBackend(const QString &name) :
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()
@@ -758,4 +765,14 @@ 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 561d4ee..199401e 100644
--- a/src/plugins/canbus/socketcan/socketcanbackend.h
+++ b/src/plugins/canbus/socketcan/socketcanbackend.h
@@ -84,6 +84,8 @@ private:
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;
diff --git a/src/plugins/canbus/systeccan/systeccan_symbols_p.h b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
index 7fe98ad..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..
@@ -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
@@ -282,6 +301,7 @@ GENERATE_SYMBOL_VARIABLE(UCANRET, UcanDeinitCanEx, tUcanHandle, quint8 /* channe
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)
{
@@ -303,6 +323,7 @@ inline bool resolveSymbols(QLibrary *systecLibrary)
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 69689a3..0663f39 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.cpp
+++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp
@@ -459,6 +459,35 @@ 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))
@@ -470,6 +499,9 @@ SystecCanBackend::SystecCanBackend(const QString &name, QObject *parent) :
std::function<void()> f = std::bind(&SystecCanBackend::resetController, this);
setResetControllerFunction(f);
+
+ std::function<CanBusStatus()> g = std::bind(&SystecCanBackend::busStatus, this);
+ setCanBusStatusGetter(g);
}
SystecCanBackend::~SystecCanBackend()
@@ -567,4 +599,11 @@ void SystecCanBackend::resetController()
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 68dcfb9..22c1193 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend.h
@@ -77,6 +77,7 @@ public:
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 b938c74..b2da322 100644
--- a/src/plugins/canbus/systeccan/systeccanbackend_p.h
+++ b/src/plugins/canbus/systeccan/systeccanbackend_p.h
@@ -95,6 +95,7 @@ public:
void readAllReceivedMessages();
bool verifyBitRate(int bitrate);
void resetController();
+ QCanBusDevice::CanBusStatus busStatus();
SystecCanBackend * const q_ptr;
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 24dbe2c..9d3bdef 100644
--- a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
+++ b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp
@@ -446,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()
@@ -540,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;
};
diff --git a/src/serialbus/doc/src/peakcan.qdoc b/src/serialbus/doc/src/peakcan.qdoc
index e6ce7ee..624e09b 100644
--- a/src/serialbus/doc/src/peakcan.qdoc
+++ b/src/serialbus/doc/src/peakcan.qdoc
@@ -110,6 +110,7 @@
\list
\li QCanBusDevice::resetController()
+ \li QCanBusDevice::busStatus()
\endlist
*/
diff --git a/src/serialbus/doc/src/socketcan.qdoc b/src/serialbus/doc/src/socketcan.qdoc
index 82a00c8..58ffa17 100644
--- a/src/serialbus/doc/src/socketcan.qdoc
+++ b/src/serialbus/doc/src/socketcan.qdoc
@@ -208,6 +208,7 @@
\list
\li QCanBusDevice::resetController() (needs libsocketcan)
+ \li QCanBusDevice::busStatus() (needs libsocketcan)
\endlist
*/
diff --git a/src/serialbus/doc/src/systeccan.qdoc b/src/serialbus/doc/src/systeccan.qdoc
index 66ce7c7..dc66023 100644
--- a/src/serialbus/doc/src/systeccan.qdoc
+++ b/src/serialbus/doc/src/systeccan.qdoc
@@ -114,6 +114,7 @@
\list
\li QCanBusDevice::resetController()
+ \li QCanBusDevice::busStatus()
\endlist
*/
diff --git a/src/serialbus/doc/src/vectorcan.qdoc b/src/serialbus/doc/src/vectorcan.qdoc
index eb4acdd..70b6521 100644
--- a/src/serialbus/doc/src/vectorcan.qdoc
+++ b/src/serialbus/doc/src/vectorcan.qdoc
@@ -106,4 +106,11 @@
was successful. If this option is enabled, the therefore received frames are marked
with QCanBusFrame::hasLocalEcho()
\endtable
+
+ VectorCAN supports the following additional functions:
+
+ \list
+ \li QCanBusDevice::busStatus()
+ \endlist
+
*/
diff --git a/src/serialbus/qcanbusdevice.cpp b/src/serialbus/qcanbusdevice.cpp
index 2bdec02..e2188ae 100644
--- a/src/serialbus/qcanbusdevice.cpp
+++ b/src/serialbus/qcanbusdevice.cpp
@@ -328,6 +328,17 @@ void QCanBusDevice::setResetControllerFunction(std::function<void()> &resetter)
}
/*!
+ * Called from the derived plugin to register a function that returns the
+ * CAN controller bus status when \a busStatus() is called.
+ */
+void QCanBusDevice::setCanBusStatusGetter(std::function<CanBusStatus()> &busStatusGetter)
+{
+ Q_D(QCanBusDevice);
+
+ d->m_busStatusGetter = busStatusGetter;
+}
+
+/*!
Sets the configuration parameter \a key for the CAN bus connection
to \a value. The potential keys are represented by \l ConfigurationKey.
@@ -464,6 +475,8 @@ qint64 QCanBusDevice::framesToWrite() const
\note This function may not be implemented in all CAN plugins.
Please refer to the plugins help pages for more information.
+
+ \sa busStatus()
*/
void QCanBusDevice::resetController()
{
@@ -478,6 +491,55 @@ void QCanBusDevice::resetController()
}
/*!
+ \since 5.14
+
+ Return true, if the CAN plugin supports requesting the CAN bus status.
+
+ \sa busStatus()
+ */
+bool QCanBusDevice::hasBusStatus() const
+{
+ return d_func()->m_busStatusGetter != nullptr;
+}
+
+/*!
+ \since 5.14
+ \enum QCanBusDevice::CanBusStatus
+
+ This enum describes possible CAN bus status values.
+
+ \value Unknown The CAN bus status is unknown
+ (e.g. not supported by the CAN plugin).
+ \value Good The CAN controller is fully operational
+ \value Warning The CAN controller is in warning status
+ \value Error The CAN controller is in error status
+ (no longer sending CAN frames)
+ \value BusOff The CAN controller is in bus off status
+ (disconnected from the CAN bus)
+*/
+
+/*!
+ \since 5.14
+
+ Returns the current CAN bus status. If the status cannot be requested,
+ QCanBusDevice::UnknownStatus is returned.
+
+ \note This function may not be implemented in all CAN plugins.
+ Please refer to the plugins help pages for more information.
+ The function hasBusStatus() can be used at runtime to check if
+ the used CAN plugin has support for requesting the CAN bus status.
+
+ \sa hasBusStatus(), hardwareControllerReset()
+*/
+QCanBusDevice::CanBusStatus QCanBusDevice::busStatus() const
+{
+ if (d_func()->m_busStatusGetter)
+ return d_func()->m_busStatusGetter();
+
+ return QCanBusDevice::CanBusStatus::Unknown;
+}
+
+/*!
\since 5.12
\enum QCanBusDevice::Direction
diff --git a/src/serialbus/qcanbusdevice.h b/src/serialbus/qcanbusdevice.h
index 911f3ac..01a5e8c 100644
--- a/src/serialbus/qcanbusdevice.h
+++ b/src/serialbus/qcanbusdevice.h
@@ -72,6 +72,15 @@ public:
};
Q_ENUM(CanBusDeviceState)
+ enum class CanBusStatus {
+ Unknown,
+ Good,
+ Warning,
+ Error,
+ BusOff
+ };
+ Q_ENUM(CanBusStatus)
+
enum ConfigurationKey {
RawFilterKey = 0,
ErrorFilterKey,
@@ -123,6 +132,8 @@ public:
qint64 framesToWrite() const;
void resetController();
+ bool hasBusStatus() const;
+ QCanBusDevice::CanBusStatus busStatus() const;
enum Direction {
Input = 1,
@@ -168,6 +179,7 @@ protected:
virtual void close() = 0;
void setResetControllerFunction(std::function<void()> &resetter);
+ void setCanBusStatusGetter(std::function<CanBusStatus()> &busStatusGetter);
static QCanBusDeviceInfo createDeviceInfo(const QString &name,
bool isVirtual = false,
diff --git a/src/serialbus/qcanbusdevice_p.h b/src/serialbus/qcanbusdevice_p.h
index 26d3e89..e74168c 100644
--- a/src/serialbus/qcanbusdevice_p.h
+++ b/src/serialbus/qcanbusdevice_p.h
@@ -76,6 +76,7 @@ public:
bool waitForWrittenEntered = false;
std::function<void()> m_resetControllerFunction;
+ std::function<QCanBusDevice::CanBusStatus()> m_busStatusGetter;
};
QT_END_NAMESPACE