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_STATIC_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[i];
333 entry.second = value;
334 } else {
335 d->configOptions.remove(i);
336 }
337 return;
338 }
339 }
340
341 if (!value.isValid())
342 return;
343
344 ConfigEntry newEntry(key, value);
345 d->configOptions.append(t: newEntry);
346}
347
348/*!
349 Returns the current value assigned to the \l ConfigurationKey \a key; otherwise
350 an invalid \l QVariant.
351
352 \sa setConfigurationParameter(), configurationKeys()
353*/
354QVariant QCanBusDevice::configurationParameter(ConfigurationKey key) const
355{
356 Q_D(const QCanBusDevice);
357
358 for (const ConfigEntry &e : d->configOptions) {
359 if (e.first == key)
360 return e.second;
361 }
362
363 return QVariant();
364}
365
366/*!
367 Returns the list of keys used by the CAN bus connection.
368
369 The meaning of the keys is equivalent to \l ConfigurationKey.
370 If a key is not explicitly mentioned, the platform's
371 default setting for the relevant key is used.
372*/
373QList<QCanBusDevice::ConfigurationKey> QCanBusDevice::configurationKeys() const
374{
375 Q_D(const QCanBusDevice);
376
377 QList<ConfigurationKey> result;
378 for (const ConfigEntry &e : d->configOptions)
379 result.append(t: e.first);
380
381 return result;
382}
383
384/*!
385 Returns the last error that has occurred. The error value is always set to last error that
386 occurred and it is never reset.
387
388 \sa errorString()
389*/
390QCanBusDevice::CanBusError QCanBusDevice::error() const
391{
392 return d_func()->lastError;
393}
394
395/*!
396 Returns a human-readable description of the last device error that occurred.
397
398 \sa error()
399*/
400QString QCanBusDevice::errorString() const
401{
402 Q_D(const QCanBusDevice);
403
404 if (d->lastError == QCanBusDevice::NoError)
405 return QString();
406
407 return d->errorText;
408}
409
410/*!
411 Returns the number of available frames. If no frames are available,
412 this function returns 0.
413
414 \sa clear(), readFrame(), readAllFrames()
415*/
416qint64 QCanBusDevice::framesAvailable() const
417{
418 Q_D(const QCanBusDevice);
419
420 QMutexLocker locker(&d->incomingFramesGuard);
421 return d->incomingFrames.size();
422}
423
424/*!
425 For buffered devices, this function returns the number of frames waiting to be written.
426 For unbuffered devices, this function always returns zero.
427
428 \note There may be additional buffering in the CAN driver and CAN hardware layer.
429 Therefore, if this function returns zero, that does not mean all CAN frames are
430 already written to the CAN bus.
431
432 \sa clear(), writeFrame()
433*/
434qint64 QCanBusDevice::framesToWrite() const
435{
436 return d_func()->outgoingFrames.size();
437}
438
439/*!
440 \since 5.14
441
442 Performs a CAN controller reset to release the CAN controller from
443 bus off state, if possible.
444
445 \note CAN controller resets disturb the running communication and
446 may take up to one second to complete. Only call this function to
447 recover from bus errors.
448
449 \note This function may not be implemented in all CAN plugins.
450 Please refer to the plugins help pages for more information.
451
452 \sa busStatus()
453*/
454void QCanBusDevice::resetController()
455{
456 const char error[] = QT_TRANSLATE_NOOP("QCanBusDevice",
457 "This CAN bus plugin does not support hardware controller reset.");
458 qCWarning(QT_CANBUS, error);
459 setError(errorText: tr(s: error), errorId: QCanBusDevice::CanBusError::ConfigurationError);
460}
461
462/*!
463 \since 5.14
464
465 Return true, if the CAN plugin supports requesting the CAN bus status.
466
467 \sa busStatus()
468 */
469bool QCanBusDevice::hasBusStatus() const
470{
471 return false;
472}
473
474/*!
475 \since 5.14
476 \enum QCanBusDevice::CanBusStatus
477
478 This enum describes possible CAN bus status values.
479
480 \value Unknown The CAN bus status is unknown
481 (e.g. not supported by the CAN plugin).
482 \value Good The CAN controller is fully operational
483 \value Warning The CAN controller is in warning status
484 \value Error The CAN controller is in error status
485 (no longer sending CAN frames)
486 \value BusOff The CAN controller is in bus off status
487 (disconnected from the CAN bus)
488*/
489
490/*!
491 \since 5.14
492
493 Returns the current CAN bus status. If the status cannot be requested,
494 QCanBusDevice::UnknownStatus is returned.
495
496 \note This function may not be implemented in all CAN plugins.
497 Please refer to the plugins help pages for more information.
498 The function hasBusStatus() can be used at runtime to check if
499 the used CAN plugin has support for requesting the CAN bus status.
500
501 \sa hasBusStatus(), resetController()
502*/
503QCanBusDevice::CanBusStatus QCanBusDevice::busStatus()
504{
505 return QCanBusDevice::CanBusStatus::Unknown;
506}
507
508/*!
509 \since 5.12
510 \enum QCanBusDevice::Direction
511
512 This enum describes possible data transmission directions.
513
514 \value Input Input direction.
515 \value Output Output direction.
516 \value AllDirections Both directions, input and output.
517*/
518
519/*!
520 \since 5.12
521 Clears the devices input or output buffers, depending on \a direction.
522
523 This function only operates on QCanBusDevice buffers. Frames that are
524 already written to the CAN driver or CAN hardware layer, or that are
525 not yet read from these layers, are not cleared by this function.
526
527 \note Clearing the output buffers is only possible for buffered devices.
528
529 \sa framesAvailable(), readFrame(), framesToWrite(), writeFrame(),
530*/
531void QCanBusDevice::clear(QCanBusDevice::Directions direction)
532{
533 Q_D(QCanBusDevice);
534
535 if (Q_UNLIKELY(d->state != ConnectedState)) {
536 const QString error = tr(s: "Cannot clear buffers as device is not connected.");
537 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
538 setError(errorText: error, errorId: CanBusError::OperationError);
539 return;
540 }
541
542 clearError();
543
544 if (direction & Direction::Input) {
545 QMutexLocker locker(&d->incomingFramesGuard);
546 d->incomingFrames.clear();
547 }
548
549 if (direction & Direction::Output)
550 d->outgoingFrames.clear();
551}
552
553/*!
554 For buffered devices, this function waits until all buffered frames
555 have been written to the device and the \l framesWritten() signal has been emitted,
556 or until \a msecs milliseconds have passed. If \a msecs is -1,
557 this function will not time out. For unbuffered devices, it returns immediately with \c false
558 as \l writeFrame() does not require a write buffer.
559
560 Returns \c true if the \l framesWritten() signal is emitted;
561 otherwise returns \c false (i.e. if the operation timed out, or if an error occurred).
562
563 \note This function will start a local event loop. This may lead to scenarios whereby
564 other application slots may be called while the execution of this function scope is blocking.
565 To avoid problems, the signals for this class should not be connected to slots.
566 Similarly this function must never be called in response to the \l framesWritten()
567 or \l errorOccurred() signals.
568
569 \sa waitForFramesReceived()
570 */
571bool QCanBusDevice::waitForFramesWritten(int msecs)
572{
573 // do not enter this function recursively
574 if (Q_UNLIKELY(d_func()->waitForWrittenEntered)) {
575 qCWarning(QT_CANBUS, "QCanBusDevice::waitForFramesWritten() must not be called "
576 "recursively. Check that no slot containing waitForFramesWritten() "
577 "is called in response to framesWritten(qint64) or "
578 "errorOccurred(CanBusError) signals.");
579 setError(errorText: tr(s: "QCanBusDevice::waitForFramesWritten() must not be called recursively."),
580 errorId: CanBusError::OperationError);
581 return false;
582 }
583
584 if (Q_UNLIKELY(d_func()->state != ConnectedState)) {
585 const QString error = tr(s: "Cannot wait for frames written as device is not connected.");
586 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
587 setError(errorText: error, errorId: CanBusError::OperationError);
588 return false;
589 }
590
591 if (!framesToWrite())
592 return false; // nothing pending, nothing to wait upon
593
594 QScopedValueRollback<bool> guard(d_func()->waitForWrittenEntered);
595 d_func()->waitForWrittenEntered = true;
596
597 enum { Written = 0, Error, Timeout };
598 QEventLoop loop;
599 connect(sender: this, signal: &QCanBusDevice::framesWritten, context: &loop, slot: [&]() { loop.exit(returnCode: Written); });
600 connect(sender: this, signal: &QCanBusDevice::errorOccurred, context: &loop, slot: [&]() { loop.exit(returnCode: Error); });
601 if (msecs >= 0)
602 QTimer::singleShot(interval: msecs, receiver: &loop, slot: [&]() { loop.exit(returnCode: Timeout); });
603
604 int result = Written;
605 while (framesToWrite() > 0) {
606 // wait till all written or time out
607 result = loop.exec(flags: QEventLoop::ExcludeUserInputEvents);
608 if (Q_UNLIKELY(result == Timeout)) {
609 const QString error = tr(s: "Timeout (%1 ms) during wait for frames written.").arg(a: msecs);
610 setError(errorText: error, errorId: CanBusError::TimeoutError);
611 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
612 }
613
614 if (result > Written)
615 return false;
616 }
617
618 clearError();
619 return true;
620}
621
622/*!
623 Blocks until new frames are available for reading and the \l framesReceived()
624 signal has been emitted, or until \a msecs milliseconds have passed. If
625 \a msecs is \c -1, this function will not time out.
626
627 Returns \c true if new frames are available for reading and the \l framesReceived()
628 signal is emitted; otherwise returns \c false (if the operation timed out
629 or if an error occurred).
630
631 \note This function will start a local event loop. This may lead to scenarios whereby
632 other application slots may be called while the execution of this function scope is blocking.
633 To avoid problems, the signals for this class should not be connected to slots.
634 Similarly this function must never be called in response to the \l framesReceived()
635 or \l errorOccurred() signals.
636
637 \sa waitForFramesWritten()
638 */
639bool QCanBusDevice::waitForFramesReceived(int msecs)
640{
641 // do not enter this function recursively
642 if (Q_UNLIKELY(d_func()->waitForReceivedEntered)) {
643 qCWarning(QT_CANBUS, "QCanBusDevice::waitForFramesReceived() must not be called "
644 "recursively. Check that no slot containing waitForFramesReceived() "
645 "is called in response to framesReceived() or "
646 "errorOccurred(CanBusError) signals.");
647 setError(errorText: tr(s: "QCanBusDevice::waitForFramesReceived() must not be called recursively."),
648 errorId: CanBusError::OperationError);
649 return false;
650 }
651
652 if (Q_UNLIKELY(d_func()->state != ConnectedState)) {
653 const QString error = tr(s: "Cannot wait for frames received as device is not connected.");
654 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
655 setError(errorText: error, errorId: CanBusError::OperationError);
656 return false;
657 }
658
659 QScopedValueRollback<bool> guard(d_func()->waitForReceivedEntered);
660 d_func()->waitForReceivedEntered = true;
661
662 enum { Received = 0, Error, Timeout };
663 QEventLoop loop;
664 connect(sender: this, signal: &QCanBusDevice::framesReceived, context: &loop, slot: [&]() { loop.exit(returnCode: Received); });
665 connect(sender: this, signal: &QCanBusDevice::errorOccurred, context: &loop, slot: [&]() { loop.exit(returnCode: Error); });
666 if (msecs >= 0)
667 QTimer::singleShot(interval: msecs, receiver: &loop, slot: [&]() { loop.exit(returnCode: Timeout); });
668
669 int result = loop.exec(flags: QEventLoop::ExcludeUserInputEvents);
670
671 if (Q_UNLIKELY(result == Timeout)) {
672 const QString error = tr(s: "Timeout (%1 ms) during wait for frames received.").arg(a: msecs);
673 setError(errorText: error, errorId: CanBusError::TimeoutError);
674 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
675 }
676
677 if (result == Received)
678 clearError();
679 return result == Received;
680}
681
682/*!
683 \fn bool QCanBusDevice::open()
684
685 This function is called by connectDevice(). Subclasses must provide
686 an implementation which returns \c true if the CAN bus connection
687 could be established; otherwise \c false. The QCanBusDevice implementation
688 ensures upon entry of this function that the device's \l state() is set
689 to \l QCanBusDevice::ConnectingState already.
690
691 The implementation must ensure that upon success the instance's \l state()
692 is set to \l QCanBusDevice::ConnectedState; otherwise
693 \l QCanBusDevice::UnconnectedState. \l setState() must be used to set the new
694 device state.
695
696 The custom implementation is responsible for opening the socket, instanciation
697 of a potentially required \l QSocketNotifier and the application of custom and default
698 \l QCanBusDevice::configurationParameter().
699
700 \sa connectDevice()
701*/
702
703/*!
704 \fn void QCanBusDevice::close()
705
706 This function is responsible for closing the CAN bus connection.
707 The implementation must ensure that the instance's
708 \l state() is set to \l QCanBusDevice::UnconnectedState.
709
710 This function's most important task is to close the socket to the CAN device
711 and to call \l QCanBusDevice::setState().
712
713 \sa disconnectDevice()
714*/
715
716/*!
717 \fn void QCanBusDevice::framesReceived()
718
719 This signal is emitted when one or more frames have been received.
720 The frames should be read using \l readFrame() and \l framesAvailable().
721*/
722
723/*!
724 Returns the next \l QCanBusFrame from the queue; otherwise returns
725 an empty QCanBusFrame. The returned frame is removed from the queue.
726
727 The queue operates according to the FIFO principle.
728
729 \sa clear(), framesAvailable(), readAllFrames()
730*/
731QCanBusFrame QCanBusDevice::readFrame()
732{
733 Q_D(QCanBusDevice);
734
735 if (Q_UNLIKELY(d->state != ConnectedState)) {
736 const QString error = tr(s: "Cannot read frame as device is not connected.");
737 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
738 setError(errorText: error, errorId: CanBusError::OperationError);
739 return QCanBusFrame(QCanBusFrame::InvalidFrame);
740 }
741
742 clearError();
743
744 QMutexLocker locker(&d->incomingFramesGuard);
745
746 if (Q_UNLIKELY(d->incomingFrames.isEmpty()))
747 return QCanBusFrame(QCanBusFrame::InvalidFrame);
748
749 return d->incomingFrames.takeFirst();
750}
751
752/*!
753 \since 5.12
754 Returns all \l{QCanBusFrame}s from the queue; otherwise returns
755 an empty QList. The returned frames are removed from the queue.
756
757 The queue operates according to the FIFO principle.
758
759 \sa clear(), framesAvailable(), readFrame()
760*/
761QList<QCanBusFrame> QCanBusDevice::readAllFrames()
762{
763 Q_D(QCanBusDevice);
764
765 if (Q_UNLIKELY(d->state != ConnectedState)) {
766 const QString error = tr(s: "Cannot read frame as device is not connected.");
767 qCWarning(QT_CANBUS, "%ls", qUtf16Printable(error));
768 setError(errorText: error, errorId: CanBusError::OperationError);
769 return QList<QCanBusFrame>();
770 }
771
772 clearError();
773
774 QMutexLocker locker(&d->incomingFramesGuard);
775
776 QList<QCanBusFrame> result;
777 result.swap(other&: d->incomingFrames);
778 return result;
779}
780
781/*!
782 \fn void QCanBusDevice::framesWritten(qint64 framesCount)
783
784 This signal is emitted every time a payload of frames has been
785 written to the CAN bus. The \a framesCount argument is set to
786 the number of frames that were written in this payload.
787*/
788
789/*!
790 \fn bool QCanBusDevice::writeFrame(const QCanBusFrame &frame)
791
792 Writes \a frame to the CAN bus and returns \c true on success;
793 otherwise \c false.
794
795 On some platforms, the frame may be put into a queue and the return
796 value may only indicate a successful insertion into the queue.
797 The actual frame will be send later on. Therefore the \l framesWritten()
798 signal is the final confirmation that the frame has been handed off to
799 the transport layer. If an error occurs the \l errorOccurred() is emitted.
800
801 As per CAN bus specification, frames of type
802 \l {QCanBusFrame::RemoteRequestFrame} {remote transfer request (RTR)}
803 do not have a payload, but a length from 0 to 8 (including). This length
804 indicates the expected response payload length from the remote party.
805 Therefore when sending a RTR frame using this function it may still
806 be required to set an arbitrary payload on \a frame. The length of
807 the arbitrary payload is what is set as size expectation for the RTR frame.
808
809 \sa QCanBusFrame::setPayload()
810*/
811
812/*!
813 \fn QString QCanBusDevice::interpretErrorFrame(const QCanBusFrame &frame)
814
815 Interprets \a frame as error frame and returns a human readable
816 description of the error.
817
818 If \a frame is not an error frame, the returned string is empty.
819*/
820
821/*!
822 Connects the device to the CAN bus. Returns \c true on success;
823 otherwise \c false.
824
825 This function calls \l open() as part of its implementation.
826
827 \sa disconnectDevice()
828*/
829bool QCanBusDevice::connectDevice()
830{
831 Q_D(QCanBusDevice);
832
833 if (Q_UNLIKELY(d->state != QCanBusDevice::UnconnectedState)) {
834 const char error[] = QT_TRANSLATE_NOOP("QCanBusDevice",
835 "Can not connect an already connected device.");
836 qCWarning(QT_CANBUS, error);
837 setError(errorText: tr(s: error), errorId: QCanBusDevice::ConnectionError);
838 return false;
839 }
840
841 setState(ConnectingState);
842
843 if (!open()) {
844 setState(UnconnectedState);
845 return false;
846 }
847
848 clearError();
849
850 //Connected is set by backend -> might be delayed by event loop
851 return true;
852}
853
854
855/*!
856 Disconnects the device from the CAN bus.
857
858 This function calls \l close() as part of its implementation.
859
860 \note This function should only be called, if connectDevice()
861 returned \c true.
862
863 \sa connectDevice()
864*/
865void QCanBusDevice::disconnectDevice()
866{
867 Q_D(QCanBusDevice);
868
869 if (Q_UNLIKELY(d->state == QCanBusDevice::UnconnectedState
870 || d->state == QCanBusDevice::ClosingState)) {
871 qCWarning(QT_CANBUS, "Can not disconnect an unconnected device.");
872 return;
873 }
874
875 setState(QCanBusDevice::ClosingState);
876
877 //Unconnected is set by backend -> might be delayed by event loop
878 close();
879}
880
881/*!
882 \fn void QCanBusDevice::stateChanged(QCanBusDevice::CanBusDeviceState state)
883
884 This signal is emitted every time the state of the device changes.
885 The new state is represented by \a state.
886
887 \sa setState(), state()
888*/
889
890/*!
891 Returns the current state of the device.
892
893 \sa setState(), stateChanged()
894*/
895QCanBusDevice::CanBusDeviceState QCanBusDevice::state() const
896{
897 return d_func()->state;
898}
899
900/*!
901 Sets the state of the device to \a newState. CAN bus implementations
902 must use this function to update the device state.
903*/
904void QCanBusDevice::setState(QCanBusDevice::CanBusDeviceState newState)
905{
906 Q_D(QCanBusDevice);
907
908 if (newState == d->state)
909 return;
910
911 d->state = newState;
912 emit stateChanged(state: newState);
913}
914
915/*!
916 * \since 6.2
917 * Returns a QCanBusDeviceInfo created from the given parameters \a plugin,
918 * \a name, \a isVirtual, and \a isFlexibleDataRateCapable.
919 * \internal
920 */
921QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &plugin, const QString &name,
922 bool isVirtual,
923 bool isFlexibleDataRateCapable)
924{
925 return createDeviceInfo(plugin, name, serialNumber: QString(), description: QString(), alias: QString(),
926 channel: 0, isVirtual, isFlexibleDataRateCapable);
927}
928
929/*!
930 \since 6.2
931 Returns a QCanBusDeviceInfo created from the given parameters \a plugin,
932 \a name, \a serialNumber, \a description, \a alias, \a channel, \a isVirtual,
933 and \a isFlexibleDataRateCapable.
934 \internal
935 */
936QCanBusDeviceInfo QCanBusDevice::createDeviceInfo(const QString &plugin,
937 const QString &name,
938 const QString &serialNumber,
939 const QString &description,
940 const QString &alias,
941 int channel,
942 bool isVirtual,
943 bool isFlexibleDataRateCapable)
944{
945 std::unique_ptr<QCanBusDeviceInfoPrivate> info(new QCanBusDeviceInfoPrivate);
946 info->plugin = plugin;
947 info->name = name;
948 info->serialNumber = serialNumber;
949 info->description = description;
950 info->alias = alias;
951 info->channel = channel;
952 info->hasFlexibleDataRate = isFlexibleDataRateCapable;
953 info->isVirtual = isVirtual;
954 return QCanBusDeviceInfo(*info.release());
955}
956
957/*!
958 \since 6.2
959
960 Returns a QCanBusDeviceInfo for the current QCanBusDevice. If the function
961 is not implemented by a sub-class of QCanBusDevice, a default constructed
962 object is returned.
963 */
964QCanBusDeviceInfo QCanBusDevice::deviceInfo() const
965{
966 return QCanBusDeviceInfo(*(new QCanBusDeviceInfoPrivate));
967}
968
969QT_END_NAMESPACE
970

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