diff options
author | Andre Hartmann <aha_1980@gmx.de> | 2019-02-23 11:18:22 +0100 |
---|---|---|
committer | Andre Hartmann <aha_1980@gmx.de> | 2019-07-17 14:21:24 +0200 |
commit | f83587a9978bd212d7cd64a8d68330a8b97572db (patch) | |
tree | d6f3421d7dbaf6b5b732f975dde4b2903d2e3454 | |
parent | 30df8839a1d0e81580fa570b9fa7d6c4217d8b25 (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>
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 |