1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtSerialBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #ifndef QCANBUSFRAME_H
38 #define QCANBUSFRAME_H
39 
40 #include <QtCore/qmetatype.h>
41 #include <QtCore/qobject.h>
42 #include <QtSerialBus/qtserialbusglobal.h>
43 
44 QT_BEGIN_NAMESPACE
45 
46 class QDataStream;
47 
48 class Q_SERIALBUS_EXPORT QCanBusFrame
49 {
50 public:
51     class TimeStamp {
52     public:
53         Q_DECL_CONSTEXPR TimeStamp(qint64 s = 0, qint64 usec = 0) Q_DECL_NOTHROW
secs(s)54             : secs(s), usecs(usec) {}
55 
fromMicroSeconds(qint64 usec)56         Q_DECL_CONSTEXPR static TimeStamp fromMicroSeconds(qint64 usec) Q_DECL_NOTHROW
57         { return TimeStamp(usec / 1000000, usec % 1000000); }
58 
seconds()59         Q_DECL_CONSTEXPR qint64 seconds() const Q_DECL_NOTHROW { return secs; }
microSeconds()60         Q_DECL_CONSTEXPR qint64 microSeconds() const Q_DECL_NOTHROW { return usecs; }
61 
62     private:
63         qint64 secs;
64         qint64 usecs;
65     };
66 
67     enum FrameType {
68         UnknownFrame        = 0x0,
69         DataFrame           = 0x1,
70         ErrorFrame          = 0x2,
71         RemoteRequestFrame  = 0x3,
72         InvalidFrame        = 0x4
73     };
74 
75     explicit QCanBusFrame(FrameType type = DataFrame) Q_DECL_NOTHROW :
76         isExtendedFrame(0x0),
77         version(Qt_5_10),
78         isFlexibleDataRate(0x0),
79         isBitrateSwitch(0x0),
80         isErrorStateIndicator(0x0),
81         isLocalEcho(0x0),
82         reserved0(0x0)
83     {
84         Q_UNUSED(reserved0);
85         ::memset(reserved, 0, sizeof(reserved));
86         setFrameId(0x0);
87         setFrameType(type);
88     }
89 
90     enum FrameError {
91         NoError                     = 0,
92         TransmissionTimeoutError    = (1 << 0),
93         LostArbitrationError        = (1 << 1),
94         ControllerError             = (1 << 2),
95         ProtocolViolationError      = (1 << 3),
96         TransceiverError            = (1 << 4),
97         MissingAcknowledgmentError  = (1 << 5),
98         BusOffError                 = (1 << 6),
99         BusError                    = (1 << 7),
100         ControllerRestartError      = (1 << 8),
101         UnknownError                = (1 << 9),
102         AnyError                    = 0x1FFFFFFFU
103         //only 29 bits usable
104     };
Q_DECLARE_FLAGS(FrameErrors,FrameError)105     Q_DECLARE_FLAGS(FrameErrors, FrameError)
106     Q_FLAGS(FrameErrors)
107 
108     explicit QCanBusFrame(quint32 identifier, const QByteArray &data) :
109         format(DataFrame),
110         isExtendedFrame(0x0),
111         version(Qt_5_10),
112         isFlexibleDataRate(data.length() > 8 ? 0x1 : 0x0),
113         isBitrateSwitch(0x0),
114         isErrorStateIndicator(0x0),
115         isLocalEcho(0x0),
116         reserved0(0x0),
117         load(data)
118     {
119         ::memset(reserved, 0, sizeof(reserved));
120         setFrameId(identifier);
121     }
122 
isValid()123     bool isValid() const Q_DECL_NOTHROW
124     {
125         if (format == InvalidFrame)
126             return false;
127 
128         // long id used, but extended flag not set
129         if (!isExtendedFrame && (canId & 0x1FFFF800U))
130             return false;
131 
132         if (!isValidFrameId)
133             return false;
134 
135         // maximum permitted payload size in CAN or CAN FD
136         const int length = load.length();
137         if (isFlexibleDataRate) {
138             if (format == RemoteRequestFrame)
139                 return false;
140 
141             return length <= 8 || length == 12 || length == 16 || length == 20
142                     || length == 24 || length == 32 || length == 48 || length == 64;
143         }
144 
145         return length <= 8;
146     }
147 
frameType()148     FrameType frameType() const Q_DECL_NOTHROW
149     {
150         switch (format) {
151         case 0x1: return DataFrame;
152         case 0x2: return ErrorFrame;
153         case 0x3: return RemoteRequestFrame;
154         case 0x4: return InvalidFrame;
155         // no default to trigger warning
156         }
157 
158         return UnknownFrame;
159     }
160 
setFrameType(FrameType newFormat)161     void setFrameType(FrameType newFormat) Q_DECL_NOTHROW
162     {
163         switch (newFormat) {
164         case DataFrame:
165             format = 0x1; return;
166         case ErrorFrame:
167             format = 0x2; return;
168         case RemoteRequestFrame:
169             format = 0x3; return;
170         case UnknownFrame:
171             format = 0x0; return;
172         case InvalidFrame:
173             format = 0x4; return;
174         }
175     }
176 
hasExtendedFrameFormat()177     bool hasExtendedFrameFormat() const Q_DECL_NOTHROW { return (isExtendedFrame & 0x1); }
setExtendedFrameFormat(bool isExtended)178     void setExtendedFrameFormat(bool isExtended) Q_DECL_NOTHROW
179     {
180         isExtendedFrame = (isExtended & 0x1);
181     }
182 
frameId()183     quint32 frameId() const Q_DECL_NOTHROW
184     {
185         if (Q_UNLIKELY(format == ErrorFrame))
186             return 0;
187         return (canId & 0x1FFFFFFFU);
188     }
setFrameId(quint32 newFrameId)189     void setFrameId(quint32 newFrameId)
190     {
191         if (Q_LIKELY(newFrameId < 0x20000000U)) {
192             isValidFrameId = true;
193             canId = newFrameId;
194             setExtendedFrameFormat(isExtendedFrame || (newFrameId & 0x1FFFF800U));
195         } else {
196             isValidFrameId = false;
197             canId = 0;
198         }
199     }
200 
setPayload(const QByteArray & data)201     void setPayload(const QByteArray &data)
202     {
203         load = data;
204         if (data.length() > 8)
205             isFlexibleDataRate = 0x1;
206     }
setTimeStamp(TimeStamp ts)207     void setTimeStamp(TimeStamp ts) Q_DECL_NOTHROW { stamp = ts; }
208 
payload()209     QByteArray payload() const { return load; }
timeStamp()210     TimeStamp timeStamp() const Q_DECL_NOTHROW { return stamp; }
211 
error()212     FrameErrors error() const Q_DECL_NOTHROW
213     {
214         if (format != ErrorFrame)
215             return NoError;
216 
217         return FrameErrors(canId & 0x1FFFFFFFU);
218     }
setError(FrameErrors e)219     void setError(FrameErrors e)
220     {
221         if (format != ErrorFrame)
222             return;
223         canId = (e & AnyError);
224     }
225 
226     QString toString() const;
227 
hasFlexibleDataRateFormat()228     bool hasFlexibleDataRateFormat() const Q_DECL_NOTHROW { return (isFlexibleDataRate & 0x1); }
setFlexibleDataRateFormat(bool isFlexibleData)229     void setFlexibleDataRateFormat(bool isFlexibleData) Q_DECL_NOTHROW
230     {
231         isFlexibleDataRate = (isFlexibleData & 0x1);
232         if (!isFlexibleData) {
233             isBitrateSwitch = 0x0;
234             isErrorStateIndicator = 0x0;
235         }
236     }
237 
hasBitrateSwitch()238     bool hasBitrateSwitch() const Q_DECL_NOTHROW { return (isBitrateSwitch & 0x1); }
setBitrateSwitch(bool bitrateSwitch)239     void setBitrateSwitch(bool bitrateSwitch) Q_DECL_NOTHROW
240     {
241         isBitrateSwitch = (bitrateSwitch & 0x1);
242         if (bitrateSwitch)
243             isFlexibleDataRate = 0x1;
244     }
245 
hasErrorStateIndicator()246     bool hasErrorStateIndicator() const Q_DECL_NOTHROW { return (isErrorStateIndicator & 0x1); }
setErrorStateIndicator(bool errorStateIndicator)247     void setErrorStateIndicator(bool errorStateIndicator) Q_DECL_NOTHROW
248     {
249         isErrorStateIndicator = (errorStateIndicator & 0x1);
250         if (errorStateIndicator)
251             isFlexibleDataRate = 0x1;
252     }
hasLocalEcho()253     bool hasLocalEcho() const Q_DECL_NOTHROW { return (isLocalEcho & 0x1); }
setLocalEcho(bool localEcho)254     void setLocalEcho(bool localEcho) Q_DECL_NOTHROW
255     {
256         isLocalEcho = (localEcho & 0x1);
257     }
258 
259 #ifndef QT_NO_DATASTREAM
260     friend Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &, const QCanBusFrame &);
261     friend Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &, QCanBusFrame &);
262 #endif
263 
264 private:
265     enum Version {
266         Qt_5_8 = 0x0,
267         Qt_5_9 = 0x1,
268         Qt_5_10 = 0x2
269     };
270 
271     quint32 canId:29; // acts as container for error codes too
272     quint8 format:3; // max of 8 frame types
273 
274     quint8 isExtendedFrame:1;
275     quint8 version:5;
276     quint8 isValidFrameId:1;
277     quint8 isFlexibleDataRate:1;
278 
279     quint8 isBitrateSwitch:1;
280     quint8 isErrorStateIndicator:1;
281     quint8 isLocalEcho:1;
282     quint8 reserved0:5;
283 
284     // reserved for future use
285     quint8 reserved[2];
286 
287     QByteArray load;
288     TimeStamp stamp;
289 };
290 
291 Q_DECLARE_TYPEINFO(QCanBusFrame, Q_MOVABLE_TYPE);
292 Q_DECLARE_TYPEINFO(QCanBusFrame::FrameError, Q_PRIMITIVE_TYPE);
293 Q_DECLARE_TYPEINFO(QCanBusFrame::FrameType, Q_PRIMITIVE_TYPE);
294 Q_DECLARE_TYPEINFO(QCanBusFrame::TimeStamp, Q_PRIMITIVE_TYPE);
295 
296 Q_DECLARE_OPERATORS_FOR_FLAGS(QCanBusFrame::FrameErrors)
297 
298 #ifndef QT_NO_DATASTREAM
299 Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &, const QCanBusFrame &);
300 Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &, QCanBusFrame &);
301 #endif
302 
303 QT_END_NAMESPACE
304 
305 Q_DECLARE_METATYPE(QCanBusFrame::FrameType)
306 Q_DECLARE_METATYPE(QCanBusFrame::FrameErrors)
307 
308 #endif // QCANBUSFRAME_H
309