summaryrefslogtreecommitdiffstats
path: root/src/plugins/canbus/socketcan
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/canbus/socketcan')
-rw-r--r--src/plugins/canbus/socketcan/main.cpp11
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.cpp141
-rw-r--r--src/plugins/canbus/socketcan/socketcanbackend.h9
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