diff options
-rw-r--r-- | examples/serialbus/can/connectdialog.cpp | 2 | ||||
-rw-r--r-- | src/plugins/canbus/canbus.pro | 2 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/main.cpp | 69 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/plugin.json | 3 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/systeccan.pro | 19 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/systeccan_symbols_p.h | 277 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/systeccanbackend.cpp | 496 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/systeccanbackend.h | 76 | ||||
-rw-r--r-- | src/plugins/canbus/systeccan/systeccanbackend_p.h | 110 | ||||
-rw-r--r-- | src/serialbus/doc/src/qtcanbus-backends.qdoc | 4 | ||||
-rw-r--r-- | src/serialbus/doc/src/systeccan.qdoc | 100 |
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(¶m, 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, ¶m); + 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 +*/ |