From a88ecda86028228174a1ec4e53df235ebac33dcc Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Tue, 2 Oct 2018 11:41:16 +0200 Subject: Add QCanBusDevice::resetController() for CAN controller reset Currently missing: * VectorCAN: no information in the documentation found * PassthroughCAN: no documentation [ChangeLog][QCanBus][QCanBusDevice] Added the function QCanBusDevice::resetController() to reset a CAN controller from bus off state, as far as supported by the various plugins. Fixes: QTBUG-54943 Change-Id: Ic098054b012726c0c69970c0ae84f434c2b3964a Reviewed-by: Denis Shienkov --- src/plugins/canbus/peakcan/peakcanbackend.cpp | 9 ++++++ src/plugins/canbus/peakcan/peakcanbackend.h | 2 ++ src/plugins/canbus/socketcan/socketcanbackend.cpp | 8 +++++ src/plugins/canbus/socketcan/socketcanbackend.h | 1 + src/plugins/canbus/systeccan/systeccan_symbols_p.h | 2 ++ src/plugins/canbus/systeccan/systeccanbackend.cpp | 14 +++++++++ src/plugins/canbus/systeccan/systeccanbackend.h | 2 ++ src/plugins/canbus/systeccan/systeccanbackend_p.h | 1 + src/plugins/canbus/tinycan/tinycanbackend.cpp | 24 +++++++++++++-- src/plugins/canbus/tinycan/tinycanbackend.h | 2 ++ src/plugins/canbus/tinycan/tinycanbackend_p.h | 1 + src/serialbus/doc/src/peakcan.qdoc | 7 +++++ src/serialbus/doc/src/socketcan.qdoc | 9 +++++- src/serialbus/doc/src/systeccan.qdoc | 7 +++++ src/serialbus/doc/src/tinycan.qdoc | 9 +++++- src/serialbus/qcanbusdevice.cpp | 36 ++++++++++++++++++++++ src/serialbus/qcanbusdevice.h | 6 ++++ src/serialbus/qcanbusdevice_p.h | 2 ++ 18 files changed, 138 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp index 2f4097e..30d3b8c 100644 --- a/src/plugins/canbus/peakcan/peakcanbackend.cpp +++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp @@ -717,6 +717,9 @@ PeakCanBackend::PeakCanBackend(const QString &name, QObject *parent) d->setupChannel(name.toLatin1()); d->setupDefaultConfigurations(); + + std::function f = std::bind(&PeakCanBackend::resetController, this); + setResetControllerFunction(f); } PeakCanBackend::~PeakCanBackend() @@ -808,4 +811,10 @@ QString PeakCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame) return QString(); } +void PeakCanBackend::resetController() +{ + close(); + open(); +} + QT_END_NAMESPACE diff --git a/src/plugins/canbus/peakcan/peakcanbackend.h b/src/plugins/canbus/peakcan/peakcanbackend.h index 7f7083e..6a9cda2 100644 --- a/src/plugins/canbus/peakcan/peakcanbackend.h +++ b/src/plugins/canbus/peakcan/peakcanbackend.h @@ -72,6 +72,8 @@ public: static QList interfaces(); private: + void resetController(); + PeakCanBackendPrivate * const d_ptr; }; diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp index cac1db5..9e99a57 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.cpp +++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp @@ -194,6 +194,9 @@ SocketCanBackend::SocketCanBackend(const QString &name) : } resetConfigurations(); + + std::function f = std::bind(&SocketCanBackend::resetController, this); + setResetControllerFunction(f); } SocketCanBackend::~SocketCanBackend() @@ -750,4 +753,9 @@ void SocketCanBackend::readSocket() enqueueReceivedFrames(newFrames); } +void SocketCanBackend::resetController() +{ + libSocketCan->restart(canSocketName); +} + QT_END_NAMESPACE diff --git a/src/plugins/canbus/socketcan/socketcanbackend.h b/src/plugins/canbus/socketcan/socketcanbackend.h index 1392251..561d4ee 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.h +++ b/src/plugins/canbus/socketcan/socketcanbackend.h @@ -83,6 +83,7 @@ private: void resetConfigurations(); bool connectSocket(); bool applyConfigurationParameter(int key, const QVariant &value); + void resetController(); 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 102817c..8a36327 100644 --- a/src/plugins/canbus/systeccan/systeccan_symbols_p.h +++ b/src/plugins/canbus/systeccan/systeccan_symbols_p.h @@ -280,6 +280,7 @@ 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 *) inline bool resolveSymbols(QLibrary *systecLibrary) @@ -300,6 +301,7 @@ inline bool resolveSymbols(QLibrary *systecLibrary) RESOLVE_SYMBOL(UcanInitCanEx2); RESOLVE_SYMBOL(UcanDeinitCanEx); RESOLVE_SYMBOL(UcanReadCanMsgEx); + RESOLVE_SYMBOL(UcanResetCan); RESOLVE_SYMBOL(UcanWriteCanMsgEx); return true; diff --git a/src/plugins/canbus/systeccan/systeccanbackend.cpp b/src/plugins/canbus/systeccan/systeccanbackend.cpp index 3fdd135..54666d0 100644 --- a/src/plugins/canbus/systeccan/systeccanbackend.cpp +++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp @@ -454,6 +454,11 @@ bool SystecCanBackendPrivate::verifyBitRate(int bitrate) return true; } +void SystecCanBackendPrivate::resetController() +{ + ::UcanResetCan(handle); +} + SystecCanBackend::SystecCanBackend(const QString &name, QObject *parent) : QCanBusDevice(parent), d_ptr(new SystecCanBackendPrivate(this)) @@ -462,6 +467,9 @@ SystecCanBackend::SystecCanBackend(const QString &name, QObject *parent) : d->setupChannel(name); d->setupDefaultConfigurations(); + + std::function f = std::bind(&SystecCanBackend::resetController, this); + setResetControllerFunction(f); } SystecCanBackend::~SystecCanBackend() @@ -553,4 +561,10 @@ QString SystecCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame) return QString(); } +void SystecCanBackend::resetController() +{ + Q_D(SystecCanBackend); + d->resetController(); +} + QT_END_NAMESPACE diff --git a/src/plugins/canbus/systeccan/systeccanbackend.h b/src/plugins/canbus/systeccan/systeccanbackend.h index cb62808..68dcfb9 100644 --- a/src/plugins/canbus/systeccan/systeccanbackend.h +++ b/src/plugins/canbus/systeccan/systeccanbackend.h @@ -76,6 +76,8 @@ public: int channelNumber); private: + void resetController(); + SystecCanBackendPrivate * const d_ptr; }; diff --git a/src/plugins/canbus/systeccan/systeccanbackend_p.h b/src/plugins/canbus/systeccan/systeccanbackend_p.h index 28eb7ff..b938c74 100644 --- a/src/plugins/canbus/systeccan/systeccanbackend_p.h +++ b/src/plugins/canbus/systeccan/systeccanbackend_p.h @@ -94,6 +94,7 @@ public: void startWrite(); void readAllReceivedMessages(); bool verifyBitRate(int bitrate); + void resetController(); SystecCanBackend * const q_ptr; diff --git a/src/plugins/canbus/tinycan/tinycanbackend.cpp b/src/plugins/canbus/tinycan/tinycanbackend.cpp index 882cb47..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(); } } @@ -468,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); @@ -498,6 +509,9 @@ TinyCanBackend::TinyCanBackend(const QString &name, QObject *parent) d->setupChannel(name); d->setupDefaultConfigurations(); + + std::function f = std::bind(&TinyCanBackend::resetController, this); + setResetControllerFunction(f); } TinyCanBackend::~TinyCanBackend() @@ -591,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 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/serialbus/doc/src/peakcan.qdoc b/src/serialbus/doc/src/peakcan.qdoc index a3d848d..e6ce7ee 100644 --- a/src/serialbus/doc/src/peakcan.qdoc +++ b/src/serialbus/doc/src/peakcan.qdoc @@ -105,4 +105,11 @@ 100000, 125000, 250000, 500000, 800000, 1000000. Note that this configuration parameter can only be adjusted while the QCanBusDevice is not connected. \endtable + + PeakCAN supports the following additional functions: + + \list + \li QCanBusDevice::resetController() + \endlist + */ diff --git a/src/serialbus/doc/src/socketcan.qdoc b/src/serialbus/doc/src/socketcan.qdoc index 9ae778d..82a00c8 100644 --- a/src/serialbus/doc/src/socketcan.qdoc +++ b/src/serialbus/doc/src/socketcan.qdoc @@ -203,4 +203,11 @@ \snippet snippetmain.cpp SocketCan Filter Example Extended frame format and flexible data-rate are supported in SocketCAN. - */ + + SocketCAN supports the following additional functions: + + \list + \li QCanBusDevice::resetController() (needs libsocketcan) + \endlist + +*/ diff --git a/src/serialbus/doc/src/systeccan.qdoc b/src/serialbus/doc/src/systeccan.qdoc index af34665..66ce7c7 100644 --- a/src/serialbus/doc/src/systeccan.qdoc +++ b/src/serialbus/doc/src/systeccan.qdoc @@ -109,4 +109,11 @@ is disabled by default. If this option is enabled, the therefore received frames are marked with QCanBusFrame::hasLocalEcho() \endtable + + SystecCAN supports the following additional functions: + + \list + \li QCanBusDevice::resetController() + \endlist + */ diff --git a/src/serialbus/doc/src/tinycan.qdoc b/src/serialbus/doc/src/tinycan.qdoc index 43349dc..8479576 100644 --- a/src/serialbus/doc/src/tinycan.qdoc +++ b/src/serialbus/doc/src/tinycan.qdoc @@ -95,4 +95,11 @@ \li Determines the bit rate of the CAN bus connection. The following bit rates are supported: 10000, 20000, 50000, 100000, 125000, 250000, 500000, 800000, 1000000. \endtable - */ + + TinyCAN supports the following additional functions: + + \list + \li QCanBusDevice::resetController() + \endlist + +*/ diff --git a/src/serialbus/qcanbusdevice.cpp b/src/serialbus/qcanbusdevice.cpp index 22f9d20..2bdec02 100644 --- a/src/serialbus/qcanbusdevice.cpp +++ b/src/serialbus/qcanbusdevice.cpp @@ -316,6 +316,17 @@ bool QCanBusDevice::hasOutgoingFrames() const return !d->outgoingFrames.isEmpty(); } +/*! + * Called from the derived plugin to register a function that performs the + * CAN controller hardware reset when \a resetController() is called. + */ +void QCanBusDevice::setResetControllerFunction(std::function &resetter) +{ + Q_D(QCanBusDevice); + + d->m_resetControllerFunction = resetter; +} + /*! Sets the configuration parameter \a key for the CAN bus connection to \a value. The potential keys are represented by \l ConfigurationKey. @@ -441,6 +452,31 @@ qint64 QCanBusDevice::framesToWrite() const return d_func()->outgoingFrames.size(); } +/*! + \since 5.14 + + Performs a CAN controller reset to release the CAN controller from + bus off state, if possible. + + \note CAN controller resets disturb the running communication and + may take up to one second to complete. Only call this function to + recover from bus errors. + + \note This function may not be implemented in all CAN plugins. + Please refer to the plugins help pages for more information. +*/ +void QCanBusDevice::resetController() +{ + if (d_func()->m_resetControllerFunction) { + d_func()->m_resetControllerFunction(); + } else { + const char error[] = QT_TRANSLATE_NOOP("QCanBusDevice", + "This CAN bus plugin does not support hardware controller reset."); + qCWarning(QT_CANBUS, error); + setError(tr(error), QCanBusDevice::CanBusError::ConfigurationError); + } +} + /*! \since 5.12 \enum QCanBusDevice::Direction diff --git a/src/serialbus/qcanbusdevice.h b/src/serialbus/qcanbusdevice.h index b590510..911f3ac 100644 --- a/src/serialbus/qcanbusdevice.h +++ b/src/serialbus/qcanbusdevice.h @@ -41,6 +41,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QCanBusDevicePrivate; @@ -120,6 +122,8 @@ public: qint64 framesAvailable() const; qint64 framesToWrite() const; + void resetController(); + enum Direction { Input = 1, Output = 2, @@ -163,6 +167,8 @@ protected: virtual bool open() = 0; virtual void close() = 0; + void setResetControllerFunction(std::function &resetter); + static QCanBusDeviceInfo createDeviceInfo(const QString &name, bool isVirtual = false, bool isFlexibleDataRateCapable = false); diff --git a/src/serialbus/qcanbusdevice_p.h b/src/serialbus/qcanbusdevice_p.h index faeae65..26d3e89 100644 --- a/src/serialbus/qcanbusdevice_p.h +++ b/src/serialbus/qcanbusdevice_p.h @@ -74,6 +74,8 @@ public: bool waitForReceivedEntered = false; bool waitForWrittenEntered = false; + + std::function m_resetControllerFunction; }; QT_END_NAMESPACE -- cgit v1.2.3