#ifndef METAWATCH_H #define METAWATCH_H #include #include #include #include #include #include #include using QTM_PREPEND_NAMESPACE(QBluetoothSocket); using QTM_PREPEND_NAMESPACE(QBluetoothAddress); using QTM_PREPEND_NAMESPACE(QSystemAlignedTimer); namespace sowatch { class MetaWatchPaintEngine; class MetaWatch : public Watch { Q_OBJECT public: explicit MetaWatch(ConfigKey *settings, QObject *parent = 0); ~MetaWatch(); static const int DelayBetweenMessages = 5; static const int VibrateLength = 500; static const int DelayBetweenRings = 2500; static const int RingLength = 250; enum MessageType { NoMessage = 0, GetDeviceType = 0x01, GetDeviceTypeResponse = 0x02, GetInformationString = 0x03, GetInformationStringResponse = 0x04, WriteOledBuffer = 0x10, ChangeOledMode = 0x12, WriteOledScrollBuffer = 0x13, AdvanceWatchHands = 0x20, SetVibrateMode = 0x23, SetRealTimeClock = 0x26, GetRealTimeClock = 0x27, GetRealTimeClockResponse = 0x28, NvalOperation = 0x30, NvalOperationResponse = 0x31, StatusChangeEvent = 0x33, ButtonEvent = 0x34, GeneralPurposePhone = 0x35, GeneralPurposeWatch = 0x36, WriteLcdBuffer = 0x40, ConfigureLcdIdleBufferSize = 0x42, UpdateLcdDisplay = 0x43, LoadLcdTemplate = 0x44, EnableButton = 0x46, DisableButton = 0x47, BatteryConfiguration = 0x53, LowBatteryWarning = 0x54, LowBatteryBluetoothOff = 0x55, ReadBatteryVoltage = 0x56, ReadBatteryVoltageResponse = 0x57, ReadLightSensor = 0x58, ReadLightSensorResponse = 0x59 }; enum NvalValue { ReservedNval = 0, LinkKey = 0x1, IdleBufferConfiguration = 0x2, TimeFormat = 0x2009, DateFormat = 0x200a }; enum Mode { IdleMode = 0, ApplicationMode = 1, NotificationMode = 2 }; enum Button { BtnA = 0, BtnB, BtnC, BtnD, BtnE, BtnF }; enum ButtonPress { PressOnly = 0, PressAndRelease = 1, HoldAndRelease = 2, LongHoldAndRelease = 3 }; QPaintEngine* paintEngine() const; int metric(PaintDeviceMetric metric) const = 0; QString model() const; QStringList buttons() const; bool isConnected() const; bool busy() const; void setDateTime(const QDateTime& dateTime); void queryDateTime(); QDateTime dateTime() const; void queryBatteryLevel(); int batteryLevel() const; void queryCharging(); bool charging() const; void updateNotificationCount(Notification::Type type, int count); void updateWeather(WeatherNotification *weather); void displayIdleScreen(); void displayNotification(Notification *notification); void displayApplication(); void vibrate(int msecs); Mode currentMode() const; Mode paintTargetMode() const; QImage* imageFor(Mode mode); QRect rectFor(Mode mode); virtual void clear(Mode mode, bool black = false) = 0; virtual void update(Mode mode, const QList& rects = QList()) = 0; void grabButton(Mode mode, Button button); void ungrabButton(Mode mode, Button button); protected: ConfigKey *_settings; // Some configurable stuff. short _notificationTimeout; bool _24hMode : 1; bool _dayMonthOrder : 1; // Notifications: timers QTimer* _idleTimer; QTimer* _ringTimer; // Buttons static const char btnToWatch[8]; QStringList _buttonNames; // Current watch state QDateTime _watchTime; short _watchBattery; short _watchBatteryAverage; bool _watchCharging; Mode _currentMode; Mode _paintMode; // Required by QPaintDevice mutable MetaWatchPaintEngine* _paintEngine; /** The shadow framebuffers for each of the watch modes */ QImage _image[3]; // Timers to retry the connection when the watch is not found. static const int connectRetryTimesSize = 6; static const int connectRetryTimes[connectRetryTimesSize]; short _connectRetries; bool _connected; QTimer* _connectTimer; QSystemAlignedTimer* _connectAlignedTimer; // Connection stuff 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; Message _partialReceived; /** Pending nvals to be written once the read operation is finished. */ QMap _nvals; static const quint8 bitRevTable[16]; static const quint16 crcTable[256]; static quint16 calcCrc(const QByteArray& data, int size); static quint16 calcCrc(const Message& msg); /** Attempt a connection to the watch. */ virtual void retryConnect(); /** Sends a message to the watch. Does not block. */ virtual void send(const Message& msg); /** Sends a message to the watch if a message of the same type is not * already queued. Does not block. */ void sendIfNotQueued(const Message& msg); static uint nvalSize(NvalValue value); void nvalWrite(NvalValue value, int data); /* Some functions that wrap sending some watch messages. */ void setVibrateMode(bool enable, uint on, uint off, uint cycles); void updateLcdLine(Mode mode, const QImage& image, int line); void updateLcdLines(Mode mode, const QImage& image, int lineA, int lineB); void updateLcdLines(Mode mode, const QImage& image, const QVector& lines); void configureLcdIdleSystemArea(bool entireScreen); void updateLcdDisplay(Mode mode, bool copy = true); void loadLcdTemplate(Mode mode, int templ); void enableButton(Mode mode, Button button, ButtonPress press); void disableButton(Mode mode, Button button, ButtonPress press); void handleMessage(const Message& msg); void handleDeviceTypeMessage(const Message& msg); void handleRealTimeClockMessage(const Message& msg); void handleNvalOperationMessage(const Message& msg); void handleStatusChangeMessage(const Message& msg); void handleButtonEventMessage(const Message& msg); void handleBatteryVoltageMessage(const Message& msg); /** To be overriden; should configure a newly connected watch. */ virtual void handleWatchConnected() = 0; private slots: void settingChanged(const QString& key); void socketConnected(); void socketDisconnected(); void socketData(); void socketError(QBluetoothSocket::SocketError error); void socketState(QBluetoothSocket::SocketState error); void timedReconnect(); void timedSend(); void timedRing(); private: void realNvalWrite(NvalValue value, int data); void realSend(const Message& msg); void realReceive(bool block); }; } #endif // METAWATCH_H