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#ifndef QCANBUSFRAME_H
5#define QCANBUSFRAME_H
6
7#include <QtCore/qmetatype.h>
8#include <QtCore/qobject.h>
9#include <QtSerialBus/qtserialbusglobal.h>
10
11QT_BEGIN_NAMESPACE
12
13class QDataStream;
14
15class Q_SERIALBUS_EXPORT QCanBusFrame
16{
17 Q_GADGET
18
19public:
20 using FrameId = quint32;
21
22 class TimeStamp {
23 public:
24 constexpr TimeStamp(qint64 s = 0, qint64 usec = 0) noexcept
25 : secs(s), usecs(usec) {}
26
27 constexpr static TimeStamp fromMicroSeconds(qint64 usec) noexcept
28 { return TimeStamp(usec / 1000000, usec % 1000000); }
29
30 constexpr qint64 seconds() const noexcept { return secs; }
31 constexpr qint64 microSeconds() const noexcept { return usecs; }
32
33 private:
34 qint64 secs;
35 qint64 usecs;
36 };
37
38 enum FrameType {
39 UnknownFrame = 0x0,
40 DataFrame = 0x1,
41 ErrorFrame = 0x2,
42 RemoteRequestFrame = 0x3,
43 InvalidFrame = 0x4
44 };
45 Q_ENUM(FrameType)
46
47 explicit QCanBusFrame(FrameType type = DataFrame) noexcept :
48 isExtendedFrame(0x0),
49 version(Qt_5_10),
50 isFlexibleDataRate(0x0),
51 isBitrateSwitch(0x0),
52 isErrorStateIndicator(0x0),
53 isLocalEcho(0x0),
54 reserved0(0x0)
55 {
56 Q_UNUSED(reserved0);
57 ::memset(s: reserved, c: 0, n: sizeof(reserved));
58 setFrameId(0x0);
59 setFrameType(type);
60 }
61
62 enum FrameError {
63 NoError = 0,
64 TransmissionTimeoutError = (1 << 0),
65 LostArbitrationError = (1 << 1),
66 ControllerError = (1 << 2),
67 ProtocolViolationError = (1 << 3),
68 TransceiverError = (1 << 4),
69 MissingAcknowledgmentError = (1 << 5),
70 BusOffError = (1 << 6),
71 BusError = (1 << 7),
72 ControllerRestartError = (1 << 8),
73 UnknownError = (1 << 9),
74 AnyError = 0x1FFFFFFFU
75 //only 29 bits usable
76 };
77 Q_DECLARE_FLAGS(FrameErrors, FrameError)
78 Q_FLAGS(FrameErrors)
79 Q_ENUM(FrameError)
80
81 explicit QCanBusFrame(QCanBusFrame::FrameId identifier, const QByteArray &data) :
82 format(DataFrame),
83 isExtendedFrame(0x0),
84 version(Qt_5_10),
85 isFlexibleDataRate(data.size() > 8 ? 0x1 : 0x0),
86 isBitrateSwitch(0x0),
87 isErrorStateIndicator(0x0),
88 isLocalEcho(0x0),
89 reserved0(0x0),
90 load(data)
91 {
92 ::memset(s: reserved, c: 0, n: sizeof(reserved));
93 setFrameId(identifier);
94 }
95
96 bool isValid() const noexcept
97 {
98 if (format == InvalidFrame)
99 return false;
100
101 // long id used, but extended flag not set
102 if (!isExtendedFrame && (canId & 0x1FFFF800U))
103 return false;
104
105 if (!isValidFrameId)
106 return false;
107
108 // maximum permitted payload size in CAN or CAN FD
109 const qsizetype length = load.size();
110 if (isFlexibleDataRate) {
111 if (format == RemoteRequestFrame)
112 return false;
113
114 return length <= 8 || length == 12 || length == 16 || length == 20
115 || length == 24 || length == 32 || length == 48 || length == 64;
116 }
117
118 return length <= 8;
119 }
120
121 constexpr FrameType frameType() const noexcept
122 {
123 switch (format) {
124 case 0x1: return DataFrame;
125 case 0x2: return ErrorFrame;
126 case 0x3: return RemoteRequestFrame;
127 case 0x4: return InvalidFrame;
128 // no default to trigger warning
129 }
130
131 return UnknownFrame;
132 }
133
134 constexpr void setFrameType(FrameType newFormat) noexcept
135 {
136 switch (newFormat) {
137 case DataFrame:
138 format = 0x1; return;
139 case ErrorFrame:
140 format = 0x2; return;
141 case RemoteRequestFrame:
142 format = 0x3; return;
143 case UnknownFrame:
144 format = 0x0; return;
145 case InvalidFrame:
146 format = 0x4; return;
147 }
148 }
149
150 constexpr bool hasExtendedFrameFormat() const noexcept { return (isExtendedFrame & 0x1); }
151 constexpr void setExtendedFrameFormat(bool isExtended) noexcept
152 {
153 isExtendedFrame = (isExtended & 0x1);
154 }
155
156 constexpr QCanBusFrame::FrameId frameId() const noexcept
157 {
158 if (Q_UNLIKELY(format == ErrorFrame))
159 return 0;
160 return (canId & 0x1FFFFFFFU);
161 }
162 constexpr void setFrameId(QCanBusFrame::FrameId newFrameId)
163 {
164 if (Q_LIKELY(newFrameId < 0x20000000U)) {
165 isValidFrameId = true;
166 canId = newFrameId;
167 setExtendedFrameFormat(isExtendedFrame || (newFrameId & 0x1FFFF800U));
168 } else {
169 isValidFrameId = false;
170 canId = 0;
171 }
172 }
173
174 void setPayload(const QByteArray &data)
175 {
176 load = data;
177 if (data.size() > 8)
178 isFlexibleDataRate = 0x1;
179 }
180 constexpr void setTimeStamp(TimeStamp ts) noexcept { stamp = ts; }
181
182 QByteArray payload() const { return load; }
183 constexpr TimeStamp timeStamp() const noexcept { return stamp; }
184
185 constexpr FrameErrors error() const noexcept
186 {
187 if (format != ErrorFrame)
188 return NoError;
189
190 return FrameErrors(canId & 0x1FFFFFFFU);
191 }
192 constexpr void setError(FrameErrors e)
193 {
194 if (format != ErrorFrame)
195 return;
196 canId = (e & AnyError).toInt();
197 }
198
199 QString toString() const;
200
201 constexpr bool hasFlexibleDataRateFormat() const noexcept { return (isFlexibleDataRate & 0x1); }
202 constexpr void setFlexibleDataRateFormat(bool isFlexibleData) noexcept
203 {
204 isFlexibleDataRate = (isFlexibleData & 0x1);
205 if (!isFlexibleData) {
206 isBitrateSwitch = 0x0;
207 isErrorStateIndicator = 0x0;
208 }
209 }
210
211 constexpr bool hasBitrateSwitch() const noexcept { return (isBitrateSwitch & 0x1); }
212 constexpr void setBitrateSwitch(bool bitrateSwitch) noexcept
213 {
214 isBitrateSwitch = (bitrateSwitch & 0x1);
215 if (bitrateSwitch)
216 isFlexibleDataRate = 0x1;
217 }
218
219 constexpr bool hasErrorStateIndicator() const noexcept { return (isErrorStateIndicator & 0x1); }
220 constexpr void setErrorStateIndicator(bool errorStateIndicator) noexcept
221 {
222 isErrorStateIndicator = (errorStateIndicator & 0x1);
223 if (errorStateIndicator)
224 isFlexibleDataRate = 0x1;
225 }
226 constexpr bool hasLocalEcho() const noexcept { return (isLocalEcho & 0x1); }
227 constexpr void setLocalEcho(bool localEcho) noexcept
228 {
229 isLocalEcho = (localEcho & 0x1);
230 }
231
232#ifndef QT_NO_DATASTREAM
233 friend Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &, const QCanBusFrame &);
234 friend Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &, QCanBusFrame &);
235#endif
236
237private:
238 enum Version {
239 Qt_5_8 = 0x0,
240 Qt_5_9 = 0x1,
241 Qt_5_10 = 0x2
242 };
243
244 quint32 canId:29; // acts as container for error codes too
245 quint8 format:3; // max of 8 frame types
246
247 quint8 isExtendedFrame:1;
248 quint8 version:5;
249 quint8 isValidFrameId:1;
250 quint8 isFlexibleDataRate:1;
251
252 quint8 isBitrateSwitch:1;
253 quint8 isErrorStateIndicator:1;
254 quint8 isLocalEcho:1;
255 quint8 reserved0:5;
256
257 // reserved for future use
258 quint8 reserved[2];
259
260 QByteArray load;
261 TimeStamp stamp;
262};
263
264Q_DECLARE_TYPEINFO(QCanBusFrame, Q_RELOCATABLE_TYPE);
265Q_DECLARE_TYPEINFO(QCanBusFrame::FrameError, Q_PRIMITIVE_TYPE);
266Q_DECLARE_TYPEINFO(QCanBusFrame::FrameType, Q_PRIMITIVE_TYPE);
267Q_DECLARE_TYPEINFO(QCanBusFrame::TimeStamp, Q_PRIMITIVE_TYPE);
268
269Q_DECLARE_OPERATORS_FOR_FLAGS(QCanBusFrame::FrameErrors)
270
271#ifndef QT_NO_DATASTREAM
272Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &, const QCanBusFrame &);
273Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &, QCanBusFrame &);
274#endif
275
276QT_END_NAMESPACE
277
278Q_DECLARE_METATYPE(QCanBusFrame::FrameType)
279Q_DECLARE_METATYPE(QCanBusFrame::FrameErrors)
280
281#endif // QCANBUSFRAME_H
282

source code of qtserialbus/src/serialbus/qcanbusframe.h