diff options
| author | Jouni Roivas <jroivas@iki.fi> | 2014-01-13 21:59:34 +0200 |
|---|---|---|
| committer | Jouni Roivas <jroivas@iki.fi> | 2014-01-13 21:59:34 +0200 |
| commit | 7e4e1e0192da304ae4efecdf8724a7c3f2c2d5ee (patch) | |
| tree | bfb0eec985e83b76ed1c9b1a8949a9f36e226f6f /src | |
| parent | 6e0fd5a7c7a4749fb342bfd8b3671485bcba3159 (diff) | |
Initial import
Diffstat (limited to 'src')
| -rw-r--r-- | src/watchconnector.cpp | 283 | ||||
| -rw-r--r-- | src/watchconnector.h | 125 | ||||
| -rw-r--r-- | src/waterwatch.cpp | 44 |
3 files changed, 452 insertions, 0 deletions
diff --git a/src/watchconnector.cpp b/src/watchconnector.cpp new file mode 100644 index 0000000..55e4b80 --- /dev/null +++ b/src/watchconnector.cpp @@ -0,0 +1,283 @@ +#include "watchconnector.h" +#include <QDateTime> + +WatchConnector::WatchConnector(QObject *parent) : + QObject(parent) +{ + socket = nullptr; +} + +WatchConnector::~WatchConnector() +{ +} + +void WatchConnector::deviceDiscovered(const QBluetoothDeviceInfo &device) +{ + //FIXME: Configurable + if (device.name().startsWith("Pebble")) { + qDebug() << "Found Pebble:" << device.name() << '(' << device.address().toString() << ')'; + handleWatch(device); + } else { + qDebug() << "Found other device:" << device.name() << '(' << device.address().toString() << ')'; + } +} + +void WatchConnector::deviceConnect(const QString name, const QString address) +{ + if (name.startsWith("Pebble")) { + QBluetoothDeviceInfo device(QBluetoothAddress(address), name, 0); + deviceDiscovered(device); + } +} + +void WatchConnector::handleWatch(const QBluetoothDeviceInfo &device) +{ + qDebug() << "handleWatch" << device.name(); + if (socket != nullptr) { + socket->close(); + socket->deleteLater(); + socket = nullptr; + } + + socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket); + qDebug() << "Creating socket"; + + // FIXME: Assuming port 1 (with Pebble) + socket->connectToService(device.address(), 1); + + connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket())); + connect(socket, SIGNAL(connected()), this, SLOT(connected())); + connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); +} + +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::readSocket() +{ + qDebug() << "read"; + + QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(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::connected() +{ + qDebug() << "Connected!"; + is_connected = true; + emit nameChanged(); + emit connectedChanged(); +} + +void WatchConnector::disconnected() +{ + qDebug() << "Disconnected!"; + is_connected = false; + + QBluetoothSocket *socket = qobject_cast<QBluetoothSocket *>(sender()); + if (!socket) return; + + socket->deleteLater(); + socket = nullptr; + emit connectedChanged(); +} + +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()); +} + +void registerWatchConnector() +{ + qmlRegisterType<WatchConnector>("watch", 0, 1, "WatchConnector"); +} diff --git a/src/watchconnector.h b/src/watchconnector.h new file mode 100644 index 0000000..59ea632 --- /dev/null +++ b/src/watchconnector.h @@ -0,0 +1,125 @@ +/* + Copyright (C) 2013 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 Jolla Ltd 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 <QObject> +#include <QtQml> +#include <QStringList> +#include <QBluetoothDeviceInfo> +#include <QBluetoothSocket> +#include <QBluetoothServiceInfo> + +using namespace QtBluetooth; + +class WatchConnector : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name NOTIFY nameChanged) + Q_PROPERTY(QString isConnected 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 QBluetoothDeviceInfo&); + void readSocket(); + void connected(); + void disconnected(); + +private: + void decodeMsg(QByteArray data); + QBluetoothSocket *socket; + bool is_connected; +}; + +void registerWatchConnector(); + +#endif // WATCHCONNECTOR_H diff --git a/src/waterwatch.cpp b/src/waterwatch.cpp new file mode 100644 index 0000000..2f65cc0 --- /dev/null +++ b/src/waterwatch.cpp @@ -0,0 +1,44 @@ +/* + Copyright (C) 2013 Jouni Roivas + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl <thomas.perl@jollamobile.com> + 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 Jolla Ltd 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. +*/ + +#include <QtQuick> + +#include <sailfishapp.h> +#include "watchconnector.h" + +int main(int argc, char *argv[]) +{ + // Registert WatchController object on QML side + registerWatchConnector(); + + return SailfishApp::main(argc, argv); +} + |
