summaryrefslogtreecommitdiff
path: root/metawatch
diff options
context:
space:
mode:
Diffstat (limited to 'metawatch')
-rw-r--r--metawatch/metawatch.cpp111
-rw-r--r--metawatch/metawatch.h41
-rw-r--r--metawatch/metawatchdigitalsimulator.cpp2
-rw-r--r--metawatch/metawatchdigitalsimulator.h2
-rw-r--r--metawatch/metawatchscanner.cpp12
-rw-r--r--metawatch/metawatchscanner.h6
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