Source code
Revision control
Copy as Markdown
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#ifndef QCANBUSFRAME_H
#define QCANBUSFRAME_H
#include <QtCore/qmetatype.h>
#include <QtCore/qobject.h>
#include <QtSerialBus/qtserialbusglobal.h>
QT_BEGIN_NAMESPACE
class QDataStream;
class Q_SERIALBUS_EXPORT QCanBusFrame
{
Q_GADGET
public:
using FrameId = quint32;
class TimeStamp {
public:
constexpr TimeStamp(qint64 s = 0, qint64 usec = 0) noexcept
: secs(s), usecs(usec) {}
constexpr static TimeStamp fromMicroSeconds(qint64 usec) noexcept
{ return TimeStamp(usec / 1000000, usec % 1000000); }
constexpr qint64 seconds() const noexcept { return secs; }
constexpr qint64 microSeconds() const noexcept { return usecs; }
private:
qint64 secs;
qint64 usecs;
};
enum FrameType {
UnknownFrame = 0x0,
DataFrame = 0x1,
ErrorFrame = 0x2,
RemoteRequestFrame = 0x3,
InvalidFrame = 0x4
};
Q_ENUM(FrameType)
explicit QCanBusFrame(FrameType type = DataFrame) noexcept :
isExtendedFrame(0x0),
version(Qt_5_10),
isFlexibleDataRate(0x0),
isBitrateSwitch(0x0),
isErrorStateIndicator(0x0),
isLocalEcho(0x0),
reserved0(0x0)
{
Q_UNUSED(reserved0);
::memset(reserved, 0, sizeof(reserved));
setFrameId(0x0);
setFrameType(type);
}
enum FrameError {
NoError = 0,
TransmissionTimeoutError = (1 << 0),
LostArbitrationError = (1 << 1),
ControllerError = (1 << 2),
ProtocolViolationError = (1 << 3),
TransceiverError = (1 << 4),
MissingAcknowledgmentError = (1 << 5),
BusOffError = (1 << 6),
BusError = (1 << 7),
ControllerRestartError = (1 << 8),
UnknownError = (1 << 9),
AnyError = 0x1FFFFFFFU
//only 29 bits usable
};
Q_DECLARE_FLAGS(FrameErrors, FrameError)
Q_ENUM(FrameError)
Q_FLAG(FrameErrors)
explicit QCanBusFrame(QCanBusFrame::FrameId identifier, const QByteArray &data) :
format(DataFrame),
isExtendedFrame(0x0),
version(Qt_5_10),
isFlexibleDataRate(data.size() > 8 ? 0x1 : 0x0),
isBitrateSwitch(0x0),
isErrorStateIndicator(0x0),
isLocalEcho(0x0),
reserved0(0x0),
load(data)
{
::memset(reserved, 0, sizeof(reserved));
setFrameId(identifier);
}
bool isValid() const noexcept
{
if (format == InvalidFrame)
return false;
// long id used, but extended flag not set
if (!isExtendedFrame && (canId & 0x1FFFF800U))
return false;
if (!isValidFrameId)
return false;
// maximum permitted payload size in CAN or CAN FD
const qsizetype length = load.size();
if (isFlexibleDataRate) {
if (format == RemoteRequestFrame)
return false;
return length <= 8 || length == 12 || length == 16 || length == 20
|| length == 24 || length == 32 || length == 48 || length == 64;
}
return length <= 8;
}
constexpr FrameType frameType() const noexcept
{
switch (format) {
case 0x1: return DataFrame;
case 0x2: return ErrorFrame;
case 0x3: return RemoteRequestFrame;
case 0x4: return InvalidFrame;
// no default to trigger warning
}
return UnknownFrame;
}
constexpr void setFrameType(FrameType newFormat) noexcept
{
switch (newFormat) {
case DataFrame:
format = 0x1; return;
case ErrorFrame:
format = 0x2; return;
case RemoteRequestFrame:
format = 0x3; return;
case UnknownFrame:
format = 0x0; return;
case InvalidFrame:
format = 0x4; return;
}
}
constexpr bool hasExtendedFrameFormat() const noexcept { return (isExtendedFrame & 0x1); }
constexpr void setExtendedFrameFormat(bool isExtended) noexcept
{
isExtendedFrame = (isExtended & 0x1);
}
constexpr QCanBusFrame::FrameId frameId() const noexcept
{
if (Q_UNLIKELY(format == ErrorFrame))
return 0;
return (canId & 0x1FFFFFFFU);
}
constexpr void setFrameId(QCanBusFrame::FrameId newFrameId)
{
if (Q_LIKELY(newFrameId < 0x20000000U)) {
isValidFrameId = true;
canId = newFrameId;
setExtendedFrameFormat(isExtendedFrame || (newFrameId & 0x1FFFF800U));
} else {
isValidFrameId = false;
canId = 0;
}
}
void setPayload(const QByteArray &data)
{
load = data;
if (data.size() > 8)
isFlexibleDataRate = 0x1;
}
constexpr void setTimeStamp(TimeStamp ts) noexcept { stamp = ts; }
QByteArray payload() const { return load; }
constexpr TimeStamp timeStamp() const noexcept { return stamp; }
constexpr FrameErrors error() const noexcept
{
if (format != ErrorFrame)
return NoError;
return FrameErrors(canId & 0x1FFFFFFFU);
}
constexpr void setError(FrameErrors e)
{
if (format != ErrorFrame)
return;
canId = (e & AnyError).toInt();
}
QString toString() const;
constexpr bool hasFlexibleDataRateFormat() const noexcept { return (isFlexibleDataRate & 0x1); }
constexpr void setFlexibleDataRateFormat(bool isFlexibleData) noexcept
{
isFlexibleDataRate = (isFlexibleData & 0x1);
if (!isFlexibleData) {
isBitrateSwitch = 0x0;
isErrorStateIndicator = 0x0;
}
}
constexpr bool hasBitrateSwitch() const noexcept { return (isBitrateSwitch & 0x1); }
constexpr void setBitrateSwitch(bool bitrateSwitch) noexcept
{
isBitrateSwitch = (bitrateSwitch & 0x1);
if (bitrateSwitch)
isFlexibleDataRate = 0x1;
}
constexpr bool hasErrorStateIndicator() const noexcept { return (isErrorStateIndicator & 0x1); }
constexpr void setErrorStateIndicator(bool errorStateIndicator) noexcept
{
isErrorStateIndicator = (errorStateIndicator & 0x1);
if (errorStateIndicator)
isFlexibleDataRate = 0x1;
}
constexpr bool hasLocalEcho() const noexcept { return (isLocalEcho & 0x1); }
constexpr void setLocalEcho(bool localEcho) noexcept
{
isLocalEcho = (localEcho & 0x1);
}
#ifndef QT_NO_DATASTREAM
friend Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &, const QCanBusFrame &);
friend Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &, QCanBusFrame &);
#endif
private:
enum Version {
Qt_5_8 = 0x0,
Qt_5_9 = 0x1,
Qt_5_10 = 0x2
};
quint32 canId:29; // acts as container for error codes too
quint8 format:3; // max of 8 frame types
quint8 isExtendedFrame:1;
quint8 version:5;
quint8 isValidFrameId:1;
quint8 isFlexibleDataRate:1;
quint8 isBitrateSwitch:1;
quint8 isErrorStateIndicator:1;
quint8 isLocalEcho:1;
quint8 reserved0:5;
// reserved for future use
quint8 reserved[2];
QByteArray load;
TimeStamp stamp;
};
Q_DECLARE_TYPEINFO(QCanBusFrame, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QCanBusFrame::FrameError, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QCanBusFrame::FrameType, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QCanBusFrame::TimeStamp, Q_PRIMITIVE_TYPE);
Q_DECLARE_OPERATORS_FOR_FLAGS(QCanBusFrame::FrameErrors)
#ifndef QT_NO_DATASTREAM
Q_SERIALBUS_EXPORT QDataStream &operator<<(QDataStream &, const QCanBusFrame &);
Q_SERIALBUS_EXPORT QDataStream &operator>>(QDataStream &, QCanBusFrame &);
#endif
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QCanBusFrame::FrameType)
Q_DECLARE_METATYPE(QCanBusFrame::FrameErrors)
#endif // QCANBUSFRAME_H