1/****************************************************************************
2**
3** Copyright (C) 2019 Andre Hartmann <aha_1980@gmx.de>
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtSerialBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "libsocketcan.h"
38
39#include <QtCore/qloggingcategory.h>
40
41#if QT_CONFIG(library)
42# include <QtCore/qlibrary.h>
43#endif
44
45QT_BEGIN_NAMESPACE
46
47Q_DECLARE_LOGGING_CATEGORY(QT_CANBUS_PLUGINS_SOCKETCAN)
48
49#define GENERATE_SYMBOL(returnType, symbolName, ...) \
50 typedef returnType (*fp_##symbolName)(__VA_ARGS__); \
51 static fp_##symbolName symbolName = nullptr;
52
53#define RESOLVE_SYMBOL(symbolName) \
54 symbolName = reinterpret_cast<fp_##symbolName>(library->resolve(#symbolName)); \
55 if (!symbolName) \
56 return false;
57
58struct can_bittiming {
59 quint32 bitrate = 0; /* Bit-rate in bits/second */
60 quint32 sample_point = 0; /* Sample point in one-tenth of a percent */
61 quint32 tq = 0; /* Time quanta (TQ) in nanoseconds */
62 quint32 prop_seg = 0; /* Propagation segment in TQs */
63 quint32 phase_seg1 = 0; /* Phase buffer segment 1 in TQs */
64 quint32 phase_seg2 = 0; /* Phase buffer segment 2 in TQs */
65 quint32 sjw = 0; /* Synchronization jump width in TQs */
66 quint32 brp = 0; /* Bit-rate prescaler */
67};
68
69enum can_state {
70 CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */
71 CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */
72 CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */
73 CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */
74 CAN_STATE_STOPPED, /* Device is stopped */
75 CAN_STATE_SLEEPING, /* Device is sleeping */
76 CAN_STATE_MAX
77};
78
79GENERATE_SYMBOL(int, can_do_restart, const char * /* name */)
80GENERATE_SYMBOL(int, can_do_stop, const char * /* name */)
81GENERATE_SYMBOL(int, can_do_start, const char * /* name */)
82GENERATE_SYMBOL(int, can_set_bitrate, const char * /* name */, quint32 /* bitrate */)
83GENERATE_SYMBOL(int, can_get_bittiming, const char * /* name */, struct can_bittiming * /* bt */)
84GENERATE_SYMBOL(int, can_get_state, const char * /* name */, int * /* state */)
85
86LibSocketCan::LibSocketCan(QString *errorString)
87{
88#if QT_CONFIG(library)
89 auto resolveSymbols = [](QLibrary *library) {
90 const QString libName = QStringLiteral("socketcan");
91 if (!library->isLoaded()) {
92 library->setFileName(libName);
93 if (!library->load()) {
94 library->setFileNameAndVersion(fileName: libName, verNum: 2);
95 if (!library->load())
96 return false;
97 }
98 }
99
100 RESOLVE_SYMBOL(can_do_start);
101 RESOLVE_SYMBOL(can_do_stop);
102 RESOLVE_SYMBOL(can_do_restart);
103 RESOLVE_SYMBOL(can_set_bitrate);
104 RESOLVE_SYMBOL(can_get_bittiming);
105 RESOLVE_SYMBOL(can_get_state);
106
107 return true;
108 };
109
110 QLibrary lib;
111 if (Q_UNLIKELY(!resolveSymbols(&lib))) {
112 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(lib.errorString()));
113 if (errorString)
114 *errorString = lib.errorString();
115 }
116#else
117 const QString error =
118 QObject::tr("Cannot load library libsocketcan as Qt was built without QLibrary.");
119 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "%ls", qUtf16Printable(error));
120 if (errorString)
121 *errorString = error;
122#endif
123}
124
125/*!
126 Brings the CAN \a interface up.
127
128 \internal
129 \note Requires appropriate permissions.
130*/
131bool LibSocketCan::start(const QString &interface)
132{
133 if (!::can_do_start) {
134 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_start() is not available.");
135 return false;
136 }
137
138 return ::can_do_start(interface.toLatin1().constData()) == 0;
139}
140
141/*!
142 Brings the CAN \a interface down.
143
144 \internal
145 \note Requires appropriate permissions.
146*/
147bool LibSocketCan::stop(const QString &interface)
148{
149 if (!::can_do_stop) {
150 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_stop() is not available.");
151 return false;
152 }
153
154 return ::can_do_stop(interface.toLatin1().constData()) == 0;
155}
156
157/*!
158 Performs a CAN controller reset on the CAN \a interface.
159
160 \internal
161 \note Reset can only be triggerd if the controller is in bus off
162 and the auto restart not turned on.
163 \note Requires appropriate permissions.
164 */
165bool LibSocketCan::restart(const QString &interface)
166{
167 if (!::can_do_restart) {
168 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_do_restart() is not available.");
169 return false;
170 }
171
172 return ::can_do_restart(interface.toLatin1().constData()) == 0;
173}
174
175/*!
176 Returns the configured bitrate for \a interface.
177 \internal
178*/
179quint32 LibSocketCan::bitrate(const QString &interface) const
180{
181 if (!::can_get_bittiming) {
182 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_get_bittiming() is not available.");
183 return 0;
184 }
185
186 struct can_bittiming bt;
187 if (::can_get_bittiming(interface.toLatin1().constData(), &bt) == 0)
188 return bt.bitrate;
189
190 return 0;
191}
192
193/*!
194 Sets the bitrate for the CAN \a interface.
195
196 \internal
197 \note Requires appropriate permissions.
198 */
199bool LibSocketCan::setBitrate(const QString &interface, quint32 bitrate)
200{
201 if (!::can_set_bitrate) {
202 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_set_bitrate() is not available.");
203 return false;
204 }
205
206 return ::can_set_bitrate(interface.toLatin1().constData(), bitrate) == 0;
207}
208
209bool LibSocketCan::hasBusStatus() const
210{
211 return ::can_get_state != nullptr;
212}
213
214QCanBusDevice::CanBusStatus LibSocketCan::busStatus(const QString &interface) const
215{
216 if (!::can_get_state) {
217 qCWarning(QT_CANBUS_PLUGINS_SOCKETCAN, "Function can_get_state() is not available.");
218 return QCanBusDevice::CanBusStatus::Unknown;
219 }
220
221 int status = 0;
222 int result = ::can_get_state(interface.toLatin1().constData(), &status);
223
224 if (result < 0)
225 return QCanBusDevice::CanBusStatus::Unknown;
226
227 switch (status) {
228 case CAN_STATE_ERROR_ACTIVE:
229 return QCanBusDevice::CanBusStatus::Good;
230 case CAN_STATE_ERROR_WARNING:
231 return QCanBusDevice::CanBusStatus::Warning;
232 case CAN_STATE_ERROR_PASSIVE:
233 return QCanBusDevice::CanBusStatus::Error;
234 case CAN_STATE_BUS_OFF:
235 return QCanBusDevice::CanBusStatus::BusOff;
236 default:
237 // Device is stopped or sleeping, so status is unknown
238 return QCanBusDevice::CanBusStatus::Unknown;
239 }
240}
241
242QT_END_NAMESPACE
243

source code of qtserialbus/src/plugins/canbus/socketcan/libsocketcan.cpp