From eff233d93aa144dad76e0929ed5577f282e4ccea Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Tue, 26 Mar 2024 07:07:27 +0100 Subject: [PATCH] Garmin protocol: refactoring and fixes of BaseTypes The boundaries are enforced on the stored value when decoding, before applying the adjustments for scale and offset. Also add some tests for the BaseTypes Introduce new FieldDefinition for Temperature and WeatherCondition (removing the static class) Add accessors for field data in the containing RecordData, thus keeping the FieldData private --- .../service/devices/garmin/GarminSupport.java | 28 +- .../garmin/fit/GlobalDefinitionsEnum.java | 25 +- .../devices/garmin/fit/RecordData.java | 45 ++- .../garmin/fit/baseTypes/BaseType.java | 2 +- .../garmin/fit/baseTypes/BaseTypeByte.java | 18 +- .../garmin/fit/baseTypes/BaseTypeDouble.java | 16 +- .../garmin/fit/baseTypes/BaseTypeFloat.java | 18 +- .../garmin/fit/baseTypes/BaseTypeInt.java | 34 +-- .../garmin/fit/baseTypes/BaseTypeLong.java | 41 +-- .../garmin/fit/baseTypes/BaseTypeShort.java | 24 +- .../FieldDefinitionTemperature.java | 12 + .../FieldDefinitionWeatherCondition.java} | 128 +++++---- .../devices/garmin/GarminSupportTest.java | 267 ++++++++++++++++++ 13 files changed, 506 insertions(+), 152 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionTemperature.java rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/{FitWeatherConditions.java => fieldDefinitions/FieldDefinitionWeatherCondition.java} (59%) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupport.java index 7150540b6..fb362463f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/GarminSupport.java @@ -29,7 +29,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateA import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.ICommunicator; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.v1.CommunicatorV1; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.v2.CommunicatorV2; -import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitWeatherConditions; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.GlobalDefinitionsEnum; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordData; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.ConfigurationMessage; @@ -144,19 +143,18 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni List weatherData = new ArrayList<>(); try { - RecordData today = new RecordData(GlobalDefinitionsEnum.TODAY_WEATHER_CONDITIONS.getRecordDefinition()); today.setFieldByName("weather_report", 0); // 0 = current, 1 = hourly_forecast, 2 = daily_forecast today.setFieldByName("timestamp", weather.timestamp); today.setFieldByName("observed_at_time", weather.timestamp); - today.setFieldByName("temperature", weather.currentTemp - 273.15); - today.setFieldByName("low_temperature", weather.todayMinTemp - 273.15); - today.setFieldByName("high_temperature", weather.todayMaxTemp - 273.15); - today.setFieldByName("condition", FitWeatherConditions.openWeatherCodeToFitWeatherStatus(weather.currentConditionCode)); + today.setFieldByName("temperature", weather.currentTemp); + today.setFieldByName("low_temperature", weather.todayMinTemp); + today.setFieldByName("high_temperature", weather.todayMaxTemp); + today.setFieldByName("condition", weather.currentConditionCode); today.setFieldByName("wind_direction", weather.windDirection); today.setFieldByName("precipitation_probability", weather.precipProbability); today.setFieldByName("wind_speed", Math.round(weather.windSpeed)); - today.setFieldByName("temperature_feels_like", weather.feelsLikeTemp - 273.15); + today.setFieldByName("temperature_feels_like", weather.feelsLikeTemp); today.setFieldByName("relative_humidity", weather.currentHumidity); today.setFieldByName("observed_location_lat", weather.latitude); today.setFieldByName("observed_location_long", weather.longitude); @@ -169,8 +167,8 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni RecordData weatherHourlyForecast = new RecordData(GlobalDefinitionsEnum.HOURLY_WEATHER_FORECAST.getRecordDefinition()); weatherHourlyForecast.setFieldByName("weather_report", 1); // 0 = current, 1 = hourly_forecast, 2 = daily_forecast weatherHourlyForecast.setFieldByName("timestamp", hourly.timestamp); - weatherHourlyForecast.setFieldByName("temperature", hourly.temp - 273.15); - weatherHourlyForecast.setFieldByName("condition", FitWeatherConditions.openWeatherCodeToFitWeatherStatus(hourly.conditionCode)); + weatherHourlyForecast.setFieldByName("temperature", hourly.temp); + weatherHourlyForecast.setFieldByName("condition", hourly.conditionCode); weatherHourlyForecast.setFieldByName("wind_direction", hourly.windDirection); weatherHourlyForecast.setFieldByName("wind_speed", Math.round(hourly.windSpeed)); weatherHourlyForecast.setFieldByName("precipitation_probability", hourly.precipProbability); @@ -185,9 +183,9 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni RecordData todayDailyForecast = new RecordData(GlobalDefinitionsEnum.DAILY_WEATHER_FORECAST.getRecordDefinition()); todayDailyForecast.setFieldByName("weather_report", 2); // 0 = current, 1 = hourly_forecast, 2 = daily_forecast todayDailyForecast.setFieldByName("timestamp", weather.timestamp); - todayDailyForecast.setFieldByName("low_temperature", weather.todayMinTemp - 273.15); - todayDailyForecast.setFieldByName("high_temperature", weather.todayMaxTemp - 273.15); - todayDailyForecast.setFieldByName("condition", FitWeatherConditions.openWeatherCodeToFitWeatherStatus(weather.currentConditionCode)); + todayDailyForecast.setFieldByName("low_temperature", weather.todayMinTemp); + todayDailyForecast.setFieldByName("high_temperature", weather.todayMaxTemp); + todayDailyForecast.setFieldByName("condition", weather.currentConditionCode); todayDailyForecast.setFieldByName("precipitation_probability", weather.precipProbability); todayDailyForecast.setFieldByName("day_of_week", weather.timestamp); weatherData.add(todayDailyForecast); @@ -200,9 +198,9 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni RecordData weatherDailyForecast = new RecordData(GlobalDefinitionsEnum.DAILY_WEATHER_FORECAST.getRecordDefinition()); weatherDailyForecast.setFieldByName("weather_report", 2); // 0 = current, 1 = hourly_forecast, 2 = daily_forecast weatherDailyForecast.setFieldByName("timestamp", weather.timestamp); - weatherDailyForecast.setFieldByName("low_temperature", daily.minTemp - 273.15); - weatherDailyForecast.setFieldByName("high_temperature", daily.maxTemp - 273.15); - weatherDailyForecast.setFieldByName("condition", FitWeatherConditions.openWeatherCodeToFitWeatherStatus(daily.conditionCode)); + weatherDailyForecast.setFieldByName("low_temperature", daily.minTemp); + weatherDailyForecast.setFieldByName("high_temperature", daily.maxTemp); + weatherDailyForecast.setFieldByName("condition", daily.conditionCode); weatherDailyForecast.setFieldByName("precipitation_probability", daily.precipProbability); weatherDailyForecast.setFieldByName("day_of_week", ts); weatherData.add(weatherDailyForecast); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalDefinitionsEnum.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalDefinitionsEnum.java index de490266f..550a9ed0a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalDefinitionsEnum.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/GlobalDefinitionsEnum.java @@ -6,7 +6,10 @@ import java.nio.ByteOrder; import java.util.Arrays; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionDayOfWeek; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionTemperature; import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionTimestamp; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionWeatherCondition; public enum GlobalDefinitionsEnum { TODAY_WEATHER_CONDITIONS(MesgType.TODAY_WEATHER_CONDITIONS, new RecordDefinition( @@ -16,14 +19,14 @@ public enum GlobalDefinitionsEnum { Arrays.asList(new FieldDefinition(0, 1, BaseType.ENUM, "weather_report"), new FieldDefinitionTimestamp(253, 4, BaseType.UINT32, "timestamp"), new FieldDefinitionTimestamp(9, 4, BaseType.UINT32, "observed_at_time"), - new FieldDefinition(1, 1, BaseType.SINT8, "temperature"), - new FieldDefinition(14, 1, BaseType.SINT8, "low_temperature"), - new FieldDefinition(13, 1, BaseType.SINT8, "high_temperature"), - new FieldDefinition(2, 1, BaseType.ENUM, "condition"), + new FieldDefinitionTemperature(1, 1, BaseType.SINT8, "temperature"), + new FieldDefinitionTemperature(14, 1, BaseType.SINT8, "low_temperature"), + new FieldDefinitionTemperature(13, 1, BaseType.SINT8, "high_temperature"), + new FieldDefinitionWeatherCondition(2, 1, BaseType.ENUM, "condition"), new FieldDefinition(3, 2, BaseType.UINT16, "wind_direction"), new FieldDefinition(5, 1, BaseType.UINT8, "precipitation_probability"), new FieldDefinition(4, 2, BaseType.UINT16, "wind_speed", 298, 0), - new FieldDefinition(6, 1, BaseType.SINT8, "temperature_feels_like"), + new FieldDefinitionTemperature(6, 1, BaseType.SINT8, "temperature_feels_like"), new FieldDefinition(7, 1, BaseType.UINT8, "relative_humidity"), new FieldDefinition(10, 4, BaseType.SINT32, "observed_location_lat"), new FieldDefinition(11, 4, BaseType.SINT32, "observed_location_long"), @@ -35,8 +38,8 @@ public enum GlobalDefinitionsEnum { MesgType.HOURLY_WEATHER_FORECAST, Arrays.asList(new FieldDefinition(0, 1, BaseType.ENUM, "weather_report"), new FieldDefinitionTimestamp(253, 4, BaseType.UINT32, "timestamp"), - new FieldDefinition(1, 1, BaseType.SINT8, "temperature"), - new FieldDefinition(2, 1, BaseType.ENUM, "condition"), + new FieldDefinitionTemperature(1, 1, BaseType.SINT8, "temperature"), + new FieldDefinitionWeatherCondition(2, 1, BaseType.ENUM, "condition"), new FieldDefinition(3, 2, BaseType.UINT16, "wind_direction"), new FieldDefinition(4, 2, BaseType.UINT16, "wind_speed", 298, 0), new FieldDefinition(5, 1, BaseType.UINT8, "precipitation_probability"), @@ -51,11 +54,11 @@ public enum GlobalDefinitionsEnum { MesgType.DAILY_WEATHER_FORECAST, Arrays.asList(new FieldDefinition(0, 1, BaseType.ENUM, "weather_report"), new FieldDefinitionTimestamp(253, 4, BaseType.UINT32, "timestamp"), - new FieldDefinition(14, 1, BaseType.SINT8, "low_temperature"), - new FieldDefinition(13, 1, BaseType.SINT8, "high_temperature"), - new FieldDefinition(2, 1, BaseType.ENUM, "condition"), + new FieldDefinitionTemperature(14, 1, BaseType.SINT8, "low_temperature"), + new FieldDefinitionTemperature(13, 1, BaseType.SINT8, "high_temperature"), + new FieldDefinitionWeatherCondition(2, 1, BaseType.ENUM, "condition"), new FieldDefinition(5, 1, BaseType.UINT8, "precipitation_probability"), - new FieldDefinition(12, 1, BaseType.ENUM, "day_of_week")))), + new FieldDefinitionDayOfWeek(12, 1, BaseType.ENUM, "day_of_week")))), ; private final MesgType mesgType; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/RecordData.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/RecordData.java index 68d92b650..81af3c14d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/RecordData.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/RecordData.java @@ -86,6 +86,36 @@ public class RecordData { } } + public Object getFieldByNumber(int number) { + for (FieldData fieldData : + fieldDataList) { + if (fieldData.getNumber() == number) { + return fieldData.decode(); + } + } + throw new IllegalArgumentException("Unknown field number " + number); + } + + public Object getFieldByName(String name) { + for (FieldData fieldData : + fieldDataList) { + if (fieldData.getName().equals(name)) { + return fieldData.decode(); + } + } + throw new IllegalArgumentException("Unknown field name " + name); + } + + public int[] getFieldsNumbers() { + int[] arr = new int[fieldDataList.size()]; + int count = 0; + for (FieldData fieldData : fieldDataList) { + int number = fieldData.getNumber(); + arr[count++] = number; + } + return arr; + } + public String toString() { StringBuilder oBuilder = new StringBuilder(); for (FieldData fieldData : @@ -102,20 +132,7 @@ public class RecordData { return oBuilder.toString(); } - - - public FieldData getFieldByNumber(int number) { - for (FieldData fieldData : - fieldDataList) { - if (number == fieldData.getNumber()) { - return fieldData; - } - } - return null; - } - - - public class FieldData { + private class FieldData { private FieldDefinition fieldDefinition; private final int position; private final int size; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseType.java index 018b4b6dd..7877c07e3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseType.java @@ -10,7 +10,7 @@ public enum BaseType { SINT16(0x83, new BaseTypeShort(false, 0x7FFF)), UINT16(0x84, new BaseTypeShort(true, 0xFFFF)), SINT32(0x85, new BaseTypeInt(false, 0x7FFFFFFF)), - UINT32(0x86, new BaseTypeInt(true, 0xFFFFFFFF)), + UINT32(0x86, new BaseTypeInt(true, 0xFFFFFFFFL)), STRING(0x07, new BaseTypeByte(true, 0x00)), FLOAT32(0x88, new BaseTypeFloat()), FLOAT64(0x89, new BaseTypeDouble()), diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeByte.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeByte.java index 3419a8801..4ada1b3ce 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeByte.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeByte.java @@ -29,17 +29,23 @@ public class BaseTypeByte implements BaseTypeInterface { @Override public Object decode(final ByteBuffer byteBuffer, int scale, int offset) { - int i = (byteBuffer.get() + offset) / scale; - if (i < min || i > max) - return invalid; - return i; + int b = unsigned ? Byte.toUnsignedInt(byteBuffer.get()) : byteBuffer.get(); + if (b < min || b > max) + return null; + if (b == invalid) + return null; + return (b + offset) / scale; } @Override public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) { + if (null == o) { + invalidate(byteBuffer); + return; + } int i = ((Number) o).intValue() * scale - offset; - if (!unsigned && (i < min || i > max)) { - byteBuffer.put((byte) invalid); + if (i < min || i > max) { + invalidate(byteBuffer); return; } byteBuffer.put((byte) i); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeDouble.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeDouble.java index f2abc6a66..e517c8410 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeDouble.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeDouble.java @@ -9,7 +9,7 @@ public class BaseTypeDouble implements BaseTypeInterface { private final double invalid; BaseTypeDouble() { - this.min = Double.MIN_VALUE; + this.min = -Double.MAX_VALUE; this.max = Double.MAX_VALUE; this.invalid = Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL); } @@ -20,14 +20,24 @@ public class BaseTypeDouble implements BaseTypeInterface { @Override public Object decode(final ByteBuffer byteBuffer, int scale, int offset) { - return (byteBuffer.getDouble() + offset) / scale; + double d = byteBuffer.getDouble(); + if (d < min || d > max) { + return null; + } + if (Double.isNaN(d) || d == invalid) + return null; + return (d + offset) / scale; } @Override public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) { + if (null == o) { + invalidate(byteBuffer); + return; + } double d = ((Number) o).doubleValue() * scale - offset; if (d < min || d > max) { - byteBuffer.putDouble(invalid); + invalidate(byteBuffer); return; } byteBuffer.putDouble(d); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeFloat.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeFloat.java index da9b0b1d9..41f713cd9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeFloat.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeFloat.java @@ -7,13 +7,11 @@ public class BaseTypeFloat implements BaseTypeInterface { private final double min; private final double max; private final double invalid; - private final boolean unsigned; BaseTypeFloat() { this.min = -Float.MAX_VALUE; this.max = Float.MAX_VALUE; this.invalid = Float.intBitsToFloat(0xFFFFFFFF); - this.unsigned = false; } public int getByteSize() { @@ -22,14 +20,24 @@ public class BaseTypeFloat implements BaseTypeInterface { @Override public Object decode(ByteBuffer byteBuffer, int scale, int offset) { - return (byteBuffer.getFloat() + offset) / scale; + float f = byteBuffer.getFloat(); + if (f < min || f > max) { + return null; + } + if (Float.isNaN(f) || f == invalid) + return null; + return (f + offset) / scale; } @Override public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) { + if (null == o) { + invalidate(byteBuffer); + return; + } float f = ((Number) o).floatValue() * scale - offset; - if (!unsigned && (f < min || f > max)) { - byteBuffer.putFloat((float) invalid); + if (f < min || f > max) { + invalidate(byteBuffer); return; } byteBuffer.putFloat((float) f); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeInt.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeInt.java index 0241c7d7f..a0615dab3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeInt.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeInt.java @@ -3,16 +3,16 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseType import java.nio.ByteBuffer; public class BaseTypeInt implements BaseTypeInterface { - private final int min; - private final int max; - private final int invalid; + private final long min; + private final long max; + private final long invalid; private final boolean unsigned; private final int size = 4; - BaseTypeInt(boolean unsigned, int invalid) { + BaseTypeInt(boolean unsigned, long invalid) { if (unsigned) { this.min = 0; - this.max = 0xffffffff; + this.max = 0xffffffffL; } else { this.min = Integer.MIN_VALUE; this.max = Integer.MAX_VALUE; @@ -27,23 +27,23 @@ public class BaseTypeInt implements BaseTypeInterface { @Override public Object decode(final ByteBuffer byteBuffer, int scale, int offset) { - if (unsigned) { - long i = ((byteBuffer.getInt() & 0xffffffffL) + offset) / scale; - return i; - } else { - int i = (byteBuffer.getInt() + offset) / scale; - if (i < min || i > max) - return invalid; - return i; - } - + long i = unsigned ? Integer.toUnsignedLong(byteBuffer.getInt()) : byteBuffer.getInt(); + if (i < min || i > max) + return null; + if (i == invalid) + return null; + return (int) ((i + offset) / scale); } @Override public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) { + if (null == o) { + invalidate(byteBuffer); + return; + } long l = ((Number) o).longValue() * scale - offset; - if (!unsigned && (l < min || l > max)) { - byteBuffer.putInt((int) invalid); + if (l < min || l > max) { + invalidate(byteBuffer); return; } byteBuffer.putInt((int) l); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeLong.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeLong.java index 1f3e54a6a..74af9461a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeLong.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeLong.java @@ -1,21 +1,22 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes; +import java.math.BigInteger; import java.nio.ByteBuffer; public class BaseTypeLong implements BaseTypeInterface { private final int size = 8; - private final double min; - private final double max; - private final double invalid; + private final BigInteger min; + private final BigInteger max; + private final long invalid; private final boolean unsigned; BaseTypeLong(boolean unsigned, long invalid) { if (unsigned) { - this.min = 0; - this.max = 0xFFFFFFFFFFFFFFFFL; + this.min = BigInteger.valueOf(0); + this.max = BigInteger.valueOf(0xFFFFFFFFFFFFFFFFL); } else { - this.min = Long.MIN_VALUE; - this.max = Long.MAX_VALUE; + this.min = BigInteger.valueOf(Long.MIN_VALUE); + this.max = BigInteger.valueOf(Long.MAX_VALUE); } this.invalid = invalid; this.unsigned = unsigned; @@ -27,24 +28,26 @@ public class BaseTypeLong implements BaseTypeInterface { @Override public Object decode(ByteBuffer byteBuffer, int scale, int offset) { - if (unsigned) { - return ((byteBuffer.getLong() & 0xFFFFFFFFFFFFFFFFL + offset) / scale); - } else { - long l = (byteBuffer.getLong() + offset) / scale; - if (l < min || l > max) - return invalid; - return l; - } + BigInteger i = unsigned ? BigInteger.valueOf(byteBuffer.getLong() & 0xFFFFFFFFFFFFFFFFL) : BigInteger.valueOf(byteBuffer.getLong()); + if (!unsigned && (i.compareTo(min) < 0 || i.compareTo(max) > 0)) + return null; + if (i.compareTo(BigInteger.valueOf(invalid)) == 0) + return null; + return (i.longValue() + offset) / scale; } @Override public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) { - long l = ((Number) o).longValue() * scale - offset; - if (!unsigned && (l < min || l > max)) { - byteBuffer.putLong((long) invalid); + if (null == o) { + invalidate(byteBuffer); return; } - byteBuffer.putLong(l); + BigInteger i = BigInteger.valueOf(((Number) o).longValue() * scale - offset); + if (!unsigned && (i.compareTo(min) < 0 || i.compareTo(max) > 0)) { + invalidate(byteBuffer); + return; + } + byteBuffer.putLong(i.longValue()); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeShort.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeShort.java index 1bbac467f..ade9d357d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeShort.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/baseTypes/BaseTypeShort.java @@ -27,23 +27,23 @@ public class BaseTypeShort implements BaseTypeInterface { @Override public Object decode(final ByteBuffer byteBuffer, int scale, int offset) { - if (unsigned) { - int s = (((byteBuffer.getShort() & 0xffff) + offset) / scale); - return s; - } else { - short s = (short) ((byteBuffer.getShort() + offset) / scale); - if (s < min || s > max) - return invalid; - return s; - } - + int s = unsigned ? Short.toUnsignedInt(byteBuffer.getShort()) : byteBuffer.getShort(); + if (s < min || s > max) + return null; + if (s == invalid) + return null; + return (s + offset) / scale; } @Override public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) { + if (null == o) { + invalidate(byteBuffer); + return; + } int i = ((Number) o).intValue() * scale - offset; - if (!unsigned && (i < min || i > max)) { - byteBuffer.putShort((short) invalid); + if (i < min || i > max) { + invalidate(byteBuffer); return; } byteBuffer.putShort((short) i); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionTemperature.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionTemperature.java new file mode 100644 index 000000000..e215025e2 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionTemperature.java @@ -0,0 +1,12 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType; + +public class FieldDefinitionTemperature extends FieldDefinition { + + public FieldDefinitionTemperature(int localNumber, int size, BaseType baseType, String name) { + super(localNumber, size, baseType, name, 1, 273); + } + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitWeatherConditions.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionWeatherCondition.java similarity index 59% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitWeatherConditions.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionWeatherCondition.java index 403bbcf52..eb3b943e0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/FitWeatherConditions.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/fit/fieldDefinitions/FieldDefinitionWeatherCondition.java @@ -1,29 +1,32 @@ -package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit; +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions; -public final class FitWeatherConditions { - public static final int CLEAR = 0; - public static final int PARTLY_CLOUDY = 1; - public static final int MOSTLY_CLOUDY = 2; - public static final int RAIN = 3; - public static final int SNOW = 4; - public static final int WINDY = 5; - public static final int THUNDERSTORMS = 6; - public static final int WINTRY_MIX = 7; - public static final int FOG = 8; - public static final int HAZY = 11; - public static final int HAIL = 12; - public static final int SCATTERED_SHOWERS = 13; - public static final int SCATTERED_THUNDERSTORMS = 14; - public static final int UNKNOWN_PRECIPITATION = 15; - public static final int LIGHT_RAIN = 16; - public static final int HEAVY_RAIN = 17; - public static final int LIGHT_SNOW = 18; - public static final int HEAVY_SNOW = 19; - public static final int LIGHT_RAIN_SNOW = 20; - public static final int HEAVY_RAIN_SNOW = 21; - public static final int CLOUDY = 22; +import java.nio.ByteBuffer; - public static int openWeatherCodeToFitWeatherStatus(int openWeatherCode) { +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType; + +public class FieldDefinitionWeatherCondition extends FieldDefinition { + + public FieldDefinitionWeatherCondition(int localNumber, int size, BaseType baseType, String name) { + super(localNumber, size, baseType, name, 1, 0); + } + + @Override + public Object decode(ByteBuffer byteBuffer) { + int idx = (int) baseType.decode(byteBuffer, scale, offset); + return Condition.values()[idx]; + } + + @Override + public void encode(ByteBuffer byteBuffer, Object o) { + if (o instanceof Condition) { + baseType.encode(byteBuffer, ((Condition) o).ordinal(), scale, offset); + return; + } + baseType.encode(byteBuffer, openWeatherCodeToFitWeatherStatus((int) o), scale, offset); + } + + private int openWeatherCodeToFitWeatherStatus(int openWeatherCode) { switch (openWeatherCode) { //Group 2xx: Thunderstorm case 200: //thunderstorm with light rain: //11d @@ -35,56 +38,56 @@ public final class FitWeatherConditions { case 230: //thunderstorm with light drizzle: //11d case 231: //thunderstorm with drizzle: //11d case 232: //thunderstorm with heavy drizzle: //11d - return THUNDERSTORMS; + return Condition.THUNDERSTORMS.ordinal(); case 221: //ragged thunderstorm: //11d - return SCATTERED_THUNDERSTORMS; + return Condition.SCATTERED_THUNDERSTORMS.ordinal(); //Group 3xx: Drizzle case 300: //light intensity drizzle: //09d case 310: //light intensity drizzle rain: //09d case 313: //shower rain and drizzle: //09d - return LIGHT_RAIN; + return Condition.LIGHT_RAIN.ordinal(); case 301: //drizzle: //09d case 311: //drizzle rain: //09d - return RAIN; + return Condition.RAIN.ordinal(); case 302: //heavy intensity drizzle: //09d case 312: //heavy intensity drizzle rain: //09d case 314: //heavy shower rain and drizzle: //09d - return HEAVY_RAIN; + return Condition.HEAVY_RAIN.ordinal(); case 321: //shower drizzle: //09d - return SCATTERED_SHOWERS; + return Condition.SCATTERED_SHOWERS.ordinal(); //Group 5xx: Rain case 500: //light rain: //10d case 520: //light intensity shower rain: //09d case 521: //shower rain: //09d - return LIGHT_RAIN; + return Condition.LIGHT_RAIN.ordinal(); case 501: //moderate rain: //10d case 531: //ragged shower rain: //09d - return RAIN; + return Condition.RAIN.ordinal(); case 502: //heavy intensity rain: //10d case 503: //very heavy rain: //10d case 504: //extreme rain: //10d case 522: //heavy intensity shower rain: //09d - return HEAVY_RAIN; + return Condition.HEAVY_RAIN.ordinal(); case 511: //freezing rain: //13d - return UNKNOWN_PRECIPITATION; + return Condition.UNKNOWN_PRECIPITATION.ordinal(); //Group 6xx: Snow case 600: //light snow: //[[file:13d.png]] - return LIGHT_SNOW; + return Condition.LIGHT_SNOW.ordinal(); case 601: //snow: //[[file:13d.png]] case 620: //light shower snow: //[[file:13d.png]] case 621: //shower snow: //[[file:13d.png]] - return SNOW; + return Condition.SNOW.ordinal(); case 602: //heavy snow: //[[file:13d.png]] case 622: //heavy shower snow: //[[file:13d.png]] - return HEAVY_SNOW; + return Condition.HEAVY_SNOW.ordinal(); case 611: //sleet: //[[file:13d.png]] case 612: //light shower sleet: //[[file:13d.png]] case 613: //shower sleet: //[[file:13d.png]] - return WINTRY_MIX; + return Condition.WINTRY_MIX.ordinal(); case 615: //light rain and snow: //[[file:13d.png]] - return LIGHT_RAIN_SNOW; + return Condition.LIGHT_RAIN_SNOW.ordinal(); case 616: //rain and snow: //[[file:13d.png]] - return HEAVY_RAIN_SNOW; + return Condition.HEAVY_RAIN_SNOW.ordinal(); //Group 7xx: Atmosphere case 701: //mist: //[[file:50d.png]] @@ -94,29 +97,29 @@ public final class FitWeatherConditions { case 751: //sand: //[[file:50d.png]] case 761: //dust: //[[file:50d.png]] case 762: //volcanic ash: //[[file:50d.png]] - return HAZY; + return Condition.HAZY.ordinal(); case 741: //fog: //[[file:50d.png]] - return FOG; + return Condition.FOG.ordinal(); case 771: //squalls: //[[file:50d.png]] case 781: //tornado: //[[file:50d.png]] - return WINDY; + return Condition.WINDY.ordinal(); //Group 800: Clear case 800: //clear sky: //[[file:01d.png]] [[file:01n.png]] - return CLEAR; + return Condition.CLEAR.ordinal(); //Group 80x: Clouds case 801: //few clouds: //[[file:02d.png]] [[file:02n.png]] case 802: //scattered clouds: //[[file:03d.png]] [[file:03d.png]] - return PARTLY_CLOUDY; + return Condition.PARTLY_CLOUDY.ordinal(); case 803: //broken clouds: //[[file:04d.png]] [[file:03d.png]] - return MOSTLY_CLOUDY; + return Condition.MOSTLY_CLOUDY.ordinal(); case 804: //overcast clouds: //[[file:04d.png]] [[file:04d.png]] - return CLOUDY; + return Condition.CLOUDY.ordinal(); //Group 90x: Extreme case 901: //tropical storm - return THUNDERSTORMS; + return Condition.THUNDERSTORMS.ordinal(); case 906: //hail - return HAIL; + return Condition.HAIL.ordinal(); case 903: //cold case 904: //hot case 905: //windy @@ -138,4 +141,31 @@ public final class FitWeatherConditions { throw new IllegalArgumentException("Unknown weather code " + openWeatherCode); } } + + enum Condition { + CLEAR, + PARTLY_CLOUDY, + MOSTLY_CLOUDY, + RAIN, + SNOW, + WINDY, + THUNDERSTORMS, + WINTRY_MIX, + FOG, + UNK9, + UNK10, + HAZY, + HAIL, + SCATTERED_SHOWERS, + SCATTERED_THUNDERSTORMS, + UNKNOWN_PRECIPITATION, + LIGHT_RAIN, + HEAVY_RAIN, + LIGHT_SNOW, + HEAVY_SNOW, + LIGHT_RAIN_SNOW, + HEAVY_RAIN_SNOW, + CLOUDY, + ; + } } 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 6983b3792..a65f316bb 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 @@ -2,8 +2,21 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin; import org.junit.Assert; import org.junit.Test; +import org.threeten.bp.Instant; +import org.threeten.bp.ZoneId; + +import java.math.BigInteger; +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.MesgType; +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; +import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -97,4 +110,258 @@ public class GarminSupportTest { } } + @Test + public void testBaseFields() { + + RecordDefinition recordDefinition = new RecordDefinition(new RecordHeader((byte) 6), ByteOrder.LITTLE_ENDIAN, MesgType.TODAY_WEATHER_CONDITIONS, 123); //just some random data + List fieldDefinitionList = new ArrayList<>(); + for (BaseType baseType : + BaseType.values()) { + fieldDefinitionList.add(new FieldDefinition(baseType.getIdentifier(), baseType.getSize(), baseType, baseType.name())); + + } + recordDefinition.setFieldDefinitions(fieldDefinitionList); + + RecordData test = new RecordData(recordDefinition); + + for (BaseType baseType : + BaseType.values()) { + System.out.println(baseType.getIdentifier()); + Object startVal, endVal; + + switch (baseType.name()) { + case "ENUM": + case "UINT8": + case "BASE_TYPE_BYTE": + startVal = 0; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) 0xff - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = -1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "SINT8": + startVal = (int) Byte.MIN_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) Byte.MAX_VALUE - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) Byte.MIN_VALUE - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "SINT16": + startVal = (int) Short.MIN_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) Short.MAX_VALUE - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) Short.MIN_VALUE - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT16": + startVal = 0; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) 0xffff - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = -1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "SINT32": + startVal = (int) Integer.MIN_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) Integer.MAX_VALUE - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) Integer.MIN_VALUE - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT32": + startVal = 0; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (long) 0xffffffffL - 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, (long) ((int) endVal & 0xffffffffL)); + startVal = 0xffffffff; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "FLOAT32": + startVal = 0.0f; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = -Float.MAX_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = Float.MAX_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (double) -Float.MAX_VALUE * 2; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "FLOAT64": + startVal = 0.0d; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = Double.MIN_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = Double.MAX_VALUE; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (double) -Double.MAX_VALUE * 2; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT8Z": + startVal = 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) 0xff; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = 0; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + startVal = -1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT16Z": + startVal = 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (int) 0xffff; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = -1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + startVal = 0; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT32Z": + startVal = 1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = (long) 0xffffffffL; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, (long) ((int) endVal & 0xffffffffL)); + startVal = -1; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + startVal = 0; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "SINT64": + startVal = BigInteger.valueOf(Long.MIN_VALUE); + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(((BigInteger) startVal).longValue(), endVal); + startVal = BigInteger.valueOf(Long.MAX_VALUE - 1); + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(((BigInteger) startVal).longValue(), endVal); + startVal = BigInteger.valueOf(Long.MAX_VALUE); + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT64": + startVal = 0L; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = BigInteger.valueOf(0xFFFFFFFFFFFFFFFFL - 1); + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(((BigInteger) startVal).longValue() & 0xFFFFFFFFFFFFFFFFL, endVal); + startVal = BigInteger.valueOf(0xFFFFFFFFFFFFFFFFL); + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "UINT64Z": + startVal = 1L; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(startVal, endVal); + startVal = BigInteger.valueOf(0xFFFFFFFFFFFFFFFFL); + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertEquals(((BigInteger) startVal).longValue() & 0xFFFFFFFFFFFFFFFFL, endVal); + startVal = 0L; + test.setFieldByName(baseType.name(), startVal); + endVal = test.getFieldByName(baseType.name()); + Assert.assertNull(endVal); + break; + case "STRING": + //TODO + break; + default: + System.out.println(baseType.name()); + Assert.assertFalse(true); //we should not end up here, if it happen we forgot a case in the switch + } + + } + + } + + @Test + public void runningTest() { + System.out.println(Instant.ofEpochSecond(System.currentTimeMillis()).atZone(ZoneId.systemDefault()).getDayOfWeek().getValue()); + } }