From 1788716a4db02e8a53d019c3db1061e7beae5809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 16 Sep 2019 16:34:16 +0200 Subject: [PATCH] Add bluetooth basics --- .../bluetooth/bluetoothserver.cpp | 409 ++++++++++++++ .../bluetooth/bluetoothserver.h | 105 ++++ .../bluetooth/bluetoothuuids.h | 35 ++ .../bluetooth/networkservice.cpp | 325 +++++++++++ .../bluetooth/networkservice.h | 78 +++ .../bluetooth/wirelessservice.cpp | 508 ++++++++++++++++++ .../bluetooth/wirelessservice.h | 100 ++++ .../libnymea-networkmanager.pro | 22 + .../networkmanagerutils.cpp | 1 + libnymea-networkmanager/networkmanagerutils.h | 1 + ...ager_0.1.1+201909161052~f3057c8~bionic.dsc | 18 + ...r_0.1.1+201909161052~f3057c8~bionic.tar.xz | Bin 0 -> 26500 bytes ...201909161052~f3057c8~bionic_source.changes | 35 ++ ...ager_0.1.1+201909161457~82b7888~bionic.dsc | 18 + ...r_0.1.1+201909161457~82b7888~bionic.tar.xz | Bin 0 -> 61216 bytes ...201909161457~82b7888~bionic_source.changes | 35 ++ 16 files changed, 1690 insertions(+) create mode 100644 libnymea-networkmanager/bluetooth/bluetoothserver.cpp create mode 100644 libnymea-networkmanager/bluetooth/bluetoothserver.h create mode 100644 libnymea-networkmanager/bluetooth/bluetoothuuids.h create mode 100644 libnymea-networkmanager/bluetooth/networkservice.cpp create mode 100644 libnymea-networkmanager/bluetooth/networkservice.h create mode 100644 libnymea-networkmanager/bluetooth/wirelessservice.cpp create mode 100644 libnymea-networkmanager/bluetooth/wirelessservice.h create mode 100644 source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc create mode 100644 source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz create mode 100644 source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic_source.changes create mode 100644 source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc create mode 100644 source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz create mode 100644 source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.changes diff --git a/libnymea-networkmanager/bluetooth/bluetoothserver.cpp b/libnymea-networkmanager/bluetooth/bluetoothserver.cpp new file mode 100644 index 0000000..eec76de --- /dev/null +++ b/libnymea-networkmanager/bluetooth/bluetoothserver.cpp @@ -0,0 +1,409 @@ +#include "bluetoothserver.h" +#include "../networkmanager.h" +#include "../networkmanagerutils.h" + +BluetoothServer::BluetoothServer(NetworkManager *networkManager) : + QObject(networkManager), + m_networkManager(networkManager) +{ + +} + +BluetoothServer::~BluetoothServer() +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Destroy bluetooth server."; + if (m_controller) + m_controller->stopAdvertising(); + + if (m_localDevice) + m_localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable); + +} + +QString BluetoothServer::modelName() const +{ + return m_modelName; +} + +void BluetoothServer::setModelName(const QString &modelName) +{ + m_modelName = modelName; +} + +QString BluetoothServer::serverName() const +{ + return m_serverName; +} + +void BluetoothServer::setServerName(const QString &serverName) +{ + m_serverName = serverName; +} + +QString BluetoothServer::softwareVersion() const +{ + return m_softwareVersion; +} + +void BluetoothServer::setSoftwareVersion(const QString &softwareVersion) +{ + m_softwareVersion = softwareVersion; +} + +bool BluetoothServer::running() const +{ + return m_running; +} + +bool BluetoothServer::connected() const +{ + return m_connected; +} + +QLowEnergyServiceData BluetoothServer::deviceInformationServiceData() +{ + QLowEnergyServiceData serviceData; + serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); + serviceData.setUuid(QBluetoothUuid::DeviceInformation); + + // Model number string 0x2a24 + QLowEnergyCharacteristicData modelNumberCharData; + modelNumberCharData.setUuid(QBluetoothUuid::ModelNumberString); + if (m_modelName.isEmpty()) { + modelNumberCharData.setValue(QString("N.A.").toUtf8()); + } else { + modelNumberCharData.setValue(m_modelName.toUtf8()); + } + + modelNumberCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(modelNumberCharData); + + // Firmware revision string 0x2a26 + QLowEnergyCharacteristicData firmwareRevisionCharData; + firmwareRevisionCharData.setUuid(QBluetoothUuid::FirmwareRevisionString); + firmwareRevisionCharData.setValue(QString(VERSION_STRING).toUtf8()); + firmwareRevisionCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(firmwareRevisionCharData); + + // Hardware revision string 0x2a27 + QLowEnergyCharacteristicData hardwareRevisionCharData; + hardwareRevisionCharData.setUuid(QBluetoothUuid::HardwareRevisionString); + hardwareRevisionCharData.setValue(m_hardwareVersion.toUtf8()); + hardwareRevisionCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(hardwareRevisionCharData); + + // Software revision string 0x2a28 + QLowEnergyCharacteristicData softwareRevisionCharData; + softwareRevisionCharData.setUuid(QBluetoothUuid::SoftwareRevisionString); + softwareRevisionCharData.setValue(m_softwareVersion.toUtf8()); + softwareRevisionCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(softwareRevisionCharData); + + // Manufacturer name string 0x2a29 + QLowEnergyCharacteristicData manufacturerNameCharData; + manufacturerNameCharData.setUuid(QBluetoothUuid::ManufacturerNameString); + manufacturerNameCharData.setValue(QString("guh GmbH").toUtf8()); + manufacturerNameCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(manufacturerNameCharData); + + return serviceData; +} + +QLowEnergyServiceData BluetoothServer::genericAccessServiceData() +{ + QLowEnergyServiceData serviceData; + serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); + serviceData.setUuid(QBluetoothUuid::GenericAccess); + + // Device name 0x2a00 + QLowEnergyCharacteristicData nameCharData; + nameCharData.setUuid(QBluetoothUuid::DeviceName); + nameCharData.setValue(m_serverName.toUtf8()); + nameCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(nameCharData); + + // Appearance 0x2a01 + QLowEnergyCharacteristicData appearanceCharData; + appearanceCharData.setUuid(QBluetoothUuid::Appearance); + appearanceCharData.setValue(QByteArray(4, 0)); + appearanceCharData.setProperties(QLowEnergyCharacteristic::Read); + serviceData.addCharacteristic(appearanceCharData); + + // Peripheral Privacy Flag 0x2a02 + QLowEnergyCharacteristicData privacyFlagCharData; + privacyFlagCharData.setUuid(QBluetoothUuid::PeripheralPrivacyFlag); + privacyFlagCharData.setValue(QByteArray(2, 0)); + privacyFlagCharData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write); + serviceData.addCharacteristic(privacyFlagCharData); + + // Reconnection Address 0x2a03 + QLowEnergyCharacteristicData reconnectionAddressCharData; + reconnectionAddressCharData.setUuid(QBluetoothUuid::ReconnectionAddress); + reconnectionAddressCharData.setValue(QByteArray()); + reconnectionAddressCharData.setProperties(QLowEnergyCharacteristic::Write); + serviceData.addCharacteristic(reconnectionAddressCharData); + + return serviceData; +} + +QLowEnergyServiceData BluetoothServer::genericAttributeServiceData() +{ + QLowEnergyServiceData serviceData; + serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); + serviceData.setUuid(QBluetoothUuid::GenericAttribute); + + QLowEnergyCharacteristicData charData; + charData.setUuid(QBluetoothUuid::ServiceChanged); + charData.setProperties(QLowEnergyCharacteristic::Indicate); + + serviceData.addCharacteristic(charData); + + return serviceData; +} + +void BluetoothServer::setRunning(bool running) +{ + if (m_running == running) + return; + + m_running = running; + emit runningChanged(m_running); +} + +void BluetoothServer::setConnected(bool connected) +{ + if (m_connected == connected) + return; + + m_connected = connected; + emit connectedChanged(m_connected); +} + +void BluetoothServer::onHostModeStateChanged(const QBluetoothLocalDevice::HostMode mode) +{ + switch (mode) { + case QBluetoothLocalDevice::HostConnectable: + qCDebug(dcNetworkManagerBluetoothServer()) << "Bluetooth host in connectable mode."; + break; + case QBluetoothLocalDevice::HostDiscoverable: + qCDebug(dcNetworkManagerBluetoothServer()) << "Bluetooth host in discoverable mode."; + break; + case QBluetoothLocalDevice::HostPoweredOff: + qCDebug(dcNetworkManagerBluetoothServer()) << "Bluetooth host in power off mode."; + break; + case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry: + qCDebug(dcNetworkManagerBluetoothServer()) << "Bluetooth host in discoverable limited inquiry mode."; + break; + } +} + +void BluetoothServer::onDeviceConnected(const QBluetoothAddress &address) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Device connected" << address.toString(); +} + +void BluetoothServer::onDeviceDisconnected(const QBluetoothAddress &address) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Device disconnected" << address.toString(); +} + +void BluetoothServer::onError(QLowEnergyController::Error error) +{ + qCWarning(dcNetworkManagerBluetoothServer()) << "Bluetooth error occured:" << error << m_controller->errorString(); +} + +void BluetoothServer::onConnected() +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Client connected" << m_controller->remoteName() << m_controller->remoteAddress(); + setConnected(true); +} + +void BluetoothServer::onDisconnected() +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Client disconnected"; + setConnected(false); + stop(); +} + +void BluetoothServer::onControllerStateChanged(QLowEnergyController::ControllerState state) +{ + switch (state) { + case QLowEnergyController::UnconnectedState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state disonnected."; + setConnected(false); + break; + case QLowEnergyController::ConnectingState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state connecting..."; + setConnected(false); + break; + case QLowEnergyController::ConnectedState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state connected." << m_controller->remoteName() << m_controller->remoteAddress(); + setConnected(true); + break; + case QLowEnergyController::DiscoveringState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state discovering..."; + break; + case QLowEnergyController::DiscoveredState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state discovered."; + break; + case QLowEnergyController::ClosingState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state closing..."; + break; + case QLowEnergyController::AdvertisingState: + qCDebug(dcNetworkManagerBluetoothServer()) << "Controller state advertising..."; + setRunning(true); + break; + } +} + +void BluetoothServer::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Service characteristic changed" << characteristic.uuid() << value; +} + +void BluetoothServer::characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Service characteristic read" << characteristic.uuid() << value; +} + +void BluetoothServer::characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Service characteristic written" << characteristic.uuid() << value; +} + +void BluetoothServer::descriptorRead(const QLowEnergyDescriptor &descriptor, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Descriptor read" << descriptor.uuid() << value; +} + +void BluetoothServer::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Descriptor written" << descriptor.uuid() << value; +} + +void BluetoothServer::serviceError(QLowEnergyService::ServiceError error) +{ + QString errorString; + switch (error) { + case QLowEnergyService::NoError: + errorString = "No error"; + break; + case QLowEnergyService::OperationError: + errorString = "Operation error"; + break; + case QLowEnergyService::CharacteristicReadError: + errorString = "Characteristic read error"; + break; + case QLowEnergyService::CharacteristicWriteError: + errorString = "Characteristic write error"; + break; + case QLowEnergyService::DescriptorReadError: + errorString = "Descriptor read error"; + break; + case QLowEnergyService::DescriptorWriteError: + errorString = "Descriptor write error"; + break; + case QLowEnergyService::UnknownError: + errorString = "Unknown error"; + break; + } + + qCWarning(dcNetworkManagerBluetoothServer()) << "Service error:" << errorString; +} + +void BluetoothServer::start() +{ + if (connected()) { + qCDebug(dcNetworkManagerBluetoothServer()) << "Start Bluetooth server called but the server is running and a client is connected. Doing nothing."; + return; + } + + if (running()) { + qCDebug(dcNetworkManagerBluetoothServer()) << "Start Bluetooth server called but the server is already running. Doing nothing."; + return; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "-------------------------------------"; + qCDebug(dcNetworkManagerBluetoothServer()) << "Starting bluetooth server..."; + qCDebug(dcNetworkManagerBluetoothServer()) << "-------------------------------------"; + + // Local bluetooth device + m_localDevice = new QBluetoothLocalDevice(this); + if (!m_localDevice->isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "Local bluetooth device is not valid."; + delete m_localDevice; + m_localDevice = nullptr; + return; + } + + connect(m_localDevice, &QBluetoothLocalDevice::hostModeStateChanged, this, &BluetoothServer::onHostModeStateChanged); + connect(m_localDevice, &QBluetoothLocalDevice::deviceConnected, this, &BluetoothServer::onDeviceConnected); + connect(m_localDevice, &QBluetoothLocalDevice::deviceDisconnected, this, &BluetoothServer::onDeviceDisconnected); + + qCDebug(dcNetworkManagerBluetoothServer()) << "Local device" << m_localDevice->name() << m_localDevice->address().toString(); + m_localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverable); + m_localDevice->powerOn(); + + + // Bluetooth low energy periperal controller + m_controller = QLowEnergyController::createPeripheral(this); + connect(m_controller, &QLowEnergyController::stateChanged, this, &BluetoothServer::onControllerStateChanged); + connect(m_controller, &QLowEnergyController::connected, this, &BluetoothServer::onConnected); + connect(m_controller, &QLowEnergyController::disconnected, this, &BluetoothServer::onDisconnected); + connect(m_controller, SIGNAL(error(QLowEnergyController::Error)), this, SLOT(onError(QLowEnergyController::Error))); + + // Note: https://www.bluetooth.com/specifications/gatt/services + m_deviceInfoService = m_controller->addService(deviceInformationServiceData(), m_controller); + m_genericAccessService = m_controller->addService(genericAccessServiceData(), m_controller); + m_genericAttributeService = m_controller->addService(genericAttributeServiceData(), m_controller); + + // Create custom services + m_networkService = new NetworkService(m_controller->addService(NetworkService::serviceData(), m_controller), m_controller); + m_wirelessService = new WirelessService(m_controller->addService(WirelessService::serviceData(), m_controller), m_controller); + + QLowEnergyAdvertisingData advertisingData; + advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral); + advertisingData.setIncludePowerLevel(true); + advertisingData.setLocalName(m_serverName); + + // FIXME: set guh manufacturer SIG data once available + + // Note: start advertising in 100 ms interval, this makes the device better discoverable on certain phones + QLowEnergyAdvertisingParameters advertisingParameters; + advertisingParameters.setInterval(100,100); + + qCDebug(dcNetworkManagerBluetoothServer()) << "Start advertising" << m_serverName << m_localDevice->address().toString(); + m_controller->startAdvertising(advertisingParameters, advertisingData, advertisingData); + + // Start the advertising timer + setRunning(true); +} + +void BluetoothServer::stop() +{ + if (connected() && m_controller) { + m_controller->disconnectFromDevice(); + return; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "-------------------------------------"; + qCDebug(dcNetworkManagerBluetoothServer()) << "Stopping bluetooth server."; + qCDebug(dcNetworkManagerBluetoothServer()) << "-------------------------------------"; + + if (m_controller) { + qCDebug(dcNetworkManagerBluetoothServer()) << "Stop advertising."; + m_controller->stopAdvertising(); + delete m_controller; + m_controller = nullptr; + } + + if (m_localDevice) { + qCDebug(dcNetworkManagerBluetoothServer()) << "Set host mode to connectable."; + m_localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable); + delete m_localDevice; + m_localDevice = nullptr; + } + + setConnected(false); + setRunning(false); +} diff --git a/libnymea-networkmanager/bluetooth/bluetoothserver.h b/libnymea-networkmanager/bluetooth/bluetoothserver.h new file mode 100644 index 0000000..171ae1a --- /dev/null +++ b/libnymea-networkmanager/bluetooth/bluetoothserver.h @@ -0,0 +1,105 @@ +#ifndef BLUETOOTHSERVER_H +#define BLUETOOTHSERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "networkservice.h" +#include "wirelessservice.h" + +class NetworkManager; + +class BluetoothServer : public QObject +{ + Q_OBJECT +public: + explicit BluetoothServer(NetworkManager *networkManager); + ~BluetoothServer(); + + // Information for the device info service + QString modelName() const; + void setModelName(const QString &modelName); + + QString serverName() const; + void setServerName(const QString &serverName); + + QString softwareVersion() const; + void setSoftwareVersion(const QString &softwareVersion); + + QString hardwareVersion() const; + void setHardwareVersion(const QString &hardwareVersion); + + bool running() const; + bool connected() const; + +private: + QString m_modelName; + QString m_serverName; + QString m_softwareVersion; + QString m_hardwareVersion; + + NetworkManager *m_networkManager = nullptr; + QBluetoothLocalDevice *m_localDevice = nullptr; + QLowEnergyController *m_controller = nullptr; + + QLowEnergyService *m_deviceInfoService = nullptr; + QLowEnergyService *m_genericAccessService = nullptr; + QLowEnergyService *m_genericAttributeService = nullptr; + + NetworkService *m_networkService = nullptr; + WirelessService *m_wirelessService = nullptr; + + bool m_running = false; + bool m_connected = false; + + QLowEnergyServiceData deviceInformationServiceData(); + QLowEnergyServiceData genericAccessServiceData(); + QLowEnergyServiceData genericAttributeServiceData(); + + void setRunning(bool running); + void setConnected(bool connected); + +signals: + void runningChanged(const bool &running); + void connectedChanged(const bool &connected); + +private slots: + // Local bluetooth device + void onHostModeStateChanged(QBluetoothLocalDevice::HostMode mode); + void onDeviceConnected(const QBluetoothAddress &address); + void onDeviceDisconnected(const QBluetoothAddress &address); + void onError(QLowEnergyController::Error error); + + // Bluetooth controller + void onConnected(); + void onDisconnected(); + void onControllerStateChanged(QLowEnergyController::ControllerState state); + + // Services + void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void descriptorRead(const QLowEnergyDescriptor &descriptor, const QByteArray &value); + void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value); + void serviceError(QLowEnergyService::ServiceError error); + +public slots: + void start(); + void stop(); + +}; + +#endif // BLUETOOTHSERVER_H diff --git a/libnymea-networkmanager/bluetooth/bluetoothuuids.h b/libnymea-networkmanager/bluetooth/bluetoothuuids.h new file mode 100644 index 0000000..bdf420e --- /dev/null +++ b/libnymea-networkmanager/bluetooth/bluetoothuuids.h @@ -0,0 +1,35 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of loopd. * + * * + * Loopd can not be copied and/or distributed without the express * + * permission of guh GmbH. * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef BLUETOOTHUUIDS_H +#define BLUETOOTHUUIDS_H + +#include + +static QBluetoothUuid networkServiceUuid = QBluetoothUuid(QUuid("ef6d6610-b8af-49e0-9eca-ab343513641c")); +static QBluetoothUuid networkStatusCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6611-b8af-49e0-9eca-ab343513641c")); +static QBluetoothUuid networkCommanderCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6612-b8af-49e0-9eca-ab343513641c")); +static QBluetoothUuid networkResponseCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6613-b8af-49e0-9eca-ab343513641c")); +static QBluetoothUuid networkingEnabledCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6614-b8af-49e0-9eca-ab343513641c")); +static QBluetoothUuid wirelessEnabledCharacteristicUuid = QBluetoothUuid(QUuid("ef6d6615-b8af-49e0-9eca-ab343513641c")); + +static QBluetoothUuid wirelessServiceUuid = QBluetoothUuid(QUuid("e081fec0-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid wirelessCommanderCharacteristicUuid = QBluetoothUuid(QUuid("e081fec1-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid wirelessResponseCharacteristicUuid = QBluetoothUuid(QUuid("e081fec2-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid wirelessStateCharacteristicUuid = QBluetoothUuid(QUuid("e081fec3-f757-4449-b9c9-bfa83133f7fc")); + +static QBluetoothUuid systemServiceUuid = QBluetoothUuid(QUuid("e081fed0-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid systemCommanderCharacteristicUuid = QBluetoothUuid(QUuid("e081fed1-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid systemResponseCharacteristicUuid = QBluetoothUuid(QUuid("e081fed2-f757-4449-b9c9-bfa83133f7fc")); +static QBluetoothUuid systemUpdateCharacteristicUuid = QBluetoothUuid(QUuid("e081fed3-f757-4449-b9c9-bfa83133f7fc")); + + +#endif // BLUETOOTHUUIDS_H diff --git a/libnymea-networkmanager/bluetooth/networkservice.cpp b/libnymea-networkmanager/bluetooth/networkservice.cpp new file mode 100644 index 0000000..007aa41 --- /dev/null +++ b/libnymea-networkmanager/bluetooth/networkservice.cpp @@ -0,0 +1,325 @@ +#include "networkservice.h" +#include "bluetoothuuids.h" + +#include +#include + +NetworkService::NetworkService(QLowEnergyService *service, NetworkManager *networkManager, QObject *parent) : + QObject(parent), + m_service(service), + m_networkManager(networkManager) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Create NetworkService."; + + // Service + connect(m_service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicChanged(QLowEnergyCharacteristic, QByteArray))); + connect(m_service, SIGNAL(characteristicRead(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicChanged(QLowEnergyCharacteristic, QByteArray))); + connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicWritten(QLowEnergyCharacteristic, QByteArray))); + connect(m_service, SIGNAL(descriptorWritten(QLowEnergyDescriptor, QByteArray)), this, SLOT(descriptorWritten(QLowEnergyDescriptor, QByteArray))); + connect(m_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(serviceError(QLowEnergyService::ServiceError))); + + // NetworkManager + connect(Loopd::instance()->networkManager(), &NetworkManager::stateChanged, this, &NetworkService::onNetworkManagerStateChanged); + connect(Loopd::instance()->networkManager(), &NetworkManager::networkingEnabledChanged, this, &NetworkService::onNetworkingEnabledChanged); + connect(Loopd::instance()->networkManager(), &NetworkManager::wirelessEnabledChanged, this, &NetworkService::onWirelessEnabledChanged); +} + +QLowEnergyService *NetworkService::service() +{ + return m_service; +} + +QLowEnergyServiceData NetworkService::serviceData() +{ + QLowEnergyServiceData serviceData; + serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); + serviceData.setUuid(networkServiceUuid); + + QLowEnergyDescriptorData clientConfigDescriptorData(QBluetoothUuid::ClientCharacteristicConfiguration, QByteArray(2, 0)); + + // Network manager status ef6d661-b8af-49e0-9eca-ab343513641c + QLowEnergyCharacteristicData networkStatusData; + networkStatusData.setUuid(networkStatusCharacteristicUuid); + networkStatusData.setValue(QByteArray(1, 0)); + networkStatusData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify); + networkStatusData.addDescriptor(clientConfigDescriptorData); + networkStatusData.setValue(NetworkService::getNetworkManagerStateByteArray(Loopd::instance()->networkManager()->state())); + serviceData.addCharacteristic(networkStatusData); + + // Network manager commander ef6d6612-b8af-49e0-9eca-ab343513641c + QLowEnergyCharacteristicData networkCommanderCharacteristicData; + networkCommanderCharacteristicData.setUuid(networkCommanderCharacteristicUuid); + networkCommanderCharacteristicData.setProperties(QLowEnergyCharacteristic::Write); + networkCommanderCharacteristicData.setValueLength(1, 1); + serviceData.addCharacteristic(networkCommanderCharacteristicData); + + // Response characteristic ef6d6613-b8af-49e0-9eca-ab343513641c + QLowEnergyCharacteristicData networkResponseCharacteristicData; + networkResponseCharacteristicData.setUuid(networkResponseCharacteristicUuid); + networkResponseCharacteristicData.setProperties(QLowEnergyCharacteristic::Notify); + networkResponseCharacteristicData.addDescriptor(clientConfigDescriptorData); + networkResponseCharacteristicData.setValueLength(1, 1); + serviceData.addCharacteristic(networkResponseCharacteristicData); + + // Networking enabled ef6d6614-b8af-49e0-9eca-ab343513641c + QLowEnergyCharacteristicData networkingEnabledStatusData; + networkingEnabledStatusData.setUuid(networkingEnabledCharacteristicUuid); + networkingEnabledStatusData.setValue(QByteArray(1, 0)); + networkingEnabledStatusData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify); + networkingEnabledStatusData.setValue(QByteArray::number(static_cast(Loopd::instance()->networkManager()->networkingEnabled()))); + serviceData.addCharacteristic(networkingEnabledStatusData); + + // Wireless enabled ef6d6615-b8af-49e0-9eca-ab343513641c + QLowEnergyCharacteristicData wirelessEnabledStatusData; + wirelessEnabledStatusData.setUuid(wirelessEnabledCharacteristicUuid); + wirelessEnabledStatusData.setValue(QByteArray(1, 0)); + wirelessEnabledStatusData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify); + wirelessEnabledStatusData.setValue(QByteArray::number(static_cast(Loopd::instance()->networkManager()->wirelessEnabled()))); + serviceData.addCharacteristic(wirelessEnabledStatusData); + + return serviceData; +} + +QByteArray NetworkService::getNetworkManagerStateByteArray(const NetworkManager::NetworkManagerState &state) +{ + QByteArray networkManagerState; + switch (state) { + case NetworkManager::NetworkManagerStateUnknown: + networkManagerState = QByteArray::fromHex("00"); + break; + case NetworkManager::NetworkManagerStateAsleep: + networkManagerState = QByteArray::fromHex("01"); + break; + case NetworkManager::NetworkManagerStateDisconnected: + networkManagerState = QByteArray::fromHex("02"); + break; + case NetworkManager::NetworkManagerStateDisconnecting: + networkManagerState = QByteArray::fromHex("03"); + break; + case NetworkManager::NetworkManagerStateConnecting: + networkManagerState = QByteArray::fromHex("04"); + break; + case NetworkManager::NetworkManagerStateConnectedLocal: + networkManagerState = QByteArray::fromHex("05"); + break; + case NetworkManager::NetworkManagerStateConnectedSite: + networkManagerState = QByteArray::fromHex("06"); + break; + case NetworkManager::NetworkManagerStateConnectedGlobal: + networkManagerState = QByteArray::fromHex("07"); + break; + } + + return networkManagerState; +} + +void NetworkService::sendResponse(const NetworkService::NetworkServiceResponse &response) +{ + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not send response. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(networkResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not send response. Characteristic not valid"; + return; + } + + switch (response) { + case NetworkServiceResponseSuccess: + m_service->writeCharacteristic(characteristic, QByteArray::fromHex("00")); + break; + case NetworkServiceResponseIvalidValue: + m_service->writeCharacteristic(characteristic, QByteArray::fromHex("01")); + break; + case NetworkServiceResponseNetworkManagerNotAvailable: + m_service->writeCharacteristic(characteristic, QByteArray::fromHex("02")); + break; + case NetworkServiceResponseWirelessNotAvailable: + m_service->writeCharacteristic(characteristic, QByteArray::fromHex("03")); + break; + default: + // Unknown error + m_service->writeCharacteristic(characteristic, QByteArray::fromHex("04")); + break; + } +} + +NetworkService::NetworkServiceCommand NetworkService::verifyCommand(const QByteArray &commandData) +{ + if (commandData.length() != 1) + return NetworkServiceCommandInvalid; + + uint commandInteger = commandData.toHex().toUInt(nullptr, 16); + switch (commandInteger) { + case NetworkServiceCommandEnableNetworking: + return NetworkServiceCommandEnableNetworking; + case NetworkServiceCommandDisableNetworking: + return NetworkServiceCommandDisableNetworking; + case NetworkServiceCommandEnableWireless: + return NetworkServiceCommandEnableWireless; + case NetworkServiceCommandDisableWireless: + return NetworkServiceCommandDisableWireless; + default: + break; + } + + return NetworkServiceCommandInvalid; +} + +void NetworkService::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + if (characteristic.uuid() == networkCommanderCharacteristicUuid) { + + NetworkServiceCommand command = verifyCommand(value); + if (command == NetworkServiceCommandInvalid) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: received invalid command" << command; + sendResponse(NetworkServiceResponseIvalidValue); + return; + } + + if (!Loopd::instance()->networkManager()->available()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Networkmanager not available"; + sendResponse(NetworkServiceResponseNetworkManagerNotAvailable); + return; + } + + processCommand(command); + + sendResponse(NetworkServiceResponseSuccess); + return; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Characteristic changed" << characteristic.uuid().toString() << value; +} + +void NetworkService::characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Characteristic read" << characteristic.uuid().toString() << value; +} + +void NetworkService::characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Characteristic written" << characteristic.uuid().toString() << value; +} + +void NetworkService::descriptorRead(const QLowEnergyDescriptor &descriptor, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Descriptor read" << descriptor.uuid().toString() << value; +} + +void NetworkService::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Descriptor written" << descriptor.uuid().toString() << value; +} + +void NetworkService::serviceError(const QLowEnergyService::ServiceError &error) +{ + QString errorString; + switch (error) { + case QLowEnergyService::NoError: + errorString = "No error"; + break; + case QLowEnergyService::OperationError: + errorString = "Operation error"; + break; + case QLowEnergyService::CharacteristicReadError: + errorString = "Characteristic read error"; + break; + case QLowEnergyService::CharacteristicWriteError: + errorString = "Characteristic write error"; + break; + case QLowEnergyService::DescriptorReadError: + errorString = "Descriptor read error"; + break; + case QLowEnergyService::DescriptorWriteError: + errorString = "Descriptor write error"; + break; + case QLowEnergyService::UnknownError: + errorString = "Unknown error"; + break; + } + + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Error:" << errorString; +} + +void NetworkService::processCommand(const NetworkServiceCommand &command) +{ + switch (command) { + case NetworkServiceCommandEnableNetworking: + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: received \"Enable networking\" command"; + Loopd::instance()->networkManager()->enableNetworking(true); + break; + case NetworkServiceCommandDisableNetworking: + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: received \"Disable networking\" command"; + Loopd::instance()->networkManager()->enableNetworking(false); + break; + case NetworkServiceCommandEnableWireless: + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: received \"Enable wireless networking\" command"; + Loopd::instance()->networkManager()->enableWireless(true); + break; + case NetworkServiceCommandDisableWireless: + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: received \"Disable wireless networking\" command"; + Loopd::instance()->networkManager()->enableWireless(false); + break; + default: + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Unhandled command" << command; + sendResponse(NetworkServiceResponseIvalidValue); + break; + } +} + +bool NetworkService::onNetworkManagerStateChanged() +{ + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not updatet network manager status. Service not valid"; + return false; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(networkStatusCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not update network manager status. Characteristic not valid"; + return false; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Notify state changed" << NetworkService::getNetworkManagerStateByteArray(Loopd::instance()->networkManager()->state()); + m_service->writeCharacteristic(characteristic, NetworkService::getNetworkManagerStateByteArray(Loopd::instance()->networkManager()->state())); + return true; +} + +bool NetworkService::onNetworkingEnabledChanged() +{ + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not set networking enabled. Service not valid"; + return false; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(networkingEnabledCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not set networking enabled. Characteristic not valid"; + return false; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Notify networking enabled changed:" << (Loopd::instance()->networkManager()->networkingEnabled() ? "enabled" : "disabled"); + m_service->writeCharacteristic(characteristic, Loopd::instance()->networkManager()->networkingEnabled() ? QByteArray::fromHex("01") : QByteArray::fromHex("00")); + return true; +} + +bool NetworkService::onWirelessEnabledChanged() +{ + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not set wireless enabled. Service not valid"; + return false; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessEnabledCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "NetworkService: Could not set wireless enabled. Characteristic not valid"; + return false; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "NetworkService: Notify wireless networking enabled changed:" << (Loopd::instance()->networkManager()->wirelessEnabled() ? "enabled" : "disabled"); + m_service->writeCharacteristic(characteristic, Loopd::instance()->networkManager()->wirelessEnabled() ? QByteArray::fromHex("01") : QByteArray::fromHex("00")); + return true; +} diff --git a/libnymea-networkmanager/bluetooth/networkservice.h b/libnymea-networkmanager/bluetooth/networkservice.h new file mode 100644 index 0000000..c9059d8 --- /dev/null +++ b/libnymea-networkmanager/bluetooth/networkservice.h @@ -0,0 +1,78 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of loopd. * + * * + * Loopd can not be copied and/or distributed without the express * + * permission of guh GmbH. * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef NETWORKSERVICE_H +#define NETWORKSERVICE_H + +#include +#include +#include + +#include "../networkmanager.h" + +class NetworkService : public QObject +{ + Q_OBJECT + +public: + enum NetworkServiceCommand { + NetworkServiceCommandInvalid = -1, + NetworkServiceCommandEnableNetworking = 0x00, + NetworkServiceCommandDisableNetworking = 0x01, + NetworkServiceCommandEnableWireless = 0x02, + NetworkServiceCommandDisableWireless = 0x03 + }; + Q_ENUM(NetworkServiceCommand) + + enum NetworkServiceResponse { + NetworkServiceResponseSuccess = 0x00, + NetworkServiceResponseIvalidValue = 0x01, + NetworkServiceResponseNetworkManagerNotAvailable = 0x02, + NetworkServiceResponseWirelessNotAvailable = 0x03, + NetworkServiceResponseUnknownError = 0x04, + }; + Q_ENUM(NetworkServiceResponse) + + explicit NetworkService(QLowEnergyService *service, NetworkManager *networkManager, QObject *parent = nullptr); + + QLowEnergyService *service(); + + static QLowEnergyServiceData serviceData(); + static QByteArray getNetworkManagerStateByteArray(const NetworkManager::NetworkManagerState &state); + +private: + QLowEnergyService *m_service = nullptr; + NetworkManager *m_networkManager = nullptr; + + void sendResponse(const NetworkServiceResponse &response); + + NetworkServiceCommand verifyCommand(const QByteArray &commandData); + +private slots: + // Service + void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void descriptorRead(const QLowEnergyDescriptor &descriptor, const QByteArray &value); + void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value); + void serviceError(const QLowEnergyService::ServiceError &error); + + // Commands + void processCommand(const NetworkServiceCommand &command); + +public slots: + bool onNetworkManagerStateChanged(); + bool onNetworkingEnabledChanged(); + bool onWirelessEnabledChanged(); + +}; + +#endif // NETWORKSERVICE_H diff --git a/libnymea-networkmanager/bluetooth/wirelessservice.cpp b/libnymea-networkmanager/bluetooth/wirelessservice.cpp new file mode 100644 index 0000000..1e3a7b3 --- /dev/null +++ b/libnymea-networkmanager/bluetooth/wirelessservice.cpp @@ -0,0 +1,508 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of loopd. * + * * + * Loopd can not be copied and/or distributed without the express * + * permission of guh GmbH. * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "wirelessservice.h" +#include "bluetoothuuids.h" +#include "loggingcategory.h" +#include "loopd.h" + +#include +#include +#include +#include + +WirelessService::WirelessService(QLowEnergyService *service, QObject *parent) : + QObject(parent), + m_service(service), + m_device(nullptr), + m_readingInputData(false) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "Create WirelessService."; + + // Service + connect(m_service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicChanged(QLowEnergyCharacteristic, QByteArray))); + connect(m_service, SIGNAL(characteristicRead(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicChanged(QLowEnergyCharacteristic, QByteArray))); + connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic, QByteArray)), this, SLOT(characteristicWritten(QLowEnergyCharacteristic, QByteArray))); + connect(m_service, SIGNAL(descriptorWritten(QLowEnergyDescriptor, QByteArray)), this, SLOT(descriptorWritten(QLowEnergyDescriptor, QByteArray))); + connect(m_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(serviceError(QLowEnergyService::ServiceError))); + + // Get the wireless network device if there is any + if (!Loopd::instance()->networkManager()->wirelessAvailable()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: There is no wireless network device available"; + return; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Using" << Loopd::instance()->networkManager()->wirelessNetworkDevices().first(); + m_device = Loopd::instance()->networkManager()->wirelessNetworkDevices().first(); + connect(m_device, &WirelessNetworkDevice::bitRateChanged, this, &WirelessService::onWirelessDeviceBitRateChanged); + connect(m_device, &WirelessNetworkDevice::stateChanged, this, &WirelessService::onWirelessDeviceStateChanged); +} + +QLowEnergyService *WirelessService::service() +{ + return m_service; +} + +QLowEnergyServiceData WirelessService::serviceData() +{ + QLowEnergyServiceData serviceData; + serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); + serviceData.setUuid(wirelessServiceUuid); + + QLowEnergyDescriptorData clientConfigDescriptorData(QBluetoothUuid::ClientCharacteristicConfiguration, QByteArray(2, 0)); + + // Wifi commander characterisitc e081fec1-f757-4449-b9c9-bfa83133f7fc + QLowEnergyCharacteristicData wirelessCommanderCharacteristicData; + wirelessCommanderCharacteristicData.setUuid(wirelessCommanderCharacteristicUuid); + wirelessCommanderCharacteristicData.setProperties(QLowEnergyCharacteristic::Write); + wirelessCommanderCharacteristicData.setValueLength(0, 20); + serviceData.addCharacteristic(wirelessCommanderCharacteristicData); + + // Response characterisitc e081fec2-f757-4449-b9c9-bfa83133f7fc + QLowEnergyCharacteristicData wirelessResponseCharacteristicData; + wirelessResponseCharacteristicData.setUuid(wirelessResponseCharacteristicUuid); + wirelessResponseCharacteristicData.setProperties(QLowEnergyCharacteristic::Notify); + wirelessResponseCharacteristicData.addDescriptor(clientConfigDescriptorData); + wirelessResponseCharacteristicData.setValueLength(0, 20); + serviceData.addCharacteristic(wirelessResponseCharacteristicData); + + // Wireless connection status characterisitc e081fec3-f757-4449-b9c9-bfa83133f7fc + QLowEnergyCharacteristicData wirelessStatusCharacteristicData; + wirelessStatusCharacteristicData.setUuid(wirelessStateCharacteristicUuid); + wirelessStatusCharacteristicData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify); + wirelessStatusCharacteristicData.addDescriptor(clientConfigDescriptorData); + wirelessStatusCharacteristicData.setValueLength(1, 1); + if (!Loopd::instance()->networkManager()->wirelessAvailable()) { + wirelessStatusCharacteristicData.setValue(WirelessService::getWirelessNetworkDeviceState(NetworkDevice::NetworkDeviceStateUnavailable)); + } else { + wirelessStatusCharacteristicData.setValue(WirelessService::getWirelessNetworkDeviceState(Loopd::instance()->networkManager()->wirelessNetworkDevices().first()->deviceState())); + } + serviceData.addCharacteristic(wirelessStatusCharacteristicData); + + return serviceData; +} + + +WirelessService::WirelessServiceResponse WirelessService::checkWirelessErrors() +{ + // Check possible errors + if (!Loopd::instance()->networkManager()->available()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: The networkmanager is not available."; + return WirelessServiceResponseNetworkManagerNotAvailable; + } + + if (!m_device) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: There is no wireless device available."; + return WirelessServiceResponseWirelessNotAvailable; + } + + if (!Loopd::instance()->networkManager()->networkingEnabled()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Networking not enabled"; + return WirelessServiceResponseNetworkingNotEnabled; + } + + if (!Loopd::instance()->networkManager()->wirelessEnabled()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless not enabled"; + return WirelessServiceResponseWirelessNotEnabled; + } + + return WirelessServiceResponseSuccess; +} + +QByteArray WirelessService::getWirelessNetworkDeviceState(const NetworkDevice::NetworkDeviceState &state) +{ + switch (state) { + case NetworkDevice::NetworkDeviceStateUnknown: + return QByteArray::fromHex("00"); + case NetworkDevice::NetworkDeviceStateUnmanaged: + return QByteArray::fromHex("01"); + case NetworkDevice::NetworkDeviceStateUnavailable: + return QByteArray::fromHex("02"); + case NetworkDevice::NetworkDeviceStateDisconnected: + return QByteArray::fromHex("03"); + case NetworkDevice::NetworkDeviceStatePrepare: + return QByteArray::fromHex("04"); + case NetworkDevice::NetworkDeviceStateConfig: + return QByteArray::fromHex("05"); + case NetworkDevice::NetworkDeviceStateNeedAuth: + return QByteArray::fromHex("06"); + case NetworkDevice::NetworkDeviceStateIpConfig: + return QByteArray::fromHex("07"); + case NetworkDevice::NetworkDeviceStateIpCheck: + return QByteArray::fromHex("08"); + case NetworkDevice::NetworkDeviceStateSecondaries: + return QByteArray::fromHex("09"); + case NetworkDevice::NetworkDeviceStateActivated: + return QByteArray::fromHex("0a"); + case NetworkDevice::NetworkDeviceStateDeactivating: + return QByteArray::fromHex("0b"); + case NetworkDevice::NetworkDeviceStateFailed: + return QByteArray::fromHex("0c"); + } + + // Unknown + return QByteArray::fromHex("00"); +} + + +void WirelessService::streamData(const QVariantMap &responseMap) +{ + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless response characteristic not valid"; + return; + } + + QByteArray data = QJsonDocument::fromVariant(responseMap).toJson(QJsonDocument::Compact) + '\n'; + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Start streaming response data:" << data.count() << "bytes"; + + int sentDataLength = 0; + QByteArray remainingData = data; + while (!remainingData.isEmpty()) { + QByteArray package = remainingData.left(20); + sentDataLength += package.count(); + m_service->writeCharacteristic(characteristic, package); + remainingData = remainingData.remove(0, package.count()); + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Finished streaming response data"; +} + +QVariantMap WirelessService::createResponse(const WirelessService::WirelessServiceCommand &command, const WirelessService::WirelessServiceResponse &responseCode) +{ + QVariantMap response; + response.insert("c", static_cast(command)); + response.insert("r", static_cast(responseCode)); + return response; +} + +void WirelessService::commandGetNetworks(const QVariantMap &request) +{ + Q_UNUSED(request) + + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless response characteristic not valid"; + return; + } + + QVariantList accessPointVariantList; + foreach (WirelessAccessPoint *accessPoint, m_device->accessPoints()) { + QVariantMap accessPointVariantMap; + accessPointVariantMap.insert("e", accessPoint->ssid()); + accessPointVariantMap.insert("m", accessPoint->macAddress()); + accessPointVariantMap.insert("s", accessPoint->signalStrength()); + accessPointVariantMap.insert("p", static_cast(accessPoint->isProtected())); + accessPointVariantList.append(accessPointVariantMap); + } + + QVariantMap response = createResponse(WirelessServiceCommandGetNetworks); + response.insert("p", accessPointVariantList); + + streamData(response); +} + +void WirelessService::commandConnect(const QVariantMap &request) +{ + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless response characteristic not valid"; + return; + } + + if (!request.contains("p")) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Connect command: Missing parameters."; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidParameters)); + return; + } + + QVariantMap parameters = request.value("p").toMap(); + if (!parameters.contains("e") || !parameters.contains("p")) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Connect command: Invalid parameters."; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidParameters)); + return; + } + + NetworkManager::NetworkManagerError networkError = Loopd::instance()->networkManager()->connectWifi(m_device->interface(), parameters.value("e").toString(), parameters.value("p").toString()); + WirelessService::WirelessServiceResponse responseCode = WirelessService::WirelessServiceResponseSuccess; + switch (networkError) { + case NetworkManager::NetworkManagerErrorNoError: + break; + case NetworkManager::NetworkManagerErrorWirelessNetworkingDisabled: + responseCode = WirelessService::WirelessServiceResponseWirelessNotEnabled; + break; + case NetworkManager::NetworkManagerErrorWirelessConnectionFailed: + responseCode = WirelessService::WirelessServiceResponseUnknownError; + break; + default: + responseCode = WirelessService::WirelessServiceResponseUnknownError; + break; + } + streamData(createResponse(WirelessServiceCommandConnect, responseCode)); +} + +void WirelessService::commandConnectHidden(const QVariantMap &request) +{ + Q_UNUSED(request) + // TODO: + qCWarning(dcNetworkManagerBluetoothServer()) << "Connect to hidden network is not implemented yet."; +} + +void WirelessService::commandDisconnect(const QVariantMap &request) +{ + Q_UNUSED(request) + + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless response characteristic not valid"; + return; + } + + m_device->disconnectDevice(); + streamData(createResponse(WirelessServiceCommandDisconnect)); +} + +void WirelessService::commandScan(const QVariantMap &request) +{ + Q_UNUSED(request) + + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless response characteristic not valid"; + return; + } + + m_device->scanWirelessNetworks(); + streamData(createResponse(WirelessServiceCommandScan)); +} + +void WirelessService::commandGetCurrentConnection(const QVariantMap &request) +{ + Q_UNUSED(request) + + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not stream wireless network list. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessResponseCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless response characteristic not valid"; + return; + } + + QVariantMap connectionDataMap; + QNetworkInterface wifiInterface = QNetworkInterface::interfaceFromName(m_device->interface()); + if (!m_device->activeAccessPoint() || !wifiInterface.isValid() || wifiInterface.addressEntries().isEmpty()) { + qCDebug(dcNetworkManagerBluetoothServer()) << "There is currently no access active accesspoint"; + connectionDataMap.insert("e", ""); + connectionDataMap.insert("m", ""); + connectionDataMap.insert("s", 0); + connectionDataMap.insert("p", 0); + connectionDataMap.insert("i", ""); + } else { + QHostAddress address = wifiInterface.addressEntries().first().ip(); + qCDebug(dcNetworkManagerBluetoothServer()) << "Current connection:" << m_device->activeAccessPoint() << address.toString(); + connectionDataMap.insert("e", m_device->activeAccessPoint()->ssid()); + connectionDataMap.insert("m", m_device->activeAccessPoint()->macAddress()); + connectionDataMap.insert("s", m_device->activeAccessPoint()->signalStrength()); + connectionDataMap.insert("p", static_cast(m_device->activeAccessPoint()->isProtected())); + connectionDataMap.insert("i", address.toString()); + } + + QVariantMap response = createResponse(WirelessServiceCommandGetCurrentConnection); + response.insert("p", connectionDataMap); + streamData(response); +} + +void WirelessService::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + // Command + if (characteristic.uuid() == wirelessCommanderCharacteristicUuid) { + // Check if currently reading + if (m_readingInputData) { + m_inputDataStream.append(value); + } else { + m_inputDataStream.clear(); + m_readingInputData = true; + m_inputDataStream.append(value); + } + + // If command finished + if (value.endsWith('\n')) { + QJsonParseError error; + QJsonDocument jsonDocument = QJsonDocument::fromJson(m_inputDataStream, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcNetworkManagerBluetoothServer()) << "Got invalid json object" << m_inputDataStream; + m_inputDataStream.clear(); + m_readingInputData = false; + return; + } + + qCDebug(dcNetworkManagerBluetoothServer()) << "Got command stream" << jsonDocument.toJson(); + + processCommand(jsonDocument.toVariant().toMap()); + + m_inputDataStream.clear(); + m_readingInputData = false; + } + + // Limit possible data stream to prevent overflow + if (m_inputDataStream.length() >= 20 * 1024) { + m_inputDataStream.clear(); + m_readingInputData = false; + return; + } + } +} + +void WirelessService::characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Characteristic read" << characteristic.uuid().toString() << value; +} + +void WirelessService::characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Characteristic written" << characteristic.uuid().toString() << value; +} + +void WirelessService::descriptorRead(const QLowEnergyDescriptor &descriptor, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Descriptor read" << descriptor.uuid().toString() << value; +} + +void WirelessService::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Descriptor written" << descriptor.uuid().toString() << value; +} + +void WirelessService::serviceError(const QLowEnergyService::ServiceError &error) +{ + QString errorString; + switch (error) { + case QLowEnergyService::NoError: + errorString = "No error"; + break; + case QLowEnergyService::OperationError: + errorString = "Operation error"; + break; + case QLowEnergyService::CharacteristicReadError: + errorString = "Characteristic read error"; + break; + case QLowEnergyService::CharacteristicWriteError: + errorString = "Characteristic write error"; + break; + case QLowEnergyService::DescriptorReadError: + errorString = "Descriptor read error"; + break; + case QLowEnergyService::DescriptorWriteError: + errorString = "Descriptor write error"; + break; + case QLowEnergyService::UnknownError: + errorString = "Unknown error"; + break; + } + + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Error:" << errorString; +} + +void WirelessService::processCommand(const QVariantMap &request) +{ + if (!request.contains("c")) { + qCWarning(dcNetworkManagerBluetoothServer()) << "Invalid request. Command value missing."; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidCommand)); + return; + } + + bool commandIntOk; + int command = request.value("c").toInt(&commandIntOk); + if (!commandIntOk) { + qCWarning(dcNetworkManagerBluetoothServer()) << "Invalid request. Could not convert method to interger."; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidCommand)); + return; + } + + // Check wireless errors + WirelessServiceResponse responseCode = checkWirelessErrors(); + if (responseCode != WirelessServiceResponseSuccess) { + streamData(createResponse(static_cast(command), responseCode)); + return; + } + + // Process method + switch (command) { + case WirelessServiceCommandGetNetworks: + commandGetNetworks(request); + break; + case WirelessServiceCommandConnect: + commandConnect(request); + break; + case WirelessServiceCommandConnectHidden: + commandConnectHidden(request); + break; + case WirelessServiceCommandDisconnect: + commandDisconnect(request); + break; + case WirelessServiceCommandScan: + commandScan(request); + break; + case WirelessServiceCommandGetCurrentConnection: + commandGetCurrentConnection(request); + break; + default: + qCWarning(dcNetworkManagerBluetoothServer()) << "Invalid request. Unknown command" << command; + streamData(createResponse(WirelessServiceCommandConnect, WirelessServiceResponseIvalidCommand)); + break; + } +} + +void WirelessService::onWirelessDeviceBitRateChanged(const int &bitRate) +{ + Q_UNUSED(bitRate) +} + +void WirelessService::onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState &state) +{ + qCDebug(dcNetworkManagerBluetoothServer()) << "WirelessService: Wireless network device state changed" << state; + + if (!m_service) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not update wireless network device state. Service not valid"; + return; + } + + QLowEnergyCharacteristic characteristic = m_service->characteristic(wirelessStateCharacteristicUuid); + if (!characteristic.isValid()) { + qCWarning(dcNetworkManagerBluetoothServer()) << "WirelessService: Could not update wireless network device state. Characteristic not valid"; + return; + } + + m_service->writeCharacteristic(characteristic, WirelessService::getWirelessNetworkDeviceState(state)); +} diff --git a/libnymea-networkmanager/bluetooth/wirelessservice.h b/libnymea-networkmanager/bluetooth/wirelessservice.h new file mode 100644 index 0000000..92c641f --- /dev/null +++ b/libnymea-networkmanager/bluetooth/wirelessservice.h @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2016 Simon Stürz * + * * + * This file is part of loopd. * + * * + * Loopd can not be copied and/or distributed without the express * + * permission of guh GmbH. * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef WIRELESSSERVICE_H +#define WIRELESSSERVICE_H + +#include +#include +#include +#include + +#include "../networkmanager.h" +#include "../wirelessaccesspoint.h" +#include "../wirelessnetworkdevice.h" + +class WirelessService : public QObject +{ + Q_OBJECT + +public: + enum WirelessServiceCommand { + WirelessServiceCommandInvalid = -1, + WirelessServiceCommandGetNetworks = 0x00, + WirelessServiceCommandConnect = 0x01, + WirelessServiceCommandConnectHidden = 0x02, + WirelessServiceCommandDisconnect = 0x03, + WirelessServiceCommandScan = 0x04, + WirelessServiceCommandGetCurrentConnection = 0x05 + }; + Q_ENUM(WirelessServiceCommand) + + enum WirelessServiceResponse { + WirelessServiceResponseSuccess = 0x00, + WirelessServiceResponseIvalidCommand = 0x01, + WirelessServiceResponseIvalidParameters = 0x02, + WirelessServiceResponseNetworkManagerNotAvailable = 0x03, + WirelessServiceResponseWirelessNotAvailable = 0x04, + WirelessServiceResponseWirelessNotEnabled = 0x05, + WirelessServiceResponseNetworkingNotEnabled = 0x06, + WirelessServiceResponseUnknownError = 0x07 + }; + Q_ENUM(WirelessServiceResponse) + + explicit WirelessService(QLowEnergyService *service, NetworkManager *networkManager, QObject *parent = nullptr); + QLowEnergyService *service(); + + static QLowEnergyServiceData serviceData(); + +private: + QLowEnergyService *m_service = nullptr; + NetworkManager *m_networkManager = nullptr; + WirelessNetworkDevice *m_device = nullptr; + + bool m_readingInputData; + QByteArray m_inputDataStream; + + WirelessServiceResponse checkWirelessErrors(); + + // Note: static to be available in serviceData + static QByteArray getWirelessNetworkDeviceState(const NetworkDevice::NetworkDeviceState &state); + + void streamData(const QVariantMap &responseMap); + + QVariantMap createResponse(const WirelessServiceCommand &command, const WirelessServiceResponse &responseCode = WirelessServiceResponseSuccess); + + // Methods + void commandGetNetworks(const QVariantMap &request); + void commandConnect(const QVariantMap &request); + void commandConnectHidden(const QVariantMap &request); + void commandDisconnect(const QVariantMap &request); + void commandScan(const QVariantMap &request); + void commandGetCurrentConnection(const QVariantMap &request); + + +private slots: + // Service + void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &value); + void descriptorRead(const QLowEnergyDescriptor &descriptor, const QByteArray &value); + void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &value); + void serviceError(const QLowEnergyService::ServiceError &error); + + // Commands + void processCommand(const QVariantMap &request); + + // Wireless network device + void onWirelessDeviceBitRateChanged(const int &bitRate); + void onWirelessDeviceStateChanged(const NetworkDevice::NetworkDeviceState &state); +}; + +#endif // WIRELESSSERVICE_H diff --git a/libnymea-networkmanager/libnymea-networkmanager.pro b/libnymea-networkmanager/libnymea-networkmanager.pro index fc24c88..bda3742 100644 --- a/libnymea-networkmanager/libnymea-networkmanager.pro +++ b/libnymea-networkmanager/libnymea-networkmanager.pro @@ -6,7 +6,13 @@ QT += dbus network QMAKE_CXXFLAGS *= -Werror -std=c++11 -g QMAKE_LFLAGS *= -std=c++11 +DEFINES += VERSION_STRING=\\\"$${VERSION_STRING}\\\" + HEADERS += \ + bluetooth/bluetoothserver.h \ + bluetooth/bluetoothuuids.h \ + bluetooth/networkservice.h \ + bluetooth/wirelessservice.h \ networkmanager.h \ networkconnection.h \ networkdevice.h \ @@ -17,6 +23,8 @@ HEADERS += \ networkmanagerutils.h \ SOURCES += \ + bluetooth/networkservice.cpp \ + bluetooth/wirelessservice.cpp \ networkmanager.cpp \ networkconnection.cpp \ networkdevice.cpp \ @@ -26,6 +34,20 @@ SOURCES += \ wirelessnetworkdevice.cpp \ networkmanagerutils.cpp \ +equals(QT_MAJOR_VERSION, 5):!lessThan(QT_MINOR_VERSION, 7) { + message(Building with Bluetooth LE server functionality. Qt $${QT_VERSION}.) + + QT += bluetooth + HEADERS += \ + bluetooth/bluetoothserver.h + + SOURCES += \ + bluetooth/bluetoothserver.cpp + + +} else { + message(Bluetooth LE server functionality not supported with Qt $${QT_VERSION}.) +} target.path = $$[QT_INSTALL_LIBS] INSTALLS += target diff --git a/libnymea-networkmanager/networkmanagerutils.cpp b/libnymea-networkmanager/networkmanagerutils.cpp index b3afbae..a1857f8 100644 --- a/libnymea-networkmanager/networkmanagerutils.cpp +++ b/libnymea-networkmanager/networkmanagerutils.cpp @@ -22,6 +22,7 @@ #include "networkmanagerutils.h" Q_LOGGING_CATEGORY(dcNetworkManager, "NetworkManager") +Q_LOGGING_CATEGORY(dcNetworkManagerBluetoothServer, "NetworkManagerBluetoothServer") QString NetworkManagerUtils::NetworkManagerUtils::networkManagerServiceString() { diff --git a/libnymea-networkmanager/networkmanagerutils.h b/libnymea-networkmanager/networkmanagerutils.h index cb9a269..742afe9 100644 --- a/libnymea-networkmanager/networkmanagerutils.h +++ b/libnymea-networkmanager/networkmanagerutils.h @@ -28,6 +28,7 @@ #include Q_DECLARE_LOGGING_CATEGORY(dcNetworkManager) +Q_DECLARE_LOGGING_CATEGORY(dcNetworkManagerBluetoothServer) class NetworkManagerUtils { diff --git a/source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc b/source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc new file mode 100644 index 0000000..bca24ea --- /dev/null +++ b/source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc @@ -0,0 +1,18 @@ +Format: 3.0 (native) +Source: libnymea-networkmanager +Binary: libnymea-networkmanager, libnymea-networkmanager-dev, libnymea-networkmanager-dbg +Architecture: any +Version: 0.1.1+201909161052~f3057c8~bionic +Maintainer: Simon Stürz +Standards-Version: 3.9.7 +Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), qt5-default, qt5-qmake, qtbase5-dev, qtbase5-dev-tools +Package-List: + libnymea-networkmanager deb libs optional arch=any + libnymea-networkmanager-dbg deb debug extra arch=any + libnymea-networkmanager-dev deb libdevel optional arch=any +Checksums-Sha1: + 8cab839f42a6ec82a5405acddea70944435ebf37 26500 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz +Checksums-Sha256: + 5d1e9c7c1fcda6a69f199f38ed88cd7ea00f4e7627221714eb21b9e1246c5ef2 26500 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz +Files: + 02d2440567e8237df586c74c7311f355 26500 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz diff --git a/source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz b/source_repository/libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..e3b7fca808fe3bcd24453e4685c51e1f0c4cca87 GIT binary patch literal 26500 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 +Changed-By: +Description: + libnymea-networkmanager - Qt 5 based library for the network-manager DBus API. + libnymea-networkmanager-dbg - Qt 5 based library for the network-manager DBus API - debug symbo + libnymea-networkmanager-dev - Qt 5 based library for the network-manager DBus API - development +Changes: + libnymea-networkmanager (0.1.1+201909161052~f3057c8~bionic) UNRELEASED; urgency=medium + . + [ Simon Stürz ] + * Add access point functionality + . + [ ] + * New Package build +Checksums-Sha1: + d74bad8dc14b32173399a686e602ad18c124dd0e 969 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc + 8cab839f42a6ec82a5405acddea70944435ebf37 26500 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz + f20b18d8c4ad3c0e4660362e762b9bf3dfd92ac4 11096 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic_source.buildinfo +Checksums-Sha256: + 14eb24a6fd3ed94cf455302225a2134aeed86f7b8d0510ff4314c4b2ba25bec0 969 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc + 5d1e9c7c1fcda6a69f199f38ed88cd7ea00f4e7627221714eb21b9e1246c5ef2 26500 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz + 281438bbb3b6223a052a80bd6eb0f023c26d9833005ce8377220ac2730d8ca23 11096 libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic_source.buildinfo +Files: + a15c2aa2ce6dc6c1b57040bdeffad63c 969 utils optional libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.dsc + 02d2440567e8237df586c74c7311f355 26500 utils optional libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic.tar.xz + 90aa93b290a36293c29fe32f881bc1b5 11096 utils optional libnymea-networkmanager_0.1.1+201909161052~f3057c8~bionic_source.buildinfo diff --git a/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc b/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc new file mode 100644 index 0000000..2acca19 --- /dev/null +++ b/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc @@ -0,0 +1,18 @@ +Format: 3.0 (native) +Source: libnymea-networkmanager +Binary: libnymea-networkmanager, libnymea-networkmanager-dev, libnymea-networkmanager-dbg +Architecture: any +Version: 0.1.1+201909161457~82b7888~bionic +Maintainer: Simon Stürz +Standards-Version: 3.9.7 +Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), qt5-default, qt5-qmake, qtbase5-dev, qtbase5-dev-tools, libqt5bluetooth5, qtconnectivity5-dev +Package-List: + libnymea-networkmanager deb libs optional arch=any + libnymea-networkmanager-dbg deb debug extra arch=any + libnymea-networkmanager-dev deb libdevel optional arch=any +Checksums-Sha1: + c0d13d4cdc79a458f87e244b671b9627771fc3ab 61216 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz +Checksums-Sha256: + 1f2c876626374e7668356e923fb55d9556f8c4cd8dc453303a0209ecc49e9d26 61216 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz +Files: + 41f55bb02977cea3ce3b89aeac7f5e21 61216 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz diff --git a/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz b/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..e610cf1b3a93ae9fe99124838dd9bc7fe910e79d GIT binary patch literal 61216 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%0AN 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 literal 0 HcmV?d00001 diff --git a/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.changes b/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.changes new file mode 100644 index 0000000..e48bdd3 --- /dev/null +++ b/source_repository/libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.changes @@ -0,0 +1,35 @@ +Format: 1.8 +Date: Mon, 16 Sep 2019 14:57:12 +0000 +Source: libnymea-networkmanager +Binary: libnymea-networkmanager libnymea-networkmanager-dev libnymea-networkmanager-dbg +Built-For-Profiles: nocheck nodoc noautodbgsym +Architecture: source +Version: 0.1.1+201909161457~82b7888~bionic +Distribution: UNRELEASED +Urgency: medium +Maintainer: Simon Stürz +Changed-By: +Description: + libnymea-networkmanager - Qt 5 based library for the network-manager DBus API. + libnymea-networkmanager-dbg - Qt 5 based library for the network-manager DBus API - debug symbo + libnymea-networkmanager-dev - Qt 5 based library for the network-manager DBus API - development +Changes: + libnymea-networkmanager (0.1.1+201909161457~82b7888~bionic) UNRELEASED; urgency=medium + . + [ Simon Stürz ] + * Add access point functionality + . + [ ] + * New Package build +Checksums-Sha1: + dfc0cf09520bbfca80ba2eca080d7704435c3775 1008 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc + c0d13d4cdc79a458f87e244b671b9627771fc3ab 61216 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz + d74e94fe208e660240ff027677dcb6112fca28ed 11139 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.buildinfo +Checksums-Sha256: + d968e6c3f9ac8765d807c589865383abd7eb6f9fdc1ad185943d7bf232e185ce 1008 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc + 1f2c876626374e7668356e923fb55d9556f8c4cd8dc453303a0209ecc49e9d26 61216 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz + 07126ba04d2b59ea4d8e901b67e76d9800163fe590cc5e8062a5c0ae120333f7 11139 libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.buildinfo +Files: + 0d506d71a468001c0f0bdc531909023b 1008 utils optional libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.dsc + 41f55bb02977cea3ce3b89aeac7f5e21 61216 utils optional libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic.tar.xz + 83582b2ab099ae8940f99411b3a34067 11139 utils optional libnymea-networkmanager_0.1.1+201909161457~82b7888~bionic_source.buildinfo