From 7283842cbed6a378d430552d327eab4a27775538 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Sun, 6 Jul 2014 17:22:25 +0200 Subject: Moved watchConnector to daemon and implemented daemon interface for QML --- app/app.pro | 9 +- app/daemonproxy.cpp | 26 ++++ app/daemonproxy.h | 66 ++++++++++ app/pebble.cpp | 8 +- daemon/daemon.pro | 9 +- daemon/dbusadaptor.cpp | 16 +-- daemon/dbusadaptor.h | 12 +- daemon/manager.cpp | 4 +- daemon/manager.h | 6 +- daemon/watchconnector.cpp | 300 ++++++++++++++++++++++++++++++++++++++++++++++ daemon/watchconnector.h | 132 ++++++++++++++++++++ lib/lib.pro | 14 --- lib/watchconnector.cpp | 300 ---------------------------------------------- lib/watchconnector.h | 132 -------------------- pebble.pro | 2 +- 15 files changed, 556 insertions(+), 480 deletions(-) create mode 100644 app/daemonproxy.cpp create mode 100644 app/daemonproxy.h create mode 100644 daemon/watchconnector.cpp create mode 100644 daemon/watchconnector.h delete mode 100644 lib/lib.pro delete mode 100644 lib/watchconnector.cpp delete mode 100644 lib/watchconnector.h diff --git a/app/app.pro b/app/app.pro index c9156f0..5d587cd 100644 --- a/app/app.pro +++ b/app/app.pro @@ -3,12 +3,13 @@ TARGET = pebble CONFIG += sailfishapp SOURCES += \ - pebble.cpp + pebble.cpp \ + daemonproxy.cpp -INCLUDEPATH += ../lib -LIBS += -L$$OUT_PWD/../lib -lpebble +HEADERS += \ + daemonproxy.h -QT += bluetooth +QT += dbus QMAKE_CXXFLAGS += -std=c++0x OTHER_FILES += \ diff --git a/app/daemonproxy.cpp b/app/daemonproxy.cpp new file mode 100644 index 0000000..24eedb5 --- /dev/null +++ b/app/daemonproxy.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -a daemon/dbusadaptor -p app/daemonproxy daemon/org.pebbled.xml + * + * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "daemonproxy.h" + +/* + * Implementation of interface class OrgPebbledInterface + */ + +OrgPebbledInterface::OrgPebbledInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +OrgPebbledInterface::~OrgPebbledInterface() +{ +} + diff --git a/app/daemonproxy.h b/app/daemonproxy.h new file mode 100644 index 0000000..7535b00 --- /dev/null +++ b/app/daemonproxy.h @@ -0,0 +1,66 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp -a daemon/dbusadaptor -p app/daemonproxy daemon/org.pebbled.xml + * + * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef DAEMONPROXY_H_1404657374 +#define DAEMONPROXY_H_1404657374 + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Proxy class for interface org.pebbled + */ +class OrgPebbledInterface: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.pebbled"; } + +public: + OrgPebbledInterface(const QString &service = "org.pebbled", + const QString &path = "/", + const QDBusConnection &connection = QDBusConnection::sessionBus(), + QObject *parent = 0); + + ~OrgPebbledInterface(); + + Q_PROPERTY(QString address READ address) + inline QString address() const + { return qvariant_cast< QString >(property("address")); } + + Q_PROPERTY(bool connected READ connected) + inline bool connected() const + { return qvariant_cast< bool >(property("connected")); } + + Q_PROPERTY(QString name READ name) + inline QString name() const + { return qvariant_cast< QString >(property("name")); } + + Q_PROPERTY(QVariantMap pebble READ pebble) + inline QVariantMap pebble() const + { return qvariant_cast< QVariantMap >(property("pebble")); } + +public Q_SLOTS: // METHODS +Q_SIGNALS: // SIGNALS + void connectedChanged(); + void pebbleChanged(); +}; + +namespace org { + typedef ::OrgPebbledInterface pebbled; +} +#endif diff --git a/app/pebble.cpp b/app/pebble.cpp index 46e6298..623621d 100644 --- a/app/pebble.cpp +++ b/app/pebble.cpp @@ -32,14 +32,12 @@ #include #include -#include "watchconnector.h" - -using namespace watch; +#include "daemonproxy.h" int main(int argc, char *argv[]) { - // Registert WatchController object on QML side - qmlRegisterType("watch", 0, 1, "WatchConnector"); + // Register Pebble daemon interface object on QML side + qmlRegisterType("org.pebbled", 0, 1, "PebbledInterface"); return SailfishApp::main(argc, argv); } diff --git a/daemon/daemon.pro b/daemon/daemon.pro index c4b6a76..deadea0 100644 --- a/daemon/daemon.pro +++ b/daemon/daemon.pro @@ -5,25 +5,24 @@ CONFIG -= app_bundle CONFIG += link_pkgconfig QT -= gui -INCLUDEPATH += ../lib -LIBS += -L$$OUT_PWD/../lib -lpebble - QT += bluetooth dbus contacts PKGCONFIG += commhistory-qt5 mlite5 QMAKE_CXXFLAGS += -std=c++0x SOURCES += \ daemon.cpp \ + manager.cpp \ voicecallmanager.cpp \ voicecallhandler.cpp \ - manager.cpp \ + watchconnector.cpp \ dbusconnector.cpp \ dbusadaptor.cpp HEADERS += \ + manager.h \ voicecallmanager.h \ voicecallhandler.h \ - manager.h \ + watchconnector.h \ dbusconnector.h \ dbusadaptor.h diff --git a/daemon/dbusadaptor.cpp b/daemon/dbusadaptor.cpp index 914f9f2..6460dca 100644 --- a/daemon/dbusadaptor.cpp +++ b/daemon/dbusadaptor.cpp @@ -1,6 +1,6 @@ /* * This file was generated by qdbusxml2cpp version 0.8 - * Command line was: qdbusxml2cpp -c DBusAdaptor -a dbusadaptor org.pebbled.xml + * Command line was: qdbusxml2cpp -a daemon/dbusadaptor -p app/daemonproxy daemon/org.pebbled.xml * * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). * @@ -18,40 +18,40 @@ #include /* - * Implementation of adaptor class DBusAdaptor + * Implementation of adaptor class PebbledAdaptor */ -DBusAdaptor::DBusAdaptor(QObject *parent) +PebbledAdaptor::PebbledAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) { // constructor setAutoRelaySignals(true); } -DBusAdaptor::~DBusAdaptor() +PebbledAdaptor::~PebbledAdaptor() { // destructor } -QString DBusAdaptor::address() const +QString PebbledAdaptor::address() const { // get the value of property address return qvariant_cast< QString >(parent()->property("address")); } -bool DBusAdaptor::connected() const +bool PebbledAdaptor::connected() const { // get the value of property connected return qvariant_cast< bool >(parent()->property("connected")); } -QString DBusAdaptor::name() const +QString PebbledAdaptor::name() const { // get the value of property name return qvariant_cast< QString >(parent()->property("name")); } -QVariantMap DBusAdaptor::pebble() const +QVariantMap PebbledAdaptor::pebble() const { // get the value of property pebble return qvariant_cast< QVariantMap >(parent()->property("pebble")); diff --git a/daemon/dbusadaptor.h b/daemon/dbusadaptor.h index 9d8759a..d1662c6 100644 --- a/daemon/dbusadaptor.h +++ b/daemon/dbusadaptor.h @@ -1,6 +1,6 @@ /* * This file was generated by qdbusxml2cpp version 0.8 - * Command line was: qdbusxml2cpp -c DBusAdaptor -a dbusadaptor org.pebbled.xml + * Command line was: qdbusxml2cpp -a daemon/dbusadaptor -p app/daemonproxy daemon/org.pebbled.xml * * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). * @@ -9,8 +9,8 @@ * before re-generating it. */ -#ifndef DBUSADAPTOR_H_1404605591 -#define DBUSADAPTOR_H_1404605591 +#ifndef DBUSADAPTOR_H_1404660047 +#define DBUSADAPTOR_H_1404660047 #include #include @@ -26,7 +26,7 @@ QT_END_NAMESPACE /* * Adaptor class for interface org.pebbled */ -class DBusAdaptor: public QDBusAbstractAdaptor +class PebbledAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.pebbled") @@ -43,8 +43,8 @@ class DBusAdaptor: public QDBusAbstractAdaptor " \n" "") public: - DBusAdaptor(QObject *parent); - virtual ~DBusAdaptor(); + PebbledAdaptor(QObject *parent); + virtual ~PebbledAdaptor(); public: // PROPERTIES Q_PROPERTY(QString address READ address) diff --git a/daemon/manager.cpp b/daemon/manager.cpp index 4ba2a8b..f25e724 100644 --- a/daemon/manager.cpp +++ b/daemon/manager.cpp @@ -37,8 +37,8 @@ Manager::Manager(watch::WatchConnector *watch, DBusConnector *dbus, VoiceCallMan dbus->findPebble(); } - DBusProxy *proxy = new DBusProxy(this); - DBusAdaptor *adaptor = new DBusAdaptor(proxy); + PebbledProxy *proxy = new PebbledProxy(this); + PebbledAdaptor *adaptor = new PebbledAdaptor(proxy); QDBusConnection connection = QDBusConnection::sessionBus(); connection.registerObject("/", proxy); connection.registerService("org.pebbled"); diff --git a/daemon/manager.h b/daemon/manager.h index b052355..b9aa01b 100644 --- a/daemon/manager.h +++ b/daemon/manager.h @@ -19,7 +19,7 @@ class Manager : public QObject { Q_OBJECT - friend class DBusProxy; + friend class PebbledProxy; QBluetoothLocalDevice btDevice; @@ -55,7 +55,7 @@ protected slots: }; -class DBusProxy : public QObject +class PebbledProxy : public QObject { Q_OBJECT Q_PROPERTY(QVariantMap pebble READ pebble) @@ -69,7 +69,7 @@ class DBusProxy : public QObject bool pebbleConnected() { return static_cast(parent())->watch->isConnected(); } public: - explicit DBusProxy(QObject *parent) : QObject(parent) {} + explicit PebbledProxy(QObject *parent) : QObject(parent) {} }; diff --git a/daemon/watchconnector.cpp b/daemon/watchconnector.cpp new file mode 100644 index 0000000..18d287e --- /dev/null +++ b/daemon/watchconnector.cpp @@ -0,0 +1,300 @@ +#include "watchconnector.h" +#include +#include + +using namespace watch; + +static int __reconnect_timeout = 5000; //ms + +WatchConnector::WatchConnector(QObject *parent) : + QObject(parent), socket(nullptr), is_connected(false) +{} + +WatchConnector::~WatchConnector() +{ +} + +void WatchConnector::deviceDiscovered(const QBluetoothDeviceInfo &device) +{ + //FIXME TODO: Configurable + if (device.name().startsWith("Pebble")) { + qDebug() << "Found Pebble:" << device.name() << '(' << device.address().toString() << ')'; + handleWatch(device.name(), device.address().toString()); + } else { + qDebug() << "Found other device:" << device.name() << '(' << device.address().toString() << ')'; + } +} + +void WatchConnector::deviceConnect(const QString &name, const QString &address) +{ + if (name.startsWith("Pebble")) handleWatch(name, address); +} + +void WatchConnector::reconnect() +{ + qDebug() << "reconnect" << _last_name; + if (!_last_name.isEmpty() && !_last_address.isEmpty()) { + deviceConnect(_last_name, _last_address); + } +} + +void WatchConnector::handleWatch(const QString &name, const QString &address) +{ + qDebug() << "handleWatch" << name << address; + if (socket != nullptr && socket->isOpen()) { + socket->close(); + socket->deleteLater(); + } + + bool emit_name = (_last_name != name); + _last_name = name; + _last_address = address; + if (emit_name) emit nameChanged(); + + qDebug() << "Creating socket"; + socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket); + + connect(socket, SIGNAL(readyRead()), SLOT(onReadSocket())); + connect(socket, SIGNAL(connected()), SLOT(onConnected())); + connect(socket, SIGNAL(disconnected()), SLOT(onDisconnected())); + connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(onError(QBluetoothSocket::SocketError))); + + // FIXME: Assuming port 1 (with Pebble) + socket->connectToService(QBluetoothAddress(address), QBluetoothUuid(QBluetoothUuid::SerialPort)); +} + +QString WatchConnector::decodeEndpoint(unsigned int val) +{ + //FIXME: Create a map of these values + switch(val) { + case watchTIME: + return "TIME"; + case watchVERSION: + return "VERSION"; + case watchPHONE_VERSION: + return "PHONE_VERSION"; + case watchSYSTEM_MESSAGE: + return "SYSTEM_MESSAGE"; + case watchMUSIC_CONTROL: + return "MUSIC_CONTROL"; + case watchPHONE_CONTROL: + return "PHONE_CONTROL"; + case watchAPPLICATION_MESSAGE: + return "APP_MSG"; + case watchLAUNCHER: + return "LAUNCHER"; + case watchLOGS: + return "LOGS"; + case watchPING: + return "PING"; + case watchLOG_DUMP: + return "DUMP"; + case watchRESET: + return "RESET"; + case watchAPP: + return "APP"; + case watchAPP_LOGS: + return "APP_LOGS"; + case watchNOTIFICATION: + return "NOTIFICATION"; + case watchRESOURCE: + return "RESOURCE"; + case watchAPP_MANAGER: + return "APP_MANAG"; + case watchSCREENSHOT: + return "SCREENSHOT"; + case watchPUTBYTES: + return "PUTBYTES"; + default: + return "Unknown: "+ QString::number(val); + } +} + +void WatchConnector::decodeMsg(QByteArray data) +{ + unsigned int datalen = 0; + int index = 0; + datalen = (data.at(index) << 8) + data.at(index+1); + index += 2; + + unsigned int endpoint = 0; + endpoint = (data.at(index) << 8) + data.at(index+1); + index += 2; + + qDebug() << "Length:" << datalen << " Endpoint:" << decodeEndpoint(endpoint); + qDebug() << "Data:" << data.mid(index).toHex(); + if (endpoint == watchPHONE_CONTROL) { + if (data.length() >= 5) { + if (data.at(4) == callHANGUP) { + emit hangup(); + } + } + } +} + +void WatchConnector::onReadSocket() +{ + qDebug() << "read"; + + QBluetoothSocket *socket = qobject_cast(sender()); + if (!socket) return; + + while (socket->bytesAvailable()) { + QByteArray line = socket->readAll(); + emit messageReceived(socket->peerName(), QString::fromUtf8(line.constData(), line.length())); + decodeMsg(line); + } +} + +void WatchConnector::onConnected() +{ + qDebug() << "Connected!"; + bool was_connected = is_connected; + is_connected = true; + if (not was_connected) emit connectedChanged(); +} + +void WatchConnector::onDisconnected() +{ + qDebug() << "Disconnected!"; + + bool was_connected = is_connected; + is_connected = false; + + QBluetoothSocket *socket = qobject_cast(sender()); + if (!socket) return; + + if (was_connected) emit connectedChanged(); + + socket->deleteLater(); + + // Try to connect again after a timeout + QTimer::singleShot(__reconnect_timeout, this, SLOT(reconnect())); +} + +void WatchConnector::onError(QBluetoothSocket::SocketError error) { + qWarning() << "Error connecting Pebble" << error << socket->errorString(); +} + +void WatchConnector::sendData(const QByteArray &data) +{ + if (socket == nullptr) return; + + socket->write(data); +} + +void WatchConnector::sendMessage(unsigned int endpoint, QByteArray data) +{ + qDebug() << "Sending message"; + QByteArray msg; + + // First send the length + msg.append((data.length() & 0xFF00) >> 8); + msg.append(data.length() & 0xFF); + + // Then the endpoint + msg.append((endpoint & 0xFF00) >> 8); + msg.append(endpoint & 0xFF); + + // Finally the data + msg.append(data); + + sendData(msg); +} + +void WatchConnector::buildData(QByteArray &res, QStringList data) +{ + for (QString d : data) + { + QByteArray tmp = d.left(0xF0).toUtf8(); + res.append(tmp.length() & 0xFF); + res.append(tmp); + } +} + +QByteArray WatchConnector::buildMessageData(unsigned int lead, QStringList data) +{ + QByteArray res; + res.append(lead & 0xFF); + buildData(res, data); + + return res; +} + +void WatchConnector::ping(unsigned int val) +{ + QByteArray res; + res.append((char)0); + + res.append((char)((val >> 24) & 0xff)); + res.append((char)((val >> 16) & 0xff)); + res.append((char)((val >> 8) & 0xff)); + res.append((char)(val & 0xff)); + + sendMessage(watchPING, res); +} + +QString WatchConnector::timeStamp() +{ + return QString::number(QDateTime::currentMSecsSinceEpoch()); +} + +void WatchConnector::sendNotification(unsigned int lead, QString sender, QString data, QString subject) +{ + QStringList tmp; + tmp.append(sender); + tmp.append(data); + tmp.append(timeStamp()); + if (lead == 0) tmp.append(subject); + + QByteArray res = buildMessageData(lead, tmp); + + sendMessage(watchNOTIFICATION, res); +} + +void WatchConnector::sendSMSNotification(QString sender, QString data) +{ + sendNotification(1, sender, data, ""); +} + +void WatchConnector::sendEmailNotification(QString sender, QString data, QString subject) +{ + sendNotification(0, sender, data, subject); +} + +void WatchConnector::phoneControl(char act, unsigned int cookie, QStringList datas) +{ + QByteArray head; + head.append((char)act); + head.append((cookie >> 24)& 0xFF); + head.append((cookie >> 16)& 0xFF); + head.append((cookie >> 8)& 0xFF); + head.append(cookie & 0xFF); + if (datas.length()>0) buildData(head, datas); + + sendMessage(watchPHONE_CONTROL, head); +} + +void WatchConnector::ring(QString number, QString name, bool incoming, unsigned int cookie) +{ + QStringList tmp; + tmp.append(number); + tmp.append(name); + + char act = callINCOMING; + if (!incoming) { + act = callOUTGOING; + } + + phoneControl(act, cookie, tmp); +} + +void WatchConnector::startPhoneCall(unsigned int cookie) +{ + phoneControl(callSTART, cookie, QStringList()); +} + +void WatchConnector::endPhoneCall(unsigned int cookie) +{ + phoneControl(callEND, cookie, QStringList()); +} diff --git a/daemon/watchconnector.h b/daemon/watchconnector.h new file mode 100644 index 0000000..493856b --- /dev/null +++ b/daemon/watchconnector.h @@ -0,0 +1,132 @@ +/* + Copyright (C) 2014 Jouni Roivas + All rights reserved. + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the authors nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef WATCHCONNECTOR_H +#define WATCHCONNECTOR_H + +#include +#include +#include +#include +#include +#include + +using namespace QtBluetooth; + +namespace watch +{ + +class WatchConnector : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString connected READ isConnected NOTIFY connectedChanged) +public: + enum { + watchTIME = 11, + watchVERSION = 16, + watchPHONE_VERSION = 17, + watchSYSTEM_MESSAGE = 18, + watchMUSIC_CONTROL = 32, + watchPHONE_CONTROL = 33, + watchAPPLICATION_MESSAGE = 48, + watchLAUNCHER = 49, + watchLOGS = 2000, + watchPING = 2001, + watchLOG_DUMP = 2002, + watchRESET = 2003, + watchAPP = 2004, + watchAPP_LOGS = 2006, + watchNOTIFICATION = 3000, + watchRESOURCE = 4000, + watchAPP_MANAGER = 6000, + watchSCREENSHOT = 8000, + watchPUTBYTES = 48879 + }; + enum { + callANSWER = 1, + callHANGUP = 2, + callGET_STATE = 3, + callINCOMING = 4, + callOUTGOING = 5, + callMISSED = 6, + callRING = 7, + callSTART = 8, + callEND = 9 + }; + explicit WatchConnector(QObject *parent = 0); + virtual ~WatchConnector(); + bool isConnected() const { return is_connected; } + QString name() const { if (socket != nullptr) return socket->peerName(); return ""; } + + QString timeStamp(); + QString decodeEndpoint(unsigned int val); + +signals: + void messageReceived(QString peer, QString msg); + void nameChanged(); + void connectedChanged(); + void hangup(); + +public slots: + void sendData(const QByteArray &data); + void sendMessage(unsigned int endpoint, QByteArray data); + void ping(unsigned int val); + void sendNotification(unsigned int lead, QString sender, QString data, QString subject); + void sendSMSNotification(QString sender, QString data); + void sendEmailNotification(QString sender, QString data, QString subject); + + void buildData(QByteArray &res, QStringList data); + QByteArray buildMessageData(unsigned int lead, QStringList data); + + void phoneControl(char act, unsigned int cookie, QStringList datas); + void ring(QString number, QString name, bool incoming=true, unsigned int cookie=0); + void startPhoneCall(unsigned int cookie=0); + void endPhoneCall(unsigned int cookie=0); + + void deviceConnect(const QString &name, const QString &address); + void deviceDiscovered(const QBluetoothDeviceInfo&); + void handleWatch(const QString &name, const QString &address); + void onReadSocket(); + void onConnected(); + void onDisconnected(); + void onError(QBluetoothSocket::SocketError error); + void reconnect(); + +private: + void decodeMsg(QByteArray data); + + QPointer socket; + bool is_connected; + QString _last_name; + QString _last_address; +}; +} + +#endif // WATCHCONNECTOR_H diff --git a/lib/lib.pro b/lib/lib.pro deleted file mode 100644 index d9e24db..0000000 --- a/lib/lib.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = lib -TARGET = pebble - -HEADERS += \ - watchconnector.h - -SOURCES += \ - watchconnector.cpp - -QT += bluetooth -QMAKE_CXXFLAGS += -std=c++0x - -INSTALLS += target -target.path = /usr/lib diff --git a/lib/watchconnector.cpp b/lib/watchconnector.cpp deleted file mode 100644 index 18d287e..0000000 --- a/lib/watchconnector.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include "watchconnector.h" -#include -#include - -using namespace watch; - -static int __reconnect_timeout = 5000; //ms - -WatchConnector::WatchConnector(QObject *parent) : - QObject(parent), socket(nullptr), is_connected(false) -{} - -WatchConnector::~WatchConnector() -{ -} - -void WatchConnector::deviceDiscovered(const QBluetoothDeviceInfo &device) -{ - //FIXME TODO: Configurable - if (device.name().startsWith("Pebble")) { - qDebug() << "Found Pebble:" << device.name() << '(' << device.address().toString() << ')'; - handleWatch(device.name(), device.address().toString()); - } else { - qDebug() << "Found other device:" << device.name() << '(' << device.address().toString() << ')'; - } -} - -void WatchConnector::deviceConnect(const QString &name, const QString &address) -{ - if (name.startsWith("Pebble")) handleWatch(name, address); -} - -void WatchConnector::reconnect() -{ - qDebug() << "reconnect" << _last_name; - if (!_last_name.isEmpty() && !_last_address.isEmpty()) { - deviceConnect(_last_name, _last_address); - } -} - -void WatchConnector::handleWatch(const QString &name, const QString &address) -{ - qDebug() << "handleWatch" << name << address; - if (socket != nullptr && socket->isOpen()) { - socket->close(); - socket->deleteLater(); - } - - bool emit_name = (_last_name != name); - _last_name = name; - _last_address = address; - if (emit_name) emit nameChanged(); - - qDebug() << "Creating socket"; - socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket); - - connect(socket, SIGNAL(readyRead()), SLOT(onReadSocket())); - connect(socket, SIGNAL(connected()), SLOT(onConnected())); - connect(socket, SIGNAL(disconnected()), SLOT(onDisconnected())); - connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(onError(QBluetoothSocket::SocketError))); - - // FIXME: Assuming port 1 (with Pebble) - socket->connectToService(QBluetoothAddress(address), QBluetoothUuid(QBluetoothUuid::SerialPort)); -} - -QString WatchConnector::decodeEndpoint(unsigned int val) -{ - //FIXME: Create a map of these values - switch(val) { - case watchTIME: - return "TIME"; - case watchVERSION: - return "VERSION"; - case watchPHONE_VERSION: - return "PHONE_VERSION"; - case watchSYSTEM_MESSAGE: - return "SYSTEM_MESSAGE"; - case watchMUSIC_CONTROL: - return "MUSIC_CONTROL"; - case watchPHONE_CONTROL: - return "PHONE_CONTROL"; - case watchAPPLICATION_MESSAGE: - return "APP_MSG"; - case watchLAUNCHER: - return "LAUNCHER"; - case watchLOGS: - return "LOGS"; - case watchPING: - return "PING"; - case watchLOG_DUMP: - return "DUMP"; - case watchRESET: - return "RESET"; - case watchAPP: - return "APP"; - case watchAPP_LOGS: - return "APP_LOGS"; - case watchNOTIFICATION: - return "NOTIFICATION"; - case watchRESOURCE: - return "RESOURCE"; - case watchAPP_MANAGER: - return "APP_MANAG"; - case watchSCREENSHOT: - return "SCREENSHOT"; - case watchPUTBYTES: - return "PUTBYTES"; - default: - return "Unknown: "+ QString::number(val); - } -} - -void WatchConnector::decodeMsg(QByteArray data) -{ - unsigned int datalen = 0; - int index = 0; - datalen = (data.at(index) << 8) + data.at(index+1); - index += 2; - - unsigned int endpoint = 0; - endpoint = (data.at(index) << 8) + data.at(index+1); - index += 2; - - qDebug() << "Length:" << datalen << " Endpoint:" << decodeEndpoint(endpoint); - qDebug() << "Data:" << data.mid(index).toHex(); - if (endpoint == watchPHONE_CONTROL) { - if (data.length() >= 5) { - if (data.at(4) == callHANGUP) { - emit hangup(); - } - } - } -} - -void WatchConnector::onReadSocket() -{ - qDebug() << "read"; - - QBluetoothSocket *socket = qobject_cast(sender()); - if (!socket) return; - - while (socket->bytesAvailable()) { - QByteArray line = socket->readAll(); - emit messageReceived(socket->peerName(), QString::fromUtf8(line.constData(), line.length())); - decodeMsg(line); - } -} - -void WatchConnector::onConnected() -{ - qDebug() << "Connected!"; - bool was_connected = is_connected; - is_connected = true; - if (not was_connected) emit connectedChanged(); -} - -void WatchConnector::onDisconnected() -{ - qDebug() << "Disconnected!"; - - bool was_connected = is_connected; - is_connected = false; - - QBluetoothSocket *socket = qobject_cast(sender()); - if (!socket) return; - - if (was_connected) emit connectedChanged(); - - socket->deleteLater(); - - // Try to connect again after a timeout - QTimer::singleShot(__reconnect_timeout, this, SLOT(reconnect())); -} - -void WatchConnector::onError(QBluetoothSocket::SocketError error) { - qWarning() << "Error connecting Pebble" << error << socket->errorString(); -} - -void WatchConnector::sendData(const QByteArray &data) -{ - if (socket == nullptr) return; - - socket->write(data); -} - -void WatchConnector::sendMessage(unsigned int endpoint, QByteArray data) -{ - qDebug() << "Sending message"; - QByteArray msg; - - // First send the length - msg.append((data.length() & 0xFF00) >> 8); - msg.append(data.length() & 0xFF); - - // Then the endpoint - msg.append((endpoint & 0xFF00) >> 8); - msg.append(endpoint & 0xFF); - - // Finally the data - msg.append(data); - - sendData(msg); -} - -void WatchConnector::buildData(QByteArray &res, QStringList data) -{ - for (QString d : data) - { - QByteArray tmp = d.left(0xF0).toUtf8(); - res.append(tmp.length() & 0xFF); - res.append(tmp); - } -} - -QByteArray WatchConnector::buildMessageData(unsigned int lead, QStringList data) -{ - QByteArray res; - res.append(lead & 0xFF); - buildData(res, data); - - return res; -} - -void WatchConnector::ping(unsigned int val) -{ - QByteArray res; - res.append((char)0); - - res.append((char)((val >> 24) & 0xff)); - res.append((char)((val >> 16) & 0xff)); - res.append((char)((val >> 8) & 0xff)); - res.append((char)(val & 0xff)); - - sendMessage(watchPING, res); -} - -QString WatchConnector::timeStamp() -{ - return QString::number(QDateTime::currentMSecsSinceEpoch()); -} - -void WatchConnector::sendNotification(unsigned int lead, QString sender, QString data, QString subject) -{ - QStringList tmp; - tmp.append(sender); - tmp.append(data); - tmp.append(timeStamp()); - if (lead == 0) tmp.append(subject); - - QByteArray res = buildMessageData(lead, tmp); - - sendMessage(watchNOTIFICATION, res); -} - -void WatchConnector::sendSMSNotification(QString sender, QString data) -{ - sendNotification(1, sender, data, ""); -} - -void WatchConnector::sendEmailNotification(QString sender, QString data, QString subject) -{ - sendNotification(0, sender, data, subject); -} - -void WatchConnector::phoneControl(char act, unsigned int cookie, QStringList datas) -{ - QByteArray head; - head.append((char)act); - head.append((cookie >> 24)& 0xFF); - head.append((cookie >> 16)& 0xFF); - head.append((cookie >> 8)& 0xFF); - head.append(cookie & 0xFF); - if (datas.length()>0) buildData(head, datas); - - sendMessage(watchPHONE_CONTROL, head); -} - -void WatchConnector::ring(QString number, QString name, bool incoming, unsigned int cookie) -{ - QStringList tmp; - tmp.append(number); - tmp.append(name); - - char act = callINCOMING; - if (!incoming) { - act = callOUTGOING; - } - - phoneControl(act, cookie, tmp); -} - -void WatchConnector::startPhoneCall(unsigned int cookie) -{ - phoneControl(callSTART, cookie, QStringList()); -} - -void WatchConnector::endPhoneCall(unsigned int cookie) -{ - phoneControl(callEND, cookie, QStringList()); -} diff --git a/lib/watchconnector.h b/lib/watchconnector.h deleted file mode 100644 index 493856b..0000000 --- a/lib/watchconnector.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright (C) 2014 Jouni Roivas - All rights reserved. - - You may use this file under the terms of BSD license as follows: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the authors nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef WATCHCONNECTOR_H -#define WATCHCONNECTOR_H - -#include -#include -#include -#include -#include -#include - -using namespace QtBluetooth; - -namespace watch -{ - -class WatchConnector : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString name READ name NOTIFY nameChanged) - Q_PROPERTY(QString connected READ isConnected NOTIFY connectedChanged) -public: - enum { - watchTIME = 11, - watchVERSION = 16, - watchPHONE_VERSION = 17, - watchSYSTEM_MESSAGE = 18, - watchMUSIC_CONTROL = 32, - watchPHONE_CONTROL = 33, - watchAPPLICATION_MESSAGE = 48, - watchLAUNCHER = 49, - watchLOGS = 2000, - watchPING = 2001, - watchLOG_DUMP = 2002, - watchRESET = 2003, - watchAPP = 2004, - watchAPP_LOGS = 2006, - watchNOTIFICATION = 3000, - watchRESOURCE = 4000, - watchAPP_MANAGER = 6000, - watchSCREENSHOT = 8000, - watchPUTBYTES = 48879 - }; - enum { - callANSWER = 1, - callHANGUP = 2, - callGET_STATE = 3, - callINCOMING = 4, - callOUTGOING = 5, - callMISSED = 6, - callRING = 7, - callSTART = 8, - callEND = 9 - }; - explicit WatchConnector(QObject *parent = 0); - virtual ~WatchConnector(); - bool isConnected() const { return is_connected; } - QString name() const { if (socket != nullptr) return socket->peerName(); return ""; } - - QString timeStamp(); - QString decodeEndpoint(unsigned int val); - -signals: - void messageReceived(QString peer, QString msg); - void nameChanged(); - void connectedChanged(); - void hangup(); - -public slots: - void sendData(const QByteArray &data); - void sendMessage(unsigned int endpoint, QByteArray data); - void ping(unsigned int val); - void sendNotification(unsigned int lead, QString sender, QString data, QString subject); - void sendSMSNotification(QString sender, QString data); - void sendEmailNotification(QString sender, QString data, QString subject); - - void buildData(QByteArray &res, QStringList data); - QByteArray buildMessageData(unsigned int lead, QStringList data); - - void phoneControl(char act, unsigned int cookie, QStringList datas); - void ring(QString number, QString name, bool incoming=true, unsigned int cookie=0); - void startPhoneCall(unsigned int cookie=0); - void endPhoneCall(unsigned int cookie=0); - - void deviceConnect(const QString &name, const QString &address); - void deviceDiscovered(const QBluetoothDeviceInfo&); - void handleWatch(const QString &name, const QString &address); - void onReadSocket(); - void onConnected(); - void onDisconnected(); - void onError(QBluetoothSocket::SocketError error); - void reconnect(); - -private: - void decodeMsg(QByteArray data); - - QPointer socket; - bool is_connected; - QString _last_name; - QString _last_address; -}; -} - -#endif // WATCHCONNECTOR_H diff --git a/pebble.pro b/pebble.pro index 2143349..2dec8f8 100644 --- a/pebble.pro +++ b/pebble.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = lib daemon app +SUBDIRS = daemon app OTHER_FILES += \ rpm/pebble.spec \ rpm/pebble.yaml -- cgit v1.2.3