diff options
author | Javier <dev.git@javispedro.com> | 2014-09-04 01:55:14 +0200 |
---|---|---|
committer | Javier <dev.git@javispedro.com> | 2014-09-04 01:55:14 +0200 |
commit | 1adf7f1bcde493ccaacedb0d9778911ad69ff335 (patch) | |
tree | 2a1c4cffb09a4406a59df25853a726a7aa86fb28 /src | |
download | salmeta-1adf7f1bcde493ccaacedb0d9778911ad69ff335.tar.gz salmeta-1adf7f1bcde493ccaacedb0d9778911ad69ff335.zip |
Initial import
Diffstat (limited to 'src')
-rw-r--r-- | src/controller.cpp | 84 | ||||
-rw-r--r-- | src/controller.h | 53 | ||||
-rw-r--r-- | src/metawatch.cpp | 183 | ||||
-rw-r--r-- | src/metawatch.h | 101 | ||||
-rw-r--r-- | src/metawatchbletransport.cpp | 141 | ||||
-rw-r--r-- | src/metawatchbletransport.h | 46 | ||||
-rw-r--r-- | src/metawatchtransport.cpp | 6 | ||||
-rw-r--r-- | src/metawatchtransport.h | 25 | ||||
-rw-r--r-- | src/notificationmonitor.cpp | 6 | ||||
-rw-r--r-- | src/notificationmonitor.h | 18 | ||||
-rw-r--r-- | src/reconnecttimer.cpp | 64 | ||||
-rw-r--r-- | src/reconnecttimer.h | 35 | ||||
-rw-r--r-- | src/salmeta.cpp | 43 | ||||
-rw-r--r-- | src/widgetinfo.cpp | 77 | ||||
-rw-r--r-- | src/widgetinfo.h | 72 | ||||
-rw-r--r-- | src/widgetview.cpp | 50 | ||||
-rw-r--r-- | src/widgetview.h | 30 |
17 files changed, 1034 insertions, 0 deletions
diff --git a/src/controller.cpp b/src/controller.cpp new file mode 100644 index 0000000..02c8252 --- /dev/null +++ b/src/controller.cpp @@ -0,0 +1,84 @@ +#include <QtCore/QDebug> +#include <QtCore/QDateTime> + +#include "controller.h" + +static const QLatin1String setting_address("address"); +static const QLatin1String setting_num_pages("num-pages"); +static const QLatin1String setting_page("page%1"); +static const QLatin1String setting_page_widget("widget%1"); + +Controller::Controller(const QString &settingsPrefix, QQuickView *view, QObject *parent) : + QObject(parent), + _settings(new MDConfGroup(this)), + _metawatch(0), + _reconnect(new ReconnectTimer(this)), + _view(new WidgetView(settingsPrefix, view, this)), + _batteryCharge(0), _batteryCharging(false) +{ + _settings->setPath(settingsPrefix); + _metawatch = new MetaWatch(_settings->value(setting_address).toString(), this); + + connect(_settings, &MDConfGroup::valueChanged, this, &Controller::handleSettingChanged); + connect(_metawatch, &MetaWatch::connected, _reconnect, &ReconnectTimer::stop); + connect(_metawatch, &MetaWatch::connected, this, &Controller::handleMetaWatchConnected); + connect(_metawatch, &MetaWatch::disconnected, _reconnect, &ReconnectTimer::start); + connect(_metawatch, &MetaWatch::batteryStatus, this, &Controller::handleMetaWatchBatteryStatus); + connect(_reconnect, &ReconnectTimer::tick, _metawatch, &MetaWatch::connectDevice); + _reconnect->start(); + + reloadPages(); +} + +int Controller::batteryCharge() const +{ + return _batteryCharge; +} + +bool Controller::batteryCharging() const +{ + return _batteryCharging; +} + +void Controller::reloadPages() +{ + +} + +void Controller::switchToPage(int page) +{ + +} + +void Controller::handleSettingChanged(const QString &key) +{ + qDebug() << "Setting" << key << "changed"; + if (key == setting_num_pages) { + _settings->value(setting_num_pages, 0); + switchToPage(0); + } +} + +void Controller::handleMetaWatchConnected() +{ + qDebug() << "MetaWatch connected, synchronizing date time"; + + _metawatch->updateDeviceType(); + _metawatch->updateBatteryStatus(); + _metawatch->setDateTime(QDateTime::currentDateTime()); + _metawatch->updateLcdDisplay(); + + _metawatch->updateWidgetList(_view->widgets()); +} + +void Controller::handleMetaWatchBatteryStatus(bool charging, int charge) +{ + if (_batteryCharging != charging) { + _batteryCharging = charging; + emit batteryChargingChanged(); + } + if (_batteryCharge != charge) { + _batteryCharge = charge; + emit batteryChargeChanged(); + } +} diff --git a/src/controller.h b/src/controller.h new file mode 100644 index 0000000..d7f2349 --- /dev/null +++ b/src/controller.h @@ -0,0 +1,53 @@ +#ifndef DAEMON_H +#define DAEMON_H + +#include <QObject> +#include <QQuickView> +#include <MDConfGroup> + +#include "metawatch.h" +#include "widgetview.h" +#include "reconnecttimer.h" + +class Controller : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int batteryCharge READ batteryCharge NOTIFY batteryChargeChanged) + Q_PROPERTY(bool batteryCharging READ batteryCharging NOTIFY batteryChargingChanged) + +public: + Controller(const QString &settingsPrefix, QQuickView *view = 0, QObject *parent = 0); + + int batteryCharge() const; + bool batteryCharging() const; + +signals: + void batteryChargeChanged(); + void batteryChargingChanged(); + +public slots: + void reloadPages(); + void switchToPage(int page); + +private: + static int parseClockUrl(const QUrl &url); + +private slots: + void handleSettingChanged(const QString &key); + void handleMetaWatchConnected(); + void handleMetaWatchBatteryStatus(bool charging, int charge); + +private: + MDConfGroup *_settings; + MetaWatch *_metawatch; + ReconnectTimer *_reconnect; + + WidgetView *_view; + + // Watch status + int _batteryCharge; + bool _batteryCharging; +}; + +#endif // DAEMON_H diff --git a/src/metawatch.cpp b/src/metawatch.cpp new file mode 100644 index 0000000..a27d0ec --- /dev/null +++ b/src/metawatch.cpp @@ -0,0 +1,183 @@ +#include <QtCore/QDataStream> +#include <QtCore/QDateTime> +#include <QtCore/QDebug> + +#include "metawatch.h" +#include "metawatchbletransport.h" + +MetaWatch::MetaWatch(const QString &btAddr, QObject *parent) : + QObject(parent) +{ + GatoPeripheral *peripheral = new GatoPeripheral(GatoAddress(btAddr), this); + _transport = new MetaWatchBLETransport(peripheral, this); + + connect(_transport, &MetaWatchTransport::connected, this, &MetaWatch::connected); + connect(_transport, &MetaWatchTransport::disconnected, this, &MetaWatch::disconnected); + connect(_transport, &MetaWatchTransport::messageReceived, this, &MetaWatch::handleTransportMessage); +} + +QList<QUrl> MetaWatch::availableClocks() +{ + QList<QUrl> clocks; + + for (int i = 0; i < 6; i++) { + clocks << QUrl("clock://" + QString::number(i)); + } + + return clocks; +} + +void MetaWatch::setDateTime(const QDateTime &dt) +{ + const QDate &date = dt.date(); + const QTime &time = dt.time(); + QByteArray data; + QDataStream s(&data, QIODevice::WriteOnly); + s.setByteOrder(QDataStream::BigEndian); + s << quint16(date.year()) << quint8(date.month()) << quint8(date.day()); + s << quint8(date.dayOfWeek() % 7); + s << quint8(time.hour()) << quint8(time.minute()) << quint8(time.second()); + + _transport->sendMessage(MessageSetRealTimeClock, 0, data); +} + +void MetaWatch::configure(WatchProperties props) +{ + _transport->sendMessage(MessageWatchPropertyOperation, props | WatchPropertyOperationWrite, QByteArray()); +} + +void MetaWatch::updateDeviceType() +{ + // Also disables HFP/MAP connection. + _transport->sendMessage(MessageGetDeviceType, 0xC0, QByteArray()); +} + +void MetaWatch::updateBatteryStatus() +{ + _transport->sendMessage(MessageGetBatteryStatus, 0, QByteArray()); +} + +void MetaWatch::updateLcdDisplay() +{ + // Switches to UiGen2 mode and to page 0. + _transport->sendMessage(MessageUpdateLcdDisplay, 0x80, QByteArray()); +} + +void MetaWatch::updateWidgetList(const QList<WidgetInfo*> &widgets) +{ + int num_widgets = 0; + + // Count valid widgets + for (int w = 0; w < widgets.size(); w++) { + const WidgetInfo *info = widgets[w]; + if (info->valid()) num_widgets++; + } + + const int max_widgets_in_one_msg = 7; + const int num_messages = (num_widgets + (max_widgets_in_one_msg - 1)) / max_widgets_in_one_msg; + int num_message = 0; + QByteArray msg; + + Q_ASSERT(num_messages < 4); + + msg.reserve(max_widgets_in_one_msg * 2); + + if (num_widgets == 0) { + msg.append(static_cast<char>(0xFF)); + msg.append(static_cast<char>(0x00)); + + // Clear all widgets + _transport->sendMessage(MessageSetWidgetList, 0x4, msg); + + return; + } + + qDebug() << "Msgs" << num_messages << num_message; + + for (int w = 0; w < num_widgets; w++) { + WidgetInfo *info = widgets[w]; + if (!info->valid()) continue; // Skip disabled/empty widget + + quint8 id = w; + quint8 options = ((info->page() << 4) & 0x30) + | ((info->size() << 2) & 0xC) | ((info->position() << 2) & 0x3); + + if (info->url().scheme() == "clock") { + id |= (clockUrlToClockId(info->url()) << 4) & 0xF0; + options |= 0x80; + } + + if (info->invert()) { + options |= 0x40; + } + + qDebug() << QString::number(id, 16) << QString::number(options, 16); + + msg.append(id); + msg.append(options); + + if (msg.size() >= max_widgets_in_one_msg * 2) { + Q_ASSERT(num_message < num_messages); + _transport->sendMessage(MessageSetWidgetList, + ((num_messages << 2) & 0xC) | (num_message & 0x3), + msg); + + msg.clear(); + msg.reserve(max_widgets_in_one_msg * 2); + num_message++; + } + } + + if (msg.size() > 0) { + Q_ASSERT(num_message < num_messages); + _transport->sendMessage(MessageSetWidgetList, + ((num_messages << 2) & 0xC) | (num_message & 0x3), + msg); + } +} + +void MetaWatch::connectDevice() +{ + _transport->connectDevice(); +} + +void MetaWatch::disconnectDevice() +{ + _transport->disconnectDevice(); +} + +int MetaWatch::clockUrlToClockId(const QUrl &url) +{ + if (url.scheme() != "clock") + return -1; + + QString host = url.host(); + if (!host.startsWith("clock")) + return -1; + + return host.mid(5).toInt(); +} + +void MetaWatch::handleTransportMessage(quint8 type, quint8 options, const QByteArray &payload) +{ + switch (type) { + case MessageGetDeviceTypeResponse: + emit deviceType(static_cast<DeviceType>(options & 0xF)); + break; + case MessageModeChangeIndication: + qDebug() << "Got mode change indication"; + break; + case MessageReadBatteryStatusResponse: + if (payload.size() < 6) { + qWarning() << "Invalid battery status response size"; + } + emit batteryStatus(payload[1], payload[2]); + break; + case MessageConnectionChange: + case MessageIntervalChanged: + // No idea what to do with these. + break; + default: + qWarning() << "Unknown message type received:" << QString::number(type, 16); + } +} diff --git a/src/metawatch.h b/src/metawatch.h new file mode 100644 index 0000000..dd02bf4 --- /dev/null +++ b/src/metawatch.h @@ -0,0 +1,101 @@ +#ifndef METAWATCH_H +#define METAWATCH_H + +#include <QObject> +#include <QBluetoothAddress> + +QT_USE_NAMESPACE_BLUETOOTH + +#include "metawatchtransport.h" +#include "widgetinfo.h" + +class MetaWatch : public QObject +{ + Q_OBJECT + Q_ENUMS(MessageTypes WatchProperty UiStyle) + Q_FLAGS(WatchProperties) + +public: + explicit MetaWatch(const QString &btAddr, QObject *parent = 0); + + enum MessageTypes { + MessageGetDeviceType = 0x01, + MessageGetDeviceTypeResponse = 0x02, + + MessageSetRealTimeClock = 0x26, + + MessageWatchPropertyOperation = 0x30, + + MessageModeChangeIndication = 0x33, + + MessageUpdateLcdDisplay = 0x43, + + MessageGetBatteryStatus = 0x56, + MessageReadBatteryStatusResponse = 0x57, + + MessageSetWidgetList = 0xA1, + + MessageSetupAccelerometer = 0xE1, + MessageAccelerometerDataResponse = 0xE0, + + // Messages from the propietary BT stack + MessageConnectionChange = 0xB9, + MessageIntervalChanged = 0xBB + }; + + enum DeviceType { + DeviceMetaWatchDigitalGen1 = 2, + DeviceMetaWatchDigitalGen2 = 5 + }; + + enum WatchProperty { + WatchPropertyHourFormat12h = 0, + WatchPropertyHourFormat24h = 1, + WatchPropertyDateFormatMMDD = 0 << 1, + WatchPropertyDateFormatDDMM = 1 << 1, + WatchPropertyShowSeconds = 1 << 2, + WatchPropertyShowSeparationLines = 1 << 3, + WatchPropertyAutobacklight = 1 << 4, + + WatchPropertyOperationRead = 0 << 7, + WatchPropertyOperationWrite = 1 << 7 + }; + Q_DECLARE_FLAGS(WatchProperties, WatchProperty) + + enum UiStyle { + UiGen1 = 0, + UiGen2 = 1 + }; + + static QList<QUrl> availableClocks(); + + void setDateTime(const QDateTime &dt); + void configure(WatchProperties props); + + void updateDeviceType(); + void updateBatteryStatus(); + void updateLcdDisplay(); // TODO: More overloads + void updateWidgetList(const QList<WidgetInfo*>& widgets); + +signals: + void connected(); + void disconnected(); + + void deviceType(DeviceType type); + void batteryStatus(bool charging, int charge); + +public slots: + void connectDevice(); + void disconnectDevice(); + +private: + static int clockUrlToClockId(const QUrl &url); + +private slots: + void handleTransportMessage(quint8 type, quint8 options, const QByteArray &payload); + +private: + MetaWatchTransport *_transport; +}; + +#endif // METAWATCH_H diff --git a/src/metawatchbletransport.cpp b/src/metawatchbletransport.cpp new file mode 100644 index 0000000..56039d3 --- /dev/null +++ b/src/metawatchbletransport.cpp @@ -0,0 +1,141 @@ +#include "metawatchbletransport.h" + +const GatoUUID MetaWatchBLETransport::ServiceUuid(quint16(0x8880)); +const GatoUUID MetaWatchBLETransport::InputCharacteristicUuid(quint16(0x8882)); +const GatoUUID MetaWatchBLETransport::OutputCharacteristicUuid(quint16(0x8881)); + +MetaWatchBLETransport::MetaWatchBLETransport(GatoPeripheral *peripheral, QObject *parent) : + MetaWatchTransport(parent), _dev(peripheral) +{ + connect(_dev, SIGNAL(connected()), SLOT(handleDeviceConnected())); + connect(_dev, SIGNAL(disconnected()), SLOT(handleDeviceDisconnected())); + connect(_dev, SIGNAL(servicesDiscovered()), SLOT(handleDeviceServices())); + connect(_dev, SIGNAL(characteristicsDiscovered(GatoService)), + SLOT(handleDeviceCharacteristics(GatoService))); + connect(_dev, SIGNAL(valueUpdated(GatoCharacteristic,QByteArray)), + SLOT(handleDeviceUpdate(GatoCharacteristic,QByteArray))); +} + +MetaWatchBLETransport::~MetaWatchBLETransport() +{ + disconnectDevice(); +} + +void MetaWatchBLETransport::sendMessage(quint8 type, quint8 options, const QByteArray &payload) +{ + QByteArray packet = encode(type, options, payload); + qDebug() << "Send:" << packet.toHex(); + _dev->writeValue(_out, packet); +} + +void MetaWatchBLETransport::connectDevice() +{ + qDebug() << "Trying to connect to" << _dev->address(); + _dev->connectPeripheral(); +} + +void MetaWatchBLETransport::disconnectDevice() +{ + _dev->disconnectPeripheral(); +} + +QByteArray MetaWatchBLETransport::encode(quint8 type, quint8 options, const QByteArray &payload) +{ + QByteArray packet; + + quint8 message_size = 6 + payload.size(); + packet.reserve(message_size); + + packet.append(0x01); + packet.append(message_size); + packet.append(type); + packet.append(options); + + packet.append(payload); + packet.append("\0\0", 2); // Empty CRC is OK for BLE + + return packet; +} + +bool MetaWatchBLETransport::decode(const QByteArray &packet, quint8 *type, quint8 *options, QByteArray *payload) +{ + if (packet.size() < 6) { + qWarning() << "Message too short"; + } + + if (packet.at(0) != 0x1) { + qWarning() << "Invalid packet header"; + return false; + } + + quint8 message_size = packet[1]; + if (message_size < 6 || message_size > 32 || message_size != packet.size()) { + qWarning() << "Invalid message size:" << message_size; + } + + *type = packet[2]; + *options = packet[3]; + + *payload = packet.mid(4, message_size - 6); + + // Ignore CRC on BLE: it's set to 0 by firmware. + + return true; +} + +void MetaWatchBLETransport::handleDeviceConnected() +{ + qDebug() << "MW connected"; + if (_dev->services().isEmpty()) { + qDebug() << "Trying to discover services"; + QList<GatoUUID> interesting_services; + interesting_services << ServiceUuid; + _dev->discoverServices(); + } +} + +void MetaWatchBLETransport::handleDeviceDisconnected() +{ + qDebug() << "MW disconnected"; + emit disconnected(); +} + +void MetaWatchBLETransport::handleDeviceServices() +{ + QList<GatoService> services = _dev->services(); + qDebug() << "Got" << services.size() << "services"; + foreach (const GatoService &s, services) { + if (s.uuid() == ServiceUuid) { + _dev->discoverCharacteristics(s); + } + } +} + +void MetaWatchBLETransport::handleDeviceCharacteristics(const GatoService &service) +{ + qDebug() << "Got characteristic"; + foreach (const GatoCharacteristic &c, service.characteristics()) { + if (c.uuid() == InputCharacteristicUuid) { + _in = c; + _dev->setNotification(_in, true); + } else if (c.uuid() == OutputCharacteristicUuid) { + _out = c; + } + if (!_in.isNull() && !_out.isNull()) { + emit connected(); + } + } +} + +void MetaWatchBLETransport::handleDeviceUpdate(const GatoCharacteristic &characteristic, const QByteArray &value) +{ + qDebug() << "Recv:" << value.toHex(); + quint8 type, options; + QByteArray payload; + + if (decode(value, &type, &options, &payload)) { + emit messageReceived(type, options, payload); + } else { + qWarning() << "Failed to decode message from metawatch:" << value.toHex(); + } +} diff --git a/src/metawatchbletransport.h b/src/metawatchbletransport.h new file mode 100644 index 0000000..973c4a8 --- /dev/null +++ b/src/metawatchbletransport.h @@ -0,0 +1,46 @@ +#ifndef METAWATCHBLETRANSPORT_H +#define METAWATCHBLETRANSPORT_H + +#include <QtCore/QObject> + +#include <gato/gatoperipheral.h> +#include <gato/gatouuid.h> +#include <gato/gatoservice.h> +#include <gato/gatocharacteristic.h> + +#include "metawatchtransport.h" + +class MetaWatchBLETransport : public MetaWatchTransport +{ + Q_OBJECT +public: + explicit MetaWatchBLETransport(GatoPeripheral *peripheral, QObject *parent = 0); + ~MetaWatchBLETransport(); + + static const GatoUUID ServiceUuid; + static const GatoUUID InputCharacteristicUuid; + static const GatoUUID OutputCharacteristicUuid; + + void sendMessage(quint8 type, quint8 options, const QByteArray &payload); + +public slots: + void connectDevice(); + void disconnectDevice(); + +private: + static QByteArray encode(quint8 type, quint8 options, const QByteArray &payload); + static bool decode(const QByteArray &msg, quint8 *type, quint8 *options, QByteArray *payload); + +private slots: + void handleDeviceConnected(); + void handleDeviceDisconnected(); + void handleDeviceServices(); + void handleDeviceCharacteristics(const GatoService &service); + void handleDeviceUpdate(const GatoCharacteristic &characteristic, const QByteArray &value); + +private: + GatoPeripheral *_dev; + GatoCharacteristic _in, _out; +}; + +#endif // METAWATCHBLETRANSPORT_H diff --git a/src/metawatchtransport.cpp b/src/metawatchtransport.cpp new file mode 100644 index 0000000..078d390 --- /dev/null +++ b/src/metawatchtransport.cpp @@ -0,0 +1,6 @@ +#include "metawatchtransport.h" + +MetaWatchTransport::MetaWatchTransport(QObject *parent) : + QObject(parent) +{ +} diff --git a/src/metawatchtransport.h b/src/metawatchtransport.h new file mode 100644 index 0000000..3d78ee2 --- /dev/null +++ b/src/metawatchtransport.h @@ -0,0 +1,25 @@ +#ifndef METAWATCHTRANSPORT_H +#define METAWATCHTRANSPORT_H + +#include <QObject> + +class MetaWatchTransport : public QObject +{ + Q_OBJECT +public: + explicit MetaWatchTransport(QObject *parent = 0); + +public: + virtual void sendMessage(quint8 type, quint8 options, const QByteArray &payload) = 0; + +public slots: + virtual void connectDevice() = 0; + virtual void disconnectDevice() = 0; + +signals: + void connected(); + void disconnected(); + void messageReceived(quint8 type, quint8 options, const QByteArray &payload); +}; + +#endif // METAWATCHTRANSPORT_H diff --git a/src/notificationmonitor.cpp b/src/notificationmonitor.cpp new file mode 100644 index 0000000..ca6f713 --- /dev/null +++ b/src/notificationmonitor.cpp @@ -0,0 +1,6 @@ +#include "notificationmonitor.h" + +NotificationMonitor::NotificationMonitor(QObject *parent) : + QObject(parent) +{ +} diff --git a/src/notificationmonitor.h b/src/notificationmonitor.h new file mode 100644 index 0000000..c7b6cb2 --- /dev/null +++ b/src/notificationmonitor.h @@ -0,0 +1,18 @@ +#ifndef NOTIFICATIONMONITOR_H +#define NOTIFICATIONMONITOR_H + +#include <QObject> + +class NotificationMonitor : public QObject +{ + Q_OBJECT +public: + explicit NotificationMonitor(QObject *parent = 0); + +signals: + +public slots: + +}; + +#endif // NOTIFICATIONMONITOR_H diff --git a/src/reconnecttimer.cpp b/src/reconnecttimer.cpp new file mode 100644 index 0000000..eaf6cbb --- /dev/null +++ b/src/reconnecttimer.cpp @@ -0,0 +1,64 @@ +#include <QtCore/QDebug> + +extern "C" { + #include <iphbd/libiphb.h> +} + +#include "reconnecttimer.h" + +static unsigned int num_wait_times = 8; +static unsigned short wait_times[8] = { + 2, 5, 10, 30, 2 * 60, 5 * 60, 10 * 60, 15 * 60 +}; + +ReconnectTimer::ReconnectTimer(QObject *parent) + : QObject(parent), + _iphb(iphb_open(0)), + _notifier(new QSocketNotifier(iphb_get_fd(_iphb), QSocketNotifier::Read, this)), + _active(false) +{ + connect(_notifier, &QSocketNotifier::activated, this, &ReconnectTimer::handleIphbActivity); +} + +ReconnectTimer::~ReconnectTimer() +{ + iphb_close(_iphb); +} + +void ReconnectTimer::start() +{ + _active = true; + _counter = 0; + setupWait(); +} + +void ReconnectTimer::stop() +{ + _active = false; + _counter = 0; + iphb_wait(_iphb, 0, 0, 0); +} + +void ReconnectTimer::setupWait() +{ + iphb_wait(_iphb, wait_times[_counter] / 2, wait_times[_counter], 0); +} + +void ReconnectTimer::handleIphbActivity() +{ + iphb_discard_wakeups(_iphb); + + qDebug() << "iphb wakeup"; + + if (!_active) { + // False awakening + return; + } + + emit tick(); + + if (++_counter > num_wait_times) + _counter = num_wait_times; + + setupWait(); +} diff --git a/src/reconnecttimer.h b/src/reconnecttimer.h new file mode 100644 index 0000000..c8d901f --- /dev/null +++ b/src/reconnecttimer.h @@ -0,0 +1,35 @@ +#ifndef RECONNECTCONTROLLER_H +#define RECONNECTCONTROLLER_H + +#include <QObject> +#include <QSocketNotifier> + +class ReconnectTimer : public QObject +{ + Q_OBJECT + +public: + explicit ReconnectTimer(QObject *parent = 0); + ~ReconnectTimer(); + +public slots: + void start(); + void stop(); + +signals: + void tick(); + +private: + void setupWait(); + +private slots: + void handleIphbActivity(); + +private: + void *_iphb; + QSocketNotifier *_notifier; + bool _active; + uint _counter; +}; + +#endif // RECONNECTCONTROLLER_H diff --git a/src/salmeta.cpp b/src/salmeta.cpp new file mode 100644 index 0000000..c4bcb0c --- /dev/null +++ b/src/salmeta.cpp @@ -0,0 +1,43 @@ +#include <QtCore/QDebug> +#include <sailfishapp.h> + +#include "controller.h" + +static bool launch_daemon = false; +static QString settings_key_prefix; + +int main(int argc, char *argv[]) +{ + QGuiApplication *app = SailfishApp::application(argc, argv); + + // TODO: Rudimentary command line parser ahead. Move to QCommandLineParser when it's ready. + const QStringList args = app->arguments(); + auto it = args.begin(); + while (it != args.end()) { + if (*it == "--daemon") { + launch_daemon = true; + } else if (*it == "--root") { + ++it; + settings_key_prefix = *it; + } + + ++it; + } + + if (launch_daemon) { + if (settings_key_prefix.isEmpty()) { + settings_key_prefix = "/apps/salmeta/watch0"; + } + + qDebug() << "Starting salmeta (daemon) with settings from" << settings_key_prefix; + + new Controller(settings_key_prefix, SailfishApp::createView()); + } else { + QQuickView *view = SailfishApp::createView(); + view->setSource(SailfishApp::pathTo("qml/salmeta.qml")); + view->show(); + } + + return app->exec(); +} + diff --git a/src/widgetinfo.cpp b/src/widgetinfo.cpp new file mode 100644 index 0000000..f8cd78a --- /dev/null +++ b/src/widgetinfo.cpp @@ -0,0 +1,77 @@ +#include "widgetinfo.h" + +WidgetInfo::WidgetInfo(QObject *parent) + : QObject(parent) +{ + +} + +bool WidgetInfo::valid() const +{ + return !_url.isEmpty(); +} + +QUrl WidgetInfo::url() const +{ + return _url; +} + +void WidgetInfo::setUrl(const QUrl &url) +{ + if (url != _url) { + _url = url; + emit urlChanged(); + } +} + +bool WidgetInfo::invert() const +{ + return _invert; +} + +void WidgetInfo::setInvert(bool invert) +{ + if (invert != _invert) { + _invert = invert; + emit invertChanged(); + } +} + +int WidgetInfo::page() const +{ + return _page; +} + +void WidgetInfo::setPage(int page) +{ + if (page != _page) { + _page = page; + emit pageChanged(); + } +} + +WidgetInfo::WidgetSize WidgetInfo::size() const +{ + return _size; +} + +void WidgetInfo::setSize(const WidgetSize &size) +{ + if (size != _size) { + _size = size; + emit sizeChanged(); + } +} + +WidgetInfo::WidgetPosition WidgetInfo::position() const +{ + return _pos; +} + +void WidgetInfo::setPosition(const WidgetPosition &pos) +{ + if (pos != _pos) { + _pos = pos; + emit positionChanged(); + } +} diff --git a/src/widgetinfo.h b/src/widgetinfo.h new file mode 100644 index 0000000..06a6149 --- /dev/null +++ b/src/widgetinfo.h @@ -0,0 +1,72 @@ +#ifndef WIDGETINFO_H +#define WIDGETINFO_H + +#include <QtCore/QObject> +#include <QtCore/QUrl> + +class WidgetInfo : public QObject +{ + Q_OBJECT + Q_ENUMS(WidgetSize WidgetPosition) + + Q_PROPERTY(bool valid READ valid NOTIFY validChanged) + Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) + Q_PROPERTY(bool invert READ invert WRITE setInvert NOTIFY invertChanged) + Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) + Q_PROPERTY(WidgetSize size READ size WRITE setSize NOTIFY sizeChanged) + Q_PROPERTY(WidgetPosition position READ position WRITE setPosition NOTIFY positionChanged) + +public: + explicit WidgetInfo(QObject *parent = 0); + + enum WidgetSize + { + Size1Q = 0, + Size2QHorizontal = 1, + Size2QVertical = 2, + Size4Q = 3 + }; + + enum WidgetPosition + { + PosNW = 0, + PosNE = 1, + PosSW = 2, + PosSE = 3 + }; + + bool valid() const; + + QUrl url() const; + void setUrl(const QUrl &url); + + bool invert() const; + void setInvert(bool invert); + + int page() const; + void setPage(int page); + + WidgetSize size() const; + void setSize(const WidgetSize &size); + + WidgetPosition position() const; + void setPosition(const WidgetPosition &pos); + +signals: + void validChanged(); + void urlChanged(); + void invertChanged(); + void pageChanged(); + void sizeChanged(); + void positionChanged(); + +private: + QUrl _url; + bool _invert; + short _page; + WidgetSize _size; + WidgetPosition _pos; + +}; + +#endif // WIDGETINFO_H diff --git a/src/widgetview.cpp b/src/widgetview.cpp new file mode 100644 index 0000000..e5bf21e --- /dev/null +++ b/src/widgetview.cpp @@ -0,0 +1,50 @@ +#include <QtQml/QQmlContext> +#include <sailfishapp.h> + +#include "widgetview.h" + +#define NUM_WIDGETS 16 + +WidgetView::WidgetView(const QString &settingsPrefix, QQuickView *view, QObject *parent) + : QObject(parent), + _settings(new MDConfGroup(this)), + _view(view) +{ + _settings->setPath(settingsPrefix); + + if (!_view) { + _view = new QQuickView; + } + + for (int w = 0; w < NUM_WIDGETS; w++) { + WidgetInfo *info = new WidgetInfo(this); + + _widgets.append(info); + _widgetObjects.append(static_cast<QObject*>(info)); + } + + reload(); + + _view->setResizeMode(QQuickView::SizeViewToRootObject); + _view->setSource(SailfishApp::pathTo("qml/widgetview.qml")); + _view->rootContext()->setContextProperty("widgets", QVariant::fromValue(_widgetObjects)); +} + +QList<WidgetInfo*> WidgetView::widgets() +{ + return _widgets; +} + +void WidgetView::reload() +{ + for (int w = 0; w < _widgets.size(); w++) { + WidgetInfo *widget = _widgets[w]; + QString base = QString("widget%1/").arg(w); + + widget->setInvert(_settings->value(base + "invert").toBool()); + widget->setPage(_settings->value(base + "page").toInt()); + widget->setSize(static_cast<WidgetInfo::WidgetSize>(_settings->value(base + "size").toInt())); + widget->setPosition(static_cast<WidgetInfo::WidgetPosition>(_settings->value(base + "position").toInt())); + widget->setUrl(_settings->value(base + "url").toUrl()); + } +} diff --git a/src/widgetview.h b/src/widgetview.h new file mode 100644 index 0000000..6ce294d --- /dev/null +++ b/src/widgetview.h @@ -0,0 +1,30 @@ +#ifndef WIDGETVIEW_H +#define WIDGETVIEW_H + +#include <QtCore/QObject> +#include <QtCore/QVector> +#include <QtQuick/QQuickView> + +#include <MDConfGroup> + +#include "widgetinfo.h" + +class WidgetView : public QObject +{ + Q_OBJECT +public: + WidgetView(const QString &settingsPrefix, QQuickView *view, QObject *parent = 0); + + QList<WidgetInfo*> widgets(); + +public slots: + void reload(); + +private: + MDConfGroup *_settings; + QQuickView *_view; + QList<WidgetInfo*> _widgets; + QObjectList _widgetObjects; +}; + +#endif // WIDGETVIEW_H |