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 "qcanbusdevice.h"
38#include "qcanbusdevice_p.h"
39#include "qcanbusdeviceinfo_p.h"
40
41#include "qcanbusframe.h"
42
43#include <QtCore/qdebug.h>
44#include <QtCore/qdatastream.h>
45#include <QtCore/qeventloop.h>
46#include <QtCore/qloggingcategory.h>
47#include <QtCore/qscopedvaluerollback.h>
48#include <QtCore/qtimer.h>
49
50QT_BEGIN_NAMESPACE
51
52Q_LOGGING_CATEGORY(QT_CANBUS, "qt.canbus")
53
54/*!
55 \class QCanBusDevice
56 \inmodule QtSerialBus
57 \since 5.8
58
59 \brief The QCanBusDevice class is the interface class for CAN bus.
60
61 QCanBusDevice communicates with a CAN plugin providing users with a convenient API.
62 The CAN plugin must be specified during the object creation.
63*/
64
65/*!
66 \enum QCanBusDevice::CanBusError
67 This enum describes all the possible error conditions.
68
69 \value NoError No errors have occurred.
70 \value ReadError An error occurred during a read operation.
71 \value WriteError An error occurred during a write operation.
72 \value ConnectionError An error occurred when attempting to open the plugin.
73 \value ConfigurationError An error occurred when attempting to set a configuration
74 parameter.
75 \value UnknownError An unknown error occurred.
76 \value OperationError An operation was attempted while the device was in
77 a state that did not permit it. This enum was introduced
78 in Qt 5.14.
79 \value TimeoutError An timeout occurred while waiting for frames written or
80 received. This enum was introduced in Qt 5.14.
81*/
82
83/*!
84 \enum QCanBusDevice::CanBusDeviceState
85 This enum describes all possible device states.
86
87 \value UnconnectedState The device is disconnected.
88 \value ConnectingState The device is being connected.
89 \value ConnectedState The device is connected to the CAN bus.
90 \value ClosingState The device is being closed.
91*/
92
93/*!
94 \enum QCanBusDevice::ConfigurationKey
95 This enum describes the possible configuration options for
96 the CAN bus connection.
97
98 \value RawFilterKey This configuration determines the type of CAN bus frames
99 that the current device accepts. The expected value
100 is \c QList<QCanBusDevice::Filter>. Passing an empty list clears
101 all previously set filters including default filters. For more details
102 see \l QCanBusDevice::Filter.
103 \value ErrorFilterKey This key defines the type of error that should be
104 forwarded via the current connection. The associated
105 value should be of type \l QCanBusFrame::FrameErrors.
106 \value LoopbackKey This key defines whether the CAN bus device should operate in loopback
107 mode. Loopback means, whenever a CAN frame is transmitted on the CAN
108 bus, a local echo of this frame is sent to all applications connected to
109 this CAN device. The expected value for this key is \c bool.
110 \value ReceiveOwnKey This key defines whether this CAN device receives its own send frames.
111 This can be used to check if the transmission was successful.
112 The expected value for this key is \c bool.
113 \value BitRateKey This key defines the CAN bitrate in bits per second. With CAN FD,
114 the payload can be transmitted at a higher data bitrate,
115 if \l QCanBusFrame::hasBitrateSwitch() is set. In this case,
116 \c QCanBusDevice::BitRateKey is only used for the CAN ID arbitration
117 phase. See also \c QCanBusDevice::DataBitRateKey
118 \value CanFdKey This key defines whether sending and receiving of CAN FD frames
119 should be enabled. The expected value for this key is \c bool.
120 \value DataBitRateKey This key defines the CAN FD payload bitrate in bits per second.
121 CAN FD allows to transmit the payload of frames with
122 \l QCanBusFrame::hasBitrateSwitch() flag at a higher data bitrate,
123 after the arbitration phase at the nominal bitrate is finished.
124 This enum value was introduced in Qt 5.9.
125 See also \c QCanBusDevice::BitRateKey
126 \value ProtocolKey This key allows to specify another protocol. For now, this
127 parameter can only be set and used in the SocketCAN plugin.
128 This enum value was introduced in Qt 5.14.
129 \value UserKey This key defines the range where custom keys start. Its most
130 common purpose is to permit platform-specific configuration
131 options.
132
133 \sa configurationParameter()
134*/
135
136/*!
137 \class QCanBusDevice::Filter
138 \inmodule QtSerialBus
139 \since 5.8
140
141 \brief The QCanBusDevice::Filter struct defines a filter for CAN bus frames.
142
143 A list of QCanBusDevice::Filter instances is passed to
144 \l QCanBusDevice::setConfigurationParameter() to enable filtering. If a received CAN frame
145 matches at least one of the filters in the list, the QCanBusDevice will accept it.
146
147 The example below demonstrates how to use the struct:
148
149 \snippet snippetmain.cpp Filter Examples
150*/
151
152/*!
153 \fn bool operator==(const QCanBusDevice::Filter &a, const QCanBusDevice::Filter &b)
154 \relates QCanBusDevice::Filter
155
156 Returns true, if the filter \a a is equal to the filter \a b,
157 otherwise returns false.
158*/
159
160/*!
161 \fn bool operator!=(const QCanBusDevice::Filter &a, const QCanBusDevice::Filter &b)
162 \relates QCanBusDevice::Filter
163
164 Returns true, if the filter \a a is not equal to the filter \a b,
165 otherwise returns false.
166*/
167
168/*!
169 \enum QCanBusDevice::Filter::FormatFilter
170 This enum describes the format pattern, which is used to filter incoming
171 CAN bus frames.
172
173 \value MatchBaseFormat The CAN bus frame must use the base frame format
174 (11 bit identifier).
175 \value MatchExtendedFormat The CAN bus frame must use the extended frame format
176 (29 bit identifier).
177 \value MatchBaseAndExtendedFormat The CAN bus frame can have a base or an extended
178 frame format.
179*/
180
181/*!
182 \variable QCanBusDevice::Filter::frameId
183
184 \brief The frame id used to filter the incoming frames.
185
186 The frameId is used in conjunction with \a frameIdMask.
187 The matching is successful if the following evaluates to \c true:
188
189 \code
190 (receivedFrameId & frameIdMask) == (frameId & frameIdMask)
191 \endcode
192
193 By default this field is set to \c 0x0.
194
195 \sa frameIdMask
196*/
197
198/*!
199 \variable QCanBusDevice::Filter::frameIdMask
200
201 \brief The bit mask that is applied to the frame id of the filter and the received frame.
202
203 The two frame ids are matching if the following evaluates to \c true:
204
205 \code
206 (receivedFrameId & frameIdMask) == (frameId & frameIdMask)
207 \endcode
208
209 By default this field is set to \c 0x0.
210
211 \sa frameId
212*/
213
214/*!
215 \variable QCanBusDevice::Filter::type
216
217 \brief The type of the frame to be filtered.
218
219 Any CAN bus frame type can be matched by setting this variable
220 to \l QCanBusFrame::InvalidFrame. The filter object is invalid if
221 type is equal to \l QCanBusFrame::UnknownFrame.
222
223 By default this field is set to \l QCanBusFrame::InvalidFrame.
224
225 \sa QCanBusFrame::FrameType
226*/
227
228/*!
229 \variable QCanBusDevice::Filter::format
230
231 \brief The frame format of the matching CAN bus frame.
232
233 By default this field is set to \l QCanBusDevice::Filter::MatchBaseAndExtendedFormat.
234*/
235
236/*!
237 \fn void QCanBusDevice::errorOccurred(CanBusError)
238
239 This signal is emitted when an error occurs.
240*/
241
242/*!
243 Constructs a serial bus device with the specified \a parent.
244*/
245QCanBusDevice::QCanBusDevice(QObject *parent) :
246 QObject(*new QCanBusDevicePrivate, parent)
247{
248}
249
250
251/*!
252 Sets the human readable description of the last device error to
253 \a errorText. \a errorId categorizes the type of error.
254
255 CAN bus implementations must use this function to update the device's
256 error state.
257
258 \sa error(), errorOccurred(), clearError()
259*/
260void QCanBusDevice::setError(const QString &errorText, CanBusError errorId)
261{
262 Q_D(QCanBusDevice);
263
264 d->errorText = errorText;
265 d->lastError = errorId;
266
267 emit errorOccurred(errorId);
268}
269
270/*!
271 \since 5.14
272 Clears the error id and the human readable description of the last
273 device error.
274
275 CAN bus implementations must use this function to update the device's
276 error state.
277
278 \sa error(), errorOccurred(), setError()
279*/
280void QCanBusDevice::clearError()
281{
282 Q_D(QCanBusDevice);
283
284 d->errorText.clear();
285 d->lastError = NoError;
286}
287
288/*!
289 Appends \a newFrames to the internal list of frames which can be
290 accessed using \l readFrame() and emits the \l framesReceived()
291 signal.
292
293 Subclasses must call this function when they receive frames.
294
295*/
296void QCanBusDevice::enqueueReceivedFrames(const QVector<QCanBusFrame> &newFrames)
297{
298 Q_D(QCanBusDevice);
299
300 if (Q_UNLIKELY(newFrames.isEmpty()))
301 return;
302
303 d->incomingFramesGuard.lock();
304 d->incomingFrames.append(l: newFrames);
305 d->incomingFramesGuard.unlock();
306 emit framesReceived();
307}
308
309/*!
310 Appends \a newFrame to the internal list of outgoing frames which
311 can be accessed by \l writeFrame().
312
313 Subclasses must call this function when they write a new frame.
314*/
315void QCanBusDevice::enqueueOutgoingFrame(const QCanBusFrame &newFrame)
316{
317 Q_D(QCanBusDevice);
318
319 d->outgoingFrames.append(t: newFrame);
320}
321
322/*!
323 Returns the next \l QCanBusFrame from the internal list of outgoing frames;
324 otherwise returns an invalid QCanBusFrame. The returned frame is removed
325 from the internal list.
326*/
327QCanBusFrame QCanBusDevice::dequeueOutgoingFrame()
328{
329 Q_D(QCanBusDevice);
330
331 if (Q_UNLIKELY(d->outgoingFrames.isEmpty()))
332 return QCanBusFrame(QCanBusFrame::InvalidFrame);
333 return d->outgoingFrames.takeFirst();
334}
335
336/*!
337 Returns \c true if the internal list of outgoing frames is not
338 empty; otherwise returns \c false.
339*/
340bool QCanBusDevice::hasOutgoingFrames() const
341{
342 Q_D(const QCanBusDevice);
343
344 return !d->outgoingFrames.isEmpty();
345}
346
347/*!
348 * \since 5.14
349 * Called from the derived plugin to register a function \a resetter which performs the
350 * CAN controller hardware reset when resetController() is called.
351 */
352void QCanBusDevice::setResetControllerFunction(std::function<void()> resetter)
353{
354 Q_D(QCanBusDevice);
355
356 d->m_resetControllerFunction = std::move(resetter);
357}
358
359/*!
360 * \since 5.14
361 * Called from the derived plugin to register a function \a busStatusGetter
362 * which returns the CAN controller bus status when busStatus() is called.
363 */
364void QCanBusDevice::setCanBusStatusGetter(std::function<CanBusStatus()> busStatusGetter)
365{
366 Q_D(QCanBusDevice);
367
368 d->m_busStatusGetter = std::move(busStatusGetter);
369}
370
371/*!
372 Sets the configuration parameter \a key for the CAN bus connection
373 to \a value. The potential keys are represented by \l ConfigurationKey.
374
375 A parameter can be unset by setting an invalid \l QVariant.
376 Unsetting a parameter implies that the configuration is reset to
377 its default setting.
378
379 \note In most cases, configuration changes only take effect
380 after a reconnect.
381
382 \sa configurationParameter()
383*/
384void QCanBusDevice::setConfigurationParameter(int key, const QVariant &value)
385{
386 Q_D(QCanBusDevice);
387
388 for (int i = 0; i < d->configOptions.size(); i++) {
389 if (d->configOptions.at(i).first == key) {
390 if (value.isValid()) {
391 ConfigEntry entry = d->configOptions.at(i);
392 entry.second = value;
393 d->configOptions.replace(i, t: entry);
394 } else {
395 d->configOptions.remove(i);
396 }
397 return;
398 }
399 }
400
401 if (!value.isValid())
402 return;
403
404 ConfigEntry newEntry(key, value);
405 d->configOptions.append(t: newEntry);
406}
407
408/*!
409 Returns the current value assigned to the \l ConfigurationKey \a key; otherwise
410 an invalid \l QVariant.
411
412 \sa setConfigurationParameter(), configurationKeys()
413*/
414QVariant QCanBusDevice::configurationParameter(int key) const
415{
416 Q_D(const QCanBusDevice);
417
418 for (const ConfigEntry &e : d->configOptions) {
419 if (e.first == key)
420 return e.second;
421 }
422
423 return QVariant();
424}
425
426/*!
427 Returns the list of keys used by the CAN bus connection.
428
429 The the meaning of the keys is equivalent to \l ConfigurationKey.
430 If a key is not explicitly mentioned the platform's
431 default setting for the relevant key is used.
432*/
433QVector<int> QCanBusDevice::configurationKeys() const
434{
435 Q_D(const QCanBusDevice);
436
437 QVector<int> result;
438 for (const ConfigEntry &e : d->configOptions)
439 result.append(t: e.first);
440
441 return result;
442}
443
444/*!
445 Returns the last error that has occurred. The error value is always set to last error that
446 occurred and it is never reset.
447
448 \sa errorString()
449*/
450QCanBusDevice::CanBusError QCanBusDevice::error() const
451{
452 return d_func()->lastError;
453}
454
455/*!
456 Returns a human-readable description of the last device error that occurred.
457
458 \sa error()
459*/
460QString QCanBusDevice::errorString() const
461{
462 Q_D(const QCanBusDevice);
463
464 if (d->lastError == QCanBusDevice::NoError)
465 return QString();
466
467 return d->errorText;
468}
469
470/*!
471 Returns the number of available frames. If no frames are available,
472 this function returns 0.
473
474 \sa clear(), readFrame(), readAllFrames()
475*/
476qint64 QCanBusDevice::framesAvailable() const
477{
478 return d_func()->incomingFrames.size();
479}
480
481/*!
482 For buffered devices, this function returns the number of frames waiting to be written.
483 For unbuffered devices, this function always returns zero.
484
485 \note There may be additional buffering in the CAN driver and CAN hardware layer.
486 Therefore, if this function returns zero, that does not mean all CAN frames are
487 already written to the CAN bus.
488
489 \sa clear(), writeFrame()
490*/
491qint64 QCanBusDevice::framesToWrite() const
492{
493 return d_func()->outgoingFrames.size();
494}
495
496/*!
497 \since 5.14
498
499 Performs a CAN controller reset to release the CAN controller from
500 bus off state, if possible.
501
502 \note CAN controller resets disturb the running communication and
503 may take up to one second to complete. Only call this function to
504 recover from bus errors.
505
506 \note This function may not be implemented in all CAN plugins.
507 Please refer to the plugins help pages for more information.
508
509 \sa busStatus()
510*/
511void QCanBusDevice::resetController()
512{
513 if (d_func()->m_resetControllerFunction) {
514 d_func()->m_resetControllerFunction();
515 } else {
516 const char error[] = QT_TRANSLATE_NOOP("QCanBusDevice",
517 "This CAN bus plugin does not support hardware controller reset.");
518 qCWarning(QT_CANBUS, error);
519 setError(errorText: tr(s: error), errorId: QCanBusDevice::CanBusError::ConfigurationError);
520 }
521}
522
523/*!
524 \since 5.14
525
526 Return true, if the CAN plugin supports requesting the CAN bus status.
527
528 \sa busStatus()
529 */
530bool QCanBusDevice::hasBusStatus() const
531{
532 return d_func()->m_busStatusGetter != nullptr;
533}
534
535/*!
536 \since 5.14
537 \enum QCanBusDevice::CanBusStatus
538
539 This enum describes possible CAN bus status values.
540
541 \value Unknown The CAN bus status is unknown
542 (e.g. not supported by the CAN plugin).
543 \value Good The CAN controller is fully operational
544 \value Warning The CAN controller is in warning status
545 \value Error The CAN controller is in error status
546 (no longer sending CAN frames)
547 \value BusOff The CAN controller is in bus off status
548 (disconnected from the CAN bus)
549*/
550
551/*!
552 \since 5.14
553
554 Returns the current CAN bus status. If the status cannot be requested,
555 QCanBusDevice::UnknownStatus is returned.
556
557 \note This function may not be implemented in all CAN plugins.
558 Please refer to the plugins help pages for more information.
559 The function hasBusStatus() can be used at runtime to check if
560 the used CAN plugin has support for requesting the CAN bus status.
561
562 \sa hasBusStatus(), resetController()
563*/
564QCanBusDevice::CanBusStatus QCanBusDevice::busStatus() const
565{
566 if (d_func()->m_busStatusGetter)
567 return d_func()->m_busStatusGetter();
568
569 return QCanBusDevice::CanBusStatus::Unknown;
570}
571
572/*!
573 \since 5.12
574 \enum QCanBusDevice::Direction
575
576 This enum describes possible data transmission directions.
577
578 \value Input Input direction.
579 \value Output Output direction.
580 \value AllDirections Both directions, input and output.
581*/
582
583/*!
584 \since 5.12
585 Clears the devices input or output buffers, depending on \a direction.
586
587 This function only operates on QCanBusDevice buffers. Frames that are
588 already written to the CAN driver or CAN hardware layer, or that are
589 not yet read from these layers, are not cleared by this function.
590
591 \note Clearing the output buffers is only possible for buffered devices.
592
593 \sa framesAvailable(), readFrame(), framesToWrite(), writeFrame(),
594*/
595void QCanBusDevice::clear(QCanBusDevice::Directions direction)
596{
597 Q_D(QCanBusDevice);
598
599 if (Q_UNLIKELY(d->state != ConnectedState)) {
600 const QString error = tr(s: "Cannot clear buffers as device is not connected.");
601 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
602 setError(errorText: error, errorId: CanBusError::OperationError);
603 return;
604 }
605
606 clearError();
607
608 if (direction & Direction::Input) {
609 QMutexLocker locker(&d->incomingFramesGuard);
610 d->incomingFrames.clear();
611 }
612
613 if (direction & Direction::Output)
614 d->outgoingFrames.clear();
615}
616
617/*!
618 For buffered devices, this function waits until all buffered frames
619 have been written to the device and the \l framesWritten() signal has been emitted,
620 or until \a msecs milliseconds have passed. If \a msecs is -1,
621 this function will not time out. For unbuffered devices, it returns immediately with \c false
622 as \l writeFrame() does not require a write buffer.
623
624 Returns \c true if the \l framesWritten() signal is emitted;
625 otherwise returns \c false (i.e. if the operation timed out, or if an error occurred).
626
627 \note This function will start a local event loop. This may lead to scenarios whereby
628 other application slots may be called while the execution of this function scope is blocking.
629 To avoid problems, the signals for this class should not be connected to slots.
630 Similarly this function must never be called in response to the \l framesWritten()
631 or \l errorOccurred() signals.
632
633 \sa waitForFramesReceived()
634 */
635bool QCanBusDevice::waitForFramesWritten(int msecs)
636{
637 // do not enter this function recursively
638 if (Q_UNLIKELY(d_func()->waitForWrittenEntered)) {
639 qCWarning(QT_CANBUS, "QCanBusDevice::waitForFramesWritten() must not be called "
640 "recursively. Check that no slot containing waitForFramesReceived() "
641 "is called in response to framesWritten(qint64) or "
642 "errorOccurred(CanBusError) signals.");
643 setError(errorText: tr(s: "QCanBusDevice::waitForFramesWritten() must not be called recursively."),
644 errorId: CanBusError::OperationError);
645 return false;
646 }
647
648 if (Q_UNLIKELY(d_func()->state != ConnectedState)) {
649 const QString error = tr(s: "Cannot wait for frames written as device is not connected.");
650 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
651 setError(errorText: error, errorId: CanBusError::OperationError);
652 return false;
653 }
654
655 if (!framesToWrite())
656 return false; // nothing pending, nothing to wait upon
657
658 QScopedValueRollback<bool> guard(d_func()->waitForWrittenEntered);
659 d_func()->waitForWrittenEntered = true;
660
661 enum { Written = 0, Error, Timeout };
662 QEventLoop loop;
663 connect(sender: this, signal: &QCanBusDevice::framesWritten, context: &loop, slot: [&]() { loop.exit(returnCode: Written); });
664 connect(sender: this, signal: &QCanBusDevice::errorOccurred, context: &loop, slot: [&]() { loop.exit(returnCode: Error); });
665 if (msecs >= 0)
666 QTimer::singleShot(interval: msecs, context: &loop, slot: [&]() { loop.exit(returnCode: Timeout); });
667
668 int result = Written;
669 while (framesToWrite() > 0) {
670 // wait till all written or time out
671 result = loop.exec(flags: QEventLoop::ExcludeUserInputEvents);
672 if (Q_UNLIKELY(result == Timeout)) {
673 const QString error = tr(s: "Timeout (%1 ms) during wait for frames written.").arg(a: msecs);
674 setError(errorText: error, errorId: CanBusError::TimeoutError);
675 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
676 }
677
678 if (result > Written)
679 return false;
680 }
681
682 clearError();
683 return true;
684}
685
686/*!
687 Blocks until new frames are available for reading and the \l framesReceived()
688 signal has been emitted, or until \a msecs milliseconds have passed. If
689 \a msecs is \c -1, this function will not time out.
690
691 Returns \c true if new frames are available for reading and the \l framesReceived()
692 signal is emitted; otherwise returns \c false (if the operation timed out
693 or if an error occurred).
694
695 \note This function will start a local event loop. This may lead to scenarios whereby
696 other application slots may be called while the execution of this function scope is blocking.
697 To avoid problems, the signals for this class should not be connected to slots.
698 Similarly this function must never be called in response to the \l framesReceived()
699 or \l errorOccurred() signals.
700
701 \sa waitForFramesWritten()
702 */
703bool QCanBusDevice::waitForFramesReceived(int msecs)
704{
705 // do not enter this function recursively
706 if (Q_UNLIKELY(d_func()->waitForReceivedEntered)) {
707 qCWarning(QT_CANBUS, "QCanBusDevice::waitForFramesReceived() must not be called "
708 "recursively. Check that no slot containing waitForFramesReceived() "
709 "is called in response to framesReceived() or "
710 "errorOccurred(CanBusError) signals.");
711 setError(errorText: tr(s: "QCanBusDevice::waitForFramesReceived() must not be called recursively."),
712 errorId: CanBusError::OperationError);
713 return false;
714 }
715
716 if (Q_UNLIKELY(d_func()->state != ConnectedState)) {
717 const QString error = tr(s: "Cannot wait for frames received as device is not connected.");
718 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
719 setError(errorText: error, errorId: CanBusError::OperationError);
720 return false;
721 }
722
723 QScopedValueRollback<bool> guard(d_func()->waitForReceivedEntered);
724 d_func()->waitForReceivedEntered = true;
725
726 enum { Received = 0, Error, Timeout };
727 QEventLoop loop;
728 connect(sender: this, signal: &QCanBusDevice::framesReceived, context: &loop, slot: [&]() { loop.exit(returnCode: Received); });
729 connect(sender: this, signal: &QCanBusDevice::errorOccurred, context: &loop, slot: [&]() { loop.exit(returnCode: Error); });
730 if (msecs >= 0)
731 QTimer::singleShot(interval: msecs, context: &loop, slot: [&]() { loop.exit(returnCode: Timeout); });
732
733 int result = loop.exec(flags: QEventLoop::ExcludeUserInputEvents);
734
735 if (Q_UNLIKELY(result == Timeout)) {
736 const QString error = tr(s: "Timeout (%1 ms) during wait for frames received.").arg(a: msecs);
737 setError(errorText: error, errorId: CanBusError::TimeoutError);
738 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
739 }
740
741 if (result == Received)
742 clearError();
743 return result == Received;
744}
745
746/*!
747 \fn bool QCanBusDevice::open()
748
749 This function is called by connectDevice(). Subclasses must provide
750 an implementation which returns \c true if the CAN bus connection
751 could be established; otherwise \c false. The QCanBusDevice implementation
752 ensures upon entry of this function that the device's \l state() is set
753 to \l QCanBusDevice::ConnectingState already.
754
755 The implementation must ensure that upon success the instance's \l state()
756 is set to \l QCanBusDevice::ConnectedState; otherwise
757 \l QCanBusDevice::UnconnectedState. \l setState() must be used to set the new
758 device state.
759
760 The custom implementation is responsible for opening the socket, instanciation
761 of a potentially required \l QSocketNotifier and the application of custom and default
762 \l QCanBusDevice::configurationParameter().
763
764 \sa connectDevice()
765*/
766
767/*!
768 \fn void QCanBusDevice::close()
769
770 This function is responsible for closing the CAN bus connection.
771 The implementation must ensure that the instance's
772 \l state() is set to \l QCanBusDevice::UnconnectedState.
773
774 This function's most important task is to close the socket to the CAN device
775 and to call \l QCanBusDevice::setState().
776
777 \sa disconnectDevice()
778*/
779
780/*!
781 \fn void QCanBusDevice::framesReceived()
782
783 This signal is emitted when one or more frames have been received.
784 The frames should be read using \l readFrame() and \l framesAvailable().
785*/
786
787/*!
788 Returns the next \l QCanBusFrame from the queue; otherwise returns
789 an empty QCanBusFrame. The returned frame is removed from the queue.
790
791 The queue operates according to the FIFO principle.
792
793 \sa clear(), framesAvailable(), readAllFrames()
794*/
795QCanBusFrame QCanBusDevice::readFrame()
796{
797 Q_D(QCanBusDevice);
798
799 if (Q_UNLIKELY(d->state != ConnectedState)) {
800 const QString error = tr(s: "Cannot read frame as device is not connected.");
801 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
802 setError(errorText: error, errorId: CanBusError::OperationError);
803 return QCanBusFrame(QCanBusFrame::InvalidFrame);
804 }
805
806 clearError();
807
808 QMutexLocker locker(&d->incomingFramesGuard);
809
810 if (Q_UNLIKELY(d->incomingFrames.isEmpty()))
811 return QCanBusFrame(QCanBusFrame::InvalidFrame);
812
813 return d->incomingFrames.takeFirst();
814}
815
816/*!
817 \since 5.12
818 Returns all \l{QCanBusFrame}s from the queue; otherwise returns
819 an empty QVector. The returned frames are removed from the queue.
820
821 The queue operates according to the FIFO principle.
822
823 \sa clear(), framesAvailable(), readFrame()
824*/
825QVector<QCanBusFrame> QCanBusDevice::readAllFrames()
826{
827 Q_D(QCanBusDevice);
828
829 if (Q_UNLIKELY(d->state != ConnectedState)) {
830 const QString error = tr(s: "Cannot read frame as device is not connected.");
831 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
832 setError(errorText: error, errorId: CanBusError::OperationError);
833 return QVector<QCanBusFrame>();
834 }
835
836 clearError();
837
838 QMutexLocker locker(&d->incomingFramesGuard);
839
840 QVector<QCanBusFrame> result;
841 result.swap(other&: d->incomingFrames);
842 return result;
843}
844
845/*!
846 \fn void QCanBusDevice::framesWritten(qint64 framesCount)
847
848 This signal is emitted every time a payload of frames has been
849 written to the CAN bus. The \a framesCount argument is set to
850 the number of frames that were written in this payload.
851*/
852
853/*!
854 \fn bool QCanBusDevice::writeFrame(const QCanBusFrame &frame)
855
856 Writes \a frame to the CAN bus and returns \c true on success;
857 otherwise \c false.
858
859 On some platforms, the frame may be put into a queue and the return
860 value may only indicate a successful insertion into the queue.
861 The actual frame will be send later on. Therefore the \l framesWritten()
862 signal is the final confirmation that the frame has been handed off to
863 the transport layer. If an error occurs the \l errorOccurred() is emitted.
864
865 As per CAN bus specification, frames of type
866 \l {QCanBusFrame::RemoteRequestFrame} {remote transfer request (RTR)}
867 do not have a payload, but a length from 0 to 8 (including). This length
868 indicates the expected response payload length from the remote party.
869 Therefore when sending a RTR frame using this function it may still
870 be required to set an arbitrary payload on \a frame. The length of
871 the arbitrary payload is what is set as size expectation for the RTR frame.
872
873 \sa QCanBusFrame::setPayload()
874*/
875
876/*!
877 \fn QString QCanBusDevice::interpretErrorFrame(const QCanBusFrame &frame)
878
879 Interprets \a frame as error frame and returns a human readable
880 description of the error.
881
882 If \a frame is not an error frame, the returned string is empty.
883*/
884
885/*!
886 Connects the device to the CAN bus. Returns \c true on success;
887 otherwise \c false.
888
889 This function calls \l open() as part of its implementation.
890
891 \sa disconnectDevice()
892*/
893bool QCanBusDevice::connectDevice()
894{
895 Q_D(QCanBusDevice);
896
897 if (Q_UNLIKELY(d->state != QCanBusDevice::UnconnectedState)) {
898 const char error[] = QT_TRANSLATE_NOOP("QCanBusDevice",
899 "Can not connect an already connected device.");
900 qCWarning(QT_CANBUS, error);
901 setError(errorText: tr(s: error), errorId: QCanBusDevice::ConnectionError);
902 return false;
903 }
904
905 setState(ConnectingState);
906
907 if (!open()) {
908 setState(UnconnectedState);
909 return false;
910 }
911
912 clearError();
913
914 //Connected is set by backend -> might be delayed by event loop
915 return true;
916}
917
918
919/*!
920 Disconnects the device from the CAN bus.
921
922 This function calls \l close() as part of its implementation.
923
924 \note This function should only be called, if connectDevice()
925 returned \c true.
926
927 \sa connectDevice()
928*/
929void QCanBusDevice::disconnectDevice()
930{
931 Q_D(QCanBusDevice);
932
933 if (Q_UNLIKELY(d->state == QCanBusDevice::UnconnectedState
934 || d->state == QCanBusDevice::ClosingState)) {
935 qCWarning(QT_CANBUS, "Can not disconnect an unconnected device.");
936 return;
937 }
938
939 setState(QCanBusDevice::ClosingState);
940
941 //Unconnected is set by backend -> might be delayed by event loop
942 close();
943}
944
945/*!
946 \fn void QCanBusDevice::stateChanged(QCanBusDevice::CanBusDeviceState state)
947
948 This signal is emitted every time the state of the device changes.
949 The new state is represented by \a state.
950
951 \sa setState(), state()
952*/
953
954/*!
955 Returns the current state of the device.
956
957 \sa setState(), stateChanged()
958*/
959QCanBusDevice::CanBusDeviceState QCanBusDevice::state() const
960{
961 return d_func()->state;
962}
963
964/*!
965 Sets the state of the device to \a newState. CAN bus implementations
966 must use this function to update the device state.
967*/
968void QCanBusDevice::setState(QCanBusDevice::CanBusDeviceState newState)
969{
970 Q_D(QCanBusDevice);
971
972 if (newState == d->state)
973 return;
974
975 d->state = newState;
976 emit stateChanged(state: newState);
977}
978
979/*!
980 * Returns a QCanBusDeviceInfo created from the given parameters \a name,
981 * \a isVirtual, and \a isFlexibleDataRateCapable.
982 * \internal
983 */
984QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, bool isVirtual,
985 bool isFlexibleDataRateCapable)
986{
987 return createDeviceInfo(name, serialNumber: QString(), description: QString(), channel: 0, isVirtual, isFlexibleDataRateCapable);
988}
989
990/*!
991 \since 5.11
992 Returns a QCanBusDeviceInfo created from the given parameters \a name,
993 \a serialNumber, \a description, \a channel, \a isVirtual, and \a
994 isFlexibleDataRateCapable.
995 \internal
996 */
997QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &name, const QString &serialNumber,
998 const QString &description, int channel,
999 bool isVirtual, bool isFlexibleDataRateCapable)
1000{
1001 QScopedPointer<QCanBusDeviceInfoPrivate> info(new QCanBusDeviceInfoPrivate);
1002 info->name = name;
1003 info->serialNumber = serialNumber;
1004 info->description = description;
1005 info->channel = channel;
1006 info->hasFlexibleDataRate = isFlexibleDataRateCapable;
1007 info->isVirtual = isVirtual;
1008 return QCanBusDeviceInfo(*info.take());
1009}
1010
1011QT_END_NAMESPACE
1012

source code of qtserialbus/src/serialbus/qcanbusdevice.cpp