diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java new file mode 100644 index 00000000..b7d42544 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthOverlayData.java @@ -0,0 +1,99 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.HealthSampleProvider; +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; +import nodomain.freeyourgadget.gadgetbridge.util.GB; + +class DatalogSessionHealthOverlayData extends DatalogSession { + + private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthOverlayData.class); + + public DatalogSessionHealthOverlayData(byte id, UUID uuid, int tag, byte item_type, short item_size) { + super(id, uuid, tag, item_type, item_size); + taginfo = "(health - overlay data " + tag + " )"; + } + + @Override + public boolean handleMessage(ByteBuffer datalogMessage, int length) { + LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); + + int initialPosition = datalogMessage.position(); + int beginOfRecordPosition; + short recordVersion; //probably + short recordType; //probably: 1=sleep, 2=deep sleep, 5=??run??ignored for now + + if (0 != (length % itemSize)) + return false;//malformed message? + + int recordCount = length / itemSize; + OverlayRecord[] overlayRecords = new OverlayRecord[recordCount]; + + for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { + beginOfRecordPosition = initialPosition + recordIdx * itemSize; + datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record + recordVersion = datalogMessage.getShort(); + if ((recordVersion != 1) && (recordVersion != 3)) + return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it + + datalogMessage.getShort();//throwaway, unknown + recordType = datalogMessage.getShort(); + + overlayRecords[recordIdx] = new OverlayRecord(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); + } + + return store(overlayRecords);//NACK if we cannot store the data yet, the watch will send the overlay records again. + } + + private boolean store(OverlayRecord[] overlayRecords) { + DBHandler dbHandler = null; + SampleProvider sampleProvider = new HealthSampleProvider(); + try { + dbHandler = GBApplication.acquireDB(); + int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); + for (OverlayRecord overlayRecord : overlayRecords) { + if (latestTimestamp < (overlayRecord.timestampStart + overlayRecord.durationSeconds)) + return false; + switch (overlayRecord.type) { + case 1: + dbHandler.changeStoredSamplesType(overlayRecord.timestampStart, (overlayRecord.timestampStart + overlayRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); + break; + case 2: + dbHandler.changeStoredSamplesType(overlayRecord.timestampStart, (overlayRecord.timestampStart + overlayRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider); + break; + default: + //TODO: other values refer to unknown activity types. + } + } + } catch (Exception ex) { + LOG.debug(ex.getMessage()); + } finally { + if (dbHandler != null) { + dbHandler.release(); + } + } + return true; + } + + private class OverlayRecord { + int type; //1=sleep, 2=deep sleep + int offsetUTC; //probably + int timestampStart; + int durationSeconds; + + public OverlayRecord(int type, int offsetUTC, int timestampStart, int durationSeconds) { + this.type = type; + this.offsetUTC = offsetUTC; + this.timestampStart = timestampStart; + this.durationSeconds = durationSeconds; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java index 7d06876f..2162f9d5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/DatalogSessionHealthSleep.java @@ -1,7 +1,5 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; -import android.widget.Toast; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,71 +25,6 @@ class DatalogSessionHealthSleep extends DatalogSession { @Override public boolean handleMessage(ByteBuffer datalogMessage, int length) { LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); - switch (this.tag) { - case 83: - return handleMessage83(datalogMessage, length); - case 84: - return handleMessage84(datalogMessage, length); - default: - return false; - } - } - - private boolean handleMessage84(ByteBuffer datalogMessage, int length) { - int initialPosition = datalogMessage.position(); - int beginOfRecordPosition; - short recordVersion; //probably - short recordType; //probably: 1=sleep, 2=deep sleep - - if (0 != (length % itemSize)) - return false;//malformed message? - - int recordCount = length / itemSize; - SleepRecord84[] sleepRecords = new SleepRecord84[recordCount]; - - for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { - beginOfRecordPosition = initialPosition + recordIdx * itemSize; - datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record - recordVersion = datalogMessage.getShort(); - if (recordVersion != 1) - return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it - - datalogMessage.getShort();//throwaway, unknown - recordType = datalogMessage.getShort(); - - sleepRecords[recordIdx] = new SleepRecord84(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); - } - - return store84(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. - } - - private boolean store84(SleepRecord84[] sleepRecords) { - DBHandler dbHandler = null; - SampleProvider sampleProvider = new HealthSampleProvider(); - try { - dbHandler = GBApplication.acquireDB(); - int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); - for (SleepRecord84 sleepRecord : sleepRecords) { - if (latestTimestamp < (sleepRecord.timestampStart + sleepRecord.durationSeconds)) - return false; - if (sleepRecord.type == 2) { - dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider); - } else { - dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); - } - - } - } catch (Exception ex) { - LOG.debug(ex.getMessage()); - } finally { - if (dbHandler != null) { - dbHandler.release(); - } - } - return true; - } - - private boolean handleMessage83(ByteBuffer datalogMessage, int length) { int initialPosition = datalogMessage.position(); int beginOfRecordPosition; short recordVersion; //probably @@ -100,7 +33,7 @@ class DatalogSessionHealthSleep extends DatalogSession { return false;//malformed message? int recordCount = length / itemSize; - SleepRecord83[] sleepRecords = new SleepRecord83[recordCount]; + SleepRecord[] sleepRecords = new SleepRecord[recordCount]; for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { beginOfRecordPosition = initialPosition + recordIdx * itemSize; @@ -109,23 +42,22 @@ class DatalogSessionHealthSleep extends DatalogSession { if (recordVersion != 1) return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it - sleepRecords[recordIdx] = new SleepRecord83(datalogMessage.getInt(), + sleepRecords[recordIdx] = new SleepRecord(datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt()); } - return store83(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. + return store(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. } - private boolean store83(SleepRecord83[] sleepRecords) { + private boolean store(SleepRecord[] sleepRecords) { DBHandler dbHandler = null; SampleProvider sampleProvider = new HealthSampleProvider(); - GB.toast("Deep sleep is supported only from firmware 3.11 onwards.", Toast.LENGTH_LONG, GB.INFO); try { dbHandler = GBApplication.acquireDB(); int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); - for (SleepRecord83 sleepRecord : sleepRecords) { + for (SleepRecord sleepRecord : sleepRecords) { if (latestTimestamp < sleepRecord.bedTimeEnd) return false; dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); @@ -140,13 +72,13 @@ class DatalogSessionHealthSleep extends DatalogSession { return true; } - private class SleepRecord83 { + private class SleepRecord { int offsetUTC; //probably int bedTimeStart; int bedTimeEnd; int deepSleepSeconds; - public SleepRecord83(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { + public SleepRecord(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { this.offsetUTC = offsetUTC; this.bedTimeStart = bedTimeStart; this.bedTimeEnd = bedTimeEnd; @@ -154,17 +86,4 @@ class DatalogSessionHealthSleep extends DatalogSession { } } - private class SleepRecord84 { - int type; //1=sleep, 2=deep sleep - int offsetUTC; //probably - int timestampStart; - int durationSeconds; - - public SleepRecord84(int type, int offsetUTC, int timestampStart, int durationSeconds) { - this.type = type; - this.offsetUTC = offsetUTC; - this.timestampStart = timestampStart; - this.durationSeconds = durationSeconds; - } - } } \ No newline at end of file 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 5d261e6a..56863447 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 @@ -1881,8 +1881,10 @@ public class PebbleProtocol extends GBDeviceProtocol { if (!mDatalogSessions.containsKey(id)) { if (uuid.equals(UUID_ZERO) && log_tag == 81) { mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, log_tag, item_type, item_size)); - } else if (uuid.equals(UUID_ZERO) && (log_tag == 83 || log_tag == 84)) { + } else if (uuid.equals(UUID_ZERO) && log_tag == 83) { mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, log_tag, item_type, item_size)); + } else if (uuid.equals(UUID_ZERO) && log_tag == 84) { + mDatalogSessions.put(id, new DatalogSessionHealthOverlayData(id, uuid, log_tag, item_type, item_size)); } else { mDatalogSessions.put(id, new DatalogSession(id, uuid, log_tag, item_type, item_size)); }