From 097254756e09c4fdb329ddd42fc49179af682cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 28 Oct 2020 16:53:07 +0100 Subject: [PATCH] Add zigbee uart monitor --- debian/control | 18 +- libnymea-zigbee/libnymea-zigbee.pro | 29 +-- libnymea-zigbee/loggingcategory.cpp | 1 + libnymea-zigbee/loggingcategory.h | 1 + libnymea-zigbee/zigbeenetworkmanager.cpp | 52 ---- libnymea-zigbee/zigbeenetworkmanager.h | 4 +- ...igbeeadapter.cpp => zigbeeuartadapter.cpp} | 32 +-- .../{zigbeeadapter.h => zigbeeuartadapter.h} | 22 +- libnymea-zigbee/zigbeeuartadaptermonitor.cpp | 241 ++++++++++++++++++ libnymea-zigbee/zigbeeuartadaptermonitor.h | 64 +++++ 10 files changed, 352 insertions(+), 112 deletions(-) rename libnymea-zigbee/{zigbeeadapter.cpp => zigbeeuartadapter.cpp} (70%) rename libnymea-zigbee/{zigbeeadapter.h => zigbeeuartadapter.h} (80%) create mode 100644 libnymea-zigbee/zigbeeuartadaptermonitor.cpp create mode 100644 libnymea-zigbee/zigbeeuartadaptermonitor.h diff --git a/debian/control b/debian/control index 6118f01..f73d424 100644 --- a/debian/control +++ b/debian/control @@ -7,12 +7,13 @@ Homepage: https://nymea.io Vcs-Git: https://github.com/nymea/nymea-zigbee.git Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), + pkg-config, qt5-default, qt5-qmake, qtbase5-dev, qtbase5-dev-tools, libqt5serialport5-dev, - libreadline-dev + libudev-dev Package: libnymea-zigbee1 Section: libs @@ -22,8 +23,8 @@ Depends: ${shlibs:Depends}, libqt5network5, libqt5gui5, libqt5serialport5 -Description: Qt 5 based library for Zigbee - Qt 5 based library for Zigbee. +Description: Qt 5 based library for ZigBee + Qt 5 based library for ZigBee. Package: libnymea-zigbee-dev @@ -31,9 +32,10 @@ Section: libdevel Architecture: any Depends: libnymea-zigbee1 (= ${binary:Version}), ${shlibs:Depends}, - ${misc:Depends} -Description: Qt 5 based library for Zigbee - development files - Development files for Qt 5 based Zigbee library. + ${misc:Depends}, + pkg-config +Dscription: Qt 5 based library for ZigBee - development files + Development files for Qt 5 based ZigBee library. Package: libnymea-zigbee1-dbg @@ -43,5 +45,5 @@ Section: debug Depends: libnymea-zigbee1 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: Qt 5 based library for Zigbee - debug symbols - Debug Symbols for Qt 5 based Zigbee library. +Description: Qt 5 based library for ZigBee - debug symbols + Debug Symbols for Qt 5 based ZigBee library. diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 830fa64..6fc6d15 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -3,6 +3,9 @@ include(../config.pri) TARGET = nymea-zigbee1 TEMPLATE = lib +CONFIG += link_pkgconfig +PKGCONFIG += libudev + SOURCES += \ backends/deconz/interface/zigbeeinterfacedeconz.cpp \ backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \ @@ -31,7 +34,6 @@ SOURCES += \ zdo/zigbeedeviceobject.cpp \ zdo/zigbeedeviceobjectreply.cpp \ zdo/zigbeedeviceprofile.cpp \ - zigbeeadapter.cpp \ zigbeeadpu.cpp \ zigbeebridgecontroller.cpp \ zigbeechannelmask.cpp \ @@ -47,17 +49,11 @@ SOURCES += \ zigbeenetworkrequest.cpp \ zigbeenodeendpoint.cpp \ zigbeesecurityconfiguration.cpp \ + zigbeeuartadapter.cpp \ + zigbeeuartadaptermonitor.cpp \ zigbeeutils.cpp \ zigbeenode.cpp \ - zigbeeaddress.cpp \ - # nxp/interface/zigbeeinterface.cpp \ - # nxp/interface/zigbeeinterfacemessage.cpp \ - # nxp/interface/zigbeeinterfacerequest.cpp \ - # nxp/interface/zigbeeinterfacereply.cpp \ - # nxp/zigbeenetworknxp.cpp \ - # nxp/zigbeebridgecontrollernxp.cpp \ - # nxp/zigbeenodeendpointnxp.cpp \ - # nxp/zigbeenodenxp.cpp \ + zigbeeaddress.cpp HEADERS += \ backends/deconz/interface/deconz.h \ @@ -89,7 +85,6 @@ HEADERS += \ zdo/zigbeedeviceobject.h \ zdo/zigbeedeviceobjectreply.h \ zdo/zigbeedeviceprofile.h \ - zigbeeadapter.h \ zigbeeadpu.h \ zigbeebridgecontroller.h \ zigbeechannelmask.h \ @@ -105,17 +100,11 @@ HEADERS += \ zigbeenetworkrequest.h \ zigbeenodeendpoint.h \ zigbeesecurityconfiguration.h \ + zigbeeuartadapter.h \ + zigbeeuartadaptermonitor.h \ zigbeeutils.h \ zigbeenode.h \ - zigbeeaddress.h \ - # nxp/interface/zigbeeinterface.h \ - # nxp/interface/zigbeeinterfacemessage.h \ - # nxp/interface/zigbeeinterfacerequest.h \ - # nxp/interface/zigbeeinterfacereply.h \ - # nxp/zigbeenetworknxp.h \ - # nxp/zigbeebridgecontrollernxp.h \ - # nxp/zigbeenodeendpointnxp.h \ - # nxp/zigbeenodenxp.h \ + zigbeeaddress.h # install header file with relative subdirectory for (header, HEADERS) { diff --git a/libnymea-zigbee/loggingcategory.cpp b/libnymea-zigbee/loggingcategory.cpp index 1fb1848..7056392 100644 --- a/libnymea-zigbee/loggingcategory.cpp +++ b/libnymea-zigbee/loggingcategory.cpp @@ -35,6 +35,7 @@ Q_LOGGING_CATEGORY(dcZigbeeEndpoint, "ZigbeeEndpoint") Q_LOGGING_CATEGORY(dcZigbeeInterface, "ZigbeeInterface") Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController") Q_LOGGING_CATEGORY(dcZigbeeDeviceObject, "ZigbeeDeviceObject") +Q_LOGGING_CATEGORY(dcZigbeeAdapterMonitor, "ZigbeeAdapterMonitor") Q_LOGGING_CATEGORY(dcZigbeeClusterLibrary, "ZigbeeClusterLibrary") Q_LOGGING_CATEGORY(dcZigbeeNetworkDatabase, "ZigbeeNetworkDatabase") Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") diff --git a/libnymea-zigbee/loggingcategory.h b/libnymea-zigbee/loggingcategory.h index c32de56..a6d471d 100644 --- a/libnymea-zigbee/loggingcategory.h +++ b/libnymea-zigbee/loggingcategory.h @@ -39,6 +39,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcZigbeeEndpoint) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterface) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeDeviceObject) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeAdapterMonitor) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeClusterLibrary) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetworkDatabase) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) diff --git a/libnymea-zigbee/zigbeenetworkmanager.cpp b/libnymea-zigbee/zigbeenetworkmanager.cpp index d6e4adf..700af52 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.cpp +++ b/libnymea-zigbee/zigbeenetworkmanager.cpp @@ -32,58 +32,6 @@ #include "backends/deconz/zigbeenetworkdeconz.h" #include -#include - -QList ZigbeeNetworkManager::availableAdapters() -{ - QList adapters; - qCDebug(dcZigbeeNetwork()) << "Loading available adapters" ; - foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { - qCDebug(dcZigbeeNetwork()) << "Adapter candidate" << serialPortInfo.portName(); - qCDebug(dcZigbeeNetwork()) << " Description:" << serialPortInfo.description(); - qCDebug(dcZigbeeNetwork()) << " System location:" << serialPortInfo.systemLocation(); - qCDebug(dcZigbeeNetwork()) << " Manufacturer:" << serialPortInfo.manufacturer(); - qCDebug(dcZigbeeNetwork()) << " Serialnumber:" << serialPortInfo.serialNumber(); - - if (serialPortInfo.hasProductIdentifier()) { - qCDebug(dcZigbeeNetwork()) << " Product identifier:" << serialPortInfo.productIdentifier(); - } - - if (serialPortInfo.hasVendorIdentifier()) { - qCDebug(dcZigbeeNetwork()) << " Vendor identifier:" << serialPortInfo.vendorIdentifier(); - } - - // Check if we recognize this controller - ZigbeeAdapter adapter; - if (serialPortInfo.portName().isEmpty()) { - adapter.setName("Zigbee adapter"); - } else { - adapter.setName(serialPortInfo.portName()); - } - - if (serialPortInfo.description().isEmpty()) { - adapter.setDescription("Unknown"); - } else { - adapter.setDescription(serialPortInfo.description()); - } - adapter.setSystemLocation(serialPortInfo.systemLocation()); - - // Check if we recognize this adapter from USB information - if (serialPortInfo.manufacturer().toLower().contains("dresden elektronik")) { - adapter.setBackendSuggestionAvailable(true); - adapter.setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendTypeDeconz); - adapter.setSuggestedBaudRate(38400); - } else if (serialPortInfo.manufacturer().toLower().contains("nxp")) { - adapter.setBackendSuggestionAvailable(true); - adapter.setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendTypeNxp); - adapter.setSuggestedBaudRate(115200); - } - - adapters.append(adapter); - } - - return adapters; -} QStringList ZigbeeNetworkManager::availableZigbeeBackendTypes() { diff --git a/libnymea-zigbee/zigbeenetworkmanager.h b/libnymea-zigbee/zigbeenetworkmanager.h index c62e80a..9b4a5cc 100644 --- a/libnymea-zigbee/zigbeenetworkmanager.h +++ b/libnymea-zigbee/zigbeenetworkmanager.h @@ -30,14 +30,14 @@ #include -#include "zigbeeadapter.h" +#include "zigbeeuartadapter.h" #include "zigbeenetwork.h" class ZigbeeNetworkManager { Q_GADGET + public: - static QList availableAdapters(); static QStringList availableZigbeeBackendTypes(); static ZigbeeNetwork *createZigbeeNetwork(Zigbee::ZigbeeBackendType backend, QObject *parent = nullptr); }; diff --git a/libnymea-zigbee/zigbeeadapter.cpp b/libnymea-zigbee/zigbeeuartadapter.cpp similarity index 70% rename from libnymea-zigbee/zigbeeadapter.cpp rename to libnymea-zigbee/zigbeeuartadapter.cpp index f4b285b..ad540ac 100644 --- a/libnymea-zigbee/zigbeeadapter.cpp +++ b/libnymea-zigbee/zigbeeuartadapter.cpp @@ -25,76 +25,76 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "zigbeeadapter.h" +#include "zigbeeuartadapter.h" -ZigbeeAdapter::ZigbeeAdapter() +ZigbeeUartAdapter::ZigbeeUartAdapter() { } -QString ZigbeeAdapter::name() const +QString ZigbeeUartAdapter::name() const { return m_name; } -void ZigbeeAdapter::setName(const QString &name) +void ZigbeeUartAdapter::setName(const QString &name) { m_name = name; } -QString ZigbeeAdapter::description() const +QString ZigbeeUartAdapter::description() const { return m_description; } -void ZigbeeAdapter::setDescription(const QString &description) +void ZigbeeUartAdapter::setDescription(const QString &description) { m_description = description; } -QString ZigbeeAdapter::systemLocation() const +QString ZigbeeUartAdapter::systemLocation() const { return m_systemLocation; } -void ZigbeeAdapter::setSystemLocation(const QString &systemLocation) +void ZigbeeUartAdapter::setSystemLocation(const QString &systemLocation) { m_systemLocation = systemLocation; } -bool ZigbeeAdapter::backendSuggestionAvailable() const +bool ZigbeeUartAdapter::backendSuggestionAvailable() const { return m_backendSuggestionAvailable; } -void ZigbeeAdapter::setBackendSuggestionAvailable(bool backendSuggestionAvailable) +void ZigbeeUartAdapter::setBackendSuggestionAvailable(bool backendSuggestionAvailable) { m_backendSuggestionAvailable = backendSuggestionAvailable; } -Zigbee::ZigbeeBackendType ZigbeeAdapter::suggestedZigbeeBackendType() const +Zigbee::ZigbeeBackendType ZigbeeUartAdapter::suggestedZigbeeBackendType() const { return m_suggestedZigbeeBackendType; } -void ZigbeeAdapter::setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendType backendType) +void ZigbeeUartAdapter::setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendType backendType) { m_suggestedZigbeeBackendType = backendType; } -qint32 ZigbeeAdapter::suggestedBaudRate() const +qint32 ZigbeeUartAdapter::suggestedBaudRate() const { return m_suggestedBaudRate; } -void ZigbeeAdapter::setSuggestedBaudRate(qint32 baudRate) +void ZigbeeUartAdapter::setSuggestedBaudRate(qint32 baudRate) { m_suggestedBaudRate = baudRate; } -QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter) +QDebug operator<<(QDebug debug, const ZigbeeUartAdapter &adapter) { - debug.nospace() << "ZigbeeAdapter(" << adapter.name() << " - " << adapter.description(); + debug.nospace() << "ZigbeeUartAdapter(" << adapter.name() << " - " << adapter.description(); debug.nospace() << ", " << adapter.systemLocation(); if (adapter.backendSuggestionAvailable()) { debug.nospace() << "Suggested backend: " << adapter.suggestedZigbeeBackendType(); diff --git a/libnymea-zigbee/zigbeeadapter.h b/libnymea-zigbee/zigbeeuartadapter.h similarity index 80% rename from libnymea-zigbee/zigbeeadapter.h rename to libnymea-zigbee/zigbeeuartadapter.h index 273e60e..f766d8d 100644 --- a/libnymea-zigbee/zigbeeadapter.h +++ b/libnymea-zigbee/zigbeeuartadapter.h @@ -25,26 +25,18 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef ZIGBEEADAPTER_H -#define ZIGBEEADAPTER_H +#ifndef ZIGBEEUARTADAPTER_H +#define ZIGBEEUARTADAPTER_H -#include +#include #include #include "zigbee.h" -class ZigbeeAdapter +class ZigbeeUartAdapter { - Q_GADGET - Q_PROPERTY(QString name READ name) - Q_PROPERTY(QString description READ description) - Q_PROPERTY(QString systemLocation READ systemLocation) - Q_PROPERTY(bool backendSuggestionAvailable READ backendSuggestionAvailable) - Q_PROPERTY(Zigbee::ZigbeeBackendType suggestedZigbeeBackendType READ suggestedZigbeeBackendType) - Q_PROPERTY(qint32 suggestedBaudRate READ suggestedBaudRate) - public: - explicit ZigbeeAdapter(); + explicit ZigbeeUartAdapter(); QString name() const; void setName(const QString &name); @@ -74,7 +66,9 @@ private: qint32 m_suggestedBaudRate = 38400; }; -QDebug operator<<(QDebug debug, const ZigbeeAdapter &adapter); +Q_DECLARE_METATYPE(ZigbeeUartAdapter) + +QDebug operator<<(QDebug debug, const ZigbeeUartAdapter &adapter); #endif // ZIGBEEADAPTER_H diff --git a/libnymea-zigbee/zigbeeuartadaptermonitor.cpp b/libnymea-zigbee/zigbeeuartadaptermonitor.cpp new file mode 100644 index 0000000..096779b --- /dev/null +++ b/libnymea-zigbee/zigbeeuartadaptermonitor.cpp @@ -0,0 +1,241 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeeuartadaptermonitor.h" +#include "loggingcategory.h" + +#include + +ZigbeeUartAdapterMonitor::ZigbeeUartAdapterMonitor(QObject *parent) : QObject(parent) +{ + qRegisterMetaType(); + + m_udev = udev_new(); + if (!m_udev) { + qCWarning(dcZigbeeAdapterMonitor()) << "Could not initialize udev for the adapter monitor"; + return; + } + + // Read initially all tty devices + struct udev_enumerate *enumerate = udev_enumerate_new(m_udev); + if (!enumerate) { + qCWarning(dcZigbeeAdapterMonitor()) << "Could not create udev enumerate for initial device reading for the adapter monitor."; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + udev_enumerate_add_match_subsystem(enumerate, "tty"); + + if (udev_enumerate_scan_devices(enumerate) < 0) { + qCWarning(dcZigbeeAdapterMonitor()) << "Failed to scan devices from udev enumerate."; + udev_enumerate_unref(enumerate); + enumerate = nullptr; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + qCDebug(dcZigbeeAdapterMonitor()) << "Load initial list of available serial ports..."; + struct udev_list_entry *devices = nullptr; + devices = udev_enumerate_get_list_entry(enumerate); + struct udev_list_entry *dev_list_entry = nullptr; + udev_list_entry_foreach(dev_list_entry, devices) { + struct udev_device *device = nullptr; + const char *path; + path = udev_list_entry_get_name(dev_list_entry); + device = udev_device_new_from_syspath(m_udev, path); + + // Print properties + struct udev_list_entry *properties = udev_device_get_properties_list_entry(device); + struct udev_list_entry *property_list_entry = nullptr; + udev_list_entry_foreach(property_list_entry, properties) { + qCDebug(dcZigbeeAdapterMonitor()) << " - Property" << udev_list_entry_get_name(property_list_entry) << udev_list_entry_get_value(property_list_entry); + } + + QString devicePath = QString::fromLatin1(udev_device_get_property_value(device,"DEVNAME")); + QString manufacturerString = QString::fromLatin1(udev_device_get_property_value(device,"ID_VENDOR_ENC")); + QString descriptionString = QString::fromLatin1(udev_device_get_property_value(device,"ID_MODEL_ENC")); + QString serialNumberString = QString::fromLatin1(udev_device_get_property_value(device, "ID_SERIAL_SHORT")); + + // Clean up this device since we have all information + udev_device_unref(device); + + qCDebug(dcZigbeeAdapterMonitor()) << "[+]" << devicePath << manufacturerString << descriptionString << serialNumberString; + addAdapterInternally(devicePath); + } + + udev_enumerate_unref(enumerate); + enumerate = nullptr; + + // Create udev monitor + m_monitor = udev_monitor_new_from_netlink(m_udev, "udev"); + if (!m_monitor) { + qCWarning(dcZigbeeAdapterMonitor()) << "Could not initialize udev monitor."; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + // Set monitor filter to tty subsystem + if (udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "tty", nullptr) < 0) { + qCWarning(dcZigbeeAdapterMonitor()) << "Could not set subsystem device type filter to tty."; + udev_monitor_unref(m_monitor); + m_monitor = nullptr; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + // Enable the monitor + if (udev_monitor_enable_receiving(m_monitor) < 0) { + qCWarning(dcZigbeeAdapterMonitor()) << "Could not enable udev monitor."; + udev_monitor_unref(m_monitor); + m_monitor = nullptr; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + // Create socket notifier for read + int socketDescriptor = udev_monitor_get_fd(m_monitor); + m_notifier = new QSocketNotifier(socketDescriptor, QSocketNotifier::Read, this); + connect(m_notifier, &QSocketNotifier::activated, this, [this, socketDescriptor](int socket){ + // Make sure the socket matches + if (socketDescriptor != socket) { + qCWarning(dcZigbeeAdapterMonitor()) << "socket != socketdescriptor"; + return; + } + + // Create udev device + udev_device *device = udev_monitor_receive_device(m_monitor); + if (!device) { + qCWarning(dcZigbeeAdapterMonitor()) << "Got socket sotification but could not read device information."; + return; + } + + QString actionString = QString::fromLatin1(udev_device_get_action(device)); + QString devicePath = QString::fromLatin1(udev_device_get_property_value(device,"DEVNAME")); + QString manufacturerString = QString::fromLatin1(udev_device_get_property_value(device,"ID_VENDOR_ENC")); + QString descriptionString = QString::fromLatin1(udev_device_get_property_value(device,"ID_MODEL_ENC")); + QString serialNumberString = QString::fromLatin1(udev_device_get_property_value(device, "ID_SERIAL_SHORT")); + + // Clean udev device + udev_device_unref(device); + + // Make sure we know the action + if (actionString.isEmpty()) + return; + + if (actionString == "add") { + qCDebug(dcZigbeeAdapterMonitor()) << "[+]" << devicePath << serialNumberString; + if (!m_availableAdapters.contains(devicePath)) { + addAdapterInternally(devicePath); + } + } + + if (actionString == "remove") { + qCDebug(dcZigbeeAdapterMonitor()) << "[-]" << devicePath << serialNumberString; + if (m_availableAdapters.contains(devicePath)) { + ZigbeeUartAdapter adapter = m_availableAdapters.take(devicePath); + qCDebug(dcZigbeeAdapterMonitor()) << "Removed" << adapter; + emit adapterRemoved(adapter); + } + } + }); + + m_notifier->setEnabled(true); + m_isValid = true; +} + +QList ZigbeeUartAdapterMonitor::availableAdapters() const +{ + return m_availableAdapters.values(); +} + +bool ZigbeeUartAdapterMonitor::isValid() const +{ + return m_isValid; +} + +void ZigbeeUartAdapterMonitor::addAdapterInternally(const QString &systemLocation) +{ + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + if (serialPortInfo.systemLocation() != systemLocation) + continue; + + if (m_availableAdapters.keys().contains(systemLocation)) { + qCWarning(dcZigbeeAdapterMonitor()) << "The adapter" << systemLocation << "has already been added to the monitor."; + continue; + } + + qCDebug(dcZigbeeAdapterMonitor()) << "Adapter candidate" << serialPortInfo.portName(); + qCDebug(dcZigbeeAdapterMonitor()) << " Description:" << serialPortInfo.description(); + qCDebug(dcZigbeeAdapterMonitor()) << " System location:" << serialPortInfo.systemLocation(); + qCDebug(dcZigbeeAdapterMonitor()) << " Manufacturer:" << serialPortInfo.manufacturer(); + qCDebug(dcZigbeeAdapterMonitor()) << " Serialnumber:" << serialPortInfo.serialNumber(); + + if (serialPortInfo.hasProductIdentifier()) { + qCDebug(dcZigbeeAdapterMonitor()) << " Product identifier:" << serialPortInfo.productIdentifier(); + } + + if (serialPortInfo.hasVendorIdentifier()) { + qCDebug(dcZigbeeAdapterMonitor()) << " Vendor identifier:" << serialPortInfo.vendorIdentifier(); + } + + // Check if we recognize this controller + ZigbeeUartAdapter adapter; + if (serialPortInfo.portName().isEmpty()) { + adapter.setName("Zigbee adapter"); + } else { + adapter.setName(serialPortInfo.portName()); + } + + if (serialPortInfo.description().isEmpty()) { + adapter.setDescription("Unknown"); + } else { + adapter.setDescription(serialPortInfo.description()); + } + adapter.setSystemLocation(serialPortInfo.systemLocation()); + + // Check if we recognize this adapter from USB information + if (serialPortInfo.manufacturer().toLower().contains("dresden elektronik")) { + adapter.setBackendSuggestionAvailable(true); + adapter.setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendTypeDeconz); + adapter.setSuggestedBaudRate(38400); + } else if (serialPortInfo.manufacturer().toLower().contains("nxp")) { + adapter.setBackendSuggestionAvailable(true); + adapter.setSuggestedZigbeeBackendType(Zigbee::ZigbeeBackendTypeNxp); + adapter.setSuggestedBaudRate(115200); + } + + qCDebug(dcZigbeeAdapterMonitor()) << "Added" << adapter; + m_availableAdapters.insert(adapter.systemLocation(), adapter); + emit adapterAdded(adapter); + } + +} diff --git a/libnymea-zigbee/zigbeeuartadaptermonitor.h b/libnymea-zigbee/zigbeeuartadaptermonitor.h new file mode 100644 index 0000000..dea9521 --- /dev/null +++ b/libnymea-zigbee/zigbeeuartadaptermonitor.h @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEEUARTADAPTERMONITOR_H +#define ZIGBEEUARTADAPTERMONITOR_H + +#include +#include + +#include + +#include "zigbeeuartadapter.h" + +class ZigbeeUartAdapterMonitor : public QObject +{ + Q_OBJECT +public: + explicit ZigbeeUartAdapterMonitor(QObject *parent = nullptr); + + QList availableAdapters() const; + + bool isValid() const; + +private: + bool m_isValid = false; + struct udev *m_udev = nullptr; + struct udev_monitor *m_monitor = nullptr; + QSocketNotifier *m_notifier = nullptr; + + QHash m_availableAdapters; + + void addAdapterInternally(const QString &systemLocation); + +signals: + void adapterAdded(const ZigbeeUartAdapter &adapter); + void adapterRemoved(const ZigbeeUartAdapter &adapter); + +}; + +#endif // ZIGBEEUARTADAPTERMONITOR_H