diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java index 93dd50f97..82c3ac2de 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalFITMessage.java @@ -188,7 +188,7 @@ public class GlobalFITMessage { )); public static GlobalFITMessage MONITORING_INFO = new GlobalFITMessage(103, "MONITORING_INFO", Arrays.asList( - new FieldDefinitionPrimitive(0, BaseType.UINT32, "timestamp_in_tz"), // garmin timestamp, but in user timezone + new FieldDefinitionPrimitive(0, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone new FieldDefinitionPrimitive(1, BaseType.ENUM, "activity_type", FieldDefinitionFactory.FIELD.ARRAY), // 6 walking, 1 running, 13 ? new FieldDefinitionPrimitive(3, BaseType.UINT16, "steps_to_distance", FieldDefinitionFactory.FIELD.ARRAY, 5000, 0), // same size as activity_type? new FieldDefinitionPrimitive(4, BaseType.UINT16, "steps_to_calories", FieldDefinitionFactory.FIELD.ARRAY, 5000, 0), // same size as activity_type? @@ -251,6 +251,11 @@ public class GlobalFITMessage { new FieldDefinitionPrimitive(4, BaseType.UINT32, "enhanced_speed") )); + public static GlobalFITMessage TIMESTAMP_CORRELATION = new GlobalFITMessage(162, "TIMESTAMP_CORRELATION", Arrays.asList( + new FieldDefinitionPrimitive(3, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone + new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP) + )); + public static GlobalFITMessage FIELD_DESCRIPTION = new GlobalFITMessage(206, "FIELD_DESCRIPTION", Arrays.asList( new FieldDefinitionPrimitive(0, BaseType.UINT8, "developer_data_index"), new FieldDefinitionPrimitive(1, BaseType.UINT8, "field_definition_number"), @@ -307,7 +312,7 @@ public class GlobalFITMessage { public static GlobalFITMessage SLEEP_DATA_INFO = new GlobalFITMessage(273, "SLEEP_DATA_INFO", Arrays.asList( new FieldDefinitionPrimitive(0, BaseType.UINT8, "unk0"), // 2 new FieldDefinitionPrimitive(1, BaseType.UINT16, "sample_length"), // 60, sample time? - new FieldDefinitionPrimitive(2, BaseType.UINT32, "timestamp_in_tz"), // garmin timestamp, but in user timezone + new FieldDefinitionPrimitive(2, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone new FieldDefinitionPrimitive(3, BaseType.ENUM, "unk3"), // 1 new FieldDefinitionPrimitive(4, BaseType.STRING, "version"), // matches ETE in settings new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP) @@ -346,6 +351,19 @@ public class GlobalFITMessage { new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP) )); + public static GlobalFITMessage SKIN_TEMP_RAW = new GlobalFITMessage(397, "SKIN_TEMP_RAW", Arrays.asList( + new FieldDefinitionPrimitive(1, BaseType.FLOAT32, "deviation"), + new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP) + )); + + public static GlobalFITMessage SKIN_TEMP_OVERNIGHT = new GlobalFITMessage(398, "SKIN_TEMP_OVERNIGHT", Arrays.asList( + new FieldDefinitionPrimitive(0, BaseType.UINT32, "local_timestamp"), // garmin timestamp, but in user timezone + new FieldDefinitionPrimitive(1, BaseType.FLOAT32, "average_deviation"), + new FieldDefinitionPrimitive(2, BaseType.FLOAT32, "average_7_day_deviation"), + new FieldDefinitionPrimitive(3, BaseType.UINT8, "unk3"), + new FieldDefinitionPrimitive(253, BaseType.UINT32, "timestamp", FieldDefinitionFactory.FIELD.TIMESTAMP) + )); + public static Map KNOWN_MESSAGES = new HashMap() {{ put(0, FILE_ID); put(2, DEVICE_SETTINGS); @@ -367,6 +385,7 @@ public class GlobalFITMessage { put(140, PHYSIOLOGICAL_METRICS); put(159, WATCHFACE_SETTINGS); put(160, GPS_METADATA); + put(162, TIMESTAMP_CORRELATION); put(206, FIELD_DESCRIPTION); put(207, DEVELOPER_DATA); put(216, TIME_IN_ZONE); @@ -381,6 +400,8 @@ public class GlobalFITMessage { put(346, SLEEP_STATS); put(370, HRV_SUMMARY); put(371, HRV_VALUE); + put(397, SKIN_TEMP_RAW); + put(398, SKIN_TEMP_OVERNIGHT); }}; private final int number; private final String name; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitMonitoringInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitMonitoringInfo.java index b61bdae53..6380bd3c5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitMonitoringInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitMonitoringInfo.java @@ -21,7 +21,7 @@ public class FitMonitoringInfo extends RecordData { } @Nullable - public Long getTimestampInTz() { + public Long getLocalTimestamp() { return (Long) getFieldByNumber(0); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java index 6c0ed570f..7f0063b8f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitRecordDataFactory.java @@ -55,6 +55,8 @@ public class FitRecordDataFactory { return new FitWatchfaceSettings(recordDefinition, recordHeader); case 160: return new FitGpsMetadata(recordDefinition, recordHeader); + case 162: + return new FitTimestampCorrelation(recordDefinition, recordHeader); case 206: return new FitFieldDescription(recordDefinition, recordHeader); case 207: @@ -83,6 +85,10 @@ public class FitRecordDataFactory { return new FitHrvSummary(recordDefinition, recordHeader); case 371: return new FitHrvValue(recordDefinition, recordHeader); + case 397: + return new FitSkinTempRaw(recordDefinition, recordHeader); + case 398: + return new FitSkinTempOvernight(recordDefinition, recordHeader); } return new RecordData(recordDefinition, recordHeader); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSkinTempOvernight.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSkinTempOvernight.java new file mode 100644 index 000000000..e3efa5482 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSkinTempOvernight.java @@ -0,0 +1,47 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages; + +import androidx.annotation.Nullable; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader; + +// +// WARNING: This class was auto-generated, please avoid modifying it directly. +// See nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.codegen.FitCodeGen +// +public class FitSkinTempOvernight extends RecordData { + public FitSkinTempOvernight(final RecordDefinition recordDefinition, final RecordHeader recordHeader) { + super(recordDefinition, recordHeader); + + final int globalNumber = recordDefinition.getGlobalFITMessage().getNumber(); + if (globalNumber != 398) { + throw new IllegalArgumentException("FitSkinTempOvernight expects global messages of " + 398 + ", got " + globalNumber); + } + } + + @Nullable + public Long getLocalTimestamp() { + return (Long) getFieldByNumber(0); + } + + @Nullable + public Float getAverageDeviation() { + return (Float) getFieldByNumber(1); + } + + @Nullable + public Float getAverage7DayDeviation() { + return (Float) getFieldByNumber(2); + } + + @Nullable + public Integer getUnk3() { + return (Integer) getFieldByNumber(3); + } + + @Nullable + public Long getTimestamp() { + return (Long) getFieldByNumber(253); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSkinTempRaw.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSkinTempRaw.java new file mode 100644 index 000000000..231b6279d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSkinTempRaw.java @@ -0,0 +1,32 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages; + +import androidx.annotation.Nullable; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader; + +// +// WARNING: This class was auto-generated, please avoid modifying it directly. +// See nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.codegen.FitCodeGen +// +public class FitSkinTempRaw extends RecordData { + public FitSkinTempRaw(final RecordDefinition recordDefinition, final RecordHeader recordHeader) { + super(recordDefinition, recordHeader); + + final int globalNumber = recordDefinition.getGlobalFITMessage().getNumber(); + if (globalNumber != 397) { + throw new IllegalArgumentException("FitSkinTempRaw expects global messages of " + 397 + ", got " + globalNumber); + } + } + + @Nullable + public Float getDeviation() { + return (Float) getFieldByNumber(1); + } + + @Nullable + public Long getTimestamp() { + return (Long) getFieldByNumber(253); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSleepDataInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSleepDataInfo.java index 6684e18a1..596c274a2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSleepDataInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitSleepDataInfo.java @@ -31,7 +31,7 @@ public class FitSleepDataInfo extends RecordData { } @Nullable - public Long getTimestampInTz() { + public Long getLocalTimestamp() { return (Long) getFieldByNumber(2); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitTimestampCorrelation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitTimestampCorrelation.java new file mode 100644 index 000000000..fddf342f8 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/messages/FitTimestampCorrelation.java @@ -0,0 +1,32 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages; + +import androidx.annotation.Nullable; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDefinition; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader; + +// +// WARNING: This class was auto-generated, please avoid modifying it directly. +// See nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.codegen.FitCodeGen +// +public class FitTimestampCorrelation extends RecordData { + public FitTimestampCorrelation(final RecordDefinition recordDefinition, final RecordHeader recordHeader) { + super(recordDefinition, recordHeader); + + final int globalNumber = recordDefinition.getGlobalFITMessage().getNumber(); + if (globalNumber != 162) { + throw new IllegalArgumentException("FitTimestampCorrelation expects global messages of " + 162 + ", got " + globalNumber); + } + } + + @Nullable + public Long getLocalTimestamp() { + return (Long) getFieldByNumber(3); + } + + @Nullable + public Long getTimestamp() { + return (Long) getFieldByNumber(253); + } +} diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupportTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupportTest.java index 38d717f36..ae6666416 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupportTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupportTest.java @@ -8,7 +8,6 @@ import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; -import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.CobsCoDec; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitFile; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.GlobalFITMessage; diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporterTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporterTest.java new file mode 100644 index 000000000..9d68184fd --- /dev/null +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitImporterTest.java @@ -0,0 +1,16 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit; + +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +public class FitImporterTest { + @Test + @Ignore("helper test for development, remove this while debugging") + public void localTest() throws IOException { + final FitImporter fitImporter = new FitImporter( null, null); + fitImporter.importFile(new File("/storage/SKIN_TEMP.fit")); + } +}