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

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