| 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 |  | 
| 17 | QT_BEGIN_NAMESPACE | 
| 18 |  | 
| 19 | Q_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 | */ | 
| 210 | QCanBusDevice::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 | */ | 
| 225 | void 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 | */ | 
| 245 | void 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 | */ | 
| 261 | void 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 | */ | 
| 280 | void 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 | */ | 
| 292 | QCanBusFrame 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 | */ | 
| 305 | bool 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 | */ | 
| 325 | void 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 | */ | 
| 355 | QVariant 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 | */ | 
| 374 | QList<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 | */ | 
| 391 | QCanBusDevice::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 | */ | 
| 401 | QString 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 | */ | 
| 417 | qint64 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 | */ | 
| 432 | qint64 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 | */ | 
| 452 | void 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 |  */ | 
| 467 | bool 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 | */ | 
| 501 | QCanBusDevice::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 | */ | 
| 529 | void 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 |  */ | 
| 569 | bool 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 |  */ | 
| 637 | bool 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 | */ | 
| 729 | QCanBusFrame 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 | */ | 
| 759 | QList<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 | */ | 
| 827 | bool 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 | */ | 
| 863 | void 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 | */ | 
| 893 | QCanBusDevice::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 | */ | 
| 902 | void 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 |  */ | 
| 919 | QCanBusDeviceInfo 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 |  */ | 
| 934 | QCanBusDeviceInfo 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 |  */ | 
| 962 | QCanBusDeviceInfo QCanBusDevice::deviceInfo() const | 
| 963 | { | 
| 964 |     return QCanBusDeviceInfo(*(new QCanBusDeviceInfoPrivate)); | 
| 965 | } | 
| 966 |  | 
| 967 | QT_END_NAMESPACE | 
| 968 |  |