From cb04065d6a84bb54b485d0ad8715f09a76191412 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Thu, 28 Mar 2013 13:02:18 +0100 Subject: disable connection timer when bluetooth is off --- libsowatch/allwatchscanner.h | 1 + libsowatch/configkey.h | 1 + metawatch/metawatch.cpp | 111 +++++++++++++++++++++++++------- metawatch/metawatch.h | 41 +++++++----- metawatch/metawatchdigitalsimulator.cpp | 2 +- metawatch/metawatchdigitalsimulator.h | 2 +- metawatch/metawatchscanner.cpp | 12 +++- metawatch/metawatchscanner.h | 6 +- sowatch.pro | 28 ++++++-- sowatchd/main.cpp | 2 + sowatchd/watchhandler.cpp | 1 - sowatchui/watchesmodel.cpp | 4 +- 12 files changed, 157 insertions(+), 54 deletions(-) diff --git a/libsowatch/allwatchscanner.h b/libsowatch/allwatchscanner.h index 561c6a8..4dd915c 100644 --- a/libsowatch/allwatchscanner.h +++ b/libsowatch/allwatchscanner.h @@ -9,6 +9,7 @@ namespace sowatch { +/** This is just a simple wrapper class that runs all registered WatchScanners */ class AllWatchScanner : public WatchScanner { Q_OBJECT diff --git a/libsowatch/configkey.h b/libsowatch/configkey.h index a30ae67..5ef1acc 100644 --- a/libsowatch/configkey.h +++ b/libsowatch/configkey.h @@ -9,6 +9,7 @@ namespace sowatch { +/** Interface for a configuration key / tree */ class SOWATCH_EXPORT ConfigKey : public QObject { Q_OBJECT 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 #include #include +#include #include #include +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; @@ -137,6 +139,17 @@ public: void grabButton(Mode mode, Button button); 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; @@ -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 _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 #include -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 diff --git a/sowatch.pro b/sowatch.pro index 7f89e81..bf97875 100644 --- a/sowatch.pro +++ b/sowatch.pro @@ -1,34 +1,52 @@ TEMPLATE = subdirs +# Please comment subdirectories you do not want to build as desired + # Core library +# This is mandatory. Depends on Qt and GConf. SUBDIRS = libsowatch # The MetaWatch driver plugin +# Since this is the only watch plugin, it is mandatory. +# Depends on Qt Mobility SystemInfo and Bluetooth. SUBDIRS += metawatch metawatch.depends = libsowatch # Some watchlets -SUBDIRS += notificationswatchlet sysinfowatchlet -SUBDIRS += qmsgwatchlet qmapwatchlet +# This just shows a list of pending notifications and has no dependencies. +SUBDIRS += notificationswatchlet notificationswatchlet.depends = libsowatch + +# This shows some values from Qt SystemInfo on the watch +SUBDIRS += sysinfowatchlet sysinfowatchlet.depends = libsowatch + +# This shows some inbox messages using QtMobility +SUBDIRS += qmsgwatchlet qmsgwatchlet.depends = libsowatch + +# This shows a map around the current position using QtMobility Mapping features +SUBDIRS += qmapwatchlet qmapwatchlet.depends = libsowatch # Toy watchlets +# Shows a cat running around. No dependencies. SUBDIRS += nekowatchlet nekowatchlet.depends = libsowatch unix { + # These use D-Bus for interprocess communication. + # The main daemon. SUBDIRS += sowatchd + # Configuration interface. SUBDIRS += sowatchui sowatchd.depends = libsowatch sowatchui.depends = libsowatch sowatchd } +# Harmattan specific stuff contains(MEEGO_EDITION,harmattan) { - # Harmattan specific stuff SUBDIRS += meegohandsetnotification ckitcallnotification harmaccuweather SUBDIRS += meecastweather SUBDIRS += qmafwwatchlet @@ -38,10 +56,6 @@ contains(MEEGO_EDITION,harmattan) { harmaccuweather.depends = libsowatch meecastweather.depends = libsowatch qmafwwatchlet.depends = libsowatch -} else:simulator { - # This notification provider builds almost everywhere so it's good enough as testcase - SUBDIRS += harmaccuweather - harmaccuweather.depends = libsowatch } # Debug only watchlets diff --git a/sowatchd/main.cpp b/sowatchd/main.cpp index 6bd502b..0106118 100644 --- a/sowatchd/main.cpp +++ b/sowatchd/main.cpp @@ -60,5 +60,7 @@ int main(int argc, char *argv[]) qCritical("Could not register daemon object"); } + qDebug("sowatchd is now running"); + return app.exec(); } diff --git a/sowatchd/watchhandler.cpp b/sowatchd/watchhandler.cpp index cc75d45..89d3d95 100644 --- a/sowatchd/watchhandler.cpp +++ b/sowatchd/watchhandler.cpp @@ -32,7 +32,6 @@ WatchHandler::WatchHandler(ConfigKey *config, QObject *parent) return; } - WatchPluginInterface *watchPlugin = registry->getWatchPlugin(driver); if (!watchPlugin) { qWarning() << "Invalid driver" << driver; diff --git a/sowatchui/watchesmodel.cpp b/sowatchui/watchesmodel.cpp index f8afcd4..0f1fa3d 100644 --- a/sowatchui/watchesmodel.cpp +++ b/sowatchui/watchesmodel.cpp @@ -88,12 +88,14 @@ void WatchesModel::addFoundWatch(const QVariantMap &info) QString name = base.arg(""); int num = 1; + // Create the setting keys in numerical order + // e.g. if watch1 is already existing, use watch2, etc. while (existing.contains(name)) { num++; name = base.arg(num); } - // Load the autodetected settings + // Load the autodetected settings into the new key ConfigKey* newkey = _config->getSubkey(name); foreach (const QString& key, info.keys()) { newkey->set(key, info[key]); -- cgit v1.2.3