File indexing completed on 2024-06-09 05:46:35

0001 /*
0002  * Copyright 2019 Eike Hein <hein@kde.org>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  */
0020 
0021 #include "parrotplugin.h"
0022 #include "debug.h"
0023 #include "parrotprotocol.h"
0024 #include "parrotvehicle.h"
0025 
0026 #include <KLocalizedString>
0027 #include <KPluginFactory>
0028 
0029 #include <QJsonDocument>
0030 
0031 #ifndef Q_OS_ANDROID
0032 #include <kdnssd_version.h>
0033 #if KDNSSD_VERSION >= QT_VERSION_CHECK(5, 84, 0)
0034 #include <KDNSSD/RemoteService>
0035 #include <KDNSSD/ServiceBrowser>
0036 #else
0037 #include <DNSSD/RemoteService>
0038 #include <DNSSD/ServiceBrowser>
0039 #endif
0040 #else
0041 #include "QtZeroConf/qzeroconf.h"
0042 #include "QtZeroConf/qzeroconfservice.h"
0043 #endif
0044 
0045 ParrotPlugin::ParrotPlugin(QObject *parent, const QVariantList & /* args */)
0046     : Kirogi::VehicleSupportPlugin(parent)
0047 #ifndef Q_OS_ANDROID
0048     , m_bebop2Browser(nullptr)
0049     , m_anafiBrowser(nullptr)
0050 #endif
0051 {
0052     qCDebug(KIROGI_VEHICLESUPPORT_PARROT) << "Parrot Vehicle Support Plugin initializing ...";
0053 
0054     qRegisterMetaType<Parrot::Command>("Parrot::Command");
0055     qRegisterMetaType<ParrotCommand>();
0056 
0057     class AbstractMDNSService
0058     {
0059     public:
0060 #ifndef Q_OS_ANDROID
0061         AbstractMDNSService(KDNSSD::RemoteService::Ptr service)
0062         {
0063             name = service->serviceName();
0064             host = service->hostName();
0065             port = service->port();
0066 
0067             if (!service->textData().isEmpty()) {
0068                 data = QJsonDocument::fromJson(service->textData().firstKey().toUtf8());
0069             }
0070         }
0071 #else
0072         AbstractMDNSService(QZeroConfService service)
0073         {
0074             name = service->name();
0075             host = service->host();
0076             port = service->port();
0077 
0078             if (!service->txt().isEmpty()) {
0079                 data = QJsonDocument::fromJson(service->txt().firstKey());
0080             }
0081         }
0082 #endif
0083 
0084         QString name;
0085         QString host;
0086         uint port;
0087         QJsonDocument data;
0088     };
0089 
0090     auto serviceAdded = [this](AbstractMDNSService *service, ParrotVehicle::Type type) {
0091         if (!m_vehicles.contains(service->name)) {
0092             QString productSerial;
0093 
0094             if (!service->data.isNull() || !service->data.isObject()) {
0095                 productSerial = service->data.object().value(QStringLiteral("device_id")).toString();
0096             } else {
0097                 qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "mDNS service has no text data. We will be unable to decode the product serial.";
0098             }
0099 
0100             if (productSerial.isEmpty()) {
0101                 qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "Unable to decode product serial from mDNS service text data.";
0102             }
0103 
0104             qCDebug(KIROGI_VEHICLESUPPORT_PARROT) << "Discovered new vehicle at:" << QString("%1:%2.").arg(service->name, QString::number(service->port));
0105 
0106             ParrotVehicle *vehicle = new ParrotVehicle(type, service->host, service->port, productSerial, this);
0107             m_vehicles.insert(service->name, vehicle);
0108             emit vehicleAdded(vehicle);
0109 
0110             vehicle->connectToVehicle();
0111         } else {
0112             qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "Already have a vehicle for:" << service->name;
0113         }
0114     };
0115 
0116     auto serviceRemoved = [this](AbstractMDNSService *service) {
0117         qCDebug(KIROGI_VEHICLESUPPORT_PARROT) << "Removing vehicle at" << QString("%1:%2.").arg(service->host, QString::number(service->port));
0118 
0119         Kirogi::AbstractVehicle *vehicle = m_vehicles.value(service->name);
0120 
0121         m_vehicles.remove(service->name);
0122         emit vehicleRemoved(vehicle);
0123 
0124         delete vehicle;
0125     };
0126 
0127 #ifndef Q_OS_ANDROID
0128     m_bebop2Browser = new KDNSSD::ServiceBrowser(QStringLiteral("_arsdk-090c._udp"), true);
0129     m_anafiBrowser = new KDNSSD::ServiceBrowser(QStringLiteral("_arsdk-0914._udp"), true);
0130 
0131     if (m_bebop2Browser->isAvailable() != KDNSSD::ServiceBrowser::Working) {
0132         qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "KDNSSD mDNS browsing (Bebop 2) unavailable:" << m_bebop2Browser->isAvailable();
0133     }
0134 
0135     if (m_anafiBrowser->isAvailable() != KDNSSD::ServiceBrowser::Working) {
0136         qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "KDNSSD mDNS browsing (Anafi) unavailable:" << m_anafiBrowser->isAvailable();
0137     }
0138 
0139     QObject::connect(m_bebop2Browser, &KDNSSD::ServiceBrowser::serviceAdded, this, [serviceAdded](KDNSSD::RemoteService::Ptr service) {
0140         serviceAdded(new AbstractMDNSService(service), ParrotVehicle::Bebop2);
0141     });
0142     QObject::connect(m_bebop2Browser, &KDNSSD::ServiceBrowser::serviceRemoved, this, [serviceRemoved](KDNSSD::RemoteService::Ptr service) {
0143         serviceRemoved(new AbstractMDNSService(service));
0144     });
0145     QObject::connect(m_anafiBrowser, &KDNSSD::ServiceBrowser::serviceAdded, this, [serviceAdded](KDNSSD::RemoteService::Ptr service) {
0146         serviceAdded(new AbstractMDNSService(service), ParrotVehicle::Anafi);
0147     });
0148     QObject::connect(m_anafiBrowser, &KDNSSD::ServiceBrowser::serviceRemoved, this, [serviceRemoved](KDNSSD::RemoteService::Ptr service) {
0149         serviceRemoved(new AbstractMDNSService(service));
0150     });
0151 
0152     m_bebop2Browser->startBrowse();
0153     m_anafiBrowser->startBrowse();
0154 #else
0155     QZeroConf *bebop2Browser = new QZeroConf(this);
0156     QZeroConf *anafiBrowser = new QZeroConf(this);
0157 
0158     QObject::connect(bebop2Browser, &QZeroConf::serviceAdded, this, [serviceAdded](QZeroConfService service) {
0159         serviceAdded(new AbstractMDNSService(service), ParrotVehicle::Bebop2);
0160     });
0161     QObject::connect(bebop2Browser, &QZeroConf::serviceRemoved, this, [serviceRemoved](QZeroConfService service) {
0162         serviceRemoved(new AbstractMDNSService(service));
0163     });
0164     QObject::connect(bebop2Browser, &QZeroConf::error, this, [](QZeroConf::error_t error) {
0165         qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "QZeroConf mDNS browsing (Bebop 2) error:" << error;
0166     });
0167     QObject::connect(anafiBrowser, &QZeroConf::serviceAdded, this, [serviceAdded](QZeroConfService service) {
0168         serviceAdded(new AbstractMDNSService(service), ParrotVehicle::Anafi);
0169     });
0170     QObject::connect(anafiBrowser, &QZeroConf::serviceRemoved, this, [serviceRemoved](QZeroConfService service) {
0171         serviceRemoved(new AbstractMDNSService(service));
0172     });
0173     QObject::connect(anafiBrowser, &QZeroConf::error, this, [](QZeroConf::error_t error) {
0174         qCWarning(KIROGI_VEHICLESUPPORT_PARROT) << "QZeroConf mDNS browsing (Anafi) error:" << error;
0175     });
0176 
0177     bebop2Browser->startBrowser(QStringLiteral("_arsdk-090c._udp"));
0178     anafiBrowser->startBrowser(QStringLiteral("_arsdk-0914._udp"));
0179 #endif
0180 }
0181 
0182 ParrotPlugin::~ParrotPlugin()
0183 {
0184 #ifndef Q_OS_ANDROID
0185     delete m_bebop2Browser;
0186     delete m_anafiBrowser;
0187 #endif
0188 
0189     qCDebug(KIROGI_VEHICLESUPPORT_PARROT) << "Parrot Vehicle Support Plugin unloaded.";
0190 }
0191 
0192 QList<Kirogi::AbstractVehicle *> ParrotPlugin::vehicles() const
0193 {
0194     return m_vehicles.values();
0195 }
0196 
0197 K_PLUGIN_CLASS_WITH_JSON(ParrotPlugin, "kirogiparrotplugin.json")
0198 
0199 #include "parrotplugin.moc"