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

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