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

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