diff options
Diffstat (limited to 'src/plugins/canbus/socketcan')
-rw-r--r-- | src/plugins/canbus/socketcan/main.cpp | 11 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcanbackend.cpp | 141 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcanbackend.h | 9 |
3 files changed, 123 insertions, 38 deletions
diff --git a/src/plugins/canbus/socketcan/main.cpp b/src/plugins/canbus/socketcan/main.cpp index 715b26f..92e759b 100644 --- a/src/plugins/canbus/socketcan/main.cpp +++ b/src/plugins/canbus/socketcan/main.cpp @@ -45,14 +45,19 @@ QT_BEGIN_NAMESPACE //! [SocketCanFactory] -class SocketCanBusPlugin : public QObject, public QCanBusFactory +class SocketCanBusPlugin : public QObject, public QCanBusFactoryV2 { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QCanBusFactory" FILE "plugin.json") - Q_INTERFACES(QCanBusFactory) - + Q_INTERFACES(QCanBusFactoryV2) public: + QList<QCanBusDeviceInfo> availableDevices(QString *errorMessage) const override + { + Q_UNUSED(errorMessage); + return SocketCanBackend::interfaces(); + } + QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override { Q_UNUSED(errorMessage); diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp index def1c53..930221d 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.cpp +++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp @@ -36,8 +36,10 @@ #include "socketcanbackend.h" -#include <QtCore/qdebug.h> #include <QtCore/qdatastream.h> +#include <QtCore/qdebug.h> +#include <QtCore/qdiriterator.h> +#include <QtCore/qfile.h> #include <QtCore/qsocketnotifier.h> #include <linux/can/error.h> @@ -74,11 +76,78 @@ struct canfd_frame { QT_BEGIN_NAMESPACE +const char sysClassNetC[] = "/sys/class/net/"; +const char flagsC[] = "/flags"; +const char mtuC[] = "/mtu"; +const char typeC[] = "/type"; +const char virtualC[] = "virtual"; + +enum { + CanFlexibleDataRateMtu = 72, + TypeSocketCan = 280, + DeviceIsActive = 1 +}; + +static QByteArray fileContent(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) + return QByteArray(); + + return file.readAll().trimmed(); +} + +static bool isFlexibleDataRateCapable(const QString &canDevice) +{ + const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(mtuC); + const int mtu = fileContent(path).toInt(); + return mtu == CanFlexibleDataRateMtu; +} + +static bool isVirtual(const QString &canDevice) +{ + const QFileInfo fi(QLatin1String(sysClassNetC) + canDevice); + return fi.canonicalPath().contains(QLatin1String(virtualC)); +} + +static quint32 flags(const QString &canDevice) +{ + const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(flagsC); + const quint32 result = fileContent(path).toUInt(nullptr, 0); + return result; +} + +QList<QCanBusDeviceInfo> SocketCanBackend::interfaces() +{ + QList<QCanBusDeviceInfo> result; + QDirIterator it(sysClassNetC, + QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, + QDirIterator::Subdirectories); + + while (it.hasNext()) { + const QString dirEntry = it.next(); + if (fileContent(dirEntry + QLatin1String(typeC)).toInt() != TypeSocketCan) + continue; + + const QString deviceName = dirEntry.mid(strlen(sysClassNetC)); + if (!(flags(deviceName) & DeviceIsActive)) + continue; + + auto info = createDeviceInfo(deviceName, isVirtual(deviceName), + isFlexibleDataRateCapable(deviceName)); + result.append(info); + } + + std::sort(result.begin(), result.end(), + [](const QCanBusDeviceInfo &a, const QCanBusDeviceInfo &b) { + return a.name() < b.name(); + }); + + return result; +} + SocketCanBackend::SocketCanBackend(const QString &name) : - canSocket(-1), - notifier(nullptr), - canSocketName(name), - canFdOptionEnabled(false) + canSocketName(name) { resetConfigurations(); } @@ -130,7 +199,8 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu case QCanBusDevice::LoopbackKey: { const int loopback = value.toBool() ? 1 : 0; - if (setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback)) < 0) { + if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_LOOPBACK, + &loopback, sizeof(loopback)) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConfigurationError); break; @@ -141,8 +211,8 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu case QCanBusDevice::ReceiveOwnKey: { const int receiveOwnMessages = value.toBool() ? 1 : 0; - if (setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, - &receiveOwnMessages, sizeof(receiveOwnMessages)) < 0) { + if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, + &receiveOwnMessages, sizeof(receiveOwnMessages)) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConfigurationError); break; @@ -153,8 +223,8 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu case QCanBusDevice::ErrorFilterKey: { const int errorMask = value.value<QCanBusFrame::FrameErrors>(); - if (setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, - &errorMask, sizeof(errorMask)) < 0) { + if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, + &errorMask, sizeof(errorMask)) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConfigurationError); break; @@ -170,9 +240,9 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu // permit every frame - no restrictions (filter reset) can_filter filters = {0, 0}; socklen_t s = sizeof(can_filter); - if (setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER, - &filters, s) != 0) { - qWarning() << "Cannot unset socket filters"; + if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER, + &filters, s) != 0)) { + qWarning("Cannot unset socket filters"); setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConfigurationError); break; @@ -224,8 +294,8 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu filters[i] = filter; } - if (setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER, - filters.constData(), sizeof(filters[0]) * filters.size()) < 0) { + if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER, + filters.constData(), sizeof(filters[0]) * filters.size()) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConfigurationError); break; @@ -236,7 +306,8 @@ bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &valu case QCanBusDevice::CanFdKey: { const int fd_frames = value.toBool() ? 1 : 0; - if (setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &fd_frames, sizeof(fd_frames)) < 0) { + if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &fd_frames, sizeof(fd_frames)) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConfigurationError); break; @@ -259,14 +330,14 @@ bool SocketCanBackend::connectSocket() struct sockaddr_can address; struct ifreq interface; - if ((canSocket = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)) < 0) { + if (Q_UNLIKELY((canSocket = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConnectionError); return false; } qstrncpy(interface.ifr_name, canSocketName.toLatin1().constData(), sizeof(interface.ifr_name)); - if (ioctl(canSocket, SIOCGIFINDEX, &interface) < 0) { + if (Q_UNLIKELY(ioctl(canSocket, SIOCGIFINDEX, &interface) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConnectionError); return false; @@ -275,7 +346,7 @@ bool SocketCanBackend::connectSocket() address.can_family = AF_CAN; address.can_ifindex = interface.ifr_ifindex; - if (bind(canSocket, reinterpret_cast<struct sockaddr *>(&address), sizeof(address)) < 0) { + if (Q_UNLIKELY(bind(canSocket, reinterpret_cast<struct sockaddr *>(&address), sizeof(address)) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ConnectionError); return false; @@ -288,12 +359,13 @@ bool SocketCanBackend::connectSocket() this, &SocketCanBackend::readSocket); //apply all stored configurations - foreach (int key, configurationKeys()) { + const auto keys = configurationKeys(); + for (int key : keys) { const QVariant param = configurationParameter(key); bool success = applyConfigurationParameter(key, param); - if (!success) { - qWarning() << "Cannot apply parameter:" << QCanBusDevice::ConfigurationKey(key) - << "with value:" << param; + if (Q_UNLIKELY(!success)) { + qWarning("Cannot apply parameter: %d with value: %ls", + key, qUtf16Printable(param.toString())); } } @@ -305,9 +377,8 @@ void SocketCanBackend::setConfigurationParameter(int key, const QVariant &value) if (key == QCanBusDevice::RawFilterKey) { //verify valid/supported filters - QList<QCanBusDevice::Filter> filters - = value.value<QList<QCanBusDevice::Filter> >(); - foreach (QCanBusDevice::Filter f, filters) { + const auto filters = value.value<QList<QCanBusDevice::Filter> >(); + for (QCanBusDevice::Filter f : filters) { switch (f.type) { case QCanBusFrame::UnknownFrame: @@ -345,7 +416,7 @@ bool SocketCanBackend::writeFrame(const QCanBusFrame &newData) if (state() != ConnectedState) return false; - if (!newData.isValid()) { + if (Q_UNLIKELY(!newData.isValid())) { setError(tr("Cannot write invalid QCanBusFrame"), QCanBusDevice::WriteError); return false; } @@ -374,6 +445,8 @@ bool SocketCanBackend::writeFrame(const QCanBusFrame &newData) memset(&frame, 0, sizeof(frame)); frame.len = newData.payload().size(); frame.can_id = canId; + frame.flags = newData.hasBitrateSwitch() ? CANFD_BRS : 0; + frame.flags |= newData.hasErrorStateIndicator() ? CANFD_ESI : 0; ::memcpy(frame.data, newData.payload().constData(), frame.len); bytesWritten = ::write(canSocket, &frame, sizeof(frame)); @@ -387,7 +460,7 @@ bool SocketCanBackend::writeFrame(const QCanBusFrame &newData) bytesWritten = ::write(canSocket, &frame, sizeof(frame)); } - if (bytesWritten < 0) { + if (Q_UNLIKELY(bytesWritten < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::WriteError); return false; @@ -565,7 +638,7 @@ void SocketCanBackend::readSocket() { QVector<QCanBusFrame> newFrames; - while (true) { + for (;;) { struct canfd_frame frame; int bytesReceived; @@ -573,18 +646,18 @@ void SocketCanBackend::readSocket() if (bytesReceived <= 0) { break; - } else if (bytesReceived != CANFD_MTU && bytesReceived != CAN_MTU) { + } else if (Q_UNLIKELY(bytesReceived != CANFD_MTU && bytesReceived != CAN_MTU)) { setError(tr("ERROR SocketCanBackend: incomplete CAN frame"), QCanBusDevice::CanBusError::ReadError); continue; - } else if (frame.len > bytesReceived - offsetof(canfd_frame, data)) { + } else if (Q_UNLIKELY(frame.len > bytesReceived - offsetof(canfd_frame, data))) { setError(tr("ERROR SocketCanBackend: invalid CAN frame length"), QCanBusDevice::CanBusError::ReadError); continue; } struct timeval timeStamp; - if (ioctl(canSocket, SIOCGSTAMP, &timeStamp) < 0) { + if (Q_UNLIKELY(ioctl(canSocket, SIOCGSTAMP, &timeStamp) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ReadError); memset(&timeStamp, 0, sizeof(timeStamp)); @@ -602,6 +675,10 @@ void SocketCanBackend::readSocket() bufferedFrame.setFrameType(QCanBusFrame::RemoteRequestFrame); if (frame.can_id & CAN_ERR_FLAG) bufferedFrame.setFrameType(QCanBusFrame::ErrorFrame); + if (frame.flags & CANFD_BRS) + bufferedFrame.setBitrateSwitch(true); + if (frame.flags & CANFD_ESI) + bufferedFrame.setErrorStateIndicator(true); bufferedFrame.setFrameId(frame.can_id & CAN_EFF_MASK); diff --git a/src/plugins/canbus/socketcan/socketcanbackend.h b/src/plugins/canbus/socketcan/socketcanbackend.h index 8de92e4..70c47c8 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.h +++ b/src/plugins/canbus/socketcan/socketcanbackend.h @@ -39,6 +39,7 @@ #include <QtSerialBus/qcanbusframe.h> #include <QtSerialBus/qcanbusdevice.h> +#include <QtSerialBus/qcanbusdeviceinfo.h> #include <QtCore/qsocketnotifier.h> #include <QtCore/qstring.h> @@ -62,6 +63,8 @@ public: QString interpretErrorFrame(const QCanBusFrame &errorFrame) override; + static QList<QCanBusDeviceInfo> interfaces(); + private Q_SLOTS: void readSocket(); @@ -70,10 +73,10 @@ private: bool connectSocket(); bool applyConfigurationParameter(int key, const QVariant &value); - qint64 canSocket; - QSocketNotifier *notifier; + qint64 canSocket = -1; + QSocketNotifier *notifier = nullptr; QString canSocketName; - bool canFdOptionEnabled; + bool canFdOptionEnabled = false; }; QT_END_NAMESPACE |