From 44c7f99c581a1e89601cee2bd807d4abedefcaa9 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 27 Aug 2015 15:02:29 +0200 Subject: [PATCH] GBDeviceProtocol::decodeResponse() now returns an array GBDeviceEvents This allowed to remove some ugly hacks from pebble code, when encoding a response in a GBDeviceEventSendBytes and at the same time trying to notify generic code via another GBDeviceEnvent. --- .../pebble/GadgetbridgePblSupport.java | 4 +- .../devices/pebble/MorpheuzSupport.java | 62 ++++------ .../devices/pebble/PebbleIoThread.java | 13 ++- .../devices/pebble/PebbleProtocol.java | 109 +++++++++++------- .../devices/pebble/WeatherNeatSupport.java | 4 +- .../service/serial/GBDeviceProtocol.java | 2 +- 6 files changed, 104 insertions(+), 90 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/GadgetbridgePblSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/GadgetbridgePblSupport.java index 0c709d9e..f12bba39 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/GadgetbridgePblSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/GadgetbridgePblSupport.java @@ -33,7 +33,7 @@ public class GadgetbridgePblSupport { mPebbleProtocol = pebbleProtocol; } - public GBDeviceEvent handleMessage(ArrayList> pairs) { + public GBDeviceEvent[] handleMessage(ArrayList> pairs) { int timestamp = 0; for (Pair pair : pairs) { switch (pair.first) { @@ -75,6 +75,6 @@ public class GadgetbridgePblSupport { } GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id); - return sendBytes; + return new GBDeviceEvent[]{sendBytes}; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/MorpheuzSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/MorpheuzSupport.java index a557ed80..af368adc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/MorpheuzSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/MorpheuzSupport.java @@ -5,7 +5,6 @@ import android.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.SimpleTimeZone; import java.util.TimeZone; @@ -41,7 +40,6 @@ public class MorpheuzSupport { public static final UUID uuid = UUID.fromString("5be44f1d-d262-4ea6-aa30-ddbec1e3cab2"); private final PebbleProtocol mPebbleProtocol; - private boolean sent_to_gadgetbridge = false; // data received from Morpheuz in native format private int smartalarm_from = -1; // time in minutes relative from 0:00 for smart alarm (earliest) private int smartalarm_to = -1;// time in minutes relative from 0:00 for smart alarm (latest) @@ -57,21 +55,15 @@ public class MorpheuzSupport { private byte[] encodeMorpheuzMessage(int key, int value) { ArrayList> pairs = new ArrayList<>(); pairs.add(new Pair(key, value)); - byte[] ackMessage = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id); - byte[] testMessage = mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, uuid, pairs); - ByteBuffer buf = ByteBuffer.allocate(ackMessage.length + testMessage.length); - - // encode ack and put in front of push message (hack for acknowledging the last message) - buf.put(ackMessage); - buf.put(testMessage); - - return buf.array(); + return mPebbleProtocol.encodeApplicationMessagePush(PebbleProtocol.ENDPOINT_APPLICATIONMESSAGE, uuid, pairs); } - public GBDeviceEvent handleMessage(ArrayList> pairs) { + public GBDeviceEvent[] handleMessage(ArrayList> pairs) { + int ctrl_message = 0; + GBDeviceEventSleepMonitorResult sleepMonitorResult = null; + for (Pair pair : pairs) { - int ctrl_message = 0; switch (pair.first) { case KEY_TRANSMIT: case KEY_GONEOFF: @@ -79,22 +71,11 @@ public class MorpheuzSupport { alarm_gone_off = (int) pair.second; LOG.info("got gone off: " + alarm_gone_off / 60 + ":" + alarm_gone_off % 60); } - /* super-ugly hack: if if did not notice GadgetBridge yet, do so and delay confirmation so Morpheuz - * will resend gone off data. The second time, we acknowledge it. - * - * this can be fixed by allowing to return multiple GBDeviceCommands - */ - if (sent_to_gadgetbridge) { - ctrl_message = MorpheuzSupport.CTRL_VERSION_DONE | MorpheuzSupport.CTRL_GONEOFF_DONE | MorpheuzSupport.CTRL_TRANSMIT_DONE | MorpheuzSupport.CTRL_SET_LAST_SENT; - } else { - GBDeviceEventSleepMonitorResult sleepMonitorResult = new GBDeviceEventSleepMonitorResult(); - sleepMonitorResult.smartalarm_from = smartalarm_from; - sleepMonitorResult.smartalarm_to = smartalarm_to; - sleepMonitorResult.alarm_gone_off = alarm_gone_off; - sleepMonitorResult.recording_base_timestamp = recording_base_timestamp; - sent_to_gadgetbridge = true; - return sleepMonitorResult; - } + sleepMonitorResult = new GBDeviceEventSleepMonitorResult(); + sleepMonitorResult.smartalarm_from = smartalarm_from; + sleepMonitorResult.smartalarm_to = smartalarm_to; + sleepMonitorResult.alarm_gone_off = alarm_gone_off; + sleepMonitorResult.recording_base_timestamp = recording_base_timestamp; break; case KEY_POINT: if (recording_base_timestamp == -1) { @@ -140,7 +121,6 @@ public class MorpheuzSupport { case KEY_VERSION: LOG.info("got version: " + ((float) ((int) pair.second) / 10.0f)); ctrl_message = MorpheuzSupport.CTRL_VERSION_DONE | MorpheuzSupport.CTRL_SET_LAST_SENT; - sent_to_gadgetbridge = false; break; case KEY_BASE: // fix timestamp @@ -156,14 +136,20 @@ public class MorpheuzSupport { LOG.info("unhandled key: " + pair.first); break; } - if (ctrl_message > 0) { - GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = encodeMorpheuzMessage(MorpheuzSupport.KEY_CTRL, ctrl_message); - return sendBytes; - } } - GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); - sendBytes.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id); - return sendBytes; + + // always ack + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = mPebbleProtocol.encodeApplicationMessageAck(uuid, mPebbleProtocol.last_id); + + // sometimes send control message + GBDeviceEventSendBytes sendBytesCtrl = null; + if (ctrl_message > 0) { + sendBytesCtrl = new GBDeviceEventSendBytes(); + sendBytesCtrl.encodedBytes = encodeMorpheuzMessage(MorpheuzSupport.KEY_CTRL, ctrl_message); + } + + // ctrl and sleep monitor might be null, thats okay + return new GBDeviceEvent[]{sendBytesAck, sendBytesCtrl, sleepMonitorResult}; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 28199529..17958601 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -237,12 +237,17 @@ public class PebbleIoThread extends GBDeviceIoThread { mInStream.skip(2); } - GBDeviceEvent deviceEvent = mPebbleProtocol.decodeResponse(buffer); - if (deviceEvent == null) { + GBDeviceEvent deviceEvents[] = mPebbleProtocol.decodeResponse(buffer); + if (deviceEvents == null) { LOG.info("unhandled message to endpoint " + endpoint + " (" + length + " bytes)"); } else { - if (!evaluateGBDeviceEventPebble(deviceEvent)) { - mPebbleSupport.evaluateGBDeviceEvent(deviceEvent); + for (GBDeviceEvent deviceEvent : deviceEvents) { + if (deviceEvent == null) { + continue; + } + if (!evaluateGBDeviceEventPebble(deviceEvent)) { + mPebbleSupport.evaluateGBDeviceEvent(deviceEvent); + } } } try { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index f8e39033..8c72ff4b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1059,15 +1059,31 @@ public class PebbleProtocol extends GBDeviceProtocol { return null; } - private GBDeviceEventDismissNotification decodeNotificationAction(ByteBuffer buf) { + private GBDeviceEventDismissNotification decodeNotificationAction2x(ByteBuffer buf) { buf.order(ByteOrder.LITTLE_ENDIAN); byte command = buf.get(); if (command == 0x02) { // dismiss notification ? - if (isFw3x) { - buf.getLong(); // skip 8 bytes of UUID - buf.getInt(); // skip 4 bytes of UUID + int id = buf.getInt(); + short action = buf.getShort(); // at least the low byte should be the action - or not? + if (action == 0x0001) { + GBDeviceEventDismissNotification devEvtDismissNotification = new GBDeviceEventDismissNotification(); + devEvtDismissNotification.notificationID = id; + return devEvtDismissNotification; } + LOG.info("unexpected paramerter in dismiss action: " + action); + } + + return null; + } + + private GBDeviceEventDismissNotification decodeNotificationAction3x(ByteBuffer buf) { + buf.order(ByteOrder.LITTLE_ENDIAN); + + byte command = buf.get(); + if (command == 0x02) { // dismiss notification ? + buf.getLong(); // skip 8 bytes of UUID + buf.getInt(); // skip 4 bytes of UUID int id = buf.getInt(); short action = buf.getShort(); // at least the low byte should be the action - or not? if (action == 0x0001) { @@ -1114,26 +1130,31 @@ public class PebbleProtocol extends GBDeviceProtocol { private GBDeviceEventSendBytes decodeDatalog(ByteBuffer buf, short length) { byte command = buf.get(); byte id = buf.get(); - if (command == DATALOG_TIMEOUT) { - LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring"); - return null; - } - if (command == DATALOG_SENDDATA) { - buf.order(ByteOrder.LITTLE_ENDIAN); - int items_left = buf.getInt(); - int crc = buf.getInt(); - LOG.info("DATALOG SENDDATA. id=" + (id & 0xff) + ", items_left=" + items_left + ", total length=" + (length - 9)); - } else if (command == DATALOG_OPENSESSION) { - buf.order(ByteOrder.BIG_ENDIAN); - long uuid_high = buf.getLong(); - long uuid_low = buf.getLong(); - UUID uuid = new UUID(uuid_high, uuid_low); - buf.order(ByteOrder.LITTLE_ENDIAN); - int timestamp = buf.getInt(); - int log_tag = buf.getInt(); - byte item_type = buf.get(); - short item_size = buf.get(); - LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", item_type=" + item_type + ", item_size=" + item_size); + switch (command) { + case DATALOG_TIMEOUT: + LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring"); + return null; + case DATALOG_SENDDATA: + buf.order(ByteOrder.LITTLE_ENDIAN); + int items_left = buf.getInt(); + int crc = buf.getInt(); + LOG.info("DATALOG SENDDATA. id=" + (id & 0xff) + ", items_left=" + items_left + ", total length=" + (length - 9)); + break; + case DATALOG_OPENSESSION: + buf.order(ByteOrder.BIG_ENDIAN); + long uuid_high = buf.getLong(); + long uuid_low = buf.getLong(); + UUID uuid = new UUID(uuid_high, uuid_low); + buf.order(ByteOrder.LITTLE_ENDIAN); + int timestamp = buf.getInt(); + int log_tag = buf.getInt(); + byte item_type = buf.get(); + short item_size = buf.get(); + LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", item_type=" + item_type + ", item_size=" + item_size); + break; + default: + LOG.info("unknown DATALOG command: " + (command & 0xff)); + break; } LOG.info("sending ACK (0x85)"); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); @@ -1142,12 +1163,12 @@ public class PebbleProtocol extends GBDeviceProtocol { } @Override - public GBDeviceEvent decodeResponse(byte[] responseData) { + public GBDeviceEvent[] decodeResponse(byte[] responseData) { ByteBuffer buf = ByteBuffer.wrap(responseData); buf.order(ByteOrder.BIG_ENDIAN); short length = buf.getShort(); short endpoint = buf.getShort(); - GBDeviceEvent devEvt = null; + GBDeviceEvent devEvts[] = null; byte pebbleCmd = -1; switch (endpoint) { case ENDPOINT_MUSICCONTROL: @@ -1178,7 +1199,7 @@ public class PebbleProtocol extends GBDeviceProtocol { default: break; } - devEvt = musicCmd; + devEvts = new GBDeviceEvent[]{musicCmd}; break; case ENDPOINT_PHONECONTROL: pebbleCmd = buf.get(); @@ -1191,7 +1212,7 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info("Unknown PHONECONTROL event" + pebbleCmd); break; } - devEvt = callCmd; + devEvts = new GBDeviceEvent[]{callCmd}; break; case ENDPOINT_FIRMWAREVERSION: pebbleCmd = buf.get(); @@ -1213,7 +1234,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } else if (hwRev == -3) { // basalt emulator versionCmd.hwVersion = "dvt"; } - devEvt = versionCmd; + devEvts = new GBDeviceEvent[]{versionCmd}; break; case ENDPOINT_APPMANAGER: pebbleCmd = buf.get(); @@ -1253,12 +1274,12 @@ public class PebbleProtocol extends GBDeviceProtocol { break; } } - devEvt = appInfoCmd; + devEvts = new GBDeviceEvent[]{appInfoCmd}; break; case APPMANAGER_GETUUIDS: GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodeSimpleMessage(ENDPOINT_APPMANAGER, APPMANAGER_GETAPPBANKSTATUS); - devEvt = sendBytes; + devEvts = new GBDeviceEvent[]{sendBytes}; tmpUUIDS.clear(); slotsUsed = buf.getInt(); for (int i = 0; i < slotsUsed; i++) { @@ -1282,7 +1303,7 @@ public class PebbleProtocol extends GBDeviceProtocol { deleteRes.event = GBDeviceEventAppManagement.Event.FAILURE; break; } - devEvt = deleteRes; + devEvts = new GBDeviceEvent[]{deleteRes}; break; default: LOG.info("Unknown APPMANAGER event" + pebbleCmd); @@ -1303,7 +1324,7 @@ public class PebbleProtocol extends GBDeviceProtocol { installRes.event = GBDeviceEventAppManagement.Event.FAILURE; break; } - devEvt = installRes; + devEvts = new GBDeviceEvent[]{installRes}; break; case ENDPOINT_APPLICATIONMESSAGE: pebbleCmd = buf.get(); @@ -1317,13 +1338,13 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info("got APPLICATIONMESSAGE PUSH from UUID " + uuid); if (WeatherNeatSupport.uuid.equals(uuid)) { ArrayList> dict = decodeDict(buf); - devEvt = mWeatherNeatSupport.handleMessage(dict); + devEvts = mWeatherNeatSupport.handleMessage(dict); } else if (MorpheuzSupport.uuid.equals(uuid)) { ArrayList> dict = decodeDict(buf); - devEvt = mMorpheuzSupport.handleMessage(dict); + devEvts = mMorpheuzSupport.handleMessage(dict); } else if (GadgetbridgePblSupport.uuid.equals(uuid)) { ArrayList> dict = decodeDict(buf); - devEvt = mGadgetbridgePblSupport.handleMessage(dict); + devEvts = mGadgetbridgePblSupport.handleMessage(dict); } break; case APPLICATIONMESSAGE_ACK: @@ -1346,33 +1367,35 @@ public class PebbleProtocol extends GBDeviceProtocol { LOG.info("Pebble asked for Phone/App Version - repLYING!"); GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodePhoneVersion(PHONEVERSION_REMOTE_OS_ANDROID); - devEvt = sendBytes; + devEvts = new GBDeviceEvent[]{sendBytes}; break; default: break; } break; case ENDPOINT_DATALOG: - devEvt = decodeDatalog(buf, length); + devEvts = new GBDeviceEvent[]{decodeDatalog(buf, length)}; break; case ENDPOINT_SCREENSHOT: - devEvt = decodeScreenshot(buf, length); + devEvts = new GBDeviceEvent[]{decodeScreenshot(buf, length)}; break; case ENDPOINT_EXTENSIBLENOTIFS: + devEvts = new GBDeviceEvent[]{decodeNotificationAction2x(buf)}; + break; case ENDPOINT_NOTIFICATIONACTION: - devEvt = decodeNotificationAction(buf); + devEvts = new GBDeviceEvent[]{decodeNotificationAction3x(buf)}; break; case ENDPOINT_PING: - devEvt = decodePing(buf); + devEvts = new GBDeviceEvent[]{decodePing(buf)}; break; case ENDPOINT_APPFETCH: - devEvt = decodeAppFetch(buf); + devEvts = new GBDeviceEvent[]{decodeAppFetch(buf)}; break; default: break; } - return devEvt; + return devEvts; } public void setForceProtocol(boolean force) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java index 0ddc190d..cd6c5bb9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java @@ -48,9 +48,9 @@ public class WeatherNeatSupport { return buf.array(); } - public GBDeviceEvent handleMessage(ArrayList> pairs) { + public GBDeviceEvent[] handleMessage(ArrayList> pairs) { GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodeWeatherNeatMessage("Berlin", "22 C", "cloudy", 0); - return sendBytes; + return new GBDeviceEvent[] {sendBytes}; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 20133c3b..e99e0c25 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -63,7 +63,7 @@ public abstract class GBDeviceProtocol { return null; } - public GBDeviceEvent decodeResponse(byte[] responseData) { + public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } } \ No newline at end of file