From ec0a9a5c9d1c2464907393fecdbb2d80e4587c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 31 Aug 2016 14:36:34 +0200 Subject: [PATCH] basic bluetooth server infrastructure --- server/bluetoothserver.cpp | 158 +++++++++++++++++++++++++++++++++++++ server/bluetoothserver.h | 43 ++++++++++ server/guhcore.cpp | 8 ++ server/guhcore.h | 4 + server/server.pri | 18 +++++ server/server.pro | 2 +- 6 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 server/bluetoothserver.cpp create mode 100644 server/bluetoothserver.h diff --git a/server/bluetoothserver.cpp b/server/bluetoothserver.cpp new file mode 100644 index 00000000..906c36dc --- /dev/null +++ b/server/bluetoothserver.cpp @@ -0,0 +1,158 @@ +#include "bluetoothserver.h" +#include "loggingcategories.h" + +#include +#include + +namespace guhserver { + +static const QLatin1String serviceUuid("81679f09-1404-4242-b685-a7f7e23df8cf"); + +BluetoothServer::BluetoothServer(QObject *parent) : + TransportInterface(parent), + m_server(0) +{ + +} + +BluetoothServer::~BluetoothServer() +{ + stopServer(); +} + +bool BluetoothServer::hardwareAvailable() +{ + QBluetoothLocalDevice localDevice; + return localDevice.isValid(); +} + +void BluetoothServer::sendData(const QUuid &clientId, const QVariantMap &data) +{ + QBluetoothSocket *client = 0; + client = m_clientList.value(clientId); + if (client) + client->write(QJsonDocument::fromVariant(data).toJson() + "\n"); +} + +void BluetoothServer::sendData(const QList &clients, const QVariantMap &data) +{ + foreach (const QUuid &client, clients) + sendData(client, data); +} + +void BluetoothServer::onClientConnected() +{ + // Got a new client connected + QBluetoothSocket *client = m_server->nextPendingConnection(); + if (!client) + return; + + qCDebug(dcConnection) << "Bluetooth server: new client connected:" << client->localName() << client->localAddress().toString(); + + QUuid clientId = QUuid::createUuid(); + m_clientList.insert(clientId, client); + + connect(client, SIGNAL(readyRead()), this, SLOT(readData())); + connect(client, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(onError(QBluetoothSocket::SocketError))); + connect(client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); + + emit clientConnected(clientId); +} + +void BluetoothServer::onClientDisconnected() +{ + QBluetoothSocket *client = qobject_cast(sender()); + if (!client) + return; + + qCDebug(dcConnection) << "Bluetooth server: 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; +} + +void BluetoothServer::readData() +{ + QBluetoothSocket *client = qobject_cast(sender()); + if (!client) + return; + + while (client->canReadLine()) { + QByteArray line = client->readLine().trimmed(); + qCDebug(dcConnection()) << "Bluetooth server: line in:" << QString::fromUtf8(line.constData(), line.length()); + } +} + +bool BluetoothServer::startServer() +{ + if (m_server) + return true; + + // Check if Bluetooth is available on this device + QBluetoothLocalDevice localDevice; + if (localDevice.isValid()) { + // Turn Bluetooth on + localDevice.powerOn(); + // Make it visible to others + localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable); + } else { + qCWarning(dcConnection()) << "Bluetooth server: could find any bluetooth hardware"; + return false; + } + + 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(); + return false; + } + + qCDebug(dcConnection) << "Started bluetooth server" << m_server->serverAddress().toString(); + + QBluetoothServiceInfo::Sequence classId; + classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList, classId); + + classId.prepend(QVariant::fromValue(QBluetoothUuid(serviceUuid))); + + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,classId); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, tr("guhIO JSON-RPC")); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, tr("The JSON-RPC interface for guhIO.")); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, "guh.io"); + m_serviceInfo.setServiceUuid(QBluetoothUuid(serviceUuid)); + + QBluetoothServiceInfo::Sequence publicBrowse; + publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse); + + QBluetoothServiceInfo::Sequence protocolDescriptorList; + QBluetoothServiceInfo::Sequence protocol; + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + protocol.clear(); + protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)) + << QVariant::fromValue(quint8(m_server->serverPort())); + protocolDescriptorList.append(QVariant::fromValue(protocol)); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList); + m_serviceInfo.registerService(localDevice.address()); + return true; +} + +bool BluetoothServer::stopServer() +{ + foreach (QBluetoothSocket *client, m_clientList.values()) { + client->close(); + } + + m_server->close(); + m_server->deleteLater(); + m_server = 0; + return true; +} + +} diff --git a/server/bluetoothserver.h b/server/bluetoothserver.h new file mode 100644 index 00000000..d7b4661d --- /dev/null +++ b/server/bluetoothserver.h @@ -0,0 +1,43 @@ +#ifndef BLUETOOTHSERVER_H +#define BLUETOOTHSERVER_H + +#include +#include +#include + +#include "transportinterface.h" + +namespace guhserver { + +class BluetoothServer : public TransportInterface +{ + Q_OBJECT +public: + explicit BluetoothServer(QObject *parent = 0); + ~BluetoothServer(); + + static bool hardwareAvailable(); + + void sendData(const QUuid &clientId, const QVariantMap &data) override; + void sendData(const QList &clients, const QVariantMap &data) override; + +private: + QBluetoothServer *m_server; + QBluetoothServiceInfo m_serviceInfo; + QHash m_clientList; + +private slots: + void onClientConnected(); + void onClientDisconnected(); + void onError(QBluetoothSocket::SocketError error); + void readData(); + +public slots: + bool startServer() override; + bool stopServer() override; + +}; + +} + +#endif // BLUETOOTHSERVER_H diff --git a/server/guhcore.cpp b/server/guhcore.cpp index 98865bcb..23c71419 100644 --- a/server/guhcore.cpp +++ b/server/guhcore.cpp @@ -381,6 +381,11 @@ ServerManager *GuhCore::serverManager() const return m_serverManager; } +BluetoothServer *GuhCore::bluetoothServer() const +{ + return m_bluetoothServer; +} + #ifdef TESTING_ENABLED MockTcpServer *GuhCore::tcpServer() const { @@ -427,10 +432,13 @@ GuhCore::GuhCore(QObject *parent) : m_webSocketServer = new WebSocketServer(m_configuration->webSocketAddress(), m_configuration->webSocketPort(), m_configuration->sslEnabled(), this); + m_bluetoothServer = new BluetoothServer(this); + // Register transport interface in the JSON RPC server m_serverManager->jsonServer()->registerTransportInterface(m_tcpServer); m_serverManager->jsonServer()->registerTransportInterface(m_webSocketServer); m_serverManager->jsonServer()->registerTransportInterface(m_cloudManager); + m_serverManager->jsonServer()->registerTransportInterface(m_bluetoothServer); m_webServer = new WebServer(m_configuration->webServerAddress(), m_configuration->webServerPort(), m_configuration->webServerPublicFolder(), this); m_serverManager->restServer()->registerWebserver(m_webServer); diff --git a/server/guhcore.h b/server/guhcore.h index 516238df..dc0ce1e6 100644 --- a/server/guhcore.h +++ b/server/guhcore.h @@ -34,6 +34,7 @@ #include "ruleengine.h" #include "servermanager.h" #include "websocketserver.h" +#include "bluetoothserver.h" #include "cloud/cloudmanager.h" #include "time/timemanager.h" @@ -84,6 +85,7 @@ public: WebSocketServer *webSocketServer() const; CloudManager *cloudManager() const; ServerManager *serverManager() const; + BluetoothServer *bluetoothServer() const; #ifdef TESTING_ENABLED @@ -126,6 +128,8 @@ private: #endif WebSocketServer *m_webSocketServer; WebServer *m_webServer; + BluetoothServer *m_bluetoothServer; + CloudManager *m_cloudManager; QHash m_pendingActions; diff --git a/server/server.pri b/server/server.pri index ee08805f..1a9b6933 100644 --- a/server/server.pri +++ b/server/server.pri @@ -5,6 +5,15 @@ HEADERS += $$top_srcdir/server/guhcore.h \ $$top_srcdir/server/tcpserver.h \ $$top_srcdir/server/ruleengine.h \ $$top_srcdir/server/rule.h \ + $$top_srcdir/server/stateevaluator.h \ + $$top_srcdir/server/webserver.h \ + $$top_srcdir/server/transportinterface.h \ + $$top_srcdir/server/servermanager.h \ + $$top_srcdir/server/httprequest.h \ + $$top_srcdir/server/websocketserver.h \ + $$top_srcdir/server/httpreply.h \ + $$top_srcdir/server/guhconfiguration.h \ + $$top_srcdir/server/bluetoothserver.h \ $$top_srcdir/server/jsonrpc/jsonrpcserver.h \ $$top_srcdir/server/jsonrpc/jsonhandler.h \ $$top_srcdir/server/jsonrpc/devicehandler.h \ @@ -53,6 +62,15 @@ SOURCES += $$top_srcdir/server/guhcore.cpp \ $$top_srcdir/server/tcpserver.cpp \ $$top_srcdir/server/ruleengine.cpp \ $$top_srcdir/server/rule.cpp \ + $$top_srcdir/server/stateevaluator.cpp \ + $$top_srcdir/server/webserver.cpp \ + $$top_srcdir/server/transportinterface.cpp \ + $$top_srcdir/server/servermanager.cpp \ + $$top_srcdir/server/httprequest.cpp \ + $$top_srcdir/server/websocketserver.cpp \ + $$top_srcdir/server/httpreply.cpp \ + $$top_srcdir/server/guhconfiguration.cpp \ + $$top_srcdir/server/bluetoothserver.cpp \ $$top_srcdir/server/jsonrpc/jsonrpcserver.cpp \ $$top_srcdir/server/jsonrpc/jsonhandler.cpp \ $$top_srcdir/server/jsonrpc/devicehandler.cpp \ diff --git a/server/server.pro b/server/server.pro index 1cb79dfe..d47bf2e5 100644 --- a/server/server.pro +++ b/server/server.pro @@ -8,7 +8,7 @@ INCLUDEPATH += ../libguh jsonrpc target.path = /usr/bin INSTALLS += target -QT += sql xml websockets +QT += sql xml websockets bluetooth LIBS += -L$$top_builddir/libguh/ -lguh