Update bluetooth server

This commit is contained in:
Simon Stürz 2018-07-05 11:05:38 +02:00 committed by Michael Zanetti
parent 681b306b1b
commit 2231fd8f94
2 changed files with 84 additions and 49 deletions

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* Copyright (C) 2016 Simon Stürz <simon.stuerz@guh.io> * * Copyright (C) 2016-2018 Simon Stürz <simon.stuerz@guh.io> *
* * * *
* This file is part of nymea. * * This file is part of nymea. *
* * * *
@ -38,15 +38,14 @@
#include "loggingcategories.h" #include "loggingcategories.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QBluetoothLocalDevice>
namespace nymeaserver { 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. */ /*! Constructs a \l{BluetoothServer} with the given \a parent. */
BluetoothServer::BluetoothServer(QObject *parent) : BluetoothServer::BluetoothServer(QObject *parent) :
TransportInterface(ServerConfiguration(), parent), TransportInterface(ServerConfiguration(), parent)
m_server(0)
{ {
} }
@ -54,9 +53,6 @@ BluetoothServer::BluetoothServer(QObject *parent) :
/*! Destructs this \l{BluetoothServer}. */ /*! Destructs this \l{BluetoothServer}. */
BluetoothServer::~BluetoothServer() BluetoothServer::~BluetoothServer()
{ {
if (m_server && m_server->isListening())
qCDebug(dcApplication) << "Shutting down \"Bluetooth server\"";
stopServer(); stopServer();
} }
@ -72,8 +68,10 @@ void BluetoothServer::sendData(const QUuid &clientId, const QByteArray &data)
{ {
QBluetoothSocket *client = 0; QBluetoothSocket *client = 0;
client = m_clientList.value(clientId); client = m_clientList.value(clientId);
if (client) if (!client)
client->write(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Compact) + '\n'); return;
client->write(data + '\n');
} }
/*! Send the given \a data to the \a clients. */ /*! Send the given \a data to the \a clients. */
@ -83,6 +81,17 @@ void BluetoothServer::sendData(const QList<QUuid> &clients, const QByteArray &da
sendData(client, data); 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() void BluetoothServer::onClientConnected()
{ {
// Got a new client connected // Got a new client connected
@ -90,7 +99,7 @@ void BluetoothServer::onClientConnected()
if (!client) if (!client)
return; 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(); QUuid clientId = QUuid::createUuid();
m_clientList.insert(clientId, client); m_clientList.insert(clientId, client);
@ -108,14 +117,14 @@ void BluetoothServer::onClientDisconnected()
if (!client) if (!client)
return; 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); QUuid clientId = m_clientList.key(client);
m_clientList.take(clientId)->deleteLater(); m_clientList.take(clientId)->deleteLater();
} }
void BluetoothServer::onError(QBluetoothSocket::SocketError error) void BluetoothServer::onError(QBluetoothSocket::SocketError error)
{ {
qCWarning(dcConnection) << "Bluetooth server error:" << error; qCWarning(dcConnection) << "BluetoothServer: Error occured:" << error;
} }
void BluetoothServer::readData() void BluetoothServer::readData()
@ -124,42 +133,51 @@ void BluetoothServer::readData()
if (!client) if (!client)
return; return;
QByteArray message; m_receiveBuffer.append(client->readAll());
while (client->canReadLine()) { int splitIndex = m_receiveBuffer.indexOf("}\n{");
QByteArray dataLine = client->readLine(); while (splitIndex > -1) {
message.append(dataLine); emit dataAvailable(m_clientList.key(client), m_receiveBuffer.left(splitIndex + 1));
if (dataLine.endsWith('\n')) { m_receiveBuffer = m_receiveBuffer.right(m_receiveBuffer.length() - splitIndex - 2);
qCDebug(dcConnection()) << "Bluetooth data received:" << message; splitIndex = m_receiveBuffer.indexOf("}\n{");
emit dataAvailable(m_clientList.key(client), message); }
message.clear(); if (m_receiveBuffer.endsWith("}\n")) {
} emit dataAvailable(m_clientList.key(client), m_receiveBuffer);
m_receiveBuffer.clear();
} }
} }
bool BluetoothServer::startServer() bool BluetoothServer::startServer()
{ {
if (m_server) if (m_server && m_localDevice)
return true; return true;
// Check if Bluetooth is available on this device m_localDevice = new QBluetoothLocalDevice(this);
QBluetoothLocalDevice localDevice; if (!m_localDevice->isValid()) {
if (localDevice.isValid()) { qCWarning(dcConnection()) << "BluetoothServer: could find any bluetooth hardware";
qCDebug(dcConnection()) << "Bluetooth: using adapter" << localDevice.name() << localDevice.address().toString(); delete m_localDevice;
localDevice.powerOn(); m_localDevice = nullptr;
localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable);
} else {
qCWarning(dcConnection()) << "Bluetooth server: could find any bluetooth hardware";
return false; 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); m_server = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
connect(m_server, SIGNAL(newConnection()), this, SLOT(onClientConnected())); connect(m_server, SIGNAL(newConnection()), this, SLOT(onClientConnected()));
if (!m_server->listen(localDevice.address())) { if (!m_server->listen(m_localDevice->address())) {
qCWarning(dcConnection()) << "Bluetooth server: could not listen on local device." << localDevice.name(); 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; return false;
} }
qCDebug(dcConnection) << "Started bluetooth server" << m_server->serverAddress().toString(); qCDebug(dcConnection) << "BluetoothServer: Started bluetooth server" << m_server->serverAddress().toString();
// Set service attributes // Set service attributes
QBluetoothServiceInfo::Sequence browseSequence; QBluetoothServiceInfo::Sequence browseSequence;
@ -169,14 +187,14 @@ bool BluetoothServer::startServer()
QBluetoothServiceInfo::Sequence classId; QBluetoothServiceInfo::Sequence classId;
classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList, classId); 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::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::ServiceName, QVariant("nymea"));
m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, QVariant("The JSON-RPC interface for 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::ServiceProvider, QVariant("https://nymea.io"));
m_serviceInfo.setAttribute(QBluetoothServiceInfo::DocumentationUrl, QVariant("https://doc.nymea.io/jsonrpc.html"));
// Define protocol // Define protocol
QBluetoothServiceInfo::Sequence protocolDescriptorList; QBluetoothServiceInfo::Sequence protocolDescriptorList;
@ -187,15 +205,19 @@ bool BluetoothServer::startServer()
m_serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
// Set UUID // Set UUID
m_serviceInfo.setServiceUuid(serviceUuid); m_serviceInfo.setServiceUuid(nymeaServiceUuid);
// Register the service in the local device // Register the service in the local device
if (!m_serviceInfo.registerService(localDevice.address())) { if (!m_serviceInfo.registerService(m_localDevice->address())) {
qCWarning(dcConnection()) << "Bluetooth: Could not register service" << m_serviceInfo.serviceName() << serviceUuid.toString(); 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; 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; return true;
} }
@ -205,14 +227,20 @@ bool BluetoothServer::stopServer()
client->close(); client->close();
} }
if (!m_server) if (m_server) {
return true; 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_receiveBuffer.clear();
m_server->deleteLater();
m_server = 0;
return true; return true;
} }

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * *
* Copyright (C) 2016 Simon Stürz <simon.stuerz@guh.io> * * Copyright (C) 2016-2018 Simon Stürz <simon.stuerz@guh.io> *
* * * *
* This file is part of nymea. * * This file is part of nymea. *
* * * *
@ -24,6 +24,7 @@
#include <QObject> #include <QObject>
#include <QBluetoothSocket> #include <QBluetoothSocket>
#include <QBluetoothServer> #include <QBluetoothServer>
#include <QBluetoothLocalDevice>
#include "transportinterface.h" #include "transportinterface.h"
@ -42,11 +43,17 @@ public:
void sendData(const QList<QUuid> &clients, const QByteArray &data) override; void sendData(const QList<QUuid> &clients, const QByteArray &data) override;
private: private:
QBluetoothServer *m_server; QBluetoothServer *m_server = nullptr;
QBluetoothLocalDevice *m_localDevice = nullptr;
QBluetoothServiceInfo m_serviceInfo; QBluetoothServiceInfo m_serviceInfo;
// Client storage
QHash<QUuid, QBluetoothSocket *> m_clientList; QHash<QUuid, QBluetoothSocket *> m_clientList;
QByteArray m_receiveBuffer;
private slots: private slots:
void onHostModeChanged(const QBluetoothLocalDevice::HostMode &mode);
void onClientConnected(); void onClientConnected();
void onClientDisconnected(); void onClientDisconnected();
void onError(QBluetoothSocket::SocketError error); void onError(QBluetoothSocket::SocketError error);