From bde4bde8ec9d6d09874d5ae9e0ba6dc9431859b6 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Sun, 16 Oct 2011 01:03:43 +0200 Subject: adding new asynchronous Watch state queries --- libsowatch/watch.h | 27 ++++++++-- metawatch/metawatch.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++------ metawatch/metawatch.h | 27 +++++++++- 3 files changed, 163 insertions(+), 21 deletions(-) diff --git a/libsowatch/watch.h b/libsowatch/watch.h index f18ed9a..9147f9a 100644 --- a/libsowatch/watch.h +++ b/libsowatch/watch.h @@ -17,7 +17,9 @@ class SOWATCH_EXPORT Watch : public QObject, public QPaintDevice Q_OBJECT Q_PROPERTY(QString model READ model CONSTANT) Q_PROPERTY(bool connected READ isConnected) - Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime) + Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged) + Q_PROPERTY(int batteryLevel READ batteryLevel NOTIFY batteryLevelChanged) + Q_PROPERTY(bool charging READ charging NOTIFY chargingChanged) public: explicit Watch(QObject* parent = 0); @@ -34,10 +36,23 @@ public: /** Indicates if watch is too busy atm and we should limit frame rate. */ virtual bool busy() const = 0; - /** Gets the current date/time on the watch. */ - virtual QDateTime dateTime() = 0; /** Sets the current date/time on the watch. */ virtual void setDateTime(const QDateTime& dateTime) = 0; + /** Asynchronously queries battery date/time from the watch; once the + * query is finished, dateTimeChanged() will be signaled and dateTime() + * will return the updated value. */ + virtual void queryDateTime() = 0; + /** Gets the current date/time as last fetched from the watch. */ + virtual QDateTime dateTime() const = 0; + + /** Asynchronously queries battery level from the watch. */ + virtual void queryBatteryLevel() = 0; + /** Gets the battery level (range [0-100]) as last read from the watch. */ + virtual int batteryLevel() const = 0; + + /** Asynchronously queries whether the watch is connected to a charger. */ + virtual void queryCharging() = 0; + virtual bool charging() const = 0; /** Grabs a button from whatever is default function is for the current mode. */ virtual void grabButton(int button) = 0; @@ -65,6 +80,12 @@ signals: void disconnected(); /** The watch has returned to the idle screen by either inactivity or notification cleared/timeout. */ void idling(); + /** Emitted once the queryDateTime() operation is completed. */ + void dateTimeChanged(); + /** Emitted once the queryBatteryLevel() operation is completed. */ + void batteryLevelChanged(); + /** Emitted once the queryCharging() operation is completed. */ + void chargingChanged(); /** A button has been pressed. */ void buttonPressed(int button); /** A button has been pressed and then released. */ diff --git a/metawatch/metawatch.cpp b/metawatch/metawatch.cpp index 8c246aa..9ca4b2d 100644 --- a/metawatch/metawatch.cpp +++ b/metawatch/metawatch.cpp @@ -81,6 +81,7 @@ const quint16 MetaWatch::crcTable[256] = { MetaWatch::MetaWatch(const QBluetoothAddress& address, QSettings* settings, QObject* parent) : Watch(parent), _idleTimer(new QTimer(this)), _ringTimer(new QTimer(this)), + _watchTime(), _watchBattery(0), _watchBatteryAverage(0), _watchCharging(false), _currentMode(IdleMode), _paintMode(IdleMode), _paintEngine(0), _connectRetries(0), _connected(false), @@ -151,11 +152,6 @@ bool MetaWatch::busy() const _toSend.size() > 20; } -QDateTime MetaWatch::dateTime() -{ - return QDateTime::currentDateTime(); // TODO -} - void MetaWatch::setDateTime(const QDateTime &dateTime) { Message msg(SetRealTimeClock, QByteArray(8, 0)); @@ -175,6 +171,44 @@ void MetaWatch::setDateTime(const QDateTime &dateTime) send(msg); } +void MetaWatch::queryDateTime() +{ + Message msg(GetRealTimeClock); + sendIfNotQueued(msg); +} + +QDateTime MetaWatch::dateTime() const +{ + return _watchTime; +} + +void MetaWatch::queryBatteryLevel() +{ + Message msg(ReadBatteryVoltage); + sendIfNotQueued(msg); +} + +int MetaWatch::batteryLevel() const +{ + // TODO This "estimation" is quite awful, could be way more accurate. + int level = (_watchBatteryAverage - 3500) / (4100-3500); + if (level < 0) level = 0; + if (level > 100) level = 100; + + return level; +} + +void MetaWatch::queryCharging() +{ + Message msg(ReadBatteryVoltage); + sendIfNotQueued(msg); +} + +bool MetaWatch::charging() const +{ + return _watchCharging; +} + void MetaWatch::grabButton(int button) { grabButton(_currentMode, (Button) button); @@ -292,19 +326,16 @@ void MetaWatch::send(const Message &msg) } } -void MetaWatch::handleMessage(const Message &msg) +void MetaWatch::sendIfNotQueued(const Message& msg) { - switch (msg.type) { - case StatusChangeEvent: - handleStatusChangeMessage(msg); - break; - case ButtonEvent: - handleButtonEventMessage(msg); - break; - default: - qWarning() << "Unknown message of type" << msg.type << "received"; - break; + foreach (const Message& m, _toSend) { + if (m.type == msg.type) { + return; // Already on the queue, discard message. + } } + + // Otherwise, send it as requested + send(msg); } void MetaWatch::setVibrateMode(bool enable, uint on, uint off, uint cycles) @@ -428,6 +459,54 @@ void MetaWatch::disableButton(Mode mode, Button button, ButtonPress press) send(msg); } +void MetaWatch::handleMessage(const Message &msg) +{ + switch (msg.type) { + case GetDeviceTypeResponse: + handleDeviceTypeMessage(msg); + break; + case GetRealTimeClockResponse: + handleRealTimeClockMessage(msg); + break; + case StatusChangeEvent: + handleStatusChangeMessage(msg); + break; + case ButtonEvent: + handleButtonEventMessage(msg); + break; + case ReadBatteryVoltageResponse: + handleBatteryVoltageMessage(msg); + break; + default: + qWarning() << "Unknown message of type" << msg.type << "received"; + break; + } +} + +void MetaWatch::handleDeviceTypeMessage(const Message &msg) +{ + Q_ASSERT(msg.type == GetDeviceTypeResponse); + if (msg.data.size() < 1) { + qWarning() << "Short device type response"; + } + qDebug() << "got device type" << msg.data[0]; +} + +void MetaWatch::handleRealTimeClockMessage(const Message &msg) +{ + int year = ((msg.data[1] & 0xFF) << 8) | (msg.data[0] & 0xFF); + int month = msg.data[2] & 0xFF; + int day = msg.data[3] & 0xFF; + QDate d(year, month, day); + int hour = msg.data[5] & 0xFF; + int minute = msg.data[6] & 0xFF; + int second = msg.data[7] & 0xFF; + QTime t(hour, minute, second); + _watchTime = QDateTime(d, t); + + emit dateTimeChanged(); +} + void MetaWatch::handleStatusChangeMessage(const Message &msg) { Q_UNUSED(msg); @@ -458,6 +537,25 @@ void MetaWatch::handleButtonEventMessage(const Message &msg) } } +void MetaWatch::handleBatteryVoltageMessage(const Message &msg) +{ + Q_ASSERT(msg.type == ReadBatteryVoltageResponse); + if (msg.data.size() < 6) { + qWarning() << "Short battery voltage response:" << msg.data.size(); + return; + } + _watchCharging = msg.data[1]; + _watchBattery = ((msg.data[3] & 0xFF) << 8) | (msg.data[2] & 0xFF); + _watchBatteryAverage = ((msg.data[5] & 0xFF) << 8) | (msg.data[4] & 0xFF); + + qDebug() << "got battery voltage" << _watchBattery << "mV " + << "average" << _watchBatteryAverage << "mV " + << (_watchCharging ? "charging" : "discharging"); + + emit chargingChanged(); + emit batteryLevelChanged(); +} + void MetaWatch::socketConnected() { if (!_connected) { diff --git a/metawatch/metawatch.h b/metawatch/metawatch.h index badfa83..8f0d52e 100644 --- a/metawatch/metawatch.h +++ b/metawatch/metawatch.h @@ -91,8 +91,15 @@ public: bool isConnected() const; bool busy() const; - QDateTime dateTime(); void setDateTime(const QDateTime& dateTime); + void queryDateTime(); + QDateTime dateTime() const; + + void queryBatteryLevel(); + int batteryLevel() const; + + void queryCharging(); + bool charging() const; void grabButton(int button); void ungrabButton(int button); @@ -131,11 +138,17 @@ protected: QStringList _buttonNames; // Current watch state + QDateTime _watchTime; + short _watchBattery; + short _watchBatteryAverage; + bool _watchCharging; Mode _currentMode; Mode _paintMode; - // For QPaintDevice + // Required by QPaintDevice mutable MetaWatchPaintEngine* _paintEngine; + + /** The shadow framebuffers for each of the watch modes */ QImage _image[3]; // Timers to retry the connection when the watch is not found. @@ -169,8 +182,14 @@ protected: static quint16 calcCrc(const QByteArray& data, int size); static quint16 calcCrc(const Message& msg); + /** Sends a message to the watch. Does not block. */ void send(const Message& msg); + /** Sends a message to the watch if a message of the same type is not + * already queued. Does not block. + */ + void sendIfNotQueued(const Message& msg); + /* Some functions that wrap sending some watch messages. */ void setVibrateMode(bool enable, uint on, uint off, uint cycles); void updateLcdLine(Mode mode, const QImage& image, int line); void updateLcdLines(Mode mode, const QImage& image, int lineA, int lineB); @@ -182,9 +201,13 @@ protected: void disableButton(Mode mode, Button button, ButtonPress press); void handleMessage(const Message& msg); + void handleDeviceTypeMessage(const Message& msg); + void handleRealTimeClockMessage(const Message& msg); void handleStatusChangeMessage(const Message& msg); void handleButtonEventMessage(const Message& msg); + void handleBatteryVoltageMessage(const Message& msg); + /** To be overriden; should configure a newly connected watch. */ virtual void handleWatchConnected() = 0; private slots: -- cgit v1.2.3