#include #include #include #include "metawatch.h" #include "metawatchbletransport.h" MetaWatch::MetaWatch(const QString &btAddr, QObject *parent) : QObject(parent) { GatoPeripheral *peripheral = new GatoPeripheral(GatoAddress(btAddr), this); _transport = new MetaWatchBLETransport(peripheral, this); connect(_transport, &MetaWatchTransport::connected, this, &MetaWatch::connected); connect(_transport, &MetaWatchTransport::disconnected, this, &MetaWatch::disconnected); connect(_transport, &MetaWatchTransport::messageReceived, this, &MetaWatch::handleTransportMessage); } QList MetaWatch::availableClocks() { QList clocks; for (int i = 0; i < 6; i++) { clocks << QUrl("clock://" + QString::number(i)); } return clocks; } void MetaWatch::setDateTime(const QDateTime &dt) { const QDate &date = dt.date(); const QTime &time = dt.time(); QByteArray data; QDataStream s(&data, QIODevice::WriteOnly); s.setByteOrder(QDataStream::BigEndian); s << quint16(date.year()) << quint8(date.month()) << quint8(date.day()); s << quint8(date.dayOfWeek() % 7); s << quint8(time.hour()) << quint8(time.minute()) << quint8(time.second()); _transport->sendMessage(MessageSetRealTimeClock, 0, data); } void MetaWatch::configure(WatchProperties props) { _transport->sendMessage(MessageWatchPropertyOperation, props | WatchPropertyOperationWrite, QByteArray()); } void MetaWatch::updateDeviceType() { // Also disables HFP/MAP connection. _transport->sendMessage(MessageGetDeviceType, 0xC0, QByteArray()); } void MetaWatch::updateBatteryStatus() { _transport->sendMessage(MessageGetBatteryStatus, 0, QByteArray()); } void MetaWatch::updateLcdDisplay() { // Switches to UiGen2 mode and to page 0. _transport->sendMessage(MessageUpdateLcdDisplay, 0x80, QByteArray()); } void MetaWatch::updateWidgetList(const QList &widgets) { int num_widgets = 0; // Count valid widgets for (int w = 0; w < widgets.size(); w++) { const WidgetInfo *info = widgets[w]; if (info->valid()) num_widgets++; } const int max_widgets_in_one_msg = 7; const int num_messages = (num_widgets + (max_widgets_in_one_msg - 1)) / max_widgets_in_one_msg; int num_message = 0; QByteArray msg; Q_ASSERT(num_messages < 4); msg.reserve(max_widgets_in_one_msg * 2); if (num_widgets == 0) { msg.append(static_cast(0xFF)); msg.append(static_cast(0x00)); // Clear all widgets _transport->sendMessage(MessageSetWidgetList, 0x4, msg); return; } qDebug() << "Msgs" << num_messages << num_message; for (int w = 0; w < num_widgets; w++) { WidgetInfo *info = widgets[w]; if (!info->valid()) continue; // Skip disabled/empty widget quint8 id = w; quint8 options = ((info->page() << 4) & 0x30) | ((info->size() << 2) & 0xC) | ((info->position() << 2) & 0x3); if (info->url().scheme() == "clock") { id |= (clockUrlToClockId(info->url()) << 4) & 0xF0; options |= 0x80; } if (info->invert()) { options |= 0x40; } qDebug() << QString::number(id, 16) << QString::number(options, 16); msg.append(id); msg.append(options); if (msg.size() >= max_widgets_in_one_msg * 2) { Q_ASSERT(num_message < num_messages); _transport->sendMessage(MessageSetWidgetList, ((num_messages << 2) & 0xC) | (num_message & 0x3), msg); msg.clear(); msg.reserve(max_widgets_in_one_msg * 2); num_message++; } } if (msg.size() > 0) { Q_ASSERT(num_message < num_messages); _transport->sendMessage(MessageSetWidgetList, ((num_messages << 2) & 0xC) | (num_message & 0x3), msg); } } void MetaWatch::connectDevice() { _transport->connectDevice(); } void MetaWatch::disconnectDevice() { _transport->disconnectDevice(); } int MetaWatch::clockUrlToClockId(const QUrl &url) { if (url.scheme() != "clock") return -1; QString host = url.host(); if (!host.startsWith("clock")) return -1; return host.mid(5).toInt(); } void MetaWatch::handleTransportMessage(quint8 type, quint8 options, const QByteArray &payload) { switch (type) { case MessageGetDeviceTypeResponse: emit deviceType(static_cast(options & 0xF)); break; case MessageModeChangeIndication: qDebug() << "Got mode change indication"; break; case MessageReadBatteryStatusResponse: if (payload.size() < 6) { qWarning() << "Invalid battery status response size"; } emit batteryStatus(payload[1], payload[2]); break; case MessageConnectionChange: case MessageIntervalChanged: // No idea what to do with these. break; default: qWarning() << "Unknown message type received:" << QString::number(type, 16); } }