From 2231fd8f94804bcfd5bf3fefd282cb42a5f2ff79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 5 Jul 2018 11:05:38 +0200 Subject: [PATCH] Update bluetooth server --- libnymea-core/bluetoothserver.cpp | 122 ++++++++++++++++++------------ libnymea-core/bluetoothserver.h | 11 ++- 2 files changed, 84 insertions(+), 49 deletions(-) diff --git a/libnymea-core/bluetoothserver.cpp b/libnymea-core/bluetoothserver.cpp index ff509a8b..a904c43f 100644 --- a/libnymea-core/bluetoothserver.cpp +++ b/libnymea-core/bluetoothserver.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2016 Simon Stürz * + * Copyright (C) 2016-2018 Simon Stürz * * * * This file is part of nymea. * * * @@ -38,15 +38,14 @@ #include "loggingcategories.h" #include -#include namespace nymeaserver { -static const QBluetoothUuid serviceUuid(QUuid("997936b5-d2cd-4c57-b41b-c6048320cd2b")); +static const QBluetoothUuid nymeaServiceUuid(QUuid("997936b5-d2cd-4c57-b41b-c6048320cd2b")); + /*! Constructs a \l{BluetoothServer} with the given \a parent. */ BluetoothServer::BluetoothServer(QObject *parent) : - TransportInterface(ServerConfiguration(), parent), - m_server(0) + TransportInterface(ServerConfiguration(), parent) { } @@ -54,9 +53,6 @@ BluetoothServer::BluetoothServer(QObject *parent) : /*! Destructs this \l{BluetoothServer}. */ BluetoothServer::~BluetoothServer() { - if (m_server && m_server->isListening()) - qCDebug(dcApplication) << "Shutting down \"Bluetooth server\""; - stopServer(); } @@ -72,8 +68,10 @@ void BluetoothServer::sendData(const QUuid &clientId, const QByteArray &data) { QBluetoothSocket *client = 0; client = m_clientList.value(clientId); - if (client) - client->write(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Compact) + '\n'); + if (!client) + return; + + client->write(data + '\n'); } /*! Send the given \a data to the \a clients. */ @@ -83,6 +81,17 @@ void BluetoothServer::sendData(const QList &clients, const QByteArray &da sendData(client, data); } +void BluetoothServer::onHostModeChanged(const QBluetoothLocalDevice::HostMode &mode) +{ + if (!m_server || !m_localDevice) + return; + + if (mode != QBluetoothLocalDevice::HostDiscoverable || QBluetoothLocalDevice::HostDiscoverableLimitedInquiry) { + m_localDevice->powerOn(); + m_localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverableLimitedInquiry); + } +} + void BluetoothServer::onClientConnected() { // Got a new client connected @@ -90,7 +99,7 @@ void BluetoothServer::onClientConnected() if (!client) return; - qCDebug(dcConnection) << "Bluetooth server: new client connected:" << client->localName() << client->localAddress().toString(); + qCDebug(dcConnection) << "BluetoothServer: New client connected:" << client->localName() << client->localAddress().toString(); QUuid clientId = QUuid::createUuid(); m_clientList.insert(clientId, client); @@ -108,14 +117,14 @@ void BluetoothServer::onClientDisconnected() if (!client) return; - qCDebug(dcConnection) << "Bluetooth server: client disconnected:" << client->localName() << client->localAddress().toString(); + qCDebug(dcConnection) << "BluetoothServer: Client disconnected:" << client->localName() << client->localAddress().toString(); QUuid clientId = m_clientList.key(client); m_clientList.take(clientId)->deleteLater(); } void BluetoothServer::onError(QBluetoothSocket::SocketError error) { - qCWarning(dcConnection) << "Bluetooth server error:" << error; + qCWarning(dcConnection) << "BluetoothServer: Error occured:" << error; } void BluetoothServer::readData() @@ -124,42 +133,51 @@ void BluetoothServer::readData() if (!client) return; - QByteArray message; - while (client->canReadLine()) { - QByteArray dataLine = client->readLine(); - message.append(dataLine); - if (dataLine.endsWith('\n')) { - qCDebug(dcConnection()) << "Bluetooth data received:" << message; - emit dataAvailable(m_clientList.key(client), message); - message.clear(); - } + m_receiveBuffer.append(client->readAll()); + int splitIndex = m_receiveBuffer.indexOf("}\n{"); + while (splitIndex > -1) { + emit dataAvailable(m_clientList.key(client), m_receiveBuffer.left(splitIndex + 1)); + m_receiveBuffer = m_receiveBuffer.right(m_receiveBuffer.length() - splitIndex - 2); + splitIndex = m_receiveBuffer.indexOf("}\n{"); + } + if (m_receiveBuffer.endsWith("}\n")) { + emit dataAvailable(m_clientList.key(client), m_receiveBuffer); + m_receiveBuffer.clear(); } } bool BluetoothServer::startServer() { - if (m_server) + if (m_server && m_localDevice) return true; - // Check if Bluetooth is available on this device - QBluetoothLocalDevice localDevice; - if (localDevice.isValid()) { - qCDebug(dcConnection()) << "Bluetooth: using adapter" << localDevice.name() << localDevice.address().toString(); - localDevice.powerOn(); - localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable); - } else { - qCWarning(dcConnection()) << "Bluetooth server: could find any bluetooth hardware"; + m_localDevice = new QBluetoothLocalDevice(this); + if (!m_localDevice->isValid()) { + qCWarning(dcConnection()) << "BluetoothServer: could find any bluetooth hardware"; + delete m_localDevice; + m_localDevice = nullptr; return false; } + // Init adapter + qCDebug(dcConnection()) << "BluetoothServer: Using adapter" << m_localDevice->name() << m_localDevice->address().toString(); + m_localDevice->powerOn(); + m_localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverableLimitedInquiry); + connect(m_localDevice, &QBluetoothLocalDevice::hostModeStateChanged, this, &BluetoothServer::onHostModeChanged); + + // Init bluetooth server m_server = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this); connect(m_server, SIGNAL(newConnection()), this, SLOT(onClientConnected())); - if (!m_server->listen(localDevice.address())) { - qCWarning(dcConnection()) << "Bluetooth server: could not listen on local device." << localDevice.name(); + if (!m_server->listen(m_localDevice->address())) { + qCWarning(dcConnection()) << "BluetoothServer: Could not listen on local device." << m_localDevice->name(); + delete m_localDevice; + delete m_server; + m_localDevice = nullptr; + m_server = nullptr; return false; } - qCDebug(dcConnection) << "Started bluetooth server" << m_server->serverAddress().toString(); + qCDebug(dcConnection) << "BluetoothServer: Started bluetooth server" << m_server->serverAddress().toString(); // Set service attributes QBluetoothServiceInfo::Sequence browseSequence; @@ -169,14 +187,14 @@ bool BluetoothServer::startServer() QBluetoothServiceInfo::Sequence classId; classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList, classId); - classId.prepend(QVariant::fromValue(serviceUuid)); + classId.prepend(QVariant::fromValue(nymeaServiceUuid)); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId); - - m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,classId); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList, classId); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, QVariant("nymea")); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, QVariant("The JSON-RPC interface for nymea.")); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, QVariant("https://nymea.io")); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::DocumentationUrl, QVariant("https://doc.nymea.io/jsonrpc.html")); // Define protocol QBluetoothServiceInfo::Sequence protocolDescriptorList; @@ -187,15 +205,19 @@ bool BluetoothServer::startServer() m_serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList); // Set UUID - m_serviceInfo.setServiceUuid(serviceUuid); + m_serviceInfo.setServiceUuid(nymeaServiceUuid); // Register the service in the local device - if (!m_serviceInfo.registerService(localDevice.address())) { - qCWarning(dcConnection()) << "Bluetooth: Could not register service" << m_serviceInfo.serviceName() << serviceUuid.toString(); + if (!m_serviceInfo.registerService(m_localDevice->address())) { + qCWarning(dcConnection()) << "BluetoothServer: Could not register service" << m_serviceInfo.serviceName() << nymeaServiceUuid.toString(); + delete m_localDevice; + delete m_server; + m_localDevice = nullptr; + m_server = nullptr; return false; } - qCDebug(dcConnection()) << "Bluetooth: Registered successfully service" << m_serviceInfo.serviceName() << serviceUuid.toString(); + qCDebug(dcConnection()) << "BluetoothServer: Registered successfully service" << m_serviceInfo.serviceName() << nymeaServiceUuid.toString(); return true; } @@ -205,14 +227,20 @@ bool BluetoothServer::stopServer() client->close(); } - if (!m_server) - return true; + if (m_server) { + qCDebug(dcBluetooth()) << "Shutting down \"Bluetooth server\""; + m_serviceInfo.unregisterService(); + m_server->close(); + m_server->deleteLater(); + m_server = nullptr; + } - m_serviceInfo.unregisterService(); + if (m_localDevice) { + m_localDevice->deleteLater(); + m_localDevice = nullptr; + } - m_server->close(); - m_server->deleteLater(); - m_server = 0; + m_receiveBuffer.clear(); return true; } diff --git a/libnymea-core/bluetoothserver.h b/libnymea-core/bluetoothserver.h index 02b26eda..cdb96f82 100644 --- a/libnymea-core/bluetoothserver.h +++ b/libnymea-core/bluetoothserver.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2016 Simon Stürz * + * Copyright (C) 2016-2018 Simon Stürz * * * * This file is part of nymea. * * * @@ -24,6 +24,7 @@ #include #include #include +#include #include "transportinterface.h" @@ -42,11 +43,17 @@ public: void sendData(const QList &clients, const QByteArray &data) override; private: - QBluetoothServer *m_server; + QBluetoothServer *m_server = nullptr; + QBluetoothLocalDevice *m_localDevice = nullptr; QBluetoothServiceInfo m_serviceInfo; + + // Client storage QHash m_clientList; + QByteArray m_receiveBuffer; private slots: + void onHostModeChanged(const QBluetoothLocalDevice::HostMode &mode); + void onClientConnected(); void onClientDisconnected(); void onError(QBluetoothSocket::SocketError error);