mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-09 03:37:03 +01:00
Garmin: fix major issue with field encoding/decoding
Our implementation of scale and offset was backwards: we were adding offset and then dividing by scale when decoding fields, but the publicly available protocol description dictates otherwise ( http://web.archive.org/web/20240519102659/https://developer.garmin.com/fit/protocol/#scaleoffset ): "the binary quantity is divided by the scale factor and then the offset is subtracted". For this reason the sign of GARMIN_TIME_EPOCH in Timestamp field definition must be flipped as well.
This commit is contained in:
parent
404e432adf
commit
f2f6536ea8
@ -48,11 +48,11 @@ public enum BaseType {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public Object decode(ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(ByteBuffer byteBuffer, double scale, int offset) {
|
||||
return baseTypeInterface.decode(byteBuffer, scale, offset);
|
||||
}
|
||||
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
baseTypeInterface.encode(byteBuffer, o, scale, offset);
|
||||
}
|
||||
|
||||
|
@ -28,22 +28,22 @@ public class BaseTypeByte implements BaseTypeInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(final ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(final ByteBuffer byteBuffer, double scale, int offset) {
|
||||
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;
|
||||
return (int) (Math.round(b / scale) - offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
if (null == o) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
}
|
||||
int i = ((Number) o).intValue() * scale - offset;
|
||||
int i = (int) ((((Number) o).intValue() + offset) * scale);
|
||||
if (i < min || i > max) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
|
@ -19,23 +19,23 @@ public class BaseTypeDouble implements BaseTypeInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(final ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(final ByteBuffer byteBuffer, double scale, int offset) {
|
||||
double d = byteBuffer.getDouble();
|
||||
if (d < min || d > max) {
|
||||
return null;
|
||||
}
|
||||
if (Double.isNaN(d) || d == invalid)
|
||||
return null;
|
||||
return (d + offset) / scale;
|
||||
return (d / scale) - offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
if (null == o) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
}
|
||||
double d = ((Number) o).doubleValue() * scale - offset;
|
||||
double d = (((Number) o).doubleValue() + offset) * scale;
|
||||
if (d < min || d > max) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
|
@ -19,23 +19,23 @@ public class BaseTypeFloat implements BaseTypeInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(ByteBuffer byteBuffer, double scale, int offset) {
|
||||
float f = byteBuffer.getFloat();
|
||||
if (f < min || f > max) {
|
||||
return null;
|
||||
}
|
||||
if (Float.isNaN(f) || f == invalid)
|
||||
return null;
|
||||
return (f + offset) / scale;
|
||||
return (float) (f / scale) - offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
if (null == o) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
}
|
||||
float f = ((Number) o).floatValue() * scale - offset;
|
||||
float f = (float) ((((Number) o).floatValue() + offset) * scale);
|
||||
if (f < min || f > max) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
|
@ -26,22 +26,22 @@ public class BaseTypeInt implements BaseTypeInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(final ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(final ByteBuffer byteBuffer, double scale, int offset) {
|
||||
long i = unsigned ? Integer.toUnsignedLong(byteBuffer.getInt()) : byteBuffer.getInt();
|
||||
if (i < min || i > max)
|
||||
return null;
|
||||
if (i == invalid)
|
||||
return null;
|
||||
return ((i + offset) / scale);
|
||||
return (Math.round(i / scale) - offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
if (null == o) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
}
|
||||
long l = ((Number) o).longValue() * scale - offset;
|
||||
long l = (long) ((((Number) o).longValue() + offset) * scale);
|
||||
if (l < min || l > max) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
|
@ -5,9 +5,9 @@ import java.nio.ByteBuffer;
|
||||
public interface BaseTypeInterface {
|
||||
int getByteSize();
|
||||
|
||||
Object decode(ByteBuffer byteBuffer, int scale, int offset);
|
||||
Object decode(ByteBuffer byteBuffer, double scale, int offset);
|
||||
|
||||
void encode(ByteBuffer byteBuffer, Object o, int scale, int offset);
|
||||
void encode(ByteBuffer byteBuffer, Object o, double scale, int offset);
|
||||
|
||||
void invalidate(ByteBuffer byteBuffer);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@ -27,22 +28,22 @@ public class BaseTypeLong implements BaseTypeInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(ByteBuffer byteBuffer, double scale, int offset) {
|
||||
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;
|
||||
return new BigDecimal(i).divide(BigDecimal.valueOf(scale)).subtract(BigDecimal.valueOf(offset)).toBigInteger().longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
if (null == o) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
}
|
||||
BigInteger i = BigInteger.valueOf(((Number) o).longValue() * scale - offset);
|
||||
BigInteger i = new BigDecimal(((Number) o).longValue()).multiply(BigDecimal.valueOf(scale)).add(BigDecimal.valueOf(offset)).toBigInteger();
|
||||
if (!unsigned && (i.compareTo(min) < 0 || i.compareTo(max) > 0)) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
|
@ -26,22 +26,22 @@ public class BaseTypeShort implements BaseTypeInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(final ByteBuffer byteBuffer, int scale, int offset) {
|
||||
public Object decode(final ByteBuffer byteBuffer, double scale, int offset) {
|
||||
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;
|
||||
return (int) Math.round(s / scale) - offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o, int scale, int offset) {
|
||||
public void encode(ByteBuffer byteBuffer, Object o, double scale, int offset) {
|
||||
if (null == o) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
}
|
||||
int i = ((Number) o).intValue() * scale - offset;
|
||||
int i = (int) ((((Number) o).intValue() + offset) * scale);
|
||||
if (i < min || i > max) {
|
||||
invalidate(byteBuffer);
|
||||
return;
|
||||
|
@ -7,7 +7,7 @@ import static nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.Garmin
|
||||
|
||||
public class FieldDefinitionTimestamp extends FieldDefinition {
|
||||
public FieldDefinitionTimestamp(int localNumber, int size, BaseType baseType, String name) {
|
||||
super(localNumber, size, baseType, name, 1, GARMIN_TIME_EPOCH);
|
||||
super(localNumber, size, baseType, name, 1, -GARMIN_TIME_EPOCH);
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
Loading…
Reference in New Issue
Block a user