diff options
Diffstat (limited to 'metawatch')
-rw-r--r-- | metawatch/metawatch.cpp | 111 | ||||
-rw-r--r-- | metawatch/metawatch.h | 41 | ||||
-rw-r--r-- | metawatch/metawatchdigitalsimulator.cpp | 2 | ||||
-rw-r--r-- | metawatch/metawatchdigitalsimulator.h | 2 | ||||
-rw-r--r-- | metawatch/metawatchscanner.cpp | 12 | ||||
-rw-r--r-- | metawatch/metawatchscanner.h | 6 |
6 files changed, 129 insertions, 45 deletions
diff --git a/metawatch/metawatch.cpp b/metawatch/metawatch.cpp index d02e726..c287ccb 100644 --- a/metawatch/metawatch.cpp +++ b/metawatch/metawatch.cpp @@ -78,8 +78,8 @@ const quint16 MetaWatch::crcTable[256] = { #endif MetaWatch::MetaWatch(ConfigKey* settings, QObject* parent) : - Watch(parent), - _settings(settings->getSubkey(QString(), this)), + Watch(parent), + _settings(settings->getSubkey(QString(), this)), _idleTimer(new QTimer(this)), _ringTimer(new QTimer(this)), _watchTime(), _watchBattery(0), _watchBatteryAverage(0), _watchCharging(false), _currentMode(IdleMode), _paintMode(IdleMode), @@ -87,9 +87,11 @@ MetaWatch::MetaWatch(ConfigKey* settings, QObject* parent) : _connectRetries(0), _connected(false), _connectTimer(new QTimer(this)), _connectAlignedTimer(new QSystemAlignedTimer(this)), + _localDev(new QBluetoothLocalDevice(this)), _socket(0), _sendTimer(new QTimer(this)) { + // Read current device settings connect(_settings, SIGNAL(subkeyChanged(QString)), SLOT(settingChanged(QString))); _address = QBluetoothAddress(settings->value("address").toString()); @@ -99,6 +101,7 @@ MetaWatch::MetaWatch(ConfigKey* settings, QObject* parent) : _buttonNames << "A" << "B" << "C" << "D" << "E" << "F"; + // Configure timers (but do not turn them on yet) _idleTimer->setInterval(_notificationTimeout * 1000); _idleTimer->setSingleShot(true); connect(_idleTimer, SIGNAL(timeout()), SIGNAL(idling())); @@ -114,8 +117,17 @@ MetaWatch::MetaWatch(ConfigKey* settings, QObject* parent) : _sendTimer->setInterval(DelayBetweenMessages); connect(_sendTimer, SIGNAL(timeout()), SLOT(timedSend())); - // Do an initial connection attempt after a short delay - _connectTimer->start(100); + // Connect other signals + connect(_localDev, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)), SLOT(localDevModeChanged(QBluetoothLocalDevice::HostMode))); + + // Check to see if we can connect right away + if (_localDev->hostMode() != QBluetoothLocalDevice::HostPoweredOff) { + // Do an initial connection attempt after a short delay + // (To give time for other plugins to initialize, etc.) + scheduleConnect(); + } else { + qDebug() << "Not starting MetaWatch connection because BT is off"; + } } MetaWatch::~MetaWatch() @@ -170,7 +182,7 @@ void MetaWatch::setDateTime(const QDateTime &dateTime) msg.data[1] = date.year() & 0xFF; msg.data[2] = date.month(); msg.data[3] = date.day(); - // Qt week starts on Monday([1-7]), MW starts on Sunday([0-6]). + // Qt week starts on Monday([1-7]), MetaWatch week starts on Sunday([0-6]). msg.data[4] = date.dayOfWeek() % 7; msg.data[5] = time.hour(); msg.data[6] = time.minute(); @@ -322,9 +334,53 @@ quint16 MetaWatch::calcCrc(const Message& msg) return calcCrc(data, msgSize + 4); } -void MetaWatch::retryConnect() +void MetaWatch::scheduleConnect() +{ + if (_connected || + _connectAlignedTimer->isActive() || _connectTimer->isActive()) { + // Already connected or already scheduled to connect. + return; + } + + _connectRetries = 0; + _connectTimer->start(100); +} + +void MetaWatch::scheduleRetryConnect() +{ + if (_connected || + _connectAlignedTimer->isActive() || _connectTimer->isActive()) { + // Already connected or already scheduled to connect. + return; + } + + int timeToNextRetry; + if (_connectRetries >= connectRetryTimesSize) { + timeToNextRetry = connectRetryTimes[connectRetryTimesSize - 1]; + } else { + timeToNextRetry = connectRetryTimes[_connectRetries]; + _connectRetries++; // Increase the number of connection attemps + } + + qDebug() << "Backing off for" << timeToNextRetry << "seconds for next retry"; + _connectAlignedTimer->start(timeToNextRetry / 2, timeToNextRetry * 2); + if (_connectAlignedTimer->lastError() != QSystemAlignedTimer::NoError) { + // Hopefully a future version of QSystemAlignedTimer implements this fallback + // For now, we have to do it ourselves. + qDebug() << "Note: using plain QTimer for retry"; + _connectTimer->start(timeToNextRetry * 1000); + } +} + +void MetaWatch::unscheduleConnect() { - delete _socket; + _connectAlignedTimer->stop(); + _connectTimer->stop(); +} + +void MetaWatch::connectToWatch() +{ + delete _socket; //Delete socket from previous connect if any. _socket = new QBluetoothSocket(QBluetoothSocket::RfcommSocket); connect(_socket, SIGNAL(connected()), SLOT(socketConnected())); @@ -608,7 +664,8 @@ void MetaWatch::handleNvalOperationMessage(const Message& msg) // Check if there's a pending write for this nval. if (_nvals.contains(value)) { int new_data = _nvals[value]; - qDebug() << "nval" << hex << value << "currently =" << dec << data << "is pending write to =" << new_data; + qDebug() << "nval" << hex << value << "currently =" << dec << data + << "is pending write to =" << new_data; if (new_data != data) { realNvalWrite(value, _nvals[value]); } else { @@ -706,6 +763,23 @@ void MetaWatch::settingChanged(const QString &key) } } +void MetaWatch::localDevModeChanged(QBluetoothLocalDevice::HostMode state) +{ + qDebug() << "Local bluetooth device mode changed to" << state; + if (state == QBluetoothLocalDevice::HostPoweredOff) { + // Host bluetooth was powered down + // Assume the socket has been disconnected + socketDisconnected(); + // Cancel any pending connection attempts + unscheduleConnect(); + } else { + // Host bluetooth might have been powered up + if (!_connected) { + scheduleConnect(); + } + } +} + void MetaWatch::socketConnected() { if (!_connected) { @@ -734,6 +808,7 @@ void MetaWatch::socketConnected() void MetaWatch::socketDisconnected() { + // Signal disconnection if necessary if (_connected) { qDebug() << "disconnected"; @@ -744,19 +819,9 @@ void MetaWatch::socketDisconnected() emit disconnected(); } - int timeToNextRetry; - if (_connectRetries >= connectRetryTimesSize) { - timeToNextRetry = connectRetryTimes[connectRetryTimesSize - 1]; - } else { - timeToNextRetry = connectRetryTimes[_connectRetries]; - _connectRetries++; - } - qDebug() << "Backing off for" << timeToNextRetry << "seconds for next retry"; - _connectAlignedTimer->start(timeToNextRetry / 2, timeToNextRetry * 2); - if (_connectAlignedTimer->lastError() != QSystemAlignedTimer::NoError) { - // I would like to know why QtM couldn't _emulate_ here using a QTimer by itself. - qDebug() << "Note: using plain QTimer for retry"; - _connectTimer->start(timeToNextRetry * 1000); + // Setup reconnection attempt if necessary + if (_localDev->hostMode() != QBluetoothLocalDevice::HostPoweredOff) { + scheduleRetryConnect(); } } @@ -768,6 +833,8 @@ void MetaWatch::socketData() void MetaWatch::socketError(QBluetoothSocket::SocketError error) { qWarning() << "Socket error:" << error; + // Seems that sometimes a disconnection event may not be generated. + socketDisconnected(); } void MetaWatch::socketState(QBluetoothSocket::SocketState error) @@ -777,7 +844,7 @@ void MetaWatch::socketState(QBluetoothSocket::SocketState error) void MetaWatch::timedReconnect() { - retryConnect(); + connectToWatch(); } void MetaWatch::timedSend() diff --git a/metawatch/metawatch.h b/metawatch/metawatch.h index 8946884..5d7534a 100644 --- a/metawatch/metawatch.h +++ b/metawatch/metawatch.h @@ -6,15 +6,17 @@ #include <QtCore/QSettings> #include <QtConnectivity/QBluetoothAddress> #include <QtConnectivity/QBluetoothSocket> +#include <QtConnectivity/QBluetoothLocalDevice> #include <QtSystemInfo/QSystemAlignedTimer> #include <sowatch.h> +namespace sowatch +{ + using QTM_PREPEND_NAMESPACE(QBluetoothSocket); using QTM_PREPEND_NAMESPACE(QBluetoothAddress); using QTM_PREPEND_NAMESPACE(QSystemAlignedTimer); - -namespace sowatch -{ +using QTM_PREPEND_NAMESPACE(QBluetoothLocalDevice); class MetaWatchPaintEngine; @@ -138,6 +140,17 @@ public: void ungrabButton(Mode mode, Button button); protected: + // Base watch protocol stuff + struct Message { + MessageType type; + quint8 options; + QByteArray data; + Message(MessageType ntype = NoMessage, QByteArray ndata = QByteArray(), quint8 noptions = 0) : + type(ntype), options(noptions), data(ndata) + { } + }; + +protected: ConfigKey *_settings; // Some configurable stuff. @@ -159,12 +172,13 @@ protected: short _watchBatteryAverage; bool _watchCharging; Mode _currentMode; + /** The mode where paint operations done using QPaintDevice go into */ Mode _paintMode; // Required by QPaintDevice mutable MetaWatchPaintEngine* _paintEngine; - /** The shadow framebuffers for each of the watch modes */ + /** The framebuffers for each of the watch modes */ QImage _image[3]; // Timers to retry the connection when the watch is not found. @@ -176,19 +190,10 @@ protected: QSystemAlignedTimer* _connectAlignedTimer; // Connection stuff + QBluetoothLocalDevice* _localDev; QBluetoothAddress _address; QBluetoothSocket* _socket; - // Base watch protocol stuff - struct Message { - MessageType type; - quint8 options; - QByteArray data; - Message(MessageType ntype = NoMessage, QByteArray ndata = QByteArray(), quint8 noptions = 0) : - type(ntype), options(noptions), data(ndata) - { } - }; - /** The "packets to be sent" asynchronous queue **/ QQueue<Message> _toSend; QTimer* _sendTimer; @@ -202,8 +207,13 @@ protected: static quint16 calcCrc(const QByteArray& data, int size); static quint16 calcCrc(const Message& msg); + /** Reprime the connection retry timers. */ + void scheduleConnect(); + void scheduleRetryConnect(); + void unscheduleConnect(); + /** Attempt a connection to the watch. */ - virtual void retryConnect(); + virtual void connectToWatch(); /** Sends a message to the watch. Does not block. */ virtual void send(const Message& msg); @@ -239,6 +249,7 @@ protected: private slots: void settingChanged(const QString& key); + void localDevModeChanged(QBluetoothLocalDevice::HostMode state); void socketConnected(); void socketDisconnected(); void socketData(); diff --git a/metawatch/metawatchdigitalsimulator.cpp b/metawatch/metawatchdigitalsimulator.cpp index e5cd74b..dabc0f3 100644 --- a/metawatch/metawatchdigitalsimulator.cpp +++ b/metawatch/metawatchdigitalsimulator.cpp @@ -100,7 +100,7 @@ void MetaWatchDigitalSimulator::vibrate(bool on) qDebug() << "vibrate" << on; } -void MetaWatchDigitalSimulator::retryConnect() +void MetaWatchDigitalSimulator::connectToWatch() { if (!_connected && _form) { qDebug() << "simulator connected"; diff --git a/metawatch/metawatchdigitalsimulator.h b/metawatch/metawatchdigitalsimulator.h index de2efdd..8b424ec 100644 --- a/metawatch/metawatchdigitalsimulator.h +++ b/metawatch/metawatchdigitalsimulator.h @@ -26,7 +26,7 @@ public: void vibrate(bool on); - void retryConnect(); + void connectToWatch(); void send(const Message& msg); private slots: diff --git a/metawatch/metawatchscanner.cpp b/metawatch/metawatchscanner.cpp index 6a65419..1e43115 100644 --- a/metawatch/metawatchscanner.cpp +++ b/metawatch/metawatchscanner.cpp @@ -30,17 +30,23 @@ void MetaWatchScanner::handleDiscoveredService(const QBluetoothServiceInfo &info { const QBluetoothDeviceInfo dev = info.device(); QString deviceName = dev.name(); - if (deviceName.contains("MetaWatch", Qt::CaseInsensitive)) { + if (deviceName.startsWith("MetaWatch", Qt::CaseInsensitive)) { QVariantMap foundInfo; foundInfo["address"] = dev.address().toString(); foundInfo["name"] = deviceName; qDebug() << "metawatch bluetooth scan found:" << deviceName; + // "MetaWatch Digital" was AU2000 with preSTRATA firmware + // "MetaWatch SW12" seems to be STRATA + // "MetaWatch 99" seems to be AU2000 with STRATA firmware if (deviceName.contains("Digital", Qt::CaseInsensitive) || - deviceName.contains("SW12", Qt::CaseInsensitive)) { + deviceName.contains("SW12") || deviceName.contains("99")) { foundInfo["driver"] = QString("metawatch-digital"); foundInfo["next-watchlet-button"] = QString("A"); emit watchFound(foundInfo); - } else if (deviceName.contains("Analog", Qt::CaseInsensitive)) { + // "MetaWatch Analog" is the only analog watch released so far, preSTRATA fw + // "MetaWatch WDS111" (seems) analog watch with STRATA fw + } else if (deviceName.contains("Analog", Qt::CaseInsensitive) || + deviceName.contains("WDS111", Qt::CaseInsensitive)) { foundInfo["driver"] = QString("metawatch-analog"); foundInfo["next-watchlet-button"] = QString("A"); emit watchFound(foundInfo); diff --git a/metawatch/metawatchscanner.h b/metawatch/metawatchscanner.h index c98bf1a..a41633a 100644 --- a/metawatch/metawatchscanner.h +++ b/metawatch/metawatchscanner.h @@ -4,12 +4,12 @@ #include <sowatch.h> #include <QtConnectivity/QBluetoothServiceDiscoveryAgent> -using QTM_PREPEND_NAMESPACE(QBluetoothServiceDiscoveryAgent); -using QTM_PREPEND_NAMESPACE(QBluetoothServiceInfo); - namespace sowatch { +using QTM_PREPEND_NAMESPACE(QBluetoothServiceDiscoveryAgent); +using QTM_PREPEND_NAMESPACE(QBluetoothServiceInfo); + class MetaWatchScanner : public WatchScanner { Q_OBJECT |