1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtSerialBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "socketcanbackend.h"
38
39#include "libsocketcan.h"
40
41#include <QtSerialBus/qcanbusdevice.h>
42
43#include <QtCore/qdatastream.h>
44#include <QtCore/qdebug.h>
45#include <QtCore/qdiriterator.h>
46#include <QtCore/qfile.h>
47#include <QtCore/qloggingcategory.h>
48#include <QtCore/qsocketnotifier.h>
49
50#include <linux/can/error.h>
51#include <linux/can/raw.h>
52#include <linux/sockios.h>
53#include <errno.h>
54#include <unistd.h>
55#include <net/if.h>
56#include <sys/ioctl.h>
57#include <sys/time.h>
58
59#ifndef CANFD_BRS
60# define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
61#endif
62#ifndef CANFD_ESI
63# define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
64#endif
65
66QT_BEGIN_NAMESPACE
67
68Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN)
69
70const char sysClassNetC[] = "/sys/class/net/";
71const char interfaceC[] = "/device/interface";
72const char devIdC[] = "/dev_id";
73const char flagsC[] = "/flags";
74const char mtuC[] = "/mtu";
75const char typeC[] = "/type";
76const char virtualC[] = "virtual";
77
78enum {
79 CanFlexibleDataRateMtu = 72,
80 TypeSocketCan = 280,
81 DeviceIsActive = 1
82};
83
84static QByteArray fileContent(const QString &fileName)
85{
86 QFile file(fileName);
87 if (!file.open(flags: QIODevice::ReadOnly))
88 return QByteArray();
89
90 return file.readAll().trimmed();
91}
92
93static bool isFlexibleDataRateCapable(const QString &canDevice)
94{
95 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(mtuC);
96 const int mtu = fileContent(fileName: path).toInt();
97 return mtu == CanFlexibleDataRateMtu;
98}
99
100static bool isVirtual(const QString &canDevice)
101{
102 const QFileInfo fi(QLatin1String(sysClassNetC) + canDevice);
103 return fi.canonicalPath().contains(s: QLatin1String(virtualC));
104}
105
106static quint32 flags(const QString &canDevice)
107{
108 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(flagsC);
109 const quint32 result = fileContent(fileName: path).toUInt(ok: nullptr, base: 0);
110 return result;
111}
112
113static QString deviceDescription(const QString &canDevice)
114{
115 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(interfaceC);
116 const QByteArray content = fileContent(fileName: path);
117 if (content.isEmpty() && isVirtual(canDevice))
118 return QStringLiteral("Virtual CAN");
119
120 return QString::fromUtf8(str: content);
121}
122
123static int deviceChannel(const QString &canDevice)
124{
125 const QString path = QLatin1String(sysClassNetC) + canDevice + QLatin1String(devIdC);
126 const QByteArray content = fileContent(fileName: path);
127 return content.toInt(ok: nullptr, base: 0);
128}
129
130QList<QCanBusDeviceInfo> SocketCanBackend::interfaces()
131{
132 QList<QCanBusDeviceInfo> result;
133 QDirIterator it(sysClassNetC,
134 QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
135 QDirIterator::Subdirectories);
136
137 while (it.hasNext()) {
138 const QString dirEntry = it.next();
139 if (fileContent(fileName: dirEntry + QLatin1String(typeC)).toInt() != TypeSocketCan)
140 continue;
141
142 const QString deviceName = dirEntry.mid(position: strlen(s: sysClassNetC));
143 if (!(flags(canDevice: deviceName) & DeviceIsActive))
144 continue;
145
146 const QString serial;
147 const QString description = deviceDescription(canDevice: deviceName);
148 const int channel = deviceChannel(canDevice: deviceName);
149 result.append(t: std::move(createDeviceInfo(name: deviceName, serialNumber: serial, description,
150 channel, isVirtual: isVirtual(canDevice: deviceName),
151 isFlexibleDataRateCapable: isFlexibleDataRateCapable(canDevice: deviceName))));
152 }
153
154 std::sort(first: result.begin(), last: result.end(),
155 comp: [](const QCanBusDeviceInfo &a, const QCanBusDeviceInfo &b) {
156 return a.name() < b.name();
157 });
158
159 return result;
160}
161
162SocketCanBackend::SocketCanBackend(const QString &name) :
163 canSocketName(name)
164{
165 QString errorString;
166 libSocketCan.reset(p: new LibSocketCan(&errorString));
167 if (Q_UNLIKELY(!errorString.isEmpty())) {
168 qCInfo(QT_CANBUS_PLUGINS_SOCKETCAN,
169 "Cannot load library libsocketcan, some functionality will not be available.\n%ls",
170 qUtf16Printable(errorString));
171 }
172
173 resetConfigurations();
174
175 std::function<void()> f = std::bind(f: &SocketCanBackend::resetController, args: this);
176 setResetControllerFunction(f);
177
178 if (hasBusStatus()) {
179 // Only register busStatus when libsocketcan is available
180 // QCanBusDevice::hasBusStatus() will return false otherwise
181 std::function<CanBusStatus()> g = std::bind(f: &SocketCanBackend::busStatus, args: this);
182 setCanBusStatusGetter(g);
183 }
184}
185
186SocketCanBackend::~SocketCanBackend()
187{
188 close();
189}
190
191void SocketCanBackend::resetConfigurations()
192{
193 QCanBusDevice::setConfigurationParameter(
194 key: QCanBusDevice::LoopbackKey, value: true);
195 QCanBusDevice::setConfigurationParameter(
196 key: QCanBusDevice::ReceiveOwnKey, value: false);
197 QCanBusDevice::setConfigurationParameter(
198 key: QCanBusDevice::ErrorFilterKey,
199 value: QVariant::fromValue(value: QCanBusFrame::FrameErrors(QCanBusFrame::AnyError)));
200 QCanBusDevice::setConfigurationParameter(
201 key: QCanBusDevice::CanFdKey, value: false);
202 QCanBusDevice::setConfigurationParameter(
203 key: QCanBusDevice::BitRateKey, value: 500000);
204}
205
206bool SocketCanBackend::open()
207{
208 if (canSocket == -1) {
209 if (!connectSocket()) {
210 close(); // sets UnconnectedState
211 return false;
212 }
213 }
214
215 setState(QCanBusDevice::ConnectedState);
216 return true;
217}
218
219void SocketCanBackend::close()
220{
221 ::close(fd: canSocket);
222 canSocket = -1;
223
224 setState(QCanBusDevice::UnconnectedState);
225}
226
227bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &value)
228{
229 bool success = false;
230
231 switch (key) {
232 case QCanBusDevice::LoopbackKey:
233 {
234 const int loopback = value.toBool() ? 1 : 0;
235 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
236 &loopback, sizeof(loopback)) < 0)) {
237 setError(errorText: qt_error_string(errno),
238 QCanBusDevice::CanBusError::ConfigurationError);
239 break;
240 }
241 success = true;
242 break;
243 }
244 case QCanBusDevice::ReceiveOwnKey:
245 {
246 const int receiveOwnMessages = value.toBool() ? 1 : 0;
247 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
248 &receiveOwnMessages, sizeof(receiveOwnMessages)) < 0)) {
249 setError(errorText: qt_error_string(errno),
250 QCanBusDevice::CanBusError::ConfigurationError);
251 break;
252 }
253 success = true;
254 break;
255 }
256 case QCanBusDevice::ErrorFilterKey:
257 {
258 const int errorMask = value.value<QCanBusFrame::FrameErrors>();
259 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
260 &errorMask, sizeof(errorMask)) < 0)) {
261 setError(errorText: qt_error_string(errno),
262 QCanBusDevice::CanBusError::ConfigurationError);
263 break;
264 }
265 success = true;
266 break;
267 }
268 case QCanBusDevice::RawFilterKey:
269 {
270 const QList<QCanBusDevice::Filter> filterList
271 = value.value<QList<QCanBusDevice::Filter> >();
272 if (!value.isValid() || filterList.isEmpty()) {
273 // permit every frame - no restrictions (filter reset)
274 can_filter filters = {.can_id: 0, .can_mask: 0};
275 socklen_t s = sizeof(can_filter);
276 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER,
277 &filters, s) != 0)) {
278 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Cannot unset socket filters.");
279 setError(errorText: qt_error_string(errno),
280 QCanBusDevice::CanBusError::ConfigurationError);
281 break;
282 }
283 success = true;
284 break;
285 }
286
287 QVector<can_filter> filters;
288 filters.resize(asize: filterList.size());
289 for (int i = 0; i < filterList.size(); i++) {
290 const QCanBusDevice::Filter f = filterList.at(i);
291 can_filter filter = { .can_id: f.frameId, .can_mask: f.frameIdMask };
292
293 // frame type filter
294 switch (f.type) {
295 default:
296 // any other type cannot be filtered upon
297 setError(errorText: tr(s: "Cannot set filter for frame type: %1").arg(a: f.type),
298 QCanBusDevice::CanBusError::ConfigurationError);
299 return false;
300 case QCanBusFrame::InvalidFrame:
301 break;
302 case QCanBusFrame::DataFrame:
303 filter.can_mask |= CAN_RTR_FLAG;
304 break;
305 case QCanBusFrame::ErrorFrame:
306 filter.can_mask |= CAN_ERR_FLAG;
307 filter.can_id |= CAN_ERR_FLAG;
308 break;
309 case QCanBusFrame::RemoteRequestFrame:
310 filter.can_mask |= CAN_RTR_FLAG;
311 filter.can_id |= CAN_RTR_FLAG;
312 break;
313 }
314
315 // frame format filter
316 if ((f.format & QCanBusDevice::Filter::MatchBaseAndExtendedFormat)
317 == QCanBusDevice::Filter::MatchBaseAndExtendedFormat) {
318 // nothing
319 } else if (f.format & QCanBusDevice::Filter::MatchBaseFormat) {
320 filter.can_mask |= CAN_EFF_FLAG;
321 } else if (f.format & QCanBusDevice::Filter::MatchExtendedFormat) {
322 filter.can_mask |= CAN_EFF_FLAG;
323 filter.can_id |= CAN_EFF_FLAG;
324 }
325
326 filters[i] = filter;
327 }
328 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FILTER,
329 filters.constData(), sizeof(filters[0]) * filters.size()) < 0)) {
330 setError(errorText: qt_error_string(errno),
331 QCanBusDevice::CanBusError::ConfigurationError);
332 break;
333 }
334 success = true;
335 break;
336 }
337 case QCanBusDevice::CanFdKey:
338 {
339 const int fd_frames = value.toBool() ? 1 : 0;
340 if (Q_UNLIKELY(setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
341 &fd_frames, sizeof(fd_frames)) < 0)) {
342 setError(errorText: qt_error_string(errno),
343 QCanBusDevice::CanBusError::ConfigurationError);
344 break;
345 }
346 success = true;
347 break;
348 }
349 case QCanBusDevice::BitRateKey:
350 {
351 const quint32 bitRate = value.toUInt();
352 success = libSocketCan->setBitrate(interface: canSocketName, bitrate: bitRate);
353 break;
354 }
355 default:
356 setError(errorText: tr(s: "SocketCanBackend: No such configuration as %1 in SocketCanBackend").arg(a: key),
357 QCanBusDevice::CanBusError::ConfigurationError);
358 break;
359 }
360
361 return success;
362}
363
364bool SocketCanBackend::connectSocket()
365{
366 struct ifreq interface;
367
368 if (Q_UNLIKELY((canSocket = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, protocol)) < 0)) {
369 setError(errorText: qt_error_string(errno),
370 QCanBusDevice::CanBusError::ConnectionError);
371 return false;
372 }
373
374 qstrncpy(dst: interface.ifr_name, src: canSocketName.toLatin1().constData(), len: sizeof(interface.ifr_name));
375 if (Q_UNLIKELY(ioctl(canSocket, SIOCGIFINDEX, &interface) < 0)) {
376 setError(errorText: qt_error_string(errno),
377 QCanBusDevice::CanBusError::ConnectionError);
378 return false;
379 }
380
381 m_address.can_family = AF_CAN;
382 m_address.can_ifindex = interface.ifr_ifindex;
383
384 if (Q_UNLIKELY(bind(canSocket, reinterpret_cast<struct sockaddr *>(&m_address), sizeof(m_address)) < 0)) {
385 setError(errorText: qt_error_string(errno),
386 QCanBusDevice::CanBusError::ConnectionError);
387 return false;
388 }
389
390 m_iov.iov_base = &m_frame;
391 m_msg.msg_name = &m_address;
392 m_msg.msg_iov = &m_iov;
393 m_msg.msg_iovlen = 1;
394 m_msg.msg_control = &m_ctrlmsg;
395
396 delete notifier;
397
398 notifier = new QSocketNotifier(canSocket, QSocketNotifier::Read, this);
399 connect(sender: notifier, signal: &QSocketNotifier::activated,
400 receiver: this, slot: &SocketCanBackend::readSocket);
401
402 //apply all stored configurations
403 const auto keys = configurationKeys();
404 for (int key : keys) {
405 const QVariant param = configurationParameter(key);
406 bool success = applyConfigurationParameter(key, value: param);
407 if (Q_UNLIKELY(!success)) {
408 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Cannot apply parameter: %d with value: %ls.",
409 key, qUtf16Printable(param.toString()));
410 }
411 }
412
413 return true;
414}
415
416void SocketCanBackend::setConfigurationParameter(int key, const QVariant &value)
417{
418 if (key == QCanBusDevice::RawFilterKey) {
419 //verify valid/supported filters
420
421 const auto filters = value.value<QList<QCanBusDevice::Filter> >();
422 for (QCanBusDevice::Filter f : filters) {
423 switch (f.type) {
424 case QCanBusFrame::UnknownFrame:
425
426 default:
427 setError(errorText: tr(s: "Cannot set filter for frame type: %1").arg(a: f.type),
428 QCanBusDevice::CanBusError::ConfigurationError);
429 return;
430 case QCanBusFrame::InvalidFrame:
431 case QCanBusFrame::DataFrame:
432 case QCanBusFrame::ErrorFrame:
433 case QCanBusFrame::RemoteRequestFrame:
434 break;
435 }
436
437 if (f.frameId > 0x1FFFFFFFU) {
438 setError(errorText: tr(s: "FrameId %1 larger than 29 bit.").arg(a: f.frameId),
439 QCanBusDevice::CanBusError::ConfigurationError);
440 return;
441 }
442 }
443 } else if (key == QCanBusDevice::ProtocolKey) {
444 bool ok = false;
445 const int newProtocol = value.toInt(ok: &ok);
446 if (Q_UNLIKELY(!ok || (newProtocol < 0))) {
447 const QString errorString = tr(s: "Cannot set protocol to value %1.").arg(a: value.toString());
448 setError(errorText: errorString, QCanBusDevice::ConfigurationError);
449 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(errorString));
450 return;
451 }
452 protocol = newProtocol;
453 }
454 // connected & params not applyable/invalid
455 if (canSocket != -1 && !applyConfigurationParameter(key, value))
456 return;
457
458 QCanBusDevice::setConfigurationParameter(key, value);
459
460 // we need to check CAN FD option a lot -> cache it and avoid QVector lookup
461 if (key == QCanBusDevice::CanFdKey)
462 canFdOptionEnabled = value.toBool();
463}
464
465bool SocketCanBackend::writeFrame(const QCanBusFrame &newData)
466{
467 if (state() != ConnectedState)
468 return false;
469
470 if (Q_UNLIKELY(!newData.isValid())) {
471 setError(errorText: tr(s: "Cannot write invalid QCanBusFrame"), QCanBusDevice::WriteError);
472 return false;
473 }
474
475 canid_t canId = newData.frameId();
476 if (newData.hasExtendedFrameFormat())
477 canId |= CAN_EFF_FLAG;
478
479 if (newData.frameType() == QCanBusFrame::RemoteRequestFrame) {
480 canId |= CAN_RTR_FLAG;
481 } else if (newData.frameType() == QCanBusFrame::ErrorFrame) {
482 canId = static_cast<canid_t>((newData.error() & QCanBusFrame::AnyError));
483 canId |= CAN_ERR_FLAG;
484 }
485
486 if (Q_UNLIKELY(!canFdOptionEnabled && newData.hasFlexibleDataRateFormat())) {
487 const QString error = tr(s: "Cannot write CAN FD frame because CAN FD option is not enabled.");
488 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(error));
489 setError(errorText: error, QCanBusDevice::WriteError);
490 return false;
491 }
492
493 qint64 bytesWritten = 0;
494 if (newData.hasFlexibleDataRateFormat()) {
495 canfd_frame frame = {};
496 frame.len = newData.payload().size();
497 frame.can_id = canId;
498 frame.flags = newData.hasBitrateSwitch() ? CANFD_BRS : 0;
499 frame.flags |= newData.hasErrorStateIndicator() ? CANFD_ESI : 0;
500 ::memcpy(dest: frame.data, src: newData.payload().constData(), n: frame.len);
501
502 bytesWritten = ::write(fd: canSocket, buf: &frame, n: sizeof(frame));
503 } else {
504 can_frame frame = {};
505 frame.can_dlc = newData.payload().size();
506 frame.can_id = canId;
507 ::memcpy(dest: frame.data, src: newData.payload().constData(), n: frame.can_dlc);
508
509 bytesWritten = ::write(fd: canSocket, buf: &frame, n: sizeof(frame));
510 }
511
512 if (Q_UNLIKELY(bytesWritten < 0)) {
513 setError(errorText: qt_error_string(errno),
514 QCanBusDevice::CanBusError::WriteError);
515 return false;
516 }
517
518 emit framesWritten(framesCount: 1);
519
520 return true;
521}
522
523QString SocketCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
524{
525 if (errorFrame.frameType() != QCanBusFrame::ErrorFrame)
526 return QString();
527
528 // the payload may contain the error details
529 const QByteArray data = errorFrame.payload();
530 QString errorMsg;
531
532 if (errorFrame.error() & QCanBusFrame::TransmissionTimeoutError)
533 errorMsg += QStringLiteral("TX timout\n");
534
535 if (errorFrame.error() & QCanBusFrame::MissingAcknowledgmentError)
536 errorMsg += QStringLiteral("Received no ACK on transmission\n");
537
538 if (errorFrame.error() & QCanBusFrame::BusOffError)
539 errorMsg += QStringLiteral("Bus off\n");
540
541 if (errorFrame.error() & QCanBusFrame::BusError)
542 errorMsg += QStringLiteral("Bus error\n");
543
544 if (errorFrame.error() & QCanBusFrame::ControllerRestartError)
545 errorMsg += QStringLiteral("Controller restarted\n");
546
547 if (errorFrame.error() & QCanBusFrame::UnknownError)
548 errorMsg += QStringLiteral("Unknown error\n");
549
550 if (errorFrame.error() & QCanBusFrame::LostArbitrationError) {
551 errorMsg += QStringLiteral("Lost arbitration:\n");
552 if (data.size() >= 1) {
553 errorMsg += QString::number(data.at(i: 0), base: 16);
554 errorMsg += QStringLiteral(" bit\n");
555 }
556 }
557
558 if (errorFrame.error() & QCanBusFrame::ControllerError) {
559 errorMsg += QStringLiteral("Controller problem:\n");
560 if (data.size() >= 2) {
561 char b = data.at(i: 1) ;
562 if (b & CAN_ERR_CRTL_RX_OVERFLOW)
563 errorMsg += QStringLiteral(" RX buffer overflow\n");
564 if (b & CAN_ERR_CRTL_TX_OVERFLOW)
565 errorMsg += QStringLiteral(" TX buffer overflow\n");
566 if (b & CAN_ERR_CRTL_RX_WARNING)
567 errorMsg += QStringLiteral(" reached warning level for RX errors\n");
568 if (b & CAN_ERR_CRTL_TX_WARNING)
569 errorMsg += QStringLiteral(" reached warning level for TX errors\n");
570 if (b & CAN_ERR_CRTL_RX_PASSIVE)
571 errorMsg += QStringLiteral(" reached error passive status RX\n");
572 if (b & CAN_ERR_CRTL_TX_PASSIVE)
573 errorMsg += QStringLiteral(" reached error passive status TX\n");
574
575 if (b == CAN_ERR_CRTL_UNSPEC)
576 errorMsg += QStringLiteral(" Unspecified error\n");
577 }
578 }
579
580 if (errorFrame.error() & QCanBusFrame::TransceiverError) {
581 errorMsg = QStringLiteral("Transceiver status:");
582 if (data.size() >= 5) {
583 char b = data.at(i: 4);
584 if (b & CAN_ERR_TRX_CANH_NO_WIRE)
585 errorMsg += QStringLiteral(" CAN-transceiver CANH no wire\n");
586 if (b & CAN_ERR_TRX_CANH_SHORT_TO_BAT)
587 errorMsg += QStringLiteral(" CAN-transceiver CANH short to bat\n");
588 if (b & CAN_ERR_TRX_CANH_SHORT_TO_VCC)
589 errorMsg += QStringLiteral(" CAN-transceiver CANH short to vcc\n");
590 if (b & CAN_ERR_TRX_CANH_SHORT_TO_GND)
591 errorMsg += QStringLiteral(" CAN-transceiver CANH short to ground\n");
592 if (b & CAN_ERR_TRX_CANL_NO_WIRE)
593 errorMsg += QStringLiteral(" CAN-transceiver CANL no wire\n");
594 if (b & CAN_ERR_TRX_CANL_SHORT_TO_BAT)
595 errorMsg += QStringLiteral(" CAN-transceiver CANL short to bat\n");
596 if (b & CAN_ERR_TRX_CANL_SHORT_TO_VCC)
597 errorMsg += QStringLiteral(" CAN-transceiver CANL short to vcc\n");
598 if (b & CAN_ERR_TRX_CANL_SHORT_TO_GND)
599 errorMsg += QStringLiteral(" CAN-transceiver CANL short to ground\n");
600 if (b & CAN_ERR_TRX_CANL_SHORT_TO_CANH)
601 errorMsg += QStringLiteral(" CAN-transceiver CANL short to CANH\n");
602
603 if (b == CAN_ERR_TRX_UNSPEC)
604 errorMsg += QStringLiteral(" unspecified\n");
605 }
606
607 }
608
609 if (errorFrame.error() & QCanBusFrame::ProtocolViolationError) {
610 errorMsg += QStringLiteral("Protocol violation:\n");
611 if (data.size() > 3) {
612 char b = data.at(i: 2);
613 if (b & CAN_ERR_PROT_BIT)
614 errorMsg += QStringLiteral(" single bit error\n");
615 if (b & CAN_ERR_PROT_FORM)
616 errorMsg += QStringLiteral(" frame format error\n");
617 if (b & CAN_ERR_PROT_STUFF)
618 errorMsg += QStringLiteral(" bit stuffing error\n");
619 if (b & CAN_ERR_PROT_BIT0)
620 errorMsg += QStringLiteral(" unable to send dominant bit\n");
621 if (b & CAN_ERR_PROT_BIT1)
622 errorMsg += QStringLiteral(" unable to send recessive bit\n");
623 if (b & CAN_ERR_PROT_OVERLOAD)
624 errorMsg += QStringLiteral(" bus overload\n");
625 if (b & CAN_ERR_PROT_ACTIVE)
626 errorMsg += QStringLiteral(" active error announcement\n");
627 if (b & CAN_ERR_PROT_TX)
628 errorMsg += QStringLiteral(" error occurred on transmission\n");
629
630 if (b == CAN_ERR_PROT_UNSPEC)
631 errorMsg += QStringLiteral(" unspecified\n");
632 }
633 if (data.size() > 4) {
634 char b = data.at(i: 3);
635 if (b == CAN_ERR_PROT_LOC_SOF)
636 errorMsg += QStringLiteral(" start of frame\n");
637 if (b == CAN_ERR_PROT_LOC_ID28_21)
638 errorMsg += QStringLiteral(" ID bits 28 - 21 (SFF: 10 - 3)\n");
639 if (b == CAN_ERR_PROT_LOC_ID20_18)
640 errorMsg += QStringLiteral(" ID bits 20 - 18 (SFF: 2 - 0 )\n");
641 if (b == CAN_ERR_PROT_LOC_SRTR)
642 errorMsg += QStringLiteral(" substitute RTR (SFF: RTR)\n");
643 if (b == CAN_ERR_PROT_LOC_IDE)
644 errorMsg += QStringLiteral(" identifier extension\n");
645 if (b == CAN_ERR_PROT_LOC_ID17_13)
646 errorMsg += QStringLiteral(" ID bits 17-13\n");
647 if (b == CAN_ERR_PROT_LOC_ID12_05)
648 errorMsg += QStringLiteral(" ID bits 12-5\n");
649 if (b == CAN_ERR_PROT_LOC_ID04_00)
650 errorMsg += QStringLiteral(" ID bits 4-0\n");
651 if (b == CAN_ERR_PROT_LOC_RTR)
652 errorMsg += QStringLiteral(" RTR\n");
653 if (b == CAN_ERR_PROT_LOC_RES1)
654 errorMsg += QStringLiteral(" reserved bit 1\n");
655 if (b == CAN_ERR_PROT_LOC_RES0)
656 errorMsg += QStringLiteral(" reserved bit 0\n");
657 if (b == CAN_ERR_PROT_LOC_DLC)
658 errorMsg += QStringLiteral(" data length code\n");
659 if (b == CAN_ERR_PROT_LOC_DATA)
660 errorMsg += QStringLiteral(" data section\n");
661 if (b == CAN_ERR_PROT_LOC_CRC_SEQ)
662 errorMsg += QStringLiteral(" CRC sequence\n");
663 if (b == CAN_ERR_PROT_LOC_CRC_DEL)
664 errorMsg += QStringLiteral(" CRC delimiter\n");
665 if (b == CAN_ERR_PROT_LOC_ACK)
666 errorMsg += QStringLiteral(" ACK slot\n");
667 if (b == CAN_ERR_PROT_LOC_ACK_DEL)
668 errorMsg += QStringLiteral(" ACK delimiter\n");
669 if (b == CAN_ERR_PROT_LOC_EOF)
670 errorMsg += QStringLiteral(" end of frame\n");
671 if (b == CAN_ERR_PROT_LOC_INTERM)
672 errorMsg += QStringLiteral(" Intermission\n");
673
674 if (b == CAN_ERR_PROT_LOC_UNSPEC)
675 errorMsg += QStringLiteral(" unspecified\n");
676 }
677 }
678
679 // cut trailing \n
680 if (!errorMsg.isEmpty())
681 errorMsg.chop(n: 1);
682
683 return errorMsg;
684}
685
686void SocketCanBackend::readSocket()
687{
688 QVector<QCanBusFrame> newFrames;
689
690 for (;;) {
691 m_frame = {};
692 m_iov.iov_len = sizeof(m_frame);
693 m_msg.msg_namelen = sizeof(m_addr);
694 m_msg.msg_controllen = sizeof(m_ctrlmsg);
695 m_msg.msg_flags = 0;
696
697 const int bytesReceived = ::recvmsg(fd: canSocket, message: &m_msg, flags: 0);
698
699 if (bytesReceived <= 0) {
700 break;
701 } else if (Q_UNLIKELY(bytesReceived != CANFD_MTU && bytesReceived != CAN_MTU)) {
702 setError(errorText: tr(s: "ERROR SocketCanBackend: incomplete CAN frame"),
703 QCanBusDevice::CanBusError::ReadError);
704 continue;
705 } else if (Q_UNLIKELY(m_frame.len > bytesReceived - offsetof(canfd_frame, data))) {
706 setError(errorText: tr(s: "ERROR SocketCanBackend: invalid CAN frame length"),
707 QCanBusDevice::CanBusError::ReadError);
708 continue;
709 }
710
711 struct timeval timeStamp = {};
712 if (Q_UNLIKELY(ioctl(canSocket, SIOCGSTAMP, &timeStamp) < 0)) {
713 setError(errorText: qt_error_string(errno),
714 QCanBusDevice::CanBusError::ReadError);
715 timeStamp = {};
716 }
717
718 const QCanBusFrame::TimeStamp stamp(timeStamp.tv_sec, timeStamp.tv_usec);
719 QCanBusFrame bufferedFrame;
720 bufferedFrame.setTimeStamp(stamp);
721 bufferedFrame.setFlexibleDataRateFormat(bytesReceived == CANFD_MTU);
722
723 bufferedFrame.setExtendedFrameFormat(m_frame.can_id & CAN_EFF_FLAG);
724 Q_ASSERT(m_frame.len <= CANFD_MAX_DLEN);
725
726 if (m_frame.can_id & CAN_RTR_FLAG)
727 bufferedFrame.setFrameType(QCanBusFrame::RemoteRequestFrame);
728 if (m_frame.can_id & CAN_ERR_FLAG)
729 bufferedFrame.setFrameType(QCanBusFrame::ErrorFrame);
730 if (m_frame.flags & CANFD_BRS)
731 bufferedFrame.setBitrateSwitch(true);
732 if (m_frame.flags & CANFD_ESI)
733 bufferedFrame.setErrorStateIndicator(true);
734 if (m_msg.msg_flags & MSG_CONFIRM)
735 bufferedFrame.setLocalEcho(true);
736
737 bufferedFrame.setFrameId(m_frame.can_id & CAN_EFF_MASK);
738
739 const QByteArray load(reinterpret_cast<char *>(m_frame.data), m_frame.len);
740 bufferedFrame.setPayload(load);
741
742 newFrames.append(t: std::move(bufferedFrame));
743 }
744
745 enqueueReceivedFrames(newFrames);
746}
747
748void SocketCanBackend::resetController()
749{
750 libSocketCan->restart(interface: canSocketName);
751}
752
753bool SocketCanBackend::hasBusStatus() const
754{
755 if (isVirtual(canDevice: canSocketName.toLatin1()))
756 return false;
757
758 return libSocketCan->hasBusStatus();
759}
760
761QCanBusDevice::CanBusStatus SocketCanBackend::busStatus() const
762{
763 return libSocketCan->busStatus(interface: canSocketName);
764}
765
766QT_END_NAMESPACE
767

source code of qtserialbus/src/plugins/canbus/socketcan/socketcanbackend.cpp