summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/serialbus/can/connectdialog.cpp2
-rw-r--r--src/plugins/canbus/canbus.pro2
-rw-r--r--src/plugins/canbus/systeccan/main.cpp69
-rw-r--r--src/plugins/canbus/systeccan/plugin.json3
-rw-r--r--src/plugins/canbus/systeccan/systeccan.pro19
-rw-r--r--src/plugins/canbus/systeccan/systeccan_symbols_p.h277
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.cpp496
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend.h76
-rw-r--r--src/plugins/canbus/systeccan/systeccanbackend_p.h110
-rw-r--r--src/serialbus/doc/src/qtcanbus-backends.qdoc4
-rw-r--r--src/serialbus/doc/src/systeccan.qdoc100
11 files changed, 1157 insertions, 1 deletions
diff --git a/examples/serialbus/can/connectdialog.cpp b/examples/serialbus/can/connectdialog.cpp
index 38f0397..6615474 100644
--- a/examples/serialbus/can/connectdialog.cpp
+++ b/examples/serialbus/can/connectdialog.cpp
@@ -110,6 +110,8 @@ void ConnectDialog::backendChanged(const QString &backend)
m_ui->interfaceNameEdit->setPlaceholderText(QStringLiteral("usb0"));
else if (backend == QStringLiteral("socketcan"))
m_ui->interfaceNameEdit->setPlaceholderText(QStringLiteral("can0"));
+ else if (backend == QStringLiteral("systeccan"))
+ m_ui->interfaceNameEdit->setPlaceholderText(QStringLiteral("can0.0"));
else if (backend == QStringLiteral("tinycan"))
m_ui->interfaceNameEdit->setPlaceholderText(QStringLiteral("can0.0"));
else if (backend == QStringLiteral("vectorcan"))
diff --git a/src/plugins/canbus/canbus.pro b/src/plugins/canbus/canbus.pro
index 0304dcc..7d70bb9 100644
--- a/src/plugins/canbus/canbus.pro
+++ b/src/plugins/canbus/canbus.pro
@@ -7,4 +7,4 @@ qtConfig(socketcan) {
}
SUBDIRS += peakcan tinycan
-win32:SUBDIRS += vectorcan
+win32:SUBDIRS += systeccan vectorcan
diff --git a/src/plugins/canbus/systeccan/main.cpp b/src/plugins/canbus/systeccan/main.cpp
new file mode 100644
index 0000000..1302e71
--- /dev/null
+++ b/src/plugins/canbus/systeccan/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "systeccanbackend.h"
+
+#include <QtSerialBus/qcanbus.h>
+#include <QtSerialBus/qcanbusdevice.h>
+#include <QtSerialBus/qcanbusfactory.h>
+
+QT_BEGIN_NAMESPACE
+
+class SystecCanBusPlugin : public QObject, public QCanBusFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QCanBusFactory" FILE "plugin.json")
+ Q_INTERFACES(QCanBusFactory)
+
+public:
+ QCanBusDevice *createDevice(const QString &interfaceName, QString *errorMessage) const override
+ {
+ QString errorReason;
+ if (Q_UNLIKELY(!SystecCanBackend::canCreate(&errorReason))) {
+ qWarning("%ls", qUtf16Printable(errorReason));
+ if (errorMessage)
+ *errorMessage = errorReason;
+ return nullptr;
+ }
+
+ auto *device = new SystecCanBackend(interfaceName);
+ return device;
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/canbus/systeccan/plugin.json b/src/plugins/canbus/systeccan/plugin.json
new file mode 100644
index 0000000..982c78d
--- /dev/null
+++ b/src/plugins/canbus/systeccan/plugin.json
@@ -0,0 +1,3 @@
+{
+ "Key": "systeccan"
+}
diff --git a/src/plugins/canbus/systeccan/systeccan.pro b/src/plugins/canbus/systeccan/systeccan.pro
new file mode 100644
index 0000000..06d5537
--- /dev/null
+++ b/src/plugins/canbus/systeccan/systeccan.pro
@@ -0,0 +1,19 @@
+TARGET = qtsysteccanbus
+
+QT = core-private serialbus
+
+HEADERS += \
+ systeccanbackend.h \
+ systeccanbackend_p.h \
+ systeccan_symbols_p.h
+
+SOURCES += \
+ main.cpp \
+ systeccanbackend.cpp
+
+DISTFILES = plugin.json
+
+PLUGIN_TYPE = canbus
+PLUGIN_EXTENDS = serialbus
+PLUGIN_CLASS_NAME = SystecCanBusPlugin
+load(qt_plugin)
diff --git a/src/plugins/canbus/systeccan/systeccan_symbols_p.h b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
new file mode 100644
index 0000000..3b4429e
--- /dev/null
+++ b/src/plugins/canbus/systeccan/systeccan_symbols_p.h
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYSTECCAN_SYMBOLS_P_H
+#define SYSTECCAN_SYMBOLS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlibrary.h>
+#include <QtCore/qstring.h>
+
+#include <windows.h>
+#define DRV_CALLBACK_TYPE WINAPI
+
+typedef quint8 UCANRET;
+typedef quint8 tUcanHandle;
+
+#define GENERATE_SYMBOL_VARIABLE(returnType, symbolName, ...) \
+ typedef returnType (DRV_CALLBACK_TYPE *fp_##symbolName)(__VA_ARGS__); \
+ static fp_##symbolName symbolName;
+
+#define RESOLVE_SYMBOL(symbolName) \
+ symbolName = (fp_##symbolName)systecLibrary->resolve(#symbolName); \
+ if (!symbolName) \
+ return false;
+
+typedef void (DRV_CALLBACK_TYPE *tCallbackFktEx) (tUcanHandle handle, quint32 event, quint8 channel, void *args);
+
+// The Callback function is called, if certain events did occur.
+// These Defines specify the event.
+#define USBCAN_EVENT_INITHW 0 // the USB-CANmodul has been initialized
+#define USBCAN_EVENT_INITCAN 1 // the CAN interface has been initialized
+#define USBCAN_EVENT_RECEIVE 2 // a new CAN message has been received
+#define USBCAN_EVENT_STATUS 3 // the error state in the module has changed
+#define USBCAN_EVENT_DEINITCAN 4 // the CAN interface has been deinitialized (UcanDeinitCan() was called)
+#define USBCAN_EVENT_DEINITHW 5 // the USB-CANmodul has been deinitialized (UcanDeinitHardware() was called)
+#define USBCAN_EVENT_CONNECT 6 // a new USB-CANmodul has been connected
+#define USBCAN_EVENT_DISCONNECT 7 // a USB-CANmodul has been disconnected
+#define USBCAN_EVENT_FATALDISCON 8 // a USB-CANmodul has been disconnected during operation
+#define USBCAN_EVENT_RESERVED1 0x80
+
+#define kUcanModeNormal 0x00 // normal mode (send and receive)
+#define kUcanModeListenOnly 0x01 // listen only mode (only receive)
+#define kUcanModeTxEcho 0x02 // CAN messages which was sent will be received at UcanReadCanMsg..
+#define kUcanModeRxOrderCh 0x04 // reserved (not implemented in this version)
+#define kUcanModeHighResTimer 0x08 // high resolution time stamps in received CAN messages (only available with STM derivates)
+
+// ABR and ACR for mode "receive all CAN messages"
+#define USBCAN_AMR_ALL (quint32) 0xffffffff
+#define USBCAN_ACR_ALL (quint32) 0x00000000
+
+#define USBCAN_OCR_DEFAULT 0x1A // default OCR for standard GW-002
+#define USBCAN_OCR_RS485_ISOLATED 0x1E // OCR for RS485 interface and galvanic isolation
+#define USBCAN_OCR_RS485_NOT_ISOLATED 0x0A // OCR for RS485 interface without galvanic isolation
+#define USBCAN_DEFAULT_BUFFER_ENTRIES 4096
+
+// Structure with init parameters for function UcanInitCanEx() and UcanInitCanEx2()
+#pragma pack(push, 1)
+typedef struct _tUcanInitCanParam {
+ quint32 m_dwSize; // [IN] size of this structure
+ quint8 m_bMode; // [IN] selects the mode of CAN controller (see kUcanMode...)
+
+ // Baudrate Registers for GW-001 or GW-002
+ quint8 m_bBTR0; // [IN] Bus Timing Register 0 (SJA1000 - use high byte USBCAN_BAUD_...)
+ quint8 m_bBTR1; // [IN] Bus Timing Register 1 (SJA1000 - use low byte USBCAN_BAUD_...)
+
+ quint8 m_bOCR; // [IN] Output Control Register of SJA1000 (should be 0x1A)
+ quint32 m_dwAMR; // [IN] Acceptance Mask Register (SJA1000)
+ quint32 m_dwACR; // [IN] Acceptance Code Register (SJA1000)
+
+ // since version V3.00 - is ignored from function UcanInitCanEx() and until m_dwSize < 20
+ quint32 m_dwBaudrate; // [IN] Baudrate Register for Multiport 3004006, USB-CANmodul1 3204000 or USB-CANmodul2 3204002
+ // (use USBCAN_BAUDEX_...)
+
+ // since version V3.05 - is ignored until m_dwSize < 24
+ quint16 m_wNrOfRxBufferEntries; // [IN] number of receive buffer entries (default is 4096)
+ quint16 m_wNrOfTxBufferEntries; // [IN] number of transmit buffer entries (default is 4096)
+} tUcanInitCanParam;
+
+#define USBCAN_BAUDEX_1MBit 0x00020354 // = 1000 kBit/s Sample Point: 68,75%
+#define USBCAN_BAUDEX_800kBit 0x00030254 // = 800 kBit/s Sample Point: 66,67%
+#define USBCAN_BAUDEX_500kBit 0x00050354 // = 500 kBit/s Sample Point: 68,75%
+#define USBCAN_BAUDEX_250kBit 0x000B0354 // = 250 kBit/s Sample Point: 68,75%
+#define USBCAN_BAUDEX_125kBit 0x00170354 // = 125 kBit/s Sample Point: 68,75%
+#define USBCAN_BAUDEX_100kBit 0x00171466 // = 100 kBit/s Sample Point: 65,00%
+#define USBCAN_BAUDEX_50kBit 0x002F1466 // = 50 kBit/s Sample Point: 65,00%
+#define USBCAN_BAUDEX_20kBit 0x00771466 // = 20 kBit/s Sample Point: 65,00%
+#define USBCAN_BAUDEX_10kBit 0x80771466 // = 10 kBit/s Sample Point: 65,00% (CLK = 1, see L-487 since version 15)
+
+// Frame format for a CAN message (bit oriented)
+#define USBCAN_MSG_FF_STD 0x00 // Standard Frame (11-Bit-ID)
+#define USBCAN_MSG_FF_ECHO 0x20 // Tx echo (message received from UcanReadCanMsg.. was previously sent by UcanWriteCanMsg..)
+#define USBCAN_MSG_FF_RTR 0x40 // Remote Transmission Request Frame
+#define USBCAN_MSG_FF_EXT 0x80 // Extended Frame (29-Bit-ID)
+
+typedef struct _tCanMsgStruct {
+ quint32 m_dwID; // CAN Identifier
+ quint8 m_bFF; // CAN Frame format (BIT7=1: 29BitID / BIT6=1: RTR-Frame / BIT5=1: Tx echo)
+ quint8 m_bDLC; // CAN Data Length Code
+ quint8 m_bData[8]; // CAN Data
+ quint32 m_dwTime; // Time in ms
+} tCanMsgStruct;
+
+// Function return codes (encoding)
+#define USBCAN_SUCCESSFUL 0x00 // no error
+#define USBCAN_ERR 0x01 // error in library; function has not been executed
+#define USBCAN_ERRCMD 0x40 // error in module; function has not been executed
+#define USBCAN_WARNING 0x80 // Warning; function has been executed anyway
+#define USBCAN_RESERVED 0xc0 // reserved return codes (up to 255)
+
+// Error messages, that can occur in the library
+#define USBCAN_ERR_RESOURCE 0x01 // could not create a resource (memory, Handle, ...)
+#define USBCAN_ERR_MAXMODULES 0x02 // the maximum number of open modules is exceeded
+#define USBCAN_ERR_HWINUSE 0x03 // a module is already in use
+#define USBCAN_ERR_ILLVERSION 0x04 // the software versions of the module and library are incompatible
+#define USBCAN_ERR_ILLHW 0x05 // the module with the corresponding device number is not connected
+#define USBCAN_ERR_ILLHANDLE 0x06 // wrong USB-CAN-Handle handed over to the function
+#define USBCAN_ERR_ILLPARAM 0x07 // wrong parameter handed over to the function
+#define USBCAN_ERR_BUSY 0x08 // instruction can not be processed at this time
+#define USBCAN_ERR_TIMEOUT 0x09 // no answer from the module
+#define USBCAN_ERR_IOFAILED 0x0a // a request for the driver failed
+#define USBCAN_ERR_DLL_TXFULL 0x0b // the message did not fit into the transmission queue
+#define USBCAN_ERR_MAXINSTANCES 0x0c // maximum number of applications is reached
+#define USBCAN_ERR_CANNOTINIT 0x0d // CAN-interface is not yet initialized
+#define USBCAN_ERR_DISCONNECT 0x0e // USB-CANmodul was disconnected
+#define USBCAN_ERR_DISCONECT USBCAN_ERR_DISCONNECT // renamed (still defined for compatibility reason)
+#define USBCAN_ERR_NOHWCLASS 0x0f // the needed device class does not exist
+#define USBCAN_ERR_ILLCHANNEL 0x10 // illegal CAN channel for GW-001/GW-002
+#define USBCAN_ERR_RESERVED1 0x11
+#define USBCAN_ERR_ILLHWTYPE 0x12 // the API function can not be used with this hardware
+#define USBCAN_ERR_SERVER_TIMEOUT 0x13 // the command server does not send an reply of an command
+
+// Error messages, that the module returns during the command sequence
+#define USBCAN_ERRCMD_NOTEQU 0x40 // the received response does not match with the transmitted command
+#define USBCAN_ERRCMD_REGTST 0x41 // no access to the CAN controller possible
+#define USBCAN_ERRCMD_ILLCMD 0x42 // the module could not interpret the command
+#define USBCAN_ERRCMD_EEPROM 0x43 // error while reading the EEPROM occurred
+#define USBCAN_ERRCMD_RESERVED1 0x44
+#define USBCAN_ERRCMD_RESERVED2 0x45
+#define USBCAN_ERRCMD_RESERVED3 0x46
+#define USBCAN_ERRCMD_ILLBDR 0x47 // illegal baudrate values for Multiport 3004006, USB-CANmodul1 3204000 or USB-CANmodul2 3204002 in BTR0/BTR1
+#define USBCAN_ERRCMD_NOTINIT 0x48 // CAN channel was not initialized
+#define USBCAN_ERRCMD_ALREADYINIT 0x49 // CAN channel was already initialized
+#define USBCAN_ERRCMD_ILLSUBCMD 0x4A // illegal sub-command specified
+#define USBCAN_ERRCMD_ILLIDX 0x4B // illegal index specified (e.g. index for cyclic CAN message)
+#define USBCAN_ERRCMD_RUNNING 0x4C // cyclic CAN message(s) can not be defined because transmission of cyclic CAN messages is already running
+
+// Warning messages, that can occur in library
+// NOTE: These messages are only warnings. The function has been executed anyway.
+#define USBCAN_WARN_NODATA 0x80 // no CAN messages received
+#define USBCAN_WARN_SYS_RXOVERRUN 0x81 // overrun in the receive queue of the driver (but this CAN message is successfuly read)
+#define USBCAN_WARN_DLL_RXOVERRUN 0x82 // overrun in the receive queue of the library (but this CAN message is successfuly read)
+#define USBCAN_WARN_RESERVED1 0x83
+#define USBCAN_WARN_RESERVED2 0x84
+#define USBCAN_WARN_FW_TXOVERRUN 0x85 // overrun in the transmit queue of the firmware (but this CAN message was successfully stored in buffer)
+#define USBCAN_WARN_FW_RXOVERRUN 0x86 // overrun in the receive queue of the firmware (but this CAN message was successfully read)
+#define USBCAN_WARN_FW_TXMSGLOST 0x87 // (not implemented yet)
+#define USBCAN_WARN_NULL_PTR 0x90 // pointer to address is NULL (function will not work correctly)
+#define USBCAN_WARN_TXLIMIT 0x91 // function UcanWriteCanMsgEx() was called for sending more CAN messages than one
+ // But not all of them could be sent because the buffer is full.
+ // Variable pointed by pdwCount_p received the number of successfully sent CAN messages.
+#define USBCAN_WARN_BUSY 0x92 // place holder (only for internaly use)
+
+typedef struct _tUcanHardwareInfoEx {
+ DWORD m_dwSize; // [IN] size of this structure
+ tUcanHandle m_UcanHandle; // [OUT] USB-CAN-Handle assigned by the DLL
+ BYTE m_bDeviceNr; // [OUT] device number of the USB-CANmodul
+ DWORD m_dwSerialNr; // [OUT] serial number from USB-CANmodul
+ DWORD m_dwFwVersionEx; // [OUT] version of firmware
+ DWORD m_dwProductCode; // [OUT] product code (for differentiate between different hardware modules)
+ // see constants USBCAN_PRODCODE_...
+
+ DWORD m_adwUniqueId[4]; // [OUT] unique ID (available since V5.01) !!! m_dwSize must be >= USBCAN_HWINFO_SIZE_V2
+ DWORD m_dwFlags; // [OUT] additional flags
+} tUcanHardwareInfoEx;
+
+#define USBCAN_HWINFO_SIZE_V1 0x12 // size without m_adwDeviceId[]
+#define USBCAN_HWINFO_SIZE_V2 0x22 // size with m_adwDeviceId[]
+#define USBCAN_HWINFO_SIZE_V3 0x26 // size with m_adwDeviceId[] and m_dwFlags
+
+typedef struct _tUcanHardwareInitInfo {
+ DWORD m_dwSize; // [IN] size of this structure
+ BOOL m_fDoInitialize; // [IN] specifies if the found module should be initialized by the DLL
+ tUcanHandle *m_pUcanHandle; // [IN] pointer to variable receiving the USB-CAN-Handle
+ tCallbackFktEx m_fpCallbackFktEx; // [IN] pointer to callback function
+ void *m_pCallbackArg; // [IN] pointer to user defined parameter for callback function
+ BOOL m_fTryNext; // [IN] specifies if a further module should be found
+} tUcanHardwareInitInfo;
+
+typedef void (DRV_CALLBACK_TYPE *tUcanEnumCallback) (
+ DWORD dwIndex_p, // [IN] gives a sequential number of the enumerated module
+ BOOL fIsUsed_p, // [IN] set to TRUE if the module is used by another application
+ tUcanHardwareInfoEx *pHwInfoEx_p, // [IN] pointer to the hardware info structure identifying the enumerated module
+ tUcanHardwareInitInfo *pInitInfo_p, // [IN] pointer to an init structure for initializing the module
+ void *pArg_p); // [IN] user argument which was overhand with UcanEnumerateHardware()
+
+#pragma pack(pop)
+
+GENERATE_SYMBOL_VARIABLE(quint32, UcanEnumerateHardware,
+ tUcanEnumCallback /* callback */, void * /* args */,
+ BOOL /* used */,
+ quint8, quint8 /* device number low and high */,
+ quint32, quint32, /* serial low and high */
+ quint32, quint32 /* product code low and high */)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanInitHardwareEx, tUcanHandle *, quint8 /* device */,
+ tCallbackFktEx /* callback */, void *)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanDeinitHardware, tUcanHandle)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanInitCanEx2, tUcanHandle, quint8 /* channel */, tUcanInitCanParam *)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanDeinitCanEx, tUcanHandle, quint8 /* channel */)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanReadCanMsgEx, tUcanHandle, quint8 *, tCanMsgStruct *, quint32 *)
+GENERATE_SYMBOL_VARIABLE(UCANRET, UcanWriteCanMsgEx, tUcanHandle, quint8, tCanMsgStruct *, quint32 *)
+
+inline bool resolveSymbols(QLibrary *systecLibrary)
+{
+ if (!systecLibrary->isLoaded()) {
+#ifdef Q_PROCESSOR_X86_64
+ systecLibrary->setFileName(QStringLiteral("usbcan64"));
+#else
+ systecLibrary->setFileName(QStringLiteral("usbcan32"));
+#endif
+ if (!systecLibrary->load())
+ return false;
+ }
+
+ RESOLVE_SYMBOL(UcanInitHardwareEx);
+ RESOLVE_SYMBOL(UcanDeinitHardware);
+ RESOLVE_SYMBOL(UcanInitCanEx2);
+ RESOLVE_SYMBOL(UcanDeinitCanEx);
+ RESOLVE_SYMBOL(UcanReadCanMsgEx);
+ RESOLVE_SYMBOL(UcanWriteCanMsgEx);
+
+ return true;
+}
+
+#endif // SYSTECCAN_SYMBOLS_P_H
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.cpp b/src/plugins/canbus/systeccan/systeccanbackend.cpp
new file mode 100644
index 0000000..a947cd3
--- /dev/null
+++ b/src/plugins/canbus/systeccan/systeccanbackend.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "systeccanbackend.h"
+#include "systeccanbackend_p.h"
+#include "systeccan_symbols_p.h"
+
+#include <QtSerialBus/qcanbusdevice.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QLibrary, systecLibrary)
+
+bool SystecCanBackend::canCreate(QString *errorReason)
+{
+ static bool symbolsResolved = resolveSymbols(systecLibrary());
+ if (Q_UNLIKELY(!symbolsResolved)) {
+ *errorReason = systecLibrary()->errorString();
+ return false;
+ }
+ return true;
+}
+
+class OutgoingEventNotifier : public QTimer
+{
+public:
+ OutgoingEventNotifier(SystecCanBackendPrivate *d, QObject *parent) :
+ QTimer(parent),
+ dptr(d)
+ {
+ }
+
+protected:
+ void timerEvent(QTimerEvent *e) override
+ {
+ if (e->timerId() == timerId()) {
+ dptr->startWrite();
+ return;
+ }
+ QTimer::timerEvent(e);
+ }
+
+private:
+ SystecCanBackendPrivate *dptr;
+};
+
+SystecCanBackendPrivate::SystecCanBackendPrivate(SystecCanBackend *q) :
+ q_ptr(q),
+ incomingEventHandler(new IncomingEventHandler(this, q))
+{
+}
+
+static uint bitrateCodeFromBitrate(int bitrate)
+{
+ struct BitrateItem {
+ int bitrate;
+ uint code;
+ } bitrateTable[] = {
+ { 10000, USBCAN_BAUDEX_10kBit },
+ { 20000, USBCAN_BAUDEX_20kBit },
+ { 50000, USBCAN_BAUDEX_50kBit },
+ { 100000, USBCAN_BAUDEX_100kBit },
+ { 125000, USBCAN_BAUDEX_125kBit },
+ { 250000, USBCAN_BAUDEX_250kBit },
+ { 500000, USBCAN_BAUDEX_500kBit },
+ { 800000, USBCAN_BAUDEX_800kBit },
+ { 1000000, USBCAN_BAUDEX_1MBit }
+ };
+
+ const int entries = (sizeof(bitrateTable) / sizeof(*bitrateTable));
+ for (int i = 0; i < entries; ++i)
+ if (bitrateTable[i].bitrate == bitrate)
+ return bitrateTable[i].code;
+
+ return 0;
+}
+
+void IncomingEventHandler::customEvent(QEvent *event)
+{
+ dptr->eventHandler(event);
+}
+
+/*
+ * Do not call functions of USBCAN32.DLL directly from this callback handler.
+ * Use events or windows messages to notify the event to the application.
+ */
+static void DRV_CALLBACK_TYPE ucanCallback(tUcanHandle, quint32 event, quint8, void *args)
+{
+ QEvent::Type type = static_cast<QEvent::Type>(QEvent::User + event);
+ IncomingEventHandler *handler = static_cast<IncomingEventHandler *>(args);
+ qApp->postEvent(handler, new QEvent(type));
+}
+
+bool SystecCanBackendPrivate::open()
+{
+ Q_Q(SystecCanBackend);
+
+ const UCANRET initHardwareRes = ::UcanInitHardwareEx(&handle, device, ucanCallback, incomingEventHandler);
+ if (Q_UNLIKELY(initHardwareRes != USBCAN_SUCCESSFUL)) {
+ q->setError(systemErrorString(initHardwareRes), QCanBusDevice::ConnectionError);
+ return false;
+ }
+
+ const int bitrate = q->configurationParameter(QCanBusDevice::BitRateKey).toInt();
+ const bool receiveOwn = q->configurationParameter(QCanBusDevice::ReceiveOwnKey).toBool();
+
+ tUcanInitCanParam param;
+ ::memset(&param, 0, sizeof(param));
+ param.m_dwSize = sizeof(param);
+ param.m_bMode = receiveOwn ? kUcanModeTxEcho : kUcanModeNormal;
+ param.m_bOCR = USBCAN_OCR_DEFAULT;
+ param.m_dwACR = USBCAN_ACR_ALL;
+ param.m_dwAMR = USBCAN_AMR_ALL;
+ param.m_dwBaudrate = bitrateCodeFromBitrate(bitrate);
+ param.m_wNrOfRxBufferEntries = USBCAN_DEFAULT_BUFFER_ENTRIES;
+ param.m_wNrOfTxBufferEntries = USBCAN_DEFAULT_BUFFER_ENTRIES;
+
+ const UCANRET initCanResult = ::UcanInitCanEx2(handle, channel, &param);
+ if (Q_UNLIKELY(initCanResult != USBCAN_SUCCESSFUL)) {
+ ::UcanDeinitHardware(handle);
+ q->setError(systemErrorString(initCanResult), QCanBusDevice::ConnectionError);
+ return false;
+ }
+
+ return true;
+}
+
+void SystecCanBackendPrivate::close()
+{
+ Q_Q(SystecCanBackend);
+
+ enableWriteNotification(false);
+
+ if (outgoingEventNotifier) {
+ delete outgoingEventNotifier;
+ outgoingEventNotifier = nullptr;
+ }
+
+ const UCANRET deinitCanRes = UcanDeinitCanEx(handle, channel);
+ if (Q_UNLIKELY(deinitCanRes != USBCAN_SUCCESSFUL))
+ q->setError(systemErrorString(deinitCanRes), QCanBusDevice::ConfigurationError);
+
+ // TODO: other channel keeps working?
+ const UCANRET deinitHardwareRes = UcanDeinitHardware(handle);
+ if (Q_UNLIKELY(deinitHardwareRes != USBCAN_SUCCESSFUL))
+ emit q->setError(systemErrorString(deinitHardwareRes), QCanBusDevice::ConnectionError);
+}
+
+void SystecCanBackendPrivate::eventHandler(QEvent *event)
+{
+ const int code = event->type() - QEvent::User;
+
+ if (code == USBCAN_EVENT_RECEIVE)
+ readAllReceivedMessages();
+}
+
+bool SystecCanBackendPrivate::setConfigurationParameter(int key, const QVariant &value)
+{
+ Q_Q(SystecCanBackend);
+
+ switch (key) {
+ case QCanBusDevice::BitRateKey:
+ return verifyBitRate(value.toInt());
+ case QCanBusDevice::ReceiveOwnKey:
+ if (Q_UNLIKELY(q->state() != QCanBusDevice::UnconnectedState)) {
+ q->setError(SystecCanBackend::tr("Cannot configure TxEcho for open device"),
+ QCanBusDevice::ConfigurationError);
+ return false;
+ }
+ return true;
+ default:
+ q->setError(SystecCanBackend::tr("Unsupported configuration key: %1").arg(key),
+ QCanBusDevice::ConfigurationError);
+ return false;
+ }
+}
+
+bool SystecCanBackendPrivate::setupChannel(const QString &interfaceName)
+{
+ Q_Q(SystecCanBackend);
+
+ const QRegularExpression re(QStringLiteral("can(\\d)\\.(\\d)"));
+ const QRegularExpressionMatch match = re.match(interfaceName);
+
+ if (Q_LIKELY(match.hasMatch())) {
+ device = match.captured(1).toInt();
+ channel = match.captured(2).toInt();
+ } else {
+ q->setError(SystecCanBackend::tr("Invalid interface '%1'.")
+ .arg(interfaceName), QCanBusDevice::ConnectionError);
+ return false;
+ }
+
+ return true;
+}
+
+void SystecCanBackendPrivate::setupDefaultConfigurations()
+{
+ Q_Q(SystecCanBackend);
+
+ q->setConfigurationParameter(QCanBusDevice::BitRateKey, 500000);
+ q->setConfigurationParameter(QCanBusDevice::ReceiveOwnKey, false);
+}
+
+QString SystecCanBackendPrivate::systemErrorString(int errorCode)
+{
+ switch (errorCode) {
+ case USBCAN_ERR_RESOURCE:
+ return SystecCanBackend::tr("Could not create a resource (memory, handle, ...)");
+ case USBCAN_ERR_MAXMODULES:
+ return SystecCanBackend::tr("The maximum number of open modules is exceeded");
+ case USBCAN_ERR_HWINUSE:
+ return SystecCanBackend::tr("The module is already in use");
+ case USBCAN_ERR_ILLVERSION:
+ return SystecCanBackend::tr("The software versions of the module and library are incompatible");
+ case USBCAN_ERR_ILLHW:
+ return SystecCanBackend::tr("The module with the corresponding device number is not connected");
+ case USBCAN_ERR_ILLHANDLE:
+ return SystecCanBackend::tr("Wrong USB-CAN-Handle handed over to the function");
+ case USBCAN_ERR_ILLPARAM:
+ return SystecCanBackend::tr("Wrong parameter handed over to the function");
+ case USBCAN_ERR_BUSY:
+ return SystecCanBackend::tr("Instruction can not be processed at this time");
+ case USBCAN_ERR_TIMEOUT:
+ return SystecCanBackend::tr("No answer from the module");
+ case USBCAN_ERR_IOFAILED:
+ return SystecCanBackend::tr("A request for the driver failed");
+ case USBCAN_ERR_DLL_TXFULL:
+ return SystecCanBackend::tr("The message did not fit into the transmission queue");
+ case USBCAN_ERR_MAXINSTANCES:
+ return SystecCanBackend::tr("Maximum number of applications is reached");
+ case USBCAN_ERR_CANNOTINIT:
+ return SystecCanBackend::tr("CAN-interface is not yet initialized");
+ case USBCAN_ERR_DISCONNECT:
+ return SystecCanBackend::tr("USB-CANmodul was disconnected");
+ case USBCAN_ERR_NOHWCLASS:
+ return SystecCanBackend::tr("The needed device class does not exist");
+ case USBCAN_ERR_ILLCHANNEL:
+ return SystecCanBackend::tr("Illegal CAN channel for GW-001/GW-002");
+ case USBCAN_ERR_ILLHWTYPE:
+ return SystecCanBackend::tr("The API function can not be used with this hardware");
+ case USBCAN_ERR_SERVER_TIMEOUT:
+ return SystecCanBackend::tr("The command server did not send a reply to a command");
+ default:
+ return SystecCanBackend::tr("Unknown error code '%1'.").arg(errorCode);
+ }
+}
+
+void SystecCanBackendPrivate::enableWriteNotification(bool enable)
+{
+ Q_Q(SystecCanBackend);
+
+ if (outgoingEventNotifier) {
+ if (enable) {
+ if (!outgoingEventNotifier->isActive())
+ outgoingEventNotifier->start();
+ } else {
+ outgoingEventNotifier->stop();
+ }
+ } else if (enable) {
+ outgoingEventNotifier = new OutgoingEventNotifier(this, q);
+ outgoingEventNotifier->start(0);
+ }
+}
+
+void SystecCanBackendPrivate::startWrite()
+{
+ Q_Q(SystecCanBackend);
+
+ if (!q->hasOutgoingFrames()) {
+ enableWriteNotification(false);
+ return;
+ }
+
+ const QCanBusFrame frame = q->dequeueOutgoingFrame();
+ const QByteArray payload = frame.payload();
+
+ tCanMsgStruct message;
+ ::memset(&message, 0, sizeof(message));
+
+ message.m_dwID = frame.frameId();
+ message.m_bDLC = payload.size();
+
+ message.m_bFF = frame.hasExtendedFrameFormat() ? USBCAN_MSG_FF_EXT : USBCAN_MSG_FF_STD;
+
+ if (frame.frameType() == QCanBusFrame::RemoteRequestFrame)
+ message.m_bFF |= USBCAN_MSG_FF_RTR; // remote request frame without payload
+ else
+ ::memcpy(message.m_bData, payload.constData(), sizeof(message.m_bData));
+
+ const UCANRET result = ::UcanWriteCanMsgEx(handle, channel, &message, nullptr);
+ if (Q_UNLIKELY(result != USBCAN_SUCCESSFUL))
+ q->setError(systemErrorString(result), QCanBusDevice::WriteError);
+ else
+ emit q->framesWritten(qint64(1));
+
+ if (q->hasOutgoingFrames())
+ enableWriteNotification(true);
+}
+
+void SystecCanBackendPrivate::readAllReceivedMessages()
+{
+ Q_Q(SystecCanBackend);
+
+ QVector<QCanBusFrame> newFrames;
+
+ for (;;) {
+ tCanMsgStruct message;
+ ::memset(&message, 0, sizeof(message));
+
+ const UCANRET result = ::UcanReadCanMsgEx(handle, &channel, &message, nullptr);
+ if (result == USBCAN_WARN_NODATA)
+ break;
+
+ if (Q_UNLIKELY(result != USBCAN_SUCCESSFUL)) {
+ // handle errors
+
+ q->setError(systemErrorString(result), QCanBusDevice::ReadError);
+ break;
+ }
+
+ QCanBusFrame frame(message.m_dwID,
+ QByteArray(reinterpret_cast<const char *>(message.m_bData),
+ int(message.m_bDLC)));
+
+ // TODO: Timestamp can also be set to 100 us resolution with kUcanModeHighResTimer
+ frame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(message.m_dwTime * 1000));
+ frame.setExtendedFrameFormat(message.m_bFF & USBCAN_MSG_FF_EXT);
+ frame.setFrameType((message.m_bFF & USBCAN_MSG_FF_RTR)
+ ? QCanBusFrame::RemoteRequestFrame
+ : QCanBusFrame::DataFrame);
+
+ newFrames.append(frame);
+ }
+
+ q->enqueueReceivedFrames(newFrames);
+}
+
+bool SystecCanBackendPrivate::verifyBitRate(int bitrate)
+{
+ Q_Q(SystecCanBackend);
+
+ if (Q_UNLIKELY(q->state() != QCanBusDevice::UnconnectedState)) {
+ q->setError(SystecCanBackend::tr("Cannot configure bitrate for open device"),
+ QCanBusDevice::ConfigurationError);
+ return false;
+ }
+
+ if (Q_UNLIKELY(bitrateCodeFromBitrate(bitrate) == 0)) {
+ q->setError(SystecCanBackend::tr("Unsupported bitrate %1.").arg(bitrate),
+ QCanBusDevice::ConfigurationError);
+ return false;
+ }
+
+ return true;
+}
+
+SystecCanBackend::SystecCanBackend(const QString &name, QObject *parent) :
+ QCanBusDevice(parent),
+ d_ptr(new SystecCanBackendPrivate(this))
+{
+ Q_D(SystecCanBackend);
+
+ d->setupChannel(name);
+ d->setupDefaultConfigurations();
+}
+
+SystecCanBackend::~SystecCanBackend()
+{
+ if (state() == QCanBusDevice::ConnectedState)
+ close();
+
+ delete d_ptr;
+}
+
+bool SystecCanBackend::open()
+{
+ Q_D(SystecCanBackend);
+
+ if (!d->open())
+ return false;
+
+ // Apply all stored configurations except bitrate, because
+ // the bitrate can not be applied after opening the device
+ const QVector<int> keys = configurationKeys();
+ for (int key : keys) {
+ if (key == QCanBusDevice::BitRateKey)
+ continue;
+ const QVariant param = configurationParameter(key);
+ const bool success = d->setConfigurationParameter(key, param);
+ if (Q_UNLIKELY(!success)) {
+ qWarning("Cannot apply parameter %d with value %ls.",
+ key, qUtf16Printable(param.toString()));
+ }
+ }
+
+ setState(QCanBusDevice::ConnectedState);
+ return true;
+}
+
+void SystecCanBackend::close()
+{
+ Q_D(SystecCanBackend);
+
+ d->close();
+
+ setState(QCanBusDevice::UnconnectedState);
+}
+
+void SystecCanBackend::setConfigurationParameter(int key, const QVariant &value)
+{
+ Q_D(SystecCanBackend);
+
+ if (d->setConfigurationParameter(key, value))
+ QCanBusDevice::setConfigurationParameter(key, value);
+}
+
+bool SystecCanBackend::writeFrame(const QCanBusFrame &newData)
+{
+ Q_D(SystecCanBackend);
+
+ if (Q_UNLIKELY(state() != QCanBusDevice::ConnectedState))
+ return false;
+
+ if (Q_UNLIKELY(!newData.isValid())) {
+ setError(tr("Cannot write invalid QCanBusFrame"), QCanBusDevice::WriteError);
+ return false;
+ }
+
+ const QCanBusFrame::FrameType type = newData.frameType();
+ if (Q_UNLIKELY(type != QCanBusFrame::DataFrame && type != QCanBusFrame::RemoteRequestFrame)) {
+ setError(tr("Unable to write a frame with unacceptable type"),
+ QCanBusDevice::WriteError);
+ return false;
+ }
+
+ // CAN FD frame format is not supported by the hardware yet
+ if (Q_UNLIKELY(newData.payload().size() > 8)) {
+ setError(tr("CAN FD frame format not supported"), QCanBusDevice::WriteError);
+ return false;
+ }
+
+ enqueueOutgoingFrame(newData);
+ d->enableWriteNotification(true);
+
+ return true;
+}
+
+// TODO: Implement me
+QString SystecCanBackend::interpretErrorFrame(const QCanBusFrame &errorFrame)
+{
+ Q_UNUSED(errorFrame);
+
+ return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/canbus/systeccan/systeccanbackend.h b/src/plugins/canbus/systeccan/systeccanbackend.h
new file mode 100644
index 0000000..11df787
--- /dev/null
+++ b/src/plugins/canbus/systeccan/systeccanbackend.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYSTECCANBACKEND_H
+#define SYSTECCANBACKEND_H
+
+#include <QtSerialBus/qcanbusframe.h>
+#include <QtSerialBus/qcanbusdevice.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class SystecCanBackendPrivate;
+
+class SystecCanBackend : public QCanBusDevice
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(SystecCanBackend)
+ Q_DISABLE_COPY(SystecCanBackend)
+public:
+ explicit SystecCanBackend(const QString &name, QObject *parent = nullptr);
+ ~SystecCanBackend();
+
+ bool open() override;
+ void close() override;
+
+ void setConfigurationParameter(int key, const QVariant &value) override;
+
+ bool writeFrame(const QCanBusFrame &newData) override;
+
+ QString interpretErrorFrame(const QCanBusFrame &errorFrame) override;
+
+ static bool canCreate(QString *errorReason);
+
+private:
+ SystecCanBackendPrivate * const d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // SYSTECCANBACKEND_H
diff --git a/src/plugins/canbus/systeccan/systeccanbackend_p.h b/src/plugins/canbus/systeccan/systeccanbackend_p.h
new file mode 100644
index 0000000..f180102
--- /dev/null
+++ b/src/plugins/canbus/systeccan/systeccanbackend_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtSerialBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYSTECCANBACKEND_P_H
+#define SYSTECCANBACKEND_P_H
+
+#include "systeccanbackend.h"
+#include "systeccan_symbols_p.h"
+
+#if defined(Q_OS_WIN32)
+# include <qt_windows.h>
+#endif
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+class QSocketNotifier;
+class QWinEventNotifier;
+class QTimer;
+
+class IncomingEventHandler : public QObject
+{
+ // no Q_OBJECT macro!
+public:
+ explicit IncomingEventHandler(SystecCanBackendPrivate *systecPrivate, QObject *parent) :
+ QObject(parent),
+ dptr(systecPrivate) { }
+
+ void customEvent(QEvent *event);
+
+private:
+ SystecCanBackendPrivate *dptr;
+};
+
+class SystecCanBackendPrivate
+{
+ Q_DECLARE_PUBLIC(SystecCanBackend)
+
+public:
+ SystecCanBackendPrivate(SystecCanBackend *q);
+
+ bool open();
+ void close();
+ void eventHandler(QEvent *event);
+ bool setConfigurationParameter(int key, const QVariant &value);
+ bool setupChannel(const QString &interfaceName);
+ void setupDefaultConfigurations();
+ QString systemErrorString(int errorCode);
+ void enableWriteNotification(bool enable);
+ void startWrite();
+ void readAllReceivedMessages();
+ bool verifyBitRate(int bitrate);
+
+ SystecCanBackend * const q_ptr;
+
+ tUcanHandle handle = 0;
+ quint8 device = 255;
+ quint8 channel = 255;
+
+ QTimer *outgoingEventNotifier = nullptr;
+ IncomingEventHandler *incomingEventHandler = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // SYSTECCANBACKEND_P_H
diff --git a/src/serialbus/doc/src/qtcanbus-backends.qdoc b/src/serialbus/doc/src/qtcanbus-backends.qdoc
index 239ccc3..522c6f2 100644
--- a/src/serialbus/doc/src/qtcanbus-backends.qdoc
+++ b/src/serialbus/doc/src/qtcanbus-backends.qdoc
@@ -61,6 +61,10 @@
\li \l {Using SocketCAN Plugin}{SocketCAN} (\c socketcan)
\li CAN bus plugin using Linux sockets and open source drivers.
\row
+ \li SYS TEC electronic
+ \li \l {Using SystecCAN Backend}{SystecCAN} (\c systeccan)
+ \li CAN bus backend using the SYS TEC CAN adapters.
+ \row
\li PEAK-System
\li \l {Using PeakCAN Plugin}{PeakCAN} (\c peakcan)
\li CAN bus plugin using the PEAK CAN adapters.
diff --git a/src/serialbus/doc/src/systeccan.qdoc b/src/serialbus/doc/src/systeccan.qdoc
new file mode 100644
index 0000000..08ecfce
--- /dev/null
+++ b/src/serialbus/doc/src/systeccan.qdoc
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Andre Hartmann <aha_1980@gmx.de>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+ \page qtserialbus-SystecCAN-overview.html
+ \title Using SystecCAN Backend
+
+ \brief Overview of how to use the SystecCAN backend.
+
+ The SystecCAN backend encapsulates the low-level API to work with the
+ \l{http://www.systec-electronic.com/}{SYS TEC} CAN adapters.
+
+ \section1 Creating CAN Bus Devices
+
+ At first it is necessary to check that QCanBus provides the desired backend:
+
+ \code
+ if (QCanBus::instance()->plugins().contains(QStringLiteral("systeccan"))) {
+ // backend available
+ }
+ \endcode
+
+ Where \e systeccan is the backend name.
+
+ Next, a connection to a specific interface can be established:
+
+ \code
+ QCanBusDevice *device = QCanBus::instance()->createDevice(
+ QStringLiteral("systeccan"), QStringLiteral("can0.0"));
+ device->connectDevice();
+ \endcode
+
+ Where, \e can0.0 is the active CAN interface name (interface 0, channel 0).
+ The SystecCAN backend supports 64 USB interfaces (so called modules) from
+ \e can0.0 to \e can63.1. Each module can have one or two channels, they can
+ be accessed by the index canX.0 or canX.1.
+
+ \note SYS TEC also provides 8 or 16 channel CAN interfaces. These units
+ consist of an USB hub and multiple two-channel modules internally.
+
+ The device is now open for writing and reading CAN frames:
+
+ \code
+ QCanBusFrame frame;
+ frame.setFrameId(8);
+ QByteArray payload("A36E");
+ frame.setPayload(payload);
+ device->writeFrame(frame);
+ \endcode
+
+ The reading can be done using the \l {QCanBusDevice::}{readFrame()} method.
+ The \l {QCanBusDevice::}{framesReceived()} signal is emitted when at least
+ one new frame is available for reading:
+
+ \code
+ QCanBusFrame frame = device->readFrame();
+ \endcode
+
+ SystecCAN supports the following configurations that can be controlled through
+ \l {QCanBusDevice::}{setConfigurationParameter()}:
+
+ \table
+ \header
+ \li Configuration parameter key
+ \li Description
+ \row
+ \li QCanBusDevice::BitRateKey
+ \li Determines the bit rate of the CAN bus connection. The following bit rates
+ are supported: 10000, 20000, 50000, 100000, 125000, 250000, 500000, 800000,
+ and 1000000. Note that this configuration parameter can only be adjusted
+ while the QCanBusDevice is not connected.
+ \row
+ \li QCanBusDevice::ReceiveOwnKey
+ \li The reception of CAN frames on the same channel that was sending the CAN frame
+ is disabled by default.
+ \endtable
+*/