From 1cd1d83ee243db6f3ee929de1346c8e385b2148f Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 28 Mar 2015 21:06:07 +0100 Subject: implement fms file transfer (via bt obex push) --- rpm/saltoq.spec | 75 +++++++++++ rpm/saltoq.yaml | 3 + saltoqd/fmsmanager.cpp | 157 ++++++++++++++++++++++ saltoqd/fmsmanager.h | 48 +++++++ saltoqd/obexconnection.cpp | 320 +++++++++++++++++++++++++++++++++++++++++++++ saltoqd/obexconnection.h | 83 ++++++++++++ saltoqd/saltoqd.pro | 12 +- saltoqd/toqconnection.cpp | 36 ++--- saltoqd/toqconnection.h | 18 ++- saltoqd/toqmanager.cpp | 17 ++- saltoqd/toqmanager.h | 19 ++- saltoqd/weathermanager.cpp | 18 +++ saltoqd/weathermanager.h | 20 +++ 13 files changed, 799 insertions(+), 27 deletions(-) create mode 100644 rpm/saltoq.spec create mode 100644 saltoqd/fmsmanager.cpp create mode 100644 saltoqd/fmsmanager.h create mode 100644 saltoqd/obexconnection.cpp create mode 100644 saltoqd/obexconnection.h create mode 100644 saltoqd/weathermanager.cpp create mode 100644 saltoqd/weathermanager.h 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 +#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 _files; + QSet _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 +#include +#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(unicode.constData()); + OBEX_ObjectAddHeader(_obex, obj, OBEX_HDR_NAME, hd, unicode.size(), + OBEX_FL_FIT_ONE_PACKET); + + hd.bs = reinterpret_cast(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(buffer), read); + if (rc < 0) { + qWarning() << "Could not feed data to OBEX"; + } + } +} + +void ObexConnection::handleTransferDestroyed() +{ + ObexTransfer *transfer = static_cast(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(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(data); + Q_UNUSED(handle); + return socket->write(reinterpret_cast(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 +#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 _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 #include #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 _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 -- cgit v1.2.3