diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | examples/serialbus/can/mainwindow.h | 2 | ||||
-rw-r--r-- | src/plugins/canbus/peakcan/peakcanbackend.cpp | 23 | ||||
-rw-r--r-- | src/plugins/canbus/socketcan/socketcanbackend.cpp | 12 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/systeccanbackend.cpp | 12 | ||||
-rw-r--r-- | src/plugins/canbus/tinycan/tinycanbackend.cpp | 9 | ||||
-rw-r--r-- | src/plugins/canbus/vectorcan/vectorcan_symbols_p.h | 125 | ||||
-rw-r--r-- | src/plugins/canbus/vectorcan/vectorcanbackend.cpp | 284 | ||||
-rw-r--r-- | src/plugins/canbus/vectorcan/vectorcanbackend_p.h | 5 | ||||
-rw-r--r-- | src/serialbus/doc/src/vectorcan.qdoc | 9 |
10 files changed, 363 insertions, 120 deletions
diff --git a/.qmake.conf b/.qmake.conf index 16c30a1..96f7a81 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) CONFIG += warning_clean DEFINES += QT_NO_FOREACH -MODULE_VERSION = 5.14.2 +MODULE_VERSION = 5.15.0 diff --git a/examples/serialbus/can/mainwindow.h b/examples/serialbus/can/mainwindow.h index febe72d..2a7bbf0 100644 --- a/examples/serialbus/can/mainwindow.h +++ b/examples/serialbus/can/mainwindow.h @@ -51,7 +51,7 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include <QCanBusDevice> // for CanBusError +#include <QCanBusDevice> #include <QMainWindow> diff --git a/src/plugins/canbus/peakcan/peakcanbackend.cpp b/src/plugins/canbus/peakcan/peakcanbackend.cpp index 5a17b22..6e1af1c 100644 --- a/src/plugins/canbus/peakcan/peakcanbackend.cpp +++ b/src/plugins/canbus/peakcan/peakcanbackend.cpp @@ -344,7 +344,7 @@ bool PeakCanBackendPrivate::open() if (readHandle == INVALID_HANDLE_VALUE) { readHandle = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); if (Q_UNLIKELY(!readHandle)) { - const QString errorString = qt_error_string(::GetLastError()); + const QString errorString = qt_error_string(int(::GetLastError())); qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot create receive event handler: %ls", qUtf16Printable(errorString)); q->setError(errorString, QCanBusDevice::ConnectionError); @@ -404,7 +404,7 @@ void PeakCanBackendPrivate::close() #if defined(Q_OS_WIN32) if (readHandle && (readHandle != INVALID_HANDLE_VALUE)) { - const QString errorString = qt_error_string(::GetLastError()); + const QString errorString = qt_error_string(int(::GetLastError())); if (Q_UNLIKELY(!::CloseHandle(readHandle))) { qCCritical(QT_CANBUS_PLUGINS_PEAKCAN, "Cannot close read handle: %ls", qUtf16Printable(errorString)); @@ -561,8 +561,7 @@ void PeakCanBackendPrivate::startWrite() if (isFlexibleDatarateEnabled) { const int size = payload.size(); - TPCANMsgFD message; - ::memset(&message, 0, sizeof(message)); + TPCANMsgFD message = {}; message.ID = frame.frameId(); message.DLC = sizeToDlc(size); message.MSGTYPE = frame.hasExtendedFrameFormat() ? PCAN_MESSAGE_EXTENDED @@ -583,9 +582,7 @@ void PeakCanBackendPrivate::startWrite() qCWarning(QT_CANBUS_PLUGINS_PEAKCAN(), errorString); q->setError(PeakCanBackend::tr(errorString), QCanBusDevice::WriteError); } else { - TPCANMsg message; - ::memset(&message, 0, sizeof(message)); - + TPCANMsg message = {}; message.ID = frame.frameId(); message.LEN = static_cast<quint8>(payload.size()); message.MSGTYPE = frame.hasExtendedFrameFormat() ? PCAN_MESSAGE_EXTENDED @@ -619,10 +616,8 @@ void PeakCanBackendPrivate::startRead() for (;;) { if (isFlexibleDatarateEnabled) { - TPCANMsgFD message; - ::memset(&message, 0, sizeof(message)); - TPCANTimestampFD timestamp; - ::memset(×tamp, 0, sizeof(timestamp)); + TPCANMsgFD message = {}; + TPCANTimestampFD timestamp = {}; const TPCANStatus st = ::CAN_ReadFD(channelIndex, &message, ×tamp); if (st != PCAN_ERROR_OK) { @@ -649,10 +644,8 @@ void PeakCanBackendPrivate::startRead() newFrames.append(std::move(frame)); } else { - TPCANMsg message; - ::memset(&message, 0, sizeof(message)); - TPCANTimestamp timestamp; - ::memset(×tamp, 0, sizeof(timestamp)); + TPCANMsg message = {}; + TPCANTimestamp timestamp = {}; const TPCANStatus st = ::CAN_Read(channelIndex, &message, ×tamp); if (st != PCAN_ERROR_OK) { diff --git a/src/plugins/canbus/socketcan/socketcanbackend.cpp b/src/plugins/canbus/socketcan/socketcanbackend.cpp index 2ed1310..e38e187 100644 --- a/src/plugins/canbus/socketcan/socketcanbackend.cpp +++ b/src/plugins/canbus/socketcan/socketcanbackend.cpp @@ -516,8 +516,7 @@ bool SocketCanBackend::writeFrame(const QCanBusFrame &newData) qint64 bytesWritten = 0; if (newData.hasFlexibleDataRateFormat()) { - canfd_frame frame; - ::memset(&frame, 0, sizeof(frame)); + canfd_frame frame = {}; frame.len = newData.payload().size(); frame.can_id = canId; frame.flags = newData.hasBitrateSwitch() ? CANFD_BRS : 0; @@ -526,8 +525,7 @@ bool SocketCanBackend::writeFrame(const QCanBusFrame &newData) bytesWritten = ::write(canSocket, &frame, sizeof(frame)); } else { - can_frame frame; - ::memset(&frame, 0, sizeof(frame)); + can_frame frame = {}; frame.can_dlc = newData.payload().size(); frame.can_id = canId; ::memcpy(frame.data, newData.payload().constData(), frame.can_dlc); @@ -714,7 +712,7 @@ void SocketCanBackend::readSocket() QVector<QCanBusFrame> newFrames; for (;;) { - ::memset(&m_frame, 0, sizeof(m_frame)); + m_frame = {}; m_iov.iov_len = sizeof(m_frame); m_msg.msg_namelen = sizeof(m_addr); m_msg.msg_controllen = sizeof(m_ctrlmsg); @@ -734,11 +732,11 @@ void SocketCanBackend::readSocket() continue; } - struct timeval timeStamp; + struct timeval timeStamp = {}; if (Q_UNLIKELY(ioctl(canSocket, SIOCGSTAMP, &timeStamp) < 0)) { setError(qt_error_string(errno), QCanBusDevice::CanBusError::ReadError); - ::memset(&timeStamp, 0, sizeof(timeStamp)); + timeStamp = {}; } const QCanBusFrame::TimeStamp stamp(timeStamp.tv_sec, timeStamp.tv_usec); diff --git a/src/plugins/canbus/systeccan/systeccanbackend.cpp b/src/plugins/canbus/systeccan/systeccanbackend.cpp index a7de557..e5bb09b 100644 --- a/src/plugins/canbus/systeccan/systeccanbackend.cpp +++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp @@ -202,8 +202,7 @@ bool SystecCanBackendPrivate::open() const int bitrate = q->configurationParameter(QCanBusDevice::BitRateKey).toInt(); const bool receiveOwn = q->configurationParameter(QCanBusDevice::ReceiveOwnKey).toBool(); - tUcanInitCanParam param; - ::memset(¶m, 0, sizeof(param)); + tUcanInitCanParam param = {}; param.m_dwSize = sizeof(param); param.m_bMode = receiveOwn ? kUcanModeTxEcho : kUcanModeNormal; param.m_bOCR = USBCAN_OCR_DEFAULT; @@ -373,8 +372,7 @@ void SystecCanBackendPrivate::startWrite() const QCanBusFrame frame = q->dequeueOutgoingFrame(); const QByteArray payload = frame.payload(); - tCanMsgStruct message; - ::memset(&message, 0, sizeof(message)); + tCanMsgStruct message = {}; message.m_dwID = frame.frameId(); message.m_bDLC = quint8(payload.size()); @@ -403,8 +401,7 @@ void SystecCanBackendPrivate::readAllReceivedMessages() QVector<QCanBusFrame> newFrames; for (;;) { - tCanMsgStruct message; - ::memset(&message, 0, sizeof(message)); + tCanMsgStruct message = {}; const UCANRET result = ::UcanReadCanMsgEx(handle, &channel, &message, nullptr); if (result == USBCAN_WARN_NODATA) @@ -463,8 +460,7 @@ QCanBusDevice::CanBusStatus SystecCanBackendPrivate::busStatus() { Q_Q(SystecCanBackend); - tStatusStruct status; - ::memset(&status, 0, sizeof(status)); + tStatusStruct status = {}; const UCANRET result = ::UcanGetStatus(handle, &status); if (Q_UNLIKELY(result != USBCAN_SUCCESSFUL)) { diff --git a/src/plugins/canbus/tinycan/tinycanbackend.cpp b/src/plugins/canbus/tinycan/tinycanbackend.cpp index fdd5aaa..62da66d 100644 --- a/src/plugins/canbus/tinycan/tinycanbackend.cpp +++ b/src/plugins/canbus/tinycan/tinycanbackend.cpp @@ -352,8 +352,7 @@ void TinyCanBackendPrivate::startWrite() const QCanBusFrame frame = q->dequeueOutgoingFrame(); const QByteArray payload = frame.payload(); - TCanMsg message; - ::memset(&message, 0, sizeof(message)); + TCanMsg message = {}; if (Q_UNLIKELY(payload.size() > int(sizeof(message.Data.Bytes)))) { qCWarning(QT_CANBUS_PLUGINS_TINYCAN, "Cannot write frame with payload size %d.", payload.size()); @@ -389,16 +388,14 @@ void TinyCanBackendPrivate::startRead() if (!::CanReceiveGetCount(channelIndex)) break; - TCanMsg message; - ::memset(&message, 0, sizeof(message)); + TCanMsg message = {}; const int messagesToRead = 1; const int ret = ::CanReceive(channelIndex, &message, messagesToRead); if (Q_UNLIKELY(ret < 0)) { q->setError(systemErrorString(ret), QCanBusDevice::CanBusError::ReadError); - TDeviceStatus status; - ::memset(&status, 0, sizeof(status)); + TDeviceStatus status = {}; if (::CanGetDeviceStatus(channelIndex, &status) < 0) { q->setError(systemErrorString(ret), QCanBusDevice::CanBusError::ReadError); diff --git a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h index 9d6e841..4e8c9d4 100644 --- a/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h +++ b/src/plugins/canbus/vectorcan/vectorcan_symbols_p.h @@ -228,6 +228,8 @@ typedef HANDLE XLhandle; #define XL_EVENT_FLAG_OVERRUN 0x01 // Used in XLevent.flags +#define XL_CAN_MAX_DATA_LEN 64 + // structure for XL_RECEIVE_MSG, XL_TRANSMIT_MSG (32 bytes) struct s_xl_can_msg { unsigned long id; @@ -256,6 +258,9 @@ static_assert(sizeof(s_xl_can_msg) == 32, "Invalid size of s_xl_can_msg structur #define XL_CAN_STATE_FLAG_SJA_MODE 0x00000001 +#define XL_CANFD_RX_EVENT_HEADER_SIZE 32 +#define XL_CANFD_MAX_EVENT_SIZE 128 + // CAN Chip status struct s_xl_chip_state { unsigned char busStatus; @@ -285,6 +290,86 @@ typedef struct s_xl_event { } XLevent; static_assert(sizeof(s_xl_event) == 48, "Invalid size of s_xl_event structure"); +typedef struct { + quint32 id; + quint32 flags; + quint32 crc; + quint8 reserved1[12]; + quint16 totalBitCnt; + quint8 dlc; + quint8 reserved[5]; + quint8 data[XL_CAN_MAX_DATA_LEN]; +} XL_CAN_EV_RX_MSG; + +typedef struct { + quint32 canId; + quint32 msgFlags; + quint8 dlc; + quint8 reserved1; + quint16 reserved; + quint8 data[XL_CAN_MAX_DATA_LEN]; +} XL_CAN_EV_TX_REQUEST; + +typedef struct { + quint8 errorCode; + quint8 reserved[95]; +} XL_CAN_EV_ERROR; + +typedef struct { + quint8 busStatus; + quint8 txErrorCounter; + quint8 rxErrorCounter; + quint8 reserved; + quint32 reserved0; +} XL_CAN_EV_CHIP_STATE; + +typedef struct s_xl_sync_pulse_ev { + quint32 triggerSource; + quint32 reserved; + quint64 time; +} XL_SYNC_PULSE_EV; + +typedef XL_SYNC_PULSE_EV XL_CAN_EV_SYNC_PULSE; + +typedef struct { + quint32 size; + quint16 tag; + quint16 channelIndex; + quint32 userHandle; + quint16 flagsChip; + quint16 reserved0; + quint64 reserved1; + quint64 timeStamp; + union { + quint8 raw[XL_CANFD_MAX_EVENT_SIZE - XL_CANFD_RX_EVENT_HEADER_SIZE]; + XL_CAN_EV_RX_MSG canRxOkMsg; + XL_CAN_EV_RX_MSG canTxOkMsg; + XL_CAN_EV_TX_REQUEST canTxRequest; + XL_CAN_EV_ERROR canError; + XL_CAN_EV_CHIP_STATE canChipState; + XL_CAN_EV_SYNC_PULSE canSyncPulse; + } tagData; +} XLcanRxEvent; + +typedef struct { + quint32 id; + quint32 flags; + quint16 dlc; + quint16 reserved[7]; + quint16 data[XL_CAN_MAX_DATA_LEN]; +} XL_CAN_TX_MSG; + +typedef struct { + quint32 tag; + quint32 transId; + quint32 channelIndex; + quint32 reserved[3]; + union { + XL_CAN_TX_MSG canMsg; + } tagData; +} XLcanTxEvent; + + // build a channels mask from the channels index #define XL_CHANNEL_MASK(x) (quint64(1) << (x)) @@ -354,6 +439,22 @@ typedef qint16 XLstatus; #define XL_CAN_STD 01 // flag for standard ID's #define XL_CAN_EXT 02 // flag for extended ID's +#define XL_CAN_TXMSG_FLAG_EDL 0x0001 // extended data length +#define XL_CAN_TXMSG_FLAG_BRS 0x0002 // baud rate switch +#define XL_CAN_TXMSG_FLAG_RTR 0x0010 // remote transmission request +#define XL_CAN_TXMSG_FLAG_HIGHPRIO 0x0080 // high priority message - clears all send buffers - then transmits +#define XL_CAN_TXMSG_FLAG_WAKEUP 0x0200 // generate a wakeup message + +#define XL_CAN_RXMSG_FLAG_EDL 0x0001 // extended data length +#define XL_CAN_RXMSG_FLAG_BRS 0x0002 // baud rate switch +#define XL_CAN_RXMSG_FLAG_ESI 0x0004 // error state indicator +#define XL_CAN_RXMSG_FLAG_RTR 0x0010 // remote transmission request +#define XL_CAN_RXMSG_FLAG_EF 0x0200 // error frame (only posssible in XL_CAN_EV_TX_REQUEST/XL_CAN_EV_TX_REMOVED) +#define XL_CAN_RXMSG_FLAG_ARB_LOST 0x0400 // Arbitration Lost + // set if the receiving node tried to transmit a message but lost arbitration process +#define XL_CAN_RXMSG_FLAG_WAKEUP 0x2000 // high voltage message on single wire CAN +#define XL_CAN_RXMSG_FLAG_TE 0x4000 // 1: transceiver error detected + typedef struct { quint32 busType; union { @@ -447,6 +548,21 @@ typedef struct _XLacceptance { XLaccFilt xtd; } XLacceptance; +typedef struct s_XLcanFdConf { + unsigned int arbitrationBitRate; + unsigned int sjwAbr; + unsigned int tseg1Abr; + unsigned int tseg2Abr; + unsigned int dataBitRate; + unsigned int sjwDbr; + unsigned int tseg1Dbr; + unsigned int tseg2Dbr; + unsigned char reserved; + unsigned char options; + unsigned char reserved1[2]; + unsigned int reserved2; +} XLcanFdConf; + // defines for xlSetGlobalTimeSync #define XL_SET_TIMESYNC_NO_CHANGE ((unsigned long)0) #define XL_SET_TIMESYNC_ON ((unsigned long)1) @@ -476,6 +592,10 @@ GENERATE_SYMBOL_VARIABLE(XLstatus, xlReceive, XLportHandle, quint32 *, XLevent * GENERATE_SYMBOL_VARIABLE(XLstatus, xlSetNotification, XLportHandle, XLhandle *, int) GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanRequestChipState, XLportHandle, XLaccess) GENERATE_SYMBOL_VARIABLE(char *, xlGetErrorString, XLstatus) +GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanFdSetConfiguration, XLportHandle, XLaccess, XLcanFdConf *) +GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanReceive, XLportHandle, XLcanRxEvent *) +GENERATE_SYMBOL_VARIABLE(XLstatus, xlCanTransmitEx, XLportHandle, XLaccess, quint32, quint32 *, XLcanTxEvent *) +GENERATE_SYMBOL_VARIABLE(XLaccess, xlGetChannelMask, int, int, int) inline bool resolveVectorCanSymbols(QLibrary *vectorcanLibrary) { @@ -502,7 +622,10 @@ inline bool resolveVectorCanSymbols(QLibrary *vectorcanLibrary) RESOLVE_SYMBOL(xlSetNotification) RESOLVE_SYMBOL(xlCanRequestChipState) RESOLVE_SYMBOL(xlGetErrorString) - + RESOLVE_SYMBOL(xlCanFdSetConfiguration) + RESOLVE_SYMBOL(xlCanTransmitEx) + RESOLVE_SYMBOL(xlCanReceive) + RESOLVE_SYMBOL(xlGetChannelMask) return true; } diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp index 0382d66..550f744 100644 --- a/src/plugins/canbus/vectorcan/vectorcanbackend.cpp +++ b/src/plugins/canbus/vectorcan/vectorcanbackend.cpp @@ -170,12 +170,19 @@ bool VectorCanBackendPrivate::open() Q_Q(VectorCanBackend); { + XLdriverConfig config; + if (Q_UNLIKELY(::xlGetDriverConfig(&config) != XL_SUCCESS)) { + q->setError(VectorCanBackend::tr("Unable to get driver configuration"), + QCanBusDevice::CanBusError::ConnectionError); + return false; + } + channelMask = config.channel[channelIndex].channelMask; XLaccess permissionMask = channelMask; - const quint32 queueSize = 256; + const quint32 queueSize = usesCanFd ? 8192 : 256; const XLstatus status = ::xlOpenPort(&portHandle, const_cast<char *>(qPrintable(qApp->applicationName())), channelMask, &permissionMask, queueSize, - XL_INTERFACE_VERSION, XL_BUS_TYPE_CAN); + usesCanFd ? XL_INTERFACE_VERSION_V4 : XL_INTERFACE_VERSION, XL_BUS_TYPE_CAN); if (Q_UNLIKELY(status != XL_SUCCESS || portHandle == XL_INVALID_PORTHANDLE)) { q->setError(systemErrorString(status), QCanBusDevice::ConnectionError); @@ -183,6 +190,16 @@ bool VectorCanBackendPrivate::open() return false; } } + if (usesCanFd && arbBitRate != 0) { + XLcanFdConf xlfdconf = {}; + xlfdconf.dataBitRate = (dataBitRate != 0) ? dataBitRate : arbBitRate; + xlfdconf.arbitrationBitRate = arbBitRate; + + const XLstatus status = ::xlCanFdSetConfiguration(portHandle, channelMask, &xlfdconf); + if (Q_UNLIKELY(status != XL_SUCCESS)) + qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, + "Unable to change the configuration for an open channel"); + } { const XLstatus status = ::xlActivateChannel(portHandle, channelMask, @@ -252,6 +269,25 @@ bool VectorCanBackendPrivate::setConfigurationParameter(int key, const QVariant case QCanBusDevice::ReceiveOwnKey: transmitEcho = value.toBool(); return true; + case QCanBusDevice::DataBitRateKey: + return setDataBitRate(value.toUInt()); + case QCanBusDevice::CanFdKey: + { + if (value.toBool()) { + XLdriverConfig config; + if (Q_UNLIKELY(::xlGetDriverConfig(&config) == XL_SUCCESS)) { + if (config.channel[channelIndex].channelCapabilities & XL_CHANNEL_FLAG_CANFD_SUPPORT) { + usesCanFd = true; + return true; + } + } + q->setError(VectorCanBackend::tr("Unable to set CAN FD"), + QCanBusDevice::CanBusError::ConfigurationError); + return false; + } + usesCanFd = false; + return true; + } default: q->setError(VectorCanBackend::tr("Unsupported configuration key"), QCanBusDevice::ConfigurationError); @@ -261,13 +297,18 @@ bool VectorCanBackendPrivate::setConfigurationParameter(int key, const QVariant void VectorCanBackendPrivate::setupChannel(const QString &interfaceName) { + Q_Q(VectorCanBackend); if (Q_LIKELY(interfaceName.startsWith(QStringLiteral("can")))) { const QStringRef ref = interfaceName.midRef(3); bool ok = false; - const int channelIndex = ref.toInt(&ok); + channelIndex = ref.toInt(&ok); if (ok && (channelIndex >= 0 && channelIndex < XL_CONFIG_MAX_CHANNELS)) { - channelMask = XL_CHANNEL_MASK((channelIndex)); + channelMask = xlGetChannelMask(-1, channelIndex, 0); return; + } else { + channelIndex = -1; + q->setError(VectorCanBackend::tr("Unable to setup channel with interface name %1") + .arg(interfaceName), QCanBusDevice::CanBusError::ConfigurationError); } } @@ -302,29 +343,47 @@ void VectorCanBackendPrivate::startWrite() const QCanBusFrame frame = q->dequeueOutgoingFrame(); const QByteArray payload = frame.payload(); - XLevent event; - ::memset(&event, 0, sizeof(event)); - - event.tag = XL_TRANSMIT_MSG; - - s_xl_can_msg &msg = event.tagData.msg; + quint32 eventCount = 1; + XLstatus status = XL_ERROR; + if (usesCanFd) { + XLcanTxEvent event = {}; + + event.tag = XL_CAN_EV_TAG_TX_MSG; + XL_CAN_TX_MSG &msg = event.tagData.canMsg; + + msg.id = frame.frameId(); + if (frame.hasExtendedFrameFormat()) + msg.id |= XL_CAN_EXT_MSG_ID; + + msg.dlc = payload.size(); + if (frame.hasFlexibleDataRateFormat()) + msg.flags = XL_CAN_TXMSG_FLAG_EDL; + if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) + msg.flags |= XL_CAN_TXMSG_FLAG_RTR; // we do not care about the payload + else + ::memcpy(msg.data, payload.constData(), sizeof(msg.data)); + + status = ::xlCanTransmitEx(portHandle, channelMask, eventCount, &eventCount, &event); + } else { + XLevent event = {}; + event.tag = XL_TRANSMIT_MSG; + s_xl_can_msg &msg = event.tagData.msg; - msg.id = frame.frameId(); - if (frame.hasExtendedFrameFormat()) - msg.id |= XL_CAN_EXT_MSG_ID; + msg.id = frame.frameId(); + if (frame.hasExtendedFrameFormat()) + msg.id |= XL_CAN_EXT_MSG_ID; - msg.dlc = payload.size(); + msg.dlc = payload.size(); - if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) - msg.flags |= XL_CAN_MSG_FLAG_REMOTE_FRAME; // we do not care about the payload - else if (frame.frameType() == QCanBusFrame::ErrorFrame) - msg.flags |= XL_CAN_MSG_FLAG_ERROR_FRAME; // we do not care about the payload - else - ::memcpy(msg.data, payload.constData(), sizeof(msg.data)); + if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) + msg.flags |= XL_CAN_MSG_FLAG_REMOTE_FRAME; // we do not care about the payload + else if (frame.frameType() == QCanBusFrame::ErrorFrame) + msg.flags |= XL_CAN_MSG_FLAG_ERROR_FRAME; // we do not care about the payload + else + ::memcpy(msg.data, payload.constData(), sizeof(msg.data)); - quint32 eventCount = 1; - const XLstatus status = ::xlCanTransmit(portHandle, channelMask, - &eventCount, &event); + status = ::xlCanTransmit(portHandle, channelMask, &eventCount, &event); + } if (Q_UNLIKELY(status != XL_SUCCESS)) { q->setError(systemErrorString(status), QCanBusDevice::WriteError); @@ -344,38 +403,64 @@ void VectorCanBackendPrivate::startRead() for (;;) { quint32 eventCount = 1; - XLevent event; - ::memset(&event, 0, sizeof(event)); - - const XLstatus status = ::xlReceive(portHandle, &eventCount, &event); - if (Q_UNLIKELY(status != XL_SUCCESS)) { - if (status != XL_ERR_QUEUE_IS_EMPTY) { - q->setError(systemErrorString(status), - QCanBusDevice::ReadError); + if (usesCanFd) { + XLcanRxEvent event = {}; + + const XLstatus status = ::xlCanReceive(portHandle, &event); + if (Q_UNLIKELY(status != XL_SUCCESS)) { + if (status != XL_ERR_QUEUE_IS_EMPTY) { + q->setError(systemErrorString(status), QCanBusDevice::ReadError); + } + break; + } + if (event.tag != XL_CAN_EV_TAG_RX_OK) + continue; + + const XL_CAN_EV_RX_MSG &msg = event.tagData.canRxOkMsg; + + QCanBusFrame frame(msg.id & ~XL_CAN_EXT_MSG_ID, + QByteArray(reinterpret_cast<const char *>(msg.data), int(msg.dlc))); + frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStamp / 1000)); + frame.setExtendedFrameFormat(msg.id & XL_CAN_RXMSG_FLAG_EDL); + frame.setFrameType((msg.flags & XL_CAN_RXMSG_FLAG_RTR) + ? QCanBusFrame::RemoteRequestFrame + : (msg.flags & XL_CAN_RXMSG_FLAG_EF) + ? QCanBusFrame::ErrorFrame + : QCanBusFrame::DataFrame); + + newFrames.append(std::move(frame)); + } else { + XLevent event = {}; + + const XLstatus status = ::xlReceive(portHandle, &eventCount, &event); + if (Q_UNLIKELY(status != XL_SUCCESS)) { + if (status != XL_ERR_QUEUE_IS_EMPTY) { + q->setError(systemErrorString(status), + QCanBusDevice::ReadError); + } + break; } - break; + if (event.tag != XL_RECEIVE_MSG) + continue; + + const s_xl_can_msg &msg = event.tagData.msg; + + if ((msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED) && !transmitEcho) + continue; + + QCanBusFrame frame(msg.id & ~XL_CAN_EXT_MSG_ID, + QByteArray(reinterpret_cast<const char *>(msg.data), int(msg.dlc))); + frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStamp / 1000)); + frame.setExtendedFrameFormat(msg.id & XL_CAN_EXT_MSG_ID); + frame.setLocalEcho(msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED); + frame.setFrameType((msg.flags & XL_CAN_MSG_FLAG_REMOTE_FRAME) + ? QCanBusFrame::RemoteRequestFrame + : (msg.flags & XL_CAN_MSG_FLAG_ERROR_FRAME) + ? QCanBusFrame::ErrorFrame + : QCanBusFrame::DataFrame); + + newFrames.append(std::move(frame)); } - - if (event.tag != XL_RECEIVE_MSG) - continue; - - const s_xl_can_msg &msg = event.tagData.msg; - - if ((msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED) && !transmitEcho) - continue; - - QCanBusFrame frame(msg.id & ~XL_CAN_EXT_MSG_ID, - QByteArray(reinterpret_cast<const char *>(msg.data), int(msg.dlc))); - frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(event.timeStamp / 1000)); - frame.setExtendedFrameFormat(msg.id & XL_CAN_EXT_MSG_ID); - frame.setLocalEcho(msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED); - frame.setFrameType((msg.flags & XL_CAN_MSG_FLAG_REMOTE_FRAME) - ? QCanBusFrame::RemoteRequestFrame - : (msg.flags & XL_CAN_MSG_FLAG_ERROR_FRAME) - ? QCanBusFrame::ErrorFrame - : QCanBusFrame::DataFrame); - - newFrames.append(std::move(frame)); } q->enqueueReceivedFrames(newFrames); @@ -425,19 +510,40 @@ void VectorCanBackendPrivate::cleanupDriver() bool VectorCanBackendPrivate::setBitRate(quint32 bitrate) { Q_Q(VectorCanBackend); - - if (q->state() != QCanBusDevice::UnconnectedState) { + if (!usesCanFd && q->state() != QCanBusDevice::UnconnectedState) { const XLstatus status = ::xlCanSetChannelBitrate(portHandle, channelMask, bitrate); + arbBitRate = bitrate; if (Q_UNLIKELY(status != XL_SUCCESS)) { q->setError(systemErrorString(status), QCanBusDevice::CanBusError::ConfigurationError); return false; } + } else if (arbBitRate != bitrate) { + arbBitRate = bitrate; } return true; } +bool VectorCanBackendPrivate::setDataBitRate(quint32 bitrate) +{ + if (!usesCanFd) { + qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, + "Cannot set data bit rate in CAN 2.0 mode, this is only available with CAN FD"); + return false; + } + if (dataBitRate != bitrate) { + if (bitrate >= 25000) { // Minimum + dataBitRate = bitrate; + } else { + qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, + "Cannot set data bit rate to less than 25000 which is the minimum"); + return false; + } + } + return true; +} + VectorCanBackend::VectorCanBackend(const QString &name, QObject *parent) : QCanBusDevice(parent) , d_ptr(new VectorCanBackendPrivate(this)) @@ -520,9 +626,8 @@ bool VectorCanBackend::writeFrame(const QCanBusFrame &newData) return false; } - // CAN FD frame format not implemented at this stage - if (Q_UNLIKELY(newData.hasFlexibleDataRateFormat())) { - setError(tr("CAN FD frame format not supported."), + if (!d->usesCanFd && newData.hasFlexibleDataRateFormat()) { + setError(tr("Unable to write a flexible data rate format frame without CAN FD enabled."), QCanBusDevice::WriteError); return false; } @@ -556,34 +661,51 @@ QCanBusDevice::CanBusStatus VectorCanBackend::busStatus() return QCanBusDevice::CanBusStatus::Unknown; } - quint32 eventCount = 1; - XLevent event; - ::memset(&event, 0, sizeof(event)); + quint8 busStatus = 0; + if (d->usesCanFd) { + XLcanRxEvent event = {}; + + const XLstatus receiveStatus = ::xlCanReceive(d->portHandle, &event); + if (Q_UNLIKELY(receiveStatus != XL_SUCCESS)) { + const QString errorString = d->systemErrorString(receiveStatus); + qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Can not query CAN bus status: %ls.", + qUtf16Printable(errorString)); + setError(errorString, QCanBusDevice::CanBusError::ReadError); + return QCanBusDevice::CanBusStatus::Unknown; + } - const XLstatus receiveStatus = ::xlReceive(d->portHandle, &eventCount, &event); - if (Q_UNLIKELY(receiveStatus != XL_SUCCESS)) { - const QString errorString = d->systemErrorString(receiveStatus); - qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Can not query CAN bus status: %ls.", - qUtf16Printable(errorString)); - setError(errorString, QCanBusDevice::CanBusError::ReadError); - return QCanBusDevice::CanBusStatus::Unknown; - } + if (Q_LIKELY(event.tag == XL_CAN_EV_TAG_CHIP_STATE)) + busStatus = event.tagData.canChipState.busStatus; - if (Q_LIKELY(event.tag == XL_CHIP_STATE)) { - switch (event.tagData.chipState.busStatus) { - case XL_CHIPSTAT_BUSOFF: - return QCanBusDevice::CanBusStatus::BusOff; - case XL_CHIPSTAT_ERROR_PASSIVE: - return QCanBusDevice::CanBusStatus::Error; - case XL_CHIPSTAT_ERROR_WARNING: - return QCanBusDevice::CanBusStatus::Warning; - case XL_CHIPSTAT_ERROR_ACTIVE: - return QCanBusDevice::CanBusStatus::Good; + } else { + quint32 eventCount = 1; + XLevent event = {}; + + const XLstatus receiveStatus = ::xlReceive(d->portHandle, &eventCount, &event); + if (Q_UNLIKELY(receiveStatus != XL_SUCCESS)) { + const QString errorString = d->systemErrorString(receiveStatus); + qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Can not query CAN bus status: %ls.", + qUtf16Printable(errorString)); + setError(errorString, QCanBusDevice::CanBusError::ReadError); + return QCanBusDevice::CanBusStatus::Unknown; } + + if (Q_LIKELY(event.tag == XL_CHIP_STATE)) + busStatus = event.tagData.chipState.busStatus; + } + + switch (busStatus) { + case XL_CHIPSTAT_BUSOFF: + return QCanBusDevice::CanBusStatus::BusOff; + case XL_CHIPSTAT_ERROR_PASSIVE: + return QCanBusDevice::CanBusStatus::Error; + case XL_CHIPSTAT_ERROR_WARNING: + return QCanBusDevice::CanBusStatus::Warning; + case XL_CHIPSTAT_ERROR_ACTIVE: + return QCanBusDevice::CanBusStatus::Good; } - qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Unknown CAN bus status: %u", - uint(event.tagData.chipState.busStatus)); + qCWarning(QT_CANBUS_PLUGINS_VECTORCAN, "Unknown CAN bus status: %u", busStatus); return QCanBusDevice::CanBusStatus::Unknown; } diff --git a/src/plugins/canbus/vectorcan/vectorcanbackend_p.h b/src/plugins/canbus/vectorcan/vectorcanbackend_p.h index 3eafb0c..b8116a6 100644 --- a/src/plugins/canbus/vectorcan/vectorcanbackend_p.h +++ b/src/plugins/canbus/vectorcan/vectorcanbackend_p.h @@ -81,6 +81,7 @@ public: void startupDriver(); static void cleanupDriver(); bool setBitRate(quint32 bitrate); + bool setDataBitRate(quint32 bitrate); VectorCanBackend * const q_ptr; @@ -90,6 +91,10 @@ public: HANDLE readHandle = INVALID_HANDLE_VALUE; QTimer *writeNotifier = nullptr; QWinEventNotifier *readNotifier = nullptr; + quint32 dataBitRate = 0; + quint32 arbBitRate = 0; + int channelIndex = -1; + bool usesCanFd = false; }; QT_END_NAMESPACE diff --git a/src/serialbus/doc/src/vectorcan.qdoc b/src/serialbus/doc/src/vectorcan.qdoc index 70b6521..0d2921b 100644 --- a/src/serialbus/doc/src/vectorcan.qdoc +++ b/src/serialbus/doc/src/vectorcan.qdoc @@ -105,6 +105,15 @@ bus immediately appear in the receive buffer. This can be used to check if sending was successful. If this option is enabled, the therefore received frames are marked with QCanBusFrame::hasLocalEcho() + \row + \li QCanBusDevice::CanFdKey + \li Enable the use of CAN FD on the CAN bus connection. If this option is enabled, then + it is not possible to receive your own CAN frames being sent, so setting + QCanBusDevice::ReceiveOwnKey to true has no effect. Since Qt 5.15. + \row + \li QCanBusDevice::DataBitRateKey + \li Determines the data bit rate of the CAN bus connection. This is only available when + \l QCanBusDevice::CanFdKey is set to true. Since Qt 5.15. \endtable VectorCAN supports the following additional functions: |