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