summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2015-03-28 21:06:07 +0100
committerJavier <dev.git@javispedro.com>2015-03-28 21:06:07 +0100
commit1cd1d83ee243db6f3ee929de1346c8e385b2148f (patch)
tree6943fe89c2d64e262ee0114378f8700ff8ae2c08
parent08d36eb82a9cc7ef9cc3efe40f26e1a732c8c602 (diff)
downloadsaltoq-1cd1d83ee243db6f3ee929de1346c8e385b2148f.tar.gz
saltoq-1cd1d83ee243db6f3ee929de1346c8e385b2148f.zip
implement fms file transfer (via bt obex push)
-rw-r--r--rpm/saltoq.spec75
-rw-r--r--rpm/saltoq.yaml3
-rw-r--r--saltoqd/fmsmanager.cpp157
-rw-r--r--saltoqd/fmsmanager.h48
-rw-r--r--saltoqd/obexconnection.cpp320
-rw-r--r--saltoqd/obexconnection.h83
-rw-r--r--saltoqd/saltoqd.pro12
-rw-r--r--saltoqd/toqconnection.cpp36
-rw-r--r--saltoqd/toqconnection.h18
-rw-r--r--saltoqd/toqmanager.cpp17
-rw-r--r--saltoqd/toqmanager.h19
-rw-r--r--saltoqd/weathermanager.cpp18
-rw-r--r--saltoqd/weathermanager.h20
13 files changed, 799 insertions, 27 deletions
diff --git a/rpm/saltoq.spec b/rpm/saltoq.spec
new file mode 100644
index 0000000..db39c0c
--- /dev/null
+++ b/rpm/saltoq.spec
@@ -0,0 +1,75 @@
+#
+# Do NOT Edit the Auto-generated Part!
+# Generated by: spectacle version 0.27
+#
+
+Name: saltoq
+
+# >> macros
+# << macros
+
+%{!?qtc_qmake:%define qtc_qmake %qmake}
+%{!?qtc_qmake5:%define qtc_qmake5 %qmake5}
+%{!?qtc_make:%define qtc_make make}
+%{?qtc_builddir:%define _builddir %qtc_builddir}
+Summary: Qualcomm Toq manager application
+Version: 0.0.1
+Release: 1
+Group: Communications/Bluetooth
+License: GPLv3
+URL: https://gitorious.org/javispedro-jolla-misc/salmeta/
+Source0: %{name}-%{version}.tar.bz2
+Source100: saltoq.yaml
+Requires: sailfishsilica-qt5 >= 0.10.9
+Requires: sailfish-components-bluetooth-qt5
+Requires: nemo-qml-plugin-configuration-qt5
+Requires: systemd
+Requires: systemd-user-session-targets
+BuildRequires: pkgconfig(sailfishapp) >= 1.0.2
+BuildRequires: pkgconfig(Qt5Core) >= 5.2
+BuildRequires: pkgconfig(Qt5Qml)
+BuildRequires: pkgconfig(Qt5Quick)
+BuildRequires: pkgconfig(Qt5DBus)
+BuildRequires: pkgconfig(Qt5Bluetooth) >= 5.2
+BuildRequires: pkgconfig(mlite5)
+BuildRequires: pkgconfig(libiphb)
+BuildRequires: pkgconfig(zlib)
+BuildRequires: pkgconfig(commhistory-qt5)
+BuildRequires: pkgconfig(openobex)
+BuildRequires: qt5-qtconnectivity-qtbluetooth-devel
+
+%description
+Qualcomm Toq.
+
+
+%prep
+%setup -q -n %{name}-%{version}
+
+# >> setup
+# << setup
+
+%build
+# >> build pre
+# << build pre
+
+%qtc_qmake5
+
+%qtc_make %{?_smp_mflags}
+
+# >> build post
+# << build post
+
+%install
+rm -rf %{buildroot}
+# >> install pre
+# << install pre
+%qmake5_install
+
+# >> install post
+# << install post
+
+%files
+%defattr(-,root,root,-)
+%{_bindir}
+# >> files
+# << files
diff --git a/rpm/saltoq.yaml b/rpm/saltoq.yaml
index a90944b..8d90119 100644
--- a/rpm/saltoq.yaml
+++ b/rpm/saltoq.yaml
@@ -21,6 +21,9 @@ PkgConfigBR:
- Qt5Bluetooth >= 5.2
- mlite5
- libiphb
+ - zlib
+ - commhistory-qt5
+ - openobex
PkgBR:
# Workaround current sailfish qt5connectivity packaging bug
diff --git a/saltoqd/fmsmanager.cpp b/saltoqd/fmsmanager.cpp
new file mode 100644
index 0000000..26e147b
--- /dev/null
+++ b/saltoqd/fmsmanager.cpp
@@ -0,0 +1,157 @@
+#include "obexconnection.h"
+#include "fmsmanager.h"
+
+static QString generate_send_name(const QString &path, int transactionId, int checksum)
+{
+ Q_UNUSED(checksum);
+ int slash = path.lastIndexOf('/');
+ int dot = path.lastIndexOf('.');
+
+ int start = slash >= 0 ? slash + 1 : 0;
+ int len = dot > start ? (path.length() - 1) - (dot + 1) : -1;
+
+ QString base = path.mid(start, len);
+ QString ext;
+
+ if (len != -1) {
+ ext = path.mid(dot + 1);
+ }
+
+ return QString("%1_%2.%3").arg(base).arg(transactionId).arg(ext);
+}
+
+FmsManager::FmsManager(ObexConnection *obex, ToqManager *toq) :
+ QObject(toq), _obex(obex), _toq(toq),
+ _curTransfer(0)
+{
+ connect(_toq, &ToqManager::disconnected,
+ this, &FmsManager::handleToqDisconnected);
+ connect(_obex, &ObexConnection::connected,
+ this, &FmsManager::handleObexConnected);
+ connect(_obex, &ObexConnection::disconnected,
+ this, &FmsManager::handleObexDisconnected);
+
+ _toq->setEndpointListener(ToqConnection::FMSEndpoint, this);
+}
+
+void FmsManager::handleMessage(const ToqConnection::Message &msg)
+{
+ Q_ASSERT(msg.destination == ToqConnection::FMSEndpoint);
+ switch (msg.type) {
+ case 0x4001: // Reply to file transfer
+ handleTransferResult(msg.payload.object());
+ break;
+ default:
+ qWarning() << "Unknown message type" << msg.type;
+ break;
+ }
+}
+
+void FmsManager::updateFile(const QString &path, const QByteArray &contents)
+{
+ File& file = _files[path];
+ quint32 checksum = ToqConnection::checksum(contents);
+ file.mtime = QDateTime::currentDateTimeUtc();
+ if (checksum != file.checksum) {
+ file.contents = contents;
+ file.checksum = checksum;
+ _pending.insert(path);
+ handleQueue();
+ }
+}
+
+void FmsManager::deleteFile(const QString &path)
+{
+ if (_files.contains(path)) {
+ _files.remove(path);
+ _pending.insert(path);
+ handleQueue();
+ }
+}
+
+void FmsManager::handleTransferResult(const QJsonObject &msg)
+{
+ if (msg["transaction_id"].toInt() != _curTransferTransactionId) {
+ qWarning() << "Received a result for an invalid transaction id";
+ return;
+ }
+
+ int result = msg["result"].toInt();
+ if (result != 0) {
+ qWarning() << "FMS transfer file failed with result" << result;
+ }
+
+ cleanCurTransfer();
+ handleQueue();
+}
+
+void FmsManager::handleQueue()
+{
+ if (_pending.isEmpty()) return;
+ if (_curTransfer) return;
+ if (!_obex->isConnected()) return;
+
+ QString path = *_pending.begin();
+ _pending.remove(path);
+
+ if (_files.contains(path)) {
+ File &file = _files[path];
+ int transactionId = _toq->newTransactionId();
+ QString name = generate_send_name(path, transactionId, file.checksum);
+
+ QJsonObject obj;
+ obj.insert("sent_file_name", name);
+ obj.insert("file_path", path);
+ obj.insert("transaction_id", transactionId);
+ obj.insert("checksum", qint64(file.checksum));
+
+ _toq->sendMessage(ToqConnection::FMSEndpoint, ToqConnection::FMSEndpoint + 1,
+ transactionId, 1, obj);
+
+ _curTransfer = _obex->put(name, file.contents);
+ _curTransferTransactionId = transactionId;
+ _curTransferPath = path;
+
+ connect(_curTransfer, &ObexTransfer::error,
+ this, &FmsManager::handleObexError);
+ } else {
+ // TODO Remove files!
+ }
+}
+
+void FmsManager::handleToqDisconnected()
+{
+ _pending.clear();
+ if (_curTransfer) {
+ _curTransfer->cancel();
+ cleanCurTransfer();
+ }
+}
+
+void FmsManager::handleObexConnected()
+{
+ handleQueue();
+}
+
+void FmsManager::handleObexDisconnected()
+{
+ // Assume it's temporary and that we will eventually reconnect
+}
+
+void FmsManager::handleObexError(int response)
+{
+ Q_ASSERT(_curTransfer == sender());
+ Q_UNUSED(response);
+ qWarning() << "OBEX error while uploading" << _curTransferPath;
+ cleanCurTransfer();
+}
+
+void FmsManager::cleanCurTransfer()
+{
+ if (_curTransfer) {
+ _curTransfer->deleteLater();
+ _curTransfer = 0;
+ _curTransferTransactionId = 0;
+ _curTransferPath.clear();
+ }
+}
diff --git a/saltoqd/fmsmanager.h b/saltoqd/fmsmanager.h
new file mode 100644
index 0000000..3d2ab90
--- /dev/null
+++ b/saltoqd/fmsmanager.h
@@ -0,0 +1,48 @@
+#ifndef FMSMANAGER_H
+#define FMSMANAGER_H
+
+#include <QtCore/QDateTime>
+#include "toqmanager.h"
+
+class ObexTransfer;
+
+class FmsManager : public QObject, public ToqManager::EndpointHandler
+{
+ Q_OBJECT
+public:
+ explicit FmsManager(ObexConnection *obex, ToqManager *toq);
+
+ void handleMessage(const ToqConnection::Message &msg) Q_DECL_OVERRIDE;
+
+ void updateFile(const QString &path, const QByteArray &contents);
+ void deleteFile(const QString &path);
+
+private:
+ void handleTransferResult(const QJsonObject &msg);
+
+private slots:
+ void handleQueue();
+ void handleToqDisconnected();
+ void handleObexConnected();
+ void handleObexDisconnected();
+ void handleObexError(int response);
+ void cleanCurTransfer();
+
+private:
+ struct File {
+ QDateTime mtime;
+ QByteArray contents;
+ quint32 checksum;
+ };
+
+private:
+ ObexConnection *_obex;
+ ToqManager *_toq;
+ QMap<QString, File> _files;
+ QSet<QString> _pending;
+ ObexTransfer *_curTransfer;
+ int _curTransferTransactionId;
+ QString _curTransferPath;
+};
+
+#endif // FMSMANAGER_H
diff --git a/saltoqd/obexconnection.cpp b/saltoqd/obexconnection.cpp
new file mode 100644
index 0000000..28aa4e2
--- /dev/null
+++ b/saltoqd/obexconnection.cpp
@@ -0,0 +1,320 @@
+#include <QtCore/QTextCodec>
+#include <openobex/obex.h>
+#include "obexconnection.h"
+
+ObexTransfer::ObexTransfer(obex_t *obex, obex_object_t *obj, QObject *parent) :
+ QObject(parent), _obex(obex), _obj(obj)
+{
+}
+
+ObexTransfer::~ObexTransfer()
+{
+ if (_obj) {
+ OBEX_ObjectDelete(_obex, _obj);
+ }
+}
+
+void ObexTransfer::cancel()
+{
+ // TODO
+}
+
+ObexConnection::ObexConnection(ToqConnection *conn, QObject *parent) :
+ QObject(parent), _conn(conn),
+ _reconnectTimer(new QTimer(this)),
+ _obex(0), _connected(false), _busy(false)
+{
+ connect(_conn, &ToqConnection::connected,
+ this, &ObexConnection::handleToqConnected);
+ connect(_conn, &ToqConnection::disconnected,
+ this, &ObexConnection::handleToqDisconnected);
+
+ connect(_reconnectTimer, &QTimer::timeout,
+ this, &ObexConnection::tryConnect);
+
+ _reconnectTimer->setSingleShot(true);
+ _reconnectTimer->setInterval(500);
+
+ if (_conn->isConnected()) {
+ _reconnectTimer->start();
+ }
+}
+
+ObexTransfer * ObexConnection::put(const QString &name, const QByteArray &data)
+{
+ obex_object_t *obj = OBEX_ObjectNew(_obex, OBEX_CMD_PUT);
+ obex_headerdata_t hd;
+ hd.bq4 = data.size();
+ OBEX_ObjectAddHeader(_obex, obj, OBEX_HDR_LENGTH, hd, 4,
+ OBEX_FL_FIT_ONE_PACKET);
+
+ QTextCodec *codec = QTextCodec::codecForName("UTF-16BE");
+ QByteArray unicode = codec->fromUnicode(name);
+ unicode.append("\0\0", 2); // Require null terminator
+ hd.bs = reinterpret_cast<const uint8_t *>(unicode.constData());
+ OBEX_ObjectAddHeader(_obex, obj, OBEX_HDR_NAME, hd, unicode.size(),
+ OBEX_FL_FIT_ONE_PACKET);
+
+ hd.bs = reinterpret_cast<const uint8_t *>(data.constData());
+ OBEX_ObjectAddHeader(_obex, obj, OBEX_HDR_BODY, hd, data.size(), 0);
+
+ ObexTransfer *transfer = new ObexTransfer(_obex, obj, this);
+ connect(transfer, &ObexTransfer::destroyed,
+ this, &ObexConnection::handleTransferDestroyed);
+
+ _pending.push_back(transfer);
+
+ handleNextPending();
+
+ return transfer;
+}
+
+void ObexConnection::tryConnect()
+{
+ Q_ASSERT(!_socket);
+ Q_ASSERT(_conn->isConnected());
+
+ qDebug() << "Trying to connect";
+
+ _socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
+ connect(_socket, &QBluetoothSocket::connected,
+ this, &ObexConnection::handleSocketConnected);
+ connect(_socket, &QBluetoothSocket::disconnected,
+ this, &ObexConnection::handleSocketDisconnected);
+ connect(_socket, (void (QBluetoothSocket::*)(QBluetoothSocket::SocketError))&QBluetoothSocket::error,
+ this, &ObexConnection::handleSocketError);
+ connect(_socket, &QBluetoothSocket::readyRead,
+ this, &ObexConnection::handleSocketData);
+
+ _socket->connectToService(_conn->address(), 4);
+}
+
+void ObexConnection::handleToqConnected()
+{
+ tryConnect();
+}
+
+void ObexConnection::handleToqDisconnected()
+{
+ _reconnectTimer->stop();
+ if (_obex) {
+ OBEX_Cleanup(_obex);
+ _obex = 0;
+ }
+ if (_socket) {
+ _socket->disconnectFromService();
+ if (_socket) {
+ _socket->deleteLater();
+ _socket = 0;
+ }
+ }
+ _connected = false;
+ _busy = false;
+}
+
+void ObexConnection::handleSocketConnected()
+{
+ qDebug() << "OPP connected";
+
+ _obex = OBEX_Init(OBEX_TRANS_CUSTOM, handleObexEvent, 0);
+ if (!_obex) {
+ qWarning() << "Could not initialize OBEX library";
+ // If we fail to connect, the watch will eventually disconnect from us.
+ // So there's no need to do anything.
+ return;
+ }
+
+ OBEX_SetUserData(_obex, this);
+ OBEX_SetTransportMTU(_obex, OBEX_MAXIMUM_MTU, OBEX_MAXIMUM_MTU);
+
+ obex_ctrans_t trans;
+ trans.connect = obexConnect;
+ trans.disconnect = obexDisconnect;
+ trans.listen = obexListen;
+ trans.write = obexWrite;
+ trans.handleinput = obexHandleInput;
+ trans.customdata = _socket;
+ int rc = OBEX_RegisterCTransport(_obex, &trans);
+ if (rc < 0) {
+ qWarning() << "Could not initialize custom OBEX transport";
+ return;
+ }
+
+ obex_object_t *obj = OBEX_ObjectNew(_obex, OBEX_CMD_CONNECT);
+ Q_ASSERT(obj);
+
+ if (OBEX_Request(_obex, obj) < 0) {
+ qWarning() << "Could not send OBEX_CMD_CONNECT";
+ return;
+ }
+
+ _busy = true; // We're waiting for CONNECT result
+}
+
+void ObexConnection::handleSocketDisconnected()
+{
+ qDebug() << "OPP disconnected";
+ if (_obex) {
+ OBEX_Cleanup(_obex);
+ _obex = 0;
+ }
+ if (_socket) {
+ _socket->deleteLater();
+ _socket = 0;
+ }
+ emit disconnected();
+ if (_conn->isConnected()) {
+ qDebug() << "OPP socket died but main socket still alive, retrying connection";
+ _reconnectTimer->start();
+ }
+ _connected = false;
+ _busy = false;
+}
+
+void ObexConnection::handleSocketError(QBluetoothSocket::SocketError error)
+{
+ qWarning() << "OPP socket error" << error;
+}
+
+void ObexConnection::handleSocketData()
+{
+ static char buffer[4096];
+ while (_socket->bytesAvailable() > 0) {
+ qint64 read = _socket->read(buffer, sizeof(buffer));
+ int rc = OBEX_CustomDataFeed(_obex, reinterpret_cast<uint8_t*>(buffer), read);
+ if (rc < 0) {
+ qWarning() << "Could not feed data to OBEX";
+ }
+ }
+}
+
+void ObexConnection::handleTransferDestroyed()
+{
+ ObexTransfer *transfer = static_cast<ObexTransfer*>(sender());
+ _pending.removeAll(transfer);
+}
+
+void ObexConnection::handleNextPending()
+{
+ if (!_connected) return;
+ if (_busy) return;
+ if (_pending.empty()) return;
+
+ ObexTransfer *transfer = _pending.head();
+ int rc = OBEX_Request(_obex, transfer->_obj);
+ if (rc < 0) {
+ qWarning() << "Failed to perform request";
+ _socket->disconnectFromService();
+ _pending.dequeue();
+ } else {
+ qDebug() << "Request performed";
+ _busy = true;
+ }
+}
+
+void ObexConnection::handleObexEvent(obex_t *handle, obex_object_t *obj, int mode, int event, int obex_cmd, int obex_rsp)
+{
+ ObexConnection *self = static_cast<ObexConnection*>(OBEX_GetUserData(handle));
+ ObexTransfer *transfer;
+
+ Q_UNUSED(mode);
+
+ qDebug() << "OBEX event" << event << obex_cmd << obex_rsp;
+
+ switch (event) {
+ case OBEX_EV_PROGRESS:
+ qDebug() << "Progress";
+ break;
+ case OBEX_EV_REQDONE:
+ if (!self->_busy) {
+ qWarning() << "Response was requested, but we were not expecting anything";
+ }
+
+ switch (obex_cmd) {
+ case OBEX_CMD_CONNECT:
+ switch (obex_rsp) {
+ case OBEX_RSP_SUCCESS:
+ qDebug() << "OPP OBEX connected";
+ self->_connected = true;
+ self->_busy = false;
+ emit self->connected();
+ self->handleNextPending();
+ break;
+ default:
+ qWarning() << "OPP OBEX failed to connect:" << OBEX_ResponseToString(obex_rsp);
+ self->_socket->disconnectFromService();
+ break;
+ }
+
+ break;
+ case OBEX_CMD_PUT:
+ case OBEX_CMD_GET:
+ Q_ASSERT(!self->_pending.isEmpty());
+ transfer = self->_pending.dequeue();
+ self->disconnect(transfer, nullptr, self, nullptr);
+
+ if (transfer->_obj != obj) {
+ qWarning() << "Got result for a request we did not make";
+ self->_socket->disconnectFromService();
+ return;
+ }
+
+ switch (obex_rsp) {
+ case OBEX_RSP_SUCCESS:
+ qDebug() << "OPP OBEX transfer success";
+ emit transfer->finished();
+ break;
+ default:
+ qWarning() << "OPP OBEX transfer failed:" << OBEX_ResponseToString(obex_rsp);
+ emit transfer->error(obex_rsp);
+ break;
+ }
+
+ self->_busy = false;
+ self->handleNextPending();
+
+ break;
+ default:
+ // Not interested
+ break;
+ }
+
+ break;
+ }
+}
+
+int ObexConnection::obexConnect(obex_t *handle, void *data)
+{
+ Q_UNUSED(handle);
+ Q_UNUSED(data);
+ return 1;
+}
+
+int ObexConnection::obexDisconnect(obex_t *handle, void *data)
+{
+ Q_UNUSED(handle);
+ Q_UNUSED(data);
+ return 1;
+}
+
+int ObexConnection::obexListen(obex_t *handle, void *data)
+{
+ Q_UNUSED(handle);
+ Q_UNUSED(data);
+ return -1; // Should never happen
+}
+
+int ObexConnection::obexWrite(obex_t *handle, void *data, quint8 *buf, int buflen)
+{
+ QBluetoothSocket *socket = static_cast<QBluetoothSocket*>(data);
+ Q_UNUSED(handle);
+ return socket->write(reinterpret_cast<char*>(buf), buflen);
+}
+
+int ObexConnection::obexHandleInput(obex_t *handle, void *data, int timeout)
+{
+ Q_UNUSED(handle);
+ Q_UNUSED(data);
+ Q_UNUSED(timeout);
+ return 1;
+}
diff --git a/saltoqd/obexconnection.h b/saltoqd/obexconnection.h
new file mode 100644
index 0000000..431af9b
--- /dev/null
+++ b/saltoqd/obexconnection.h
@@ -0,0 +1,83 @@
+#ifndef OBEXCONNECTION_H
+#define OBEXCONNECTION_H
+
+#include <QtCore/QQueue>
+#include "toqconnection.h"
+
+typedef void* obex_t;
+typedef void* obex_object_t;
+
+class ObexConnection;
+
+class ObexTransfer : public QObject
+{
+ Q_OBJECT
+
+ friend class ObexConnection;
+
+ explicit ObexTransfer(obex_t *obex, obex_object_t *obj, QObject *parent);
+ ~ObexTransfer();
+
+public slots:
+ void cancel();
+
+signals:
+ void finished();
+ void error(int response);
+
+private:
+ obex_t *_obex;
+ obex_object_t *_obj;
+};
+
+class ObexConnection : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool connected READ isConnected)
+
+public:
+ explicit ObexConnection(ToqConnection *conn, QObject *parent = 0);
+
+ bool isConnected() const;
+
+ ObexTransfer *put(const QString &name, const QByteArray &data);
+
+signals:
+ void connected();
+ void disconnected();
+
+private slots:
+ void tryConnect();
+ void handleToqConnected();
+ void handleToqDisconnected();
+ void handleSocketConnected();
+ void handleSocketDisconnected();
+ void handleSocketError(QBluetoothSocket::SocketError error);
+ void handleSocketData();
+ void handleTransferDestroyed();
+ void handleNextPending();
+
+private:
+ static void handleObexEvent(obex_t *handle, obex_object_t *obj, int mode, int event, int obex_cmd, int obex_rsp);
+ static int obexConnect(obex_t *handle, void *data);
+ static int obexDisconnect(obex_t *handle, void *data);
+ static int obexListen(obex_t *handle, void *data);
+ static int obexWrite(obex_t *handle, void *data, quint8 *buf, int buflen);
+ static int obexHandleInput(obex_t *handle, void *data, int timeout);
+
+ ToqConnection *_conn;
+ QBluetoothSocket *_socket;
+ QTimer *_reconnectTimer;
+ obex_t *_obex;
+ bool _connected;
+
+ QQueue<ObexTransfer*> _pending;
+ bool _busy;
+};
+
+inline bool ObexConnection::isConnected() const
+{
+ return _connected;
+}
+
+#endif // OBEXCONNECTION_H
diff --git a/saltoqd/saltoqd.pro b/saltoqd/saltoqd.pro
index d0efe94..8b656ba 100644
--- a/saltoqd/saltoqd.pro
+++ b/saltoqd/saltoqd.pro
@@ -5,7 +5,7 @@ QT += dbus bluetooth
CONFIG += c++11 link_pkgconfig
-PKGCONFIG += zlib commhistory-qt5
+PKGCONFIG += zlib commhistory-qt5 openobex
INCLUDEPATH += /usr/include/commhistory-qt5
SOURCES += main.cpp \
@@ -17,7 +17,10 @@ SOURCES += main.cpp \
storagemanager.cpp \
commmanager.cpp \
notificationmanager.cpp notificationmonitor.cpp \
- voicecallmanager.cpp
+ voicecallmanager.cpp \
+ fmsmanager.cpp \
+ weathermanager.cpp \
+ obexconnection.cpp
HEADERS += \
toqconnection.h \
@@ -28,7 +31,10 @@ HEADERS += \
storagemanager.h \
commmanager.h \
notificationmanager.h notificationmonitor.h \
- voicecallmanager.h
+ voicecallmanager.h \
+ fmsmanager.h \
+ weathermanager.h \
+ obexconnection.h
DBUS_ADAPTORS += org.freedesktop.Notifications.xml
diff --git a/saltoqd/toqconnection.cpp b/saltoqd/toqconnection.cpp
index 564b7d2..9468aa8 100644
--- a/saltoqd/toqconnection.cpp
+++ b/saltoqd/toqconnection.cpp
@@ -51,12 +51,7 @@ quint32 ToqConnection::checksum(QIODevice *dev)
return crc;
}
-bool ToqConnection::isConnected() const
-{
- return _socket && _socket->state() == QBluetoothSocket::ConnectedState;
-}
-
-quint16 ToqConnection::nextTransactionId()
+quint16 ToqConnection::newTransactionId()
{
if (_lastTransactionId >= 0xFFFA) {
// The last transaction ids (as well as 0) seem to be reserved
@@ -133,7 +128,7 @@ void ToqConnection::tryConnect()
qDebug() << "Connecting to" << _address.toString();
- _socket->connectToService(_address, 1, QIODevice::ReadWrite);
+ _socket->connectToService(_address, 1);
}
void ToqConnection::handleSocketConnected()
@@ -142,23 +137,27 @@ void ToqConnection::handleSocketConnected()
Q_ASSERT(_socket);
_reconnectTimer->stop();
emit connected();
+ emit connectedChanged();
}
void ToqConnection::handleSocketDisconnected()
{
- qDebug() << "Disconnected";
- Q_ASSERT(_socket);
- _socket->deleteLater();
- _socket = 0;
- _reconnectTimer->start();
- emit disconnected();
+ if (_socket) {
+ qDebug() << "Disconnected";
+ _socket->deleteLater();
+ _socket = 0;
+ _reconnectTimer->start();
+ emit disconnected();
+ emit connectedChanged();
+ }
}
void ToqConnection::handleSocketError(QBluetoothSocket::SocketError error)
{
- Q_ASSERT(_socket);
- qWarning() << error << _socket->errorString();
- _socket->disconnectFromService();
+ if (_socket) {
+ qWarning() << error << _socket->errorString();
+ _socket->disconnectFromService();
+ }
}
void ToqConnection::handleSocketData()
@@ -188,7 +187,8 @@ void ToqConnection::handleSocketData()
// We can now safely remove the message from the input buffer,
// as we know the entire message is in the input buffer.
QByteArray data = _socket->read(HEADER_LENGTH + message_length - 4);
- emit messageReceived(unpackMessage(data));
+ Message msg = unpackMessage(data);
+ if (msg.transactionId > _lastTransactionId) _lastTransactionId = msg.transactionId;
+ emit messageReceived(msg);
}
}
-
diff --git a/saltoqd/toqconnection.h b/saltoqd/toqconnection.h
index fec20a8..0d295e2 100644
--- a/saltoqd/toqconnection.h
+++ b/saltoqd/toqconnection.h
@@ -10,7 +10,8 @@ class ToqConnection : public QObject
{
Q_OBJECT
Q_ENUMS(CoreEndpoints)
- Q_PROPERTY(bool connected READ isConnected)
+ Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged)
+ Q_PROPERTY(QBluetoothAddress address READ address CONSTANT)
public:
explicit ToqConnection(const QBluetoothAddress &address, QObject *parent = 0);
@@ -54,7 +55,9 @@ public:
static quint32 checksum(QIODevice *dev);
bool isConnected() const;
- quint16 nextTransactionId();
+ QBluetoothAddress address() const;
+
+ quint16 newTransactionId();
public slots:
void sendMessage(const Message &msg);
@@ -63,6 +66,7 @@ signals:
void connected();
void disconnected();
void messageReceived(const Message &msg);
+ void connectedChanged();
private:
Message unpackMessage(const QByteArray &data);
@@ -91,4 +95,14 @@ inline ToqConnection::Message::Message(Endpoint source, Endpoint destination, qu
{
}
+inline bool ToqConnection::isConnected() const
+{
+ return _socket && _socket->state() == QBluetoothSocket::ConnectedState;
+}
+
+inline QBluetoothAddress ToqConnection::address() const
+{
+ return _address;
+}
+
#endif // TOQCONNECTION_H
diff --git a/saltoqd/toqmanager.cpp b/saltoqd/toqmanager.cpp
index fa8f7c6..5db15c9 100644
--- a/saltoqd/toqmanager.cpp
+++ b/saltoqd/toqmanager.cpp
@@ -1,24 +1,35 @@
#include "toqmanager.h"
+#include "obexconnection.h"
+
#include "versionmanager.h"
#include "systemmanager.h"
+#include "fmsmanager.h"
#include "storagemanager.h"
#include "musicmanager.h"
#include "commmanager.h"
#include "voicecallmanager.h"
+#include "weathermanager.h"
ToqManager::ToqManager(const QBluetoothAddress &address, QObject *parent) :
QObject(parent),
_conn(new ToqConnection(address, this)),
+ _obex(new ObexConnection(_conn, this)),
_versionManager(new VersionManager(this)),
_systemManager(new SystemManager(this)),
+ _fmsManager(new FmsManager(_obex, this)),
_storageManager(new StorageManager(this)),
_musicManager(new MusicManager(this)),
_commManager(new CommManager(_storageManager, this)),
- _voiceCallManager(new VoiceCallManager(this))
+ _voiceCallManager(new VoiceCallManager(this)),
+ _weatherManager(new WeatherManager(_fmsManager, this))
{
connect(_conn, &ToqConnection::messageReceived,
this, &ToqManager::handleToqMessage);
+ connect(_conn, &ToqConnection::connected,
+ this, &ToqManager::connected);
+ connect(_conn, &ToqConnection::disconnected,
+ this, &ToqManager::disconnected);
}
void ToqManager::setEndpointListener(ToqConnection::Endpoint ep, EndpointHandler *handler)
@@ -31,7 +42,7 @@ void ToqManager::sendMessage(const ToqConnection::Message &msg)
{
if (1) {
QString json = QString::fromUtf8(msg.payload.toJson(QJsonDocument::Compact));
- qDebug() << "Sending message to" << ToqConnection::nameOfEndpoint(msg.destination) << "from" << ToqConnection::nameOfEndpoint(msg.destination) << "type" << msg.type << json;
+ qDebug() << "Sending message to" << ToqConnection::nameOfEndpoint(msg.destination) << "from" << ToqConnection::nameOfEndpoint(msg.source) << "type" << msg.type << json;
}
_conn->sendMessage(msg);
}
@@ -46,7 +57,7 @@ void ToqManager::sendMessage(ToqConnection::Endpoint source, ToqConnection::Endp
quint16 ToqManager::sendMessage(ToqConnection::Endpoint source, ToqConnection::Endpoint destination, quint32 type, const QJsonObject &payload)
{
QJsonDocument doc(payload);
- quint16 transactionId = _conn->nextTransactionId();
+ quint16 transactionId = newTransactionId();
ToqConnection::Message msg(source, destination, transactionId, type, doc);
sendMessage(msg);
return transactionId;
diff --git a/saltoqd/toqmanager.h b/saltoqd/toqmanager.h
index c1675ac..d3265a8 100644
--- a/saltoqd/toqmanager.h
+++ b/saltoqd/toqmanager.h
@@ -1,17 +1,19 @@
#ifndef TOQMANAGER_H
#define TOQMANAGER_H
-#include <functional>
#include <QtCore/QObject>
#include "toqconnection.h"
+class ObexConnection;
class VersionManager;
class SystemManager;
+class FmsManager;
class StorageManager;
class MusicManager;
class CommManager;
class VoiceCallManager;
+class WeatherManager;
class ToqManager : public QObject
{
@@ -26,6 +28,9 @@ public:
void setEndpointListener(ToqConnection::Endpoint ep, EndpointHandler *handler);
bool isConnected() const;
+
+ quint16 newTransactionId();
+
void sendMessage(const ToqConnection::Message &msg);
void sendMessage(ToqConnection::Endpoint source, ToqConnection::Endpoint destination,
quint16 transactionId, quint32 type, const QJsonObject &payload);
@@ -33,19 +38,26 @@ public:
quint32 type, const QJsonObject &payload);
void sendReply(const ToqConnection::Message &msg, quint32 type, const QJsonObject &payload);
+signals:
+ void connected();
+ void disconnected();
+
private slots:
void handleToqMessage(const ToqConnection::Message &msg);
private:
ToqConnection *_conn;
+ ObexConnection *_obex;
QHash<ToqConnection::Endpoint, EndpointHandler*> _handlers;
VersionManager *_versionManager;
SystemManager *_systemManager;
+ FmsManager *_fmsManager;
StorageManager *_storageManager;
MusicManager *_musicManager;
CommManager *_commManager;
VoiceCallManager *_voiceCallManager;
+ WeatherManager *_weatherManager;
};
inline bool ToqManager::isConnected() const
@@ -53,4 +65,9 @@ inline bool ToqManager::isConnected() const
return _conn->isConnected();
}
+inline quint16 ToqManager::newTransactionId()
+{
+ return _conn->newTransactionId();
+}
+
#endif // TOQMANAGER_H
diff --git a/saltoqd/weathermanager.cpp b/saltoqd/weathermanager.cpp
new file mode 100644
index 0000000..ce36f8c
--- /dev/null
+++ b/saltoqd/weathermanager.cpp
@@ -0,0 +1,18 @@
+#include "fmsmanager.h"
+#include "weathermanager.h"
+
+WeatherManager::WeatherManager(FmsManager *fms, ToqManager *toq) :
+ QObject(toq), _toq(toq), _fms(fms)
+{
+ connect(_toq, &ToqManager::connected,
+ this, &WeatherManager::handleToqConnected);
+}
+
+void WeatherManager::handleToqConnected()
+{
+#if 0
+ qDebug() << "Putting file";
+ QByteArray data(img_data, sizeof(img_data));
+ _fms->updateFile("/apps/weather/99.img", data);
+#endif
+}
diff --git a/saltoqd/weathermanager.h b/saltoqd/weathermanager.h
new file mode 100644
index 0000000..522f797
--- /dev/null
+++ b/saltoqd/weathermanager.h
@@ -0,0 +1,20 @@
+#ifndef WEATHERMANAGER_H
+#define WEATHERMANAGER_H
+
+#include "toqmanager.h"
+
+class WeatherManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit WeatherManager(FmsManager *fms, ToqManager *toq);
+
+private slots:
+ void handleToqConnected();
+
+private:
+ ToqManager *_toq;
+ FmsManager *_fms;
+};
+
+#endif // WEATHERMANAGER_H