1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
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 "qcanbus.h"
38 #include "qcanbusfactory.h"
39 
40 #include <QtCore/qcoreapplication.h>
41 #include <QtCore/qglobalstatic.h>
42 #include <QtCore/qlist.h>
43 #include <QtCore/qobject.h>
44 #include <QtCore/qpluginloader.h>
45 
46 #include <private/qfactoryloader_p.h>
47 
48 #define QCanBusFactory_iid "org.qt-project.Qt.QCanBusFactory"
49 
50 QT_BEGIN_NAMESPACE
51 
52 class QCanBusPrivate
53 {
54 public:
QCanBusPrivate()55     QCanBusPrivate() { }
QCanBusPrivate(int index,const QJsonObject & meta)56     QCanBusPrivate(int index, const QJsonObject &meta) : meta(meta), index(index) {}
57 
58     QJsonObject meta;
59     QObject *factory = nullptr;
60     int index = -1;
61 };
62 
63 Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qFactoryLoader,
64     (QCanBusFactory_iid, QLatin1String("/canbus")))
65 
66 typedef QMap<QString, QCanBusPrivate> QCanBusPluginStore;
67 Q_GLOBAL_STATIC(QCanBusPluginStore, qCanBusPlugins)
68 
69 static QCanBus *globalInstance = nullptr;
70 
loadPlugins()71 static void loadPlugins()
72 {
73     const QList<QJsonObject> meta = qFactoryLoader()->metaData();
74     for (int i = 0; i < meta.count(); i++) {
75         const QJsonObject obj = meta.at(i).value(QLatin1String("MetaData")).toObject();
76         if (obj.isEmpty())
77             continue;
78 
79         qCanBusPlugins()->insert(obj.value(QLatin1String("Key")).toString(), {i, obj});
80     }
81 }
82 
83 /*!
84     \class QCanBus
85     \inmodule QtSerialBus
86     \since 5.8
87 
88     \brief The QCanBus class handles registration and creation of bus plugins.
89 
90     QCanBus loads Qt CAN Bus plugins at runtime. The ownership of serial bus plugins is
91     transferred to the loader.
92 */
93 
94 /*!
95     Returns a pointer to the QCanBus class. The object is loaded if necessary. QCanBus
96     uses the singleton design pattern.
97 */
instance()98 QCanBus *QCanBus::instance()
99 {
100     if (!globalInstance)
101         globalInstance = new QCanBus();
102     return globalInstance;
103 }
104 
105 /*!
106     Returns a list of identifiers for all loaded plugins.
107 */
plugins() const108 QStringList QCanBus::plugins() const
109 {
110     return qCanBusPlugins()->keys();
111 }
112 
setErrorMessage(QString * result,const QString & message)113 static void setErrorMessage(QString *result, const QString &message)
114 {
115     if (!result)
116         return;
117 
118     *result = message;
119 }
120 
canBusFactory(const QString & plugin,QString * errorMessage)121 static QObject *canBusFactory(const QString &plugin, QString *errorMessage)
122 {
123     if (Q_UNLIKELY(!qCanBusPlugins()->contains(plugin))) {
124         setErrorMessage(errorMessage, QCanBus::tr("No such plugin: '%1'").arg(plugin));
125         return nullptr;
126     }
127 
128     QCanBusPrivate d = qCanBusPlugins()->value(plugin);
129     if (!d.factory) {
130         d.factory = qFactoryLoader->instance(d.index);
131 
132         if (d.factory)
133             qCanBusPlugins()->insert(plugin, d);
134     }
135 
136     if (Q_UNLIKELY(!d.factory))
137         setErrorMessage(errorMessage, QCanBus::tr("No factory for plugin: '%1'").arg(plugin));
138 
139     return d.factory;
140 }
141 
142 /*!
143     \since 5.9
144 
145     Returns the available interfaces for \a plugin. In case of failure, the optional
146     parameter \a errorMessage returns a textual error description.
147 
148     \note Some plugins might not or only partially support this function.
149 
150     For example, the following call returns a list of all available SocketCAN
151     interfaces (which can be used for \l createDevice()):
152 
153     \code
154         QString errorString;
155         const QList<QCanBusDeviceInfo> devices = QCanBus::instance()->availableDevices(
156             QStringLiteral("socketcan"), &errorString);
157         if (!errorString.isEmpty())
158             qDebug() << errorString;
159     \endcode
160 
161     \sa createDevice()
162 */
availableDevices(const QString & plugin,QString * errorMessage) const163 QList<QCanBusDeviceInfo> QCanBus::availableDevices(const QString &plugin, QString *errorMessage) const
164 {
165     const QObject *obj = canBusFactory(plugin, errorMessage);
166     if (Q_UNLIKELY(!obj))
167         return QList<QCanBusDeviceInfo>();
168 
169     const QCanBusFactoryV2 *factoryV2 = qobject_cast<QCanBusFactoryV2 *>(obj);
170     if (Q_UNLIKELY(!factoryV2)) {
171         setErrorMessage(errorMessage,
172                         tr("The plugin '%1' does not provide this function.").arg(plugin));
173         return QList<QCanBusDeviceInfo>();
174     }
175 
176     QString errorString;
177     QList<QCanBusDeviceInfo> result = factoryV2->availableDevices(&errorString);
178 
179     setErrorMessage(errorMessage, errorString);
180     return result;
181 }
182 
183 /*!
184     Creates a CAN bus device. \a plugin is the name of the plugin as returned by the \l plugins()
185     method. \a interfaceName is the CAN bus interface name. In case of failure, the optional
186     parameter \a errorMessage returns a textual error description.
187 
188     Ownership of the returned plugin is transferred to the caller.
189     Returns \c nullptr if no suitable device can be found.
190 
191     For example, the following call would connect to the SocketCAN interface vcan0:
192 
193     \code
194         QString errorString;
195         QCanBusDevice *device = QCanBus::instance()->createDevice(
196             QStringLiteral("socketcan"), QStringLiteral("vcan0"), &errorString);
197         if (!device)
198             qDebug() << errorString;
199         else
200             device->connectDevice();
201     \endcode
202 
203     \note The \a interfaceName is plugin-dependent. See the corresponding plugin documentation
204     for more information: \l {CAN Bus Plugins}. To get a list of available interfaces,
205     \l availableDevices() can be used.
206 
207     \sa availableDevices()
208 */
createDevice(const QString & plugin,const QString & interfaceName,QString * errorMessage) const209 QCanBusDevice *QCanBus::createDevice(const QString &plugin, const QString &interfaceName,
210                                      QString *errorMessage) const
211 {
212     const QObject *obj = canBusFactory(plugin, errorMessage);
213     if (Q_UNLIKELY(!obj))
214         return nullptr;
215 
216     const QCanBusFactoryV2 *factoryV2 = qobject_cast<QCanBusFactoryV2 *>(obj);
217     if (Q_LIKELY(factoryV2))
218         return factoryV2->createDevice(interfaceName, errorMessage);
219 
220     const QCanBusFactory *factory = qobject_cast<QCanBusFactory *>(obj);
221     if (factory)
222         return factory->createDevice(interfaceName, errorMessage);
223 
224     setErrorMessage(errorMessage,
225                     tr("The plugin '%1' does not provide this function.").arg(plugin));
226     return nullptr;
227 }
228 
QCanBus(QObject * parent)229 QCanBus::QCanBus(QObject *parent) :
230     QObject(parent)
231 {
232     loadPlugins();
233 }
234 
235 QT_END_NAMESPACE
236