summaryrefslogtreecommitdiff
path: root/liveview/liveview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'liveview/liveview.cpp')
-rw-r--r--liveview/liveview.cpp194
1 files changed, 183 insertions, 11 deletions
diff --git a/liveview/liveview.cpp b/liveview/liveview.cpp
index bd0cdbe..f4b7434 100644
--- a/liveview/liveview.cpp
+++ b/liveview/liveview.cpp
@@ -1,13 +1,19 @@
+#include <QtEndian>
+
#include "liveview.h"
using namespace sowatch;
QTM_USE_NAMESPACE
+#define PROTOCOL_DEBUG 1
+
LiveView::LiveView(ConfigKey* settings, QObject* parent) :
BluetoothWatch(QBluetoothAddress(settings->value("address").toString()), parent),
- _settings(settings->getSubkey(QString(), this))
+ _settings(settings->getSubkey(QString(), this)),
+ _sendTimer(new QTimer(this))
{
-
+ _sendTimer->setInterval(DelayBetweenMessages);
+ connect(_sendTimer, SIGNAL(timeout()), SLOT(handleSendTimerTick()));
}
LiveView::~LiveView()
@@ -35,11 +41,6 @@ QStringList LiveView::buttons() const
return QStringList();
}
-bool LiveView::isConnected() const
-{
- return false;
-}
-
bool LiveView::busy() const
{
return false; // TODO
@@ -47,15 +48,20 @@ bool LiveView::busy() const
void LiveView::setDateTime(const QDateTime& dateTime)
{
-
+ // It seems LiveView _requests_ the current date rather than expecting
+ // the phone to be sending it.
+ // Wonder what will happen during DST changes?
+ // Do nothing here.
}
+
void LiveView::queryDateTime()
{
-
+ // LiveView does not support this.
}
+
QDateTime LiveView::dateTime() const
{
- return QDateTime::currentDateTime(); // TODO
+ return QDateTime::currentDateTime();
}
void LiveView::queryBatteryLevel()
@@ -99,10 +105,176 @@ void LiveView::vibrate(int msecs)
void LiveView::setupBluetoothWatch()
{
-
+ connect(_socket, SIGNAL(readyRead()), SLOT(handleDataReceived()));
+ updateDisplayProperties();
}
void LiveView::desetupBluetoothWatch()
{
}
+
+void LiveView::send(const Message &msg)
+{
+ _sendingMsgs.enqueue(msg);
+ if (!_sendTimer->isActive()) {
+ _sendTimer->start();
+ }
+}
+
+void LiveView::updateDisplayProperties()
+{
+ static const char *software_version = "0.0.3";
+
+ send(Message(GetDisplayProperties,
+ QByteArray(software_version, strlen(software_version) + 1)));
+}
+
+void LiveView::updateSoftwareVersion()
+{
+ send(Message(GetSoftwareVersion, QByteArray(1, 0)));
+}
+
+void LiveView::enableLed()
+{
+ QByteArray data;
+ data.append(char(0xFF));
+ data.append(char(0xFF));
+ data.append(char(0x00));
+ data.append(char(0x64));
+ data.append(char(0x00));
+ data.append(char(0xFA));
+
+ send(Message(EnableLed, data));
+}
+
+void LiveView::handleMessage(const Message &msg)
+{
+ send(Message(Ack, QByteArray(1, msg.type)));
+ switch (msg.type) {
+ case GetDisplayPropertiesResponse:
+ handleDisplayProperties(msg);
+ break;
+ }
+}
+
+void LiveView::handleDisplayProperties(const Message &msg)
+{
+ updateSoftwareVersion();
+}
+
+void LiveView::handleDataReceived()
+{
+#pragma pack(push)
+#pragma pack(1)
+ static const int HEADER_SIZE = 6;
+ union header_t {
+ char c[HEADER_SIZE];
+ struct header_fields_t {
+ quint8 msg_type;
+ quint8 header_len;
+ quint32 data_len;
+ } h;
+ } header;
+#pragma pack(pop)
+
+ Q_ASSERT(sizeof(header) == HEADER_SIZE);
+
+ do {
+ qint64 dataRead;
+
+ qDebug() << "received" << _socket->bytesAvailable() << "bytes";
+
+ if (_receivingMsg.type == NoMessage) {
+ /* Still not received even the packet type */
+ /* Receive the full header. */
+ if (_socket->bytesAvailable() < HEADER_SIZE) {
+ /* Still not enough data available. */
+ return; /* Wait for more, if non blocking. */
+ }
+
+ dataRead = _socket->read(header.c, HEADER_SIZE);
+#if PROTOCOL_DEBUG
+ qDebug() << "received header" << QByteArray(header.c, HEADER_SIZE).toHex();
+#endif
+ if (dataRead < HEADER_SIZE) {
+ qWarning() << "Short read";
+ return;
+ }
+
+ _receivingMsg.type = static_cast<MessageType>(header.h.msg_type);
+ if (header.h.header_len != HEADER_SIZE - 2) {
+ qWarning() << "Unexpected header length:" << header.h.header_len;
+ }
+
+ unsigned long data_size = qFromBigEndian(header.h.data_len);
+ if (data_size > 1048576) {
+ // If input packet is > 1 MiB, consider a protocol error.
+ qWarning() << "Too large data size: " << data_size;
+ data_size = 0;
+ }
+ _receivingMsg.data.resize(data_size);
+
+ qDebug() << "got header (type=" << _receivingMsg.type <<
+ "size=" << data_size << ")";
+ }
+
+ /* We have the header; now, try to get the complete packet. */
+ if (_socket->bytesAvailable() < _receivingMsg.data.size()) {
+#if PROTOCOL_DEBUG
+ qDebug() << "Waiting for more data" << _socket->bytesAvailable() << "/" << _receivingMsg.data.size();
+#endif
+ return; /* Wait for more. */
+ }
+
+ dataRead = _socket->read(_receivingMsg.data.data(), _receivingMsg.data.size());
+ if (dataRead < _receivingMsg.data.size()) {
+ qWarning() << "Short read";
+ return;
+ }
+
+#if PROTOCOL_DEBUG
+ qDebug() << "received" << _receivingMsg.type << _receivingMsg.data.toHex();
+#endif
+ handleMessage(_receivingMsg);
+
+ // Prepare for the next packet
+ _receivingMsg.data.clear();
+ _receivingMsg.type = NoMessage;
+ } while (_socket->bytesAvailable() > 0);
+}
+
+void LiveView::handleSendTimerTick()
+{
+ static const int HEADER_SIZE = 6;
+ qDebug() << "Send tick";
+ // If there are packets to be sent...
+ if (!_sendingMsgs.empty()) {
+ // Send a message to the watch
+ Message msg = _sendingMsgs.dequeue();
+ const quint32 data_size = msg.data.size();
+ QByteArray packet;
+
+ Q_ASSERT(_connected && _socket);
+
+ packet.resize(HEADER_SIZE + data_size);
+ packet[0] = msg.type;
+ packet[1] = HEADER_SIZE - 2;
+ packet[2] = (data_size & 0xFF000000U) >> 24;
+ packet[3] = (data_size & 0x00FF0000U) >> 16;
+ packet[4] = (data_size & 0x0000FF00U) >> 8;
+ packet[5] = (data_size & 0x000000FFU);
+ packet.replace(HEADER_SIZE, data_size, msg.data);
+
+#if PROTOCOL_DEBUG
+ qDebug() << "sending" << packet.toHex();
+#endif
+
+ _socket->write(packet);
+ }
+ // If we just finished sending all packets...
+ if (_sendingMsgs.empty()) {
+ // Stop the send timer to save battery
+ _sendTimer->stop();
+ }
+}