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 "qcanbusframe.h" |
5 | |
6 | #include <QtCore/qdatastream.h> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | using namespace Qt::StringLiterals; |
11 | |
12 | /*! |
13 | \class QCanBusFrame |
14 | \inmodule QtSerialBus |
15 | \since 5.8 |
16 | |
17 | \brief QCanBusFrame is a container class representing a single CAN frame. |
18 | |
19 | \l QCanBusDevice can use QCanBusFrame for read and write operations. It contains the frame |
20 | identifier and the data payload. QCanBusFrame contains the timestamp of the moment it was read. |
21 | |
22 | \sa QCanBusFrame::TimeStamp |
23 | */ |
24 | |
25 | /*! |
26 | \fn QCanBusFrame::QCanBusFrame(QCanBusFrame::FrameType type = DataFrame) |
27 | |
28 | Constructs a CAN frame of the specified \a type. |
29 | */ |
30 | |
31 | /*! |
32 | \fn QCanBusFrame::QCanBusFrame(QCanBusFrame::FrameId identifier, const QByteArray &data) |
33 | |
34 | Constructs a CAN frame using \a identifier as the frame identifier and \a data as the payload. |
35 | */ |
36 | |
37 | /*! |
38 | \fn bool QCanBusFrame::isValid() const |
39 | |
40 | Returns \c false if the \l frameType() is \l InvalidFrame, |
41 | the \l hasExtendedFrameFormat() is not set although \l frameId() is longer than 11 bit or |
42 | the payload is longer than the maximal permitted payload length of 64 byte if \e {Flexible |
43 | Data-Rate} mode is enabled or 8 byte if it is disabled. If \l frameType() is \l RemoteRequestFrame |
44 | and the \e {Flexible Data-Rate} mode is enabled at the same time \c false is also returned. |
45 | |
46 | Otherwise this function returns \c true. |
47 | */ |
48 | |
49 | /*! |
50 | \fn QCanBusFrame::setFrameId(QCanBusFrame::FrameId newFrameId) |
51 | |
52 | Sets the identifier of the CAN frame to \a newFrameId. |
53 | |
54 | The maximum size of a CAN frame identifier is 11 bits, which can be |
55 | extended up to 29 bits by supporting the \e {CAN extended frame format}. |
56 | The \e {CAN extended frame format} setting is automatically set when a |
57 | \a newFrameId with more than 11 bits in size is given. |
58 | |
59 | When the format is extended and a \a newFrameId with up to 11 bits or less |
60 | is passed, the \e {CAN extended frame format} setting is \b not changed. |
61 | |
62 | \sa frameId(), hasExtendedFrameFormat() |
63 | */ |
64 | |
65 | /*! |
66 | \fn QCanBusFrame::setPayload(const QByteArray &data) |
67 | |
68 | Sets \a data as the payload for the CAN frame. The maximum size of payload is 8 bytes, which can |
69 | be extended up to 64 bytes by supporting \e {Flexible Data-Rate}. If \a data contains more than |
70 | 8 byte the \e {Flexible Data-Rate} flag is automatically set. Flexible Data-Rate has to be |
71 | enabled on the \l QCanBusDevice by setting the \l QCanBusDevice::CanFdKey. |
72 | |
73 | Frames of type \l RemoteRequestFrame (RTR) do not have a payload. However they have to |
74 | provide an indication of the responses expected payload length. To set the expected length it |
75 | is necessary to set a fake payload whose length matches the expected payload length of the |
76 | response. One way of doing this might be as follows: |
77 | |
78 | \code |
79 | QCanBusFrame frame(QCanBusFrame::RemoteRequestFrame); |
80 | int expectedResponseLength = ...; |
81 | frame.setPayload(QByteArray(expectedResponseLength, 0)); |
82 | \endcode |
83 | |
84 | \sa payload(), hasFlexibleDataRateFormat() |
85 | */ |
86 | |
87 | /*! |
88 | \fn QCanBusFrame::setTimeStamp(TimeStamp ts) |
89 | |
90 | Sets \a ts as the timestamp for the CAN frame. Usually, this function is not needed, because the |
91 | timestamp is created during the read operation and not needed during the write operation. |
92 | |
93 | \sa QCanBusFrame::TimeStamp |
94 | */ |
95 | |
96 | /*! |
97 | \fn QCanBusFrame::FrameId QCanBusFrame::frameId() const |
98 | |
99 | Returns the CAN frame identifier. If the CAN frame uses the |
100 | extended frame format, the identifier has a maximum of 29 bits; |
101 | otherwise 11 bits. |
102 | |
103 | If the frame is of \l ErrorFrame type, this ID is always 0. |
104 | |
105 | \sa setFrameId(), hasExtendedFrameFormat() |
106 | */ |
107 | |
108 | /*! |
109 | \fn bool QCanBusFrame::hasExtendedFrameFormat() const |
110 | |
111 | Returns \c true if the CAN frame uses a 29bit identifier; |
112 | otherwise \c false, implying an 11bit identifier. |
113 | |
114 | \sa setExtendedFrameFormat(), frameId() |
115 | */ |
116 | |
117 | /*! |
118 | \fn void QCanBusFrame::setExtendedFrameFormat(bool isExtended) |
119 | |
120 | Sets the extended frame format flag to \a isExtended. |
121 | |
122 | \sa hasExtendedFrameFormat() |
123 | */ |
124 | |
125 | /*! |
126 | \enum QCanBusFrame::Version |
127 | \internal |
128 | |
129 | This enum describes the version of the QCanBusFrame. |
130 | |
131 | With newer Qt versions, new features may be added to QCanBusFrame. To support serializing and |
132 | deserializing of frames with different features, the version needs to be incremented every |
133 | time a new feature appears. This enum describes, at which Qt version a specific QCanBusFrame |
134 | version appeared. |
135 | |
136 | \value Qt_5_8 This frame is the initial version introduced in Qt 5.8 |
137 | \value Qt_5_9 This frame version was introduced in Qt 5.9 |
138 | */ |
139 | |
140 | /*! |
141 | \enum QCanBusFrame::FrameType |
142 | |
143 | This enum describes the type of the CAN frame. |
144 | |
145 | \value UnknownFrame The frame type is unknown. |
146 | \value DataFrame This value represents a data frame. |
147 | \value ErrorFrame This value represents an error frame. |
148 | \value RemoteRequestFrame This value represents a remote request. |
149 | \value InvalidFrame This value represents an invalid frame. |
150 | This type is used for error reporting. |
151 | |
152 | \sa setFrameType() |
153 | */ |
154 | |
155 | /*! |
156 | \enum QCanBusFrame::FrameError |
157 | |
158 | This enum describes the possible error types. |
159 | |
160 | \value NoError No error has occurred. |
161 | \value TransmissionTimeoutError The transmission has timed out. |
162 | \value LostArbitrationError The frame could not be sent due to lost |
163 | arbitration on the bus. |
164 | \value ControllerError The controller encountered an error. |
165 | \value ProtocolViolationError A protocol violation has occurred. |
166 | \value TransceiverError A transceiver error occurred |
167 | \value MissingAcknowledgmentError The transmission received no |
168 | acknowledgment. |
169 | \value BusOffError The CAN bus is offline. |
170 | \value BusError A CAN bus error occurred. |
171 | \value ControllerRestartError The controller restarted. |
172 | \value UnknownError An unknown error has occurred. |
173 | \value AnyError Matches every other error type. |
174 | */ |
175 | |
176 | /*! |
177 | \fn FrameType QCanBusFrame::frameType() const |
178 | |
179 | Returns the type of the frame. |
180 | |
181 | \sa setFrameType() |
182 | */ |
183 | |
184 | /*! |
185 | \fn void QCanBusFrame::setFrameType(FrameType newType) |
186 | |
187 | Sets the type of the frame to \a newType. |
188 | |
189 | \sa frameType() |
190 | */ |
191 | |
192 | /*! |
193 | \fn QByteArray QCanBusFrame::payload() const |
194 | |
195 | Returns the data payload of the frame. |
196 | |
197 | \sa setPayload() |
198 | */ |
199 | |
200 | /*! |
201 | \fn TimeStamp QCanBusFrame::timeStamp() const |
202 | |
203 | Returns the timestamp of the frame. |
204 | |
205 | \sa QCanBusFrame::TimeStamp, QCanBusFrame::setTimeStamp() |
206 | */ |
207 | |
208 | /*! |
209 | \fn FrameErrors QCanBusFrame::error() const |
210 | |
211 | Returns the error of the current error frame. If the frame |
212 | is not an \l ErrorFrame, this function returns \l NoError. |
213 | |
214 | \sa setError() |
215 | */ |
216 | |
217 | /*! |
218 | \fn void QCanBusFrame::setError(FrameErrors error) |
219 | |
220 | Sets the frame's \a error type. This function does nothing if |
221 | \l frameType() is not an \l ErrorFrame. |
222 | |
223 | \sa error() |
224 | */ |
225 | |
226 | /*! |
227 | \fn bool QCanBusFrame::hasFlexibleDataRateFormat() const |
228 | |
229 | Returns \c true if the CAN frame uses \e {Flexible Data-Rate} which allows up to 64 data bytes, |
230 | otherwise \c false, implying at most 8 byte of payload. |
231 | |
232 | \sa setFlexibleDataRateFormat(), payload() |
233 | */ |
234 | |
235 | /*! |
236 | \fn void QCanBusFrame::setFlexibleDataRateFormat(bool isFlexibleData) |
237 | |
238 | Sets the \e {Flexible Data-Rate} flag to \a isFlexibleData. Those frames can be sent using |
239 | a higher speed on supporting controllers. Additionally the payload length limit is raised to |
240 | 64 byte. |
241 | |
242 | \sa hasFlexibleDataRateFormat() |
243 | */ |
244 | |
245 | /*! |
246 | \fn QCanBusFrame::hasBitrateSwitch() const |
247 | \since 5.9 |
248 | |
249 | Returns \c true if the CAN uses \e {Flexible Data-Rate} with \e {Bitrate Switch}, |
250 | to transfer the payload data at a higher data bitrate. |
251 | |
252 | \sa setBitrateSwitch() QCanBusDevice::DataBitRateKey |
253 | */ |
254 | |
255 | /*! |
256 | \fn void QCanBusFrame::setBitrateSwitch(bool bitrateSwitch) |
257 | \since 5.9 |
258 | |
259 | Set the \e {Flexible Data-Rate} flag \e {Bitrate Switch} flag to \a bitrateSwitch. |
260 | The data field of frames with this flag is transferred at a higher data bitrate. |
261 | |
262 | \sa hasBitrateSwitch() QCanBusDevice::DataBitRateKey |
263 | */ |
264 | |
265 | /*! |
266 | \fn QCanBusFrame::hasErrorStateIndicator() const |
267 | \since 5.9 |
268 | |
269 | Returns \c true if the CAN uses \e {Flexible Data-Rate} with \e {Error State Indicator} set. |
270 | |
271 | This flag is set by the transmitter's CAN FD hardware to indicate the transmitter's error state. |
272 | |
273 | \sa setErrorStateIndicator() |
274 | */ |
275 | |
276 | /*! |
277 | \fn void QCanBusFrame::setErrorStateIndicator(bool errorStateIndicator) |
278 | \since 5.9 |
279 | |
280 | Set the \e {Flexible Data-Rate} flag \e {Error State Indicator} flag to \a errorStateIndicator. |
281 | |
282 | When sending CAN FD frames, this flag is automatically set by the CAN FD hardware. |
283 | \c QCanBusFrame::setErrorStateIndicator() should only be used for application testing, |
284 | e.g. on virtual CAN FD busses. |
285 | |
286 | \sa hasErrorStateIndicator() |
287 | */ |
288 | |
289 | /*! |
290 | \fn QCanBusFrame::hasLocalEcho() const |
291 | \since 5.10 |
292 | |
293 | Returns \c true if the frame is a local echo frame, i.e. a frame that is received as echo when |
294 | the frame with the same content was successfully sent to the CAN bus. This flag is set for |
295 | frames sent by the application itself as well as for frames sent by other applications running |
296 | on the same system. |
297 | |
298 | QCanBusDevice::ReceiveOwnKey must be set to true to receive echo frames. |
299 | |
300 | \sa setLocalEcho() |
301 | \sa QCanBusDevice::ReceiveOwnKey |
302 | \sa QCanBusDevice::LoopbackKey |
303 | */ |
304 | |
305 | /*! |
306 | \fn void QCanBusFrame::setLocalEcho(bool echo) |
307 | \since 5.10 |
308 | |
309 | Set the \e {Local Echo} flag to \a echo. |
310 | |
311 | When sending CAN bus frames with QCanBusDevice::ReceiveOwnKey enabled, all successfully sent |
312 | frames are echoed to the receive queue and marked as local echo frames. |
313 | \c QCanBusFrame::setLocalEcho should therefore only be used for application testing, |
314 | e.g. on virtual CAN busses. |
315 | |
316 | \sa hasLocalEcho() |
317 | */ |
318 | |
319 | /*! |
320 | \class QCanBusFrame::TimeStamp |
321 | \inmodule QtSerialBus |
322 | \since 5.8 |
323 | |
324 | \brief The TimeStamp class provides timestamp information with microsecond precision. |
325 | */ |
326 | |
327 | /*! |
328 | \fn QCanBusFrame::TimeStamp::TimeStamp(qint64 s, qint64 usec) |
329 | |
330 | Constructs a TimeStamp in seconds, \a s, and microseconds, \a usec. |
331 | |
332 | \note The TimeStamp is not normalized, i.e. microseconds greater 1000000 are not |
333 | converted to seconds. |
334 | */ |
335 | |
336 | /*! |
337 | \fn static TimeStamp QCanBusFrame::TimeStamp::fromMicroSeconds(qint64 usec) |
338 | |
339 | Constructs a normalized TimeStamp from microseconds \a usec. |
340 | |
341 | The created TimeStamp is normalized, i.e. microseconds greater 1000000 are converted |
342 | to seconds. |
343 | */ |
344 | |
345 | /*! |
346 | \fn qint64 QCanBusFrame::TimeStamp::seconds() const |
347 | |
348 | Returns the seconds of the timestamp. |
349 | */ |
350 | |
351 | /*! |
352 | \fn qint64 QCanBusFrame::TimeStamp::microSeconds() const |
353 | |
354 | Returns the microseconds of the timestamp. |
355 | */ |
356 | |
357 | /*! |
358 | Returns the CAN frame as a formatted string. |
359 | |
360 | The output contains the CAN identifier in hexadecimal format, right |
361 | adjusted to 32 bit, followed by the data length in square brackets |
362 | and the payload in hexadecimal format. |
363 | |
364 | Standard identifiers are filled with spaces while extended identifiers |
365 | are filled with zeros. |
366 | |
367 | Typical outputs are: |
368 | |
369 | \code |
370 | (Error) - error frame |
371 | 7FF [1] 01 - data frame with standard identifier |
372 | 1FFFFFFF [8] 01 23 45 67 89 AB CD EF - data frame with extended identifier |
373 | 400 [10] 01 23 45 67 ... EF 01 23 - CAN FD frame |
374 | 123 [5] Remote Request - remote frame with standard identifier |
375 | 00000234 [0] Remote Request - remote frame with extended identifier |
376 | \endcode |
377 | */ |
378 | QString QCanBusFrame::toString() const |
379 | { |
380 | const FrameType type = frameType(); |
381 | |
382 | switch (type) { |
383 | case InvalidFrame: |
384 | return QStringLiteral("(Invalid)" ); |
385 | case ErrorFrame: |
386 | return QStringLiteral("(Error)" ); |
387 | case UnknownFrame: |
388 | return QStringLiteral("(Unknown)" ); |
389 | default: |
390 | break; |
391 | } |
392 | |
393 | QString result; |
394 | result.append(s: hasExtendedFrameFormat() ? u""_s : u" "_s ); |
395 | result.append(s: u"%1"_s .arg(a: static_cast<uint>(frameId()), |
396 | fieldWidth: hasExtendedFrameFormat() ? 8 : 3, |
397 | base: 16, fillChar: QLatin1Char('0')).toUpper()); |
398 | |
399 | result.append(s: hasFlexibleDataRateFormat() ? u" "_s : u" "_s ); |
400 | result.append(s: u"[%1]"_s .arg(a: payload().size(), |
401 | fieldwidth: hasFlexibleDataRateFormat() ? 2 : 0, |
402 | base: 10, fillChar: QLatin1Char('0'))); |
403 | |
404 | if (type == RemoteRequestFrame) { |
405 | result.append(s: u" Remote Request"_s ); |
406 | } else if (!payload().isEmpty()) { |
407 | const QByteArray data = payload().toHex(separator: ' ').toUpper(); |
408 | result.append(s: u" "_s ); |
409 | result.append(s: QLatin1String(data)); |
410 | } |
411 | |
412 | return result; |
413 | } |
414 | |
415 | #ifndef QT_NO_DATASTREAM |
416 | |
417 | /*! \relates QCanBusFrame |
418 | |
419 | Writes a \a frame to the stream (\a out) and returns a reference |
420 | to it. |
421 | */ |
422 | QDataStream &operator<<(QDataStream &out, const QCanBusFrame &frame) |
423 | { |
424 | out << frame.frameId(); |
425 | out << static_cast<quint8>(frame.frameType()); |
426 | out << static_cast<quint8>(frame.version); |
427 | out << frame.hasExtendedFrameFormat(); |
428 | out << frame.hasFlexibleDataRateFormat(); |
429 | out << frame.payload(); |
430 | const QCanBusFrame::TimeStamp stamp = frame.timeStamp(); |
431 | out << stamp.seconds(); |
432 | out << stamp.microSeconds(); |
433 | if (frame.version >= QCanBusFrame::Version::Qt_5_9) |
434 | out << frame.hasBitrateSwitch() << frame.hasErrorStateIndicator(); |
435 | if (frame.version >= QCanBusFrame::Version::Qt_5_10) |
436 | out << frame.hasLocalEcho(); |
437 | return out; |
438 | } |
439 | |
440 | /*! \relates QCanBusFrame |
441 | |
442 | Reads a \a frame from the stream (\a in) and returns a |
443 | reference to it. |
444 | */ |
445 | QDataStream &operator>>(QDataStream &in, QCanBusFrame &frame) |
446 | { |
447 | QCanBusFrame::FrameId frameId; |
448 | quint8 frameType; |
449 | quint8 version; |
450 | bool extendedFrameFormat; |
451 | bool flexibleDataRate; |
452 | bool bitrateSwitch = false; |
453 | bool errorStateIndicator = false; |
454 | bool localEcho = false; |
455 | QByteArray payload; |
456 | qint64 seconds; |
457 | qint64 microSeconds; |
458 | |
459 | in >> frameId >> frameType >> version >> extendedFrameFormat >> flexibleDataRate |
460 | >> payload >> seconds >> microSeconds; |
461 | |
462 | if (version >= QCanBusFrame::Version::Qt_5_9) |
463 | in >> bitrateSwitch >> errorStateIndicator; |
464 | |
465 | if (version >= QCanBusFrame::Version::Qt_5_10) |
466 | in >> localEcho; |
467 | |
468 | frame.setFrameId(frameId); |
469 | frame.version = version; |
470 | |
471 | frame.setFrameType(static_cast<QCanBusFrame::FrameType>(frameType)); |
472 | frame.setExtendedFrameFormat(extendedFrameFormat); |
473 | frame.setFlexibleDataRateFormat(flexibleDataRate); |
474 | frame.setBitrateSwitch(bitrateSwitch); |
475 | frame.setErrorStateIndicator(errorStateIndicator); |
476 | frame.setLocalEcho(localEcho); |
477 | frame.setPayload(payload); |
478 | |
479 | frame.setTimeStamp(QCanBusFrame::TimeStamp(seconds, microSeconds)); |
480 | |
481 | return in; |
482 | } |
483 | |
484 | #endif // QT_NO_DATASTREAM |
485 | |
486 | QT_END_NAMESPACE |
487 | |