diff options
Diffstat (limited to 'src/plugins/canbus/socketcan/libsocketcan.cpp')
-rw-r--r-- | src/plugins/canbus/socketcan/libsocketcan.cpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/src/plugins/canbus/socketcan/libsocketcan.cpp b/src/plugins/canbus/socketcan/libsocketcan.cpp new file mode 100644 index 0000000..c6144db --- /dev/null +++ b/src/plugins/canbus/socketcan/libsocketcan.cpp @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "libsocketcan.h" + +#include <QtCore/qloggingcategory.h> + +#if QT_CONFIG(library) +# include <QtCore/qlibrary.h> +#endif + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN) + +#define GENERATE_SYMBOL(returnType, symbolName, ...) \ + typedef returnType (*fp_##symbolName)(__VA_ARGS__); \ + static fp_##symbolName symbolName = nullptr; + +#define RESOLVE_SYMBOL(symbolName) \ + symbolName = reinterpret_cast<fp_##symbolName>(library->resolve(#symbolName)); \ + if (!symbolName) \ + return false; + +struct can_bittiming { + quint32 bitrate = 0; /* Bit-rate in bits/second */ + quint32 sample_point = 0; /* Sample point in one-tenth of a percent */ + quint32 tq = 0; /* Time quanta (TQ) in nanoseconds */ + quint32 prop_seg = 0; /* Propagation segment in TQs */ + quint32 phase_seg1 = 0; /* Phase buffer segment 1 in TQs */ + quint32 phase_seg2 = 0; /* Phase buffer segment 2 in TQs */ + quint32 sjw = 0; /* Synchronization jump width in TQs */ + quint32 brp = 0; /* Bit-rate prescaler */ +}; + +enum can_state { + CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ + CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ + CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ + CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ + CAN_STATE_STOPPED, /* Device is stopped */ + CAN_STATE_SLEEPING, /* Device is sleeping */ + CAN_STATE_MAX +}; + +GENERATE_SYMBOL(int, can_do_restart, const char * /* name */) +GENERATE_SYMBOL(int, can_do_stop, const char * /* name */) +GENERATE_SYMBOL(int, can_do_start, const char * /* name */) +GENERATE_SYMBOL(int, can_set_bitrate, const char * /* name */, quint32 /* bitrate */) +GENERATE_SYMBOL(int, can_get_bittiming, const char * /* name */, struct can_bittiming * /* bt */) +GENERATE_SYMBOL(int, can_get_state, const char * /* name */, int * /* state */) + +LibSocketCan::LibSocketCan(QString *errorString) +{ +#if QT_CONFIG(library) + auto resolveSymbols = [](QLibrary *library) { + if (!library->isLoaded()) { + library->setFileName(QStringLiteral("socketcan")); + if (!library->load()) + return false; + } + + RESOLVE_SYMBOL(can_do_start); + RESOLVE_SYMBOL(can_do_stop); + RESOLVE_SYMBOL(can_do_restart); + RESOLVE_SYMBOL(can_set_bitrate); + RESOLVE_SYMBOL(can_get_bittiming); + RESOLVE_SYMBOL(can_get_state); + + return true; + }; + + QLibrary lib; + if (Q_UNLIKELY(!resolveSymbols(&lib))) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(lib.errorString())); + if (errorString) + *errorString = lib.errorString(); + } +#else + const QString error = + QObject::tr("Cannot load library libsocketcan as Qt was built without QLibrary."); + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(error)); + if (errorString) + *errorString = error; +#endif +} + +/*! + Brings the CAN \a interface up. + + \internal + \note Requires appropriate permissions. +*/ +bool LibSocketCan::start(const QString &interface) +{ + if (!::can_do_start) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_start() is not available."); + return false; + } + + return ::can_do_start(interface.toLatin1().constData()) == 0; +} + +/*! + Brings the CAN \a interface down. + + \internal + \note Requires appropriate permissions. +*/ +bool LibSocketCan::stop(const QString &interface) +{ + if (!::can_do_stop) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_stop() is not available."); + return false; + } + + return ::can_do_stop(interface.toLatin1().constData()) == 0; +} + +/*! + Performs a CAN controller reset on the CAN \a interface. + + \internal + \note Reset can only be triggerd if the controller is in bus off + and the auto restart not turned on. + \note Requires appropriate permissions. + */ +bool LibSocketCan::restart(const QString &interface) +{ + if (!::can_do_restart) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_restart() is not available."); + return false; + } + + return ::can_do_restart(interface.toLatin1().constData()) == 0; +} + +/*! + Returns the configured bitrate for \a interface. + \internal +*/ +quint32 LibSocketCan::bitrate(const QString &interface) const +{ + if (!::can_get_bittiming) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_get_bittiming() is not available."); + return 0; + } + + struct can_bittiming bt; + if (::can_get_bittiming(interface.toLatin1().constData(), &bt) == 0) + return bt.bitrate; + + return 0; +} + +/*! + Sets the bitrate for the CAN \a interface. + + \internal + \note Requires appropriate permissions. + */ +bool LibSocketCan::setBitrate(const QString &interface, quint32 bitrate) +{ + if (!::can_set_bitrate) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_set_bitrate() is not available."); + return false; + } + + return ::can_set_bitrate(interface.toLatin1().constData(), bitrate) == 0; +} + +bool LibSocketCan::hasBusStatus() const +{ + return ::can_get_state != nullptr; +} + +QCanBusDevice::CanBusStatus LibSocketCan::busStatus(const QString &interface) const +{ + if (!::can_get_state) { + qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_get_state() is not available."); + return QCanBusDevice::CanBusStatus::Unknown; + } + + int status = 0; + int result = ::can_get_state(interface.toLatin1().constData(), &status); + + if (result < 0) + return QCanBusDevice::CanBusStatus::Unknown; + + switch (status) { + case CAN_STATE_ERROR_ACTIVE: + return QCanBusDevice::CanBusStatus::Good; + case CAN_STATE_ERROR_WARNING: + return QCanBusDevice::CanBusStatus::Warning; + case CAN_STATE_ERROR_PASSIVE: + return QCanBusDevice::CanBusStatus::Error; + case CAN_STATE_BUS_OFF: + return QCanBusDevice::CanBusStatus::BusOff; + default: + // Device is stopped or sleeping, so status is unknown + return QCanBusDevice::CanBusStatus::Unknown; + } +} + +QT_END_NAMESPACE |