mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Garmin: extend FIT file parsing 6
This commit is contained in:
+11
-11
@@ -444,9 +444,9 @@ public class GlobalFITMessage {
|
||||
new FieldDefinitionPrimitive(74, BaseType.UINT16, "opponent_score"),
|
||||
new FieldDefinitionPrimitive(75, BaseType.UINT16, "stroke_count", FieldDefinitionFactory.FIELD.ARRAY),
|
||||
new FieldDefinitionPrimitive(76, BaseType.UINT16, "zone_count", FieldDefinitionFactory.FIELD.ARRAY),
|
||||
new FieldDefinitionPrimitive(77, BaseType.UINT16, "avg_vertical_oscillation", FieldDefinitionFactory.FIELD.ARRAY, 10, 0), // mm
|
||||
new FieldDefinitionPrimitive(78, BaseType.UINT16, "avg_stance_time_percen", FieldDefinitionFactory.FIELD.ARRAY, 100, 0), // %
|
||||
new FieldDefinitionPrimitive(79, BaseType.UINT16, "avg_stance_time", FieldDefinitionFactory.FIELD.ARRAY, 10, 0), // ms
|
||||
new FieldDefinitionPrimitive(77, BaseType.UINT16, "avg_vertical_oscillation", 10, 0), // mm
|
||||
new FieldDefinitionPrimitive(78, BaseType.UINT16, "avg_stance_time_percent", 100, 0), // %
|
||||
new FieldDefinitionPrimitive(79, BaseType.UINT16, "avg_stance_time", 10, 0), // ms
|
||||
new FieldDefinitionPrimitive(80, BaseType.UINT8, "avg_fractional_cadence", 128, 0), // rpm
|
||||
new FieldDefinitionPrimitive(81, BaseType.UINT8, "max_fractional_cadence", 128, 0), // rpm
|
||||
new FieldDefinitionPrimitive(82, BaseType.UINT8, "total_fractional_cycles", 128, 0), // cycles
|
||||
@@ -546,12 +546,12 @@ public class GlobalFITMessage {
|
||||
new FieldDefinitionPrimitive(51, BaseType.UINT16, "ball_speed", 100, 0), // m/s
|
||||
new FieldDefinitionPrimitive(52, BaseType.UINT16, "cadence256", 256, 0), // RPM
|
||||
new FieldDefinitionPrimitive(53, BaseType.UINT8, "fractional_cadence", 128, 0), // rpm
|
||||
new FieldDefinitionPrimitive(54, BaseType.UINT16, "avg_total_hemoglobin_conc", FieldDefinitionFactory.FIELD.ARRAY,100, 0), // g/dL
|
||||
new FieldDefinitionPrimitive(55, BaseType.UINT16, "min_total_hemoglobin_conc", FieldDefinitionFactory.FIELD.ARRAY,100, 0), // g/dL
|
||||
new FieldDefinitionPrimitive(56, BaseType.UINT16, "max_total_hemoglobin_conc", FieldDefinitionFactory.FIELD.ARRAY,100, 0), // g/dL
|
||||
new FieldDefinitionPrimitive(57, BaseType.UINT16, "avg_saturated_hemoglobin_percent", FieldDefinitionFactory.FIELD.ARRAY,10, 0), // %
|
||||
new FieldDefinitionPrimitive(58, BaseType.UINT16, "min_saturated_hemoglobin_percent", FieldDefinitionFactory.FIELD.ARRAY,10, 0), // %
|
||||
new FieldDefinitionPrimitive(59, BaseType.UINT16, "max_saturated_hemoglobin_percent", FieldDefinitionFactory.FIELD.ARRAY,10, 0), // %
|
||||
new FieldDefinitionPrimitive(54, BaseType.UINT16, "avg_total_hemoglobin_conc", 100, 0), // g/dL
|
||||
new FieldDefinitionPrimitive(55, BaseType.UINT16, "min_total_hemoglobin_conc", 100, 0), // g/dL
|
||||
new FieldDefinitionPrimitive(56, BaseType.UINT16, "max_total_hemoglobin_conc", 100, 0), // g/dL
|
||||
new FieldDefinitionPrimitive(57, BaseType.UINT16, "avg_saturated_hemoglobin_percent", 10, 0), // %
|
||||
new FieldDefinitionPrimitive(58, BaseType.UINT16, "min_saturated_hemoglobin_percent", 10, 0), // %
|
||||
new FieldDefinitionPrimitive(59, BaseType.UINT16, "max_saturated_hemoglobin_percent", 10, 0), // %
|
||||
new FieldDefinitionPrimitive(62, BaseType.UINT8, "device_index"),
|
||||
new FieldDefinitionPrimitive(67, BaseType.SINT8, "left_pco"), // mm
|
||||
new FieldDefinitionPrimitive(68, BaseType.SINT8, "right_pco"), // mm
|
||||
@@ -1338,8 +1338,8 @@ public class GlobalFITMessage {
|
||||
));
|
||||
|
||||
public static GlobalFITMessage DEVELOPER_DATA = new GlobalFITMessage(207, "DEVELOPER_DATA", Arrays.asList(
|
||||
new FieldDefinitionPrimitive(0, BaseType.BASE_TYPE_BYTE, 16, "developer_id"),
|
||||
new FieldDefinitionPrimitive(1, BaseType.BASE_TYPE_BYTE, 16, "application_id"),
|
||||
new FieldDefinitionPrimitive(0, BaseType.BASE_TYPE_BYTE, 16, "developer_id", FieldDefinitionFactory.FIELD.ARRAY, 1, 0),
|
||||
new FieldDefinitionPrimitive(1, BaseType.BASE_TYPE_BYTE, 16, "application_id", FieldDefinitionFactory.FIELD.ARRAY, 1, 0),
|
||||
new FieldDefinitionPrimitive(2, BaseType.UINT16, "manufacturer_id"),
|
||||
new FieldDefinitionPrimitive(3, BaseType.UINT8, "developer_data_index"),
|
||||
new FieldDefinitionPrimitive(4, BaseType.UINT32, "application_version")
|
||||
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitRecordDataBuilder;
|
||||
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 FitBeatsInterval extends RecordData {
|
||||
public FitBeatsInterval(final RecordDefinition recordDefinition, final RecordHeader recordHeader) {
|
||||
super(recordDefinition, recordHeader);
|
||||
|
||||
final int globalNumber = recordDefinition.getGlobalFITMessage().getNumber();
|
||||
if (globalNumber != 290) {
|
||||
throw new IllegalArgumentException("FitBeatsInterval expects global messages of " + 290 + ", got " + globalNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getTimestampMs() {
|
||||
return (Integer) getFieldByNumber(0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getTime() {
|
||||
return (Integer) getFieldByNumber(1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getTimestamp() {
|
||||
return (Long) getFieldByNumber(253);
|
||||
}
|
||||
|
||||
public static class Builder extends FitRecordDataBuilder {
|
||||
public Builder() {
|
||||
super(290);
|
||||
}
|
||||
|
||||
public Builder setTimestampMs(final Integer value) {
|
||||
setFieldByNumber(0, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTime(final Integer value) {
|
||||
setFieldByNumber(1, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTimestamp(final Long value) {
|
||||
setFieldByNumber(253, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FitBeatsInterval build() {
|
||||
return (FitBeatsInterval) super.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-8
@@ -40,13 +40,35 @@ public class FitDeveloperData extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getDeveloperId() {
|
||||
return (Integer) getFieldByNumber(0);
|
||||
public Number[] getDeveloperId() {
|
||||
final Object object = getFieldByNumber(0);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getApplicationId() {
|
||||
return (Integer) getFieldByNumber(1);
|
||||
public Number[] getApplicationId() {
|
||||
final Object object = getFieldByNumber(1);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -72,13 +94,13 @@ public class FitDeveloperData extends RecordData {
|
||||
super(207);
|
||||
}
|
||||
|
||||
public Builder setDeveloperId(final Integer value) {
|
||||
setFieldByNumber(0, value);
|
||||
public Builder setDeveloperId(final Number[] value) {
|
||||
setFieldByNumber(0, (Object[]) value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setApplicationId(final Integer value) {
|
||||
setFieldByNumber(1, value);
|
||||
public Builder setApplicationId(final Number[] value) {
|
||||
setFieldByNumber(1, (Object[]) value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+12
-45
@@ -422,51 +422,18 @@ public class FitLap extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getAvgVerticalOscillation() {
|
||||
final Object object = getFieldByNumber(77);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getAvgVerticalOscillation() {
|
||||
return (Float) getFieldByNumber(77);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getAvgStanceTimePercen() {
|
||||
final Object object = getFieldByNumber(78);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getAvgStanceTimePercent() {
|
||||
return (Float) getFieldByNumber(78);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getAvgStanceTime() {
|
||||
final Object object = getFieldByNumber(79);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getAvgStanceTime() {
|
||||
return (Float) getFieldByNumber(79);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -1148,18 +1115,18 @@ public class FitLap extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgVerticalOscillation(final Number[] value) {
|
||||
setFieldByNumber(77, (Object[]) value);
|
||||
public Builder setAvgVerticalOscillation(final Float value) {
|
||||
setFieldByNumber(77, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgStanceTimePercen(final Number[] value) {
|
||||
setFieldByNumber(78, (Object[]) value);
|
||||
public Builder setAvgStanceTimePercent(final Float value) {
|
||||
setFieldByNumber(78, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgStanceTime(final Number[] value) {
|
||||
setFieldByNumber(79, (Object[]) value);
|
||||
public Builder setAvgStanceTime(final Float value) {
|
||||
setFieldByNumber(79, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+24
-90
@@ -245,99 +245,33 @@ public class FitRecord extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getAvgTotalHemoglobinConc() {
|
||||
final Object object = getFieldByNumber(54);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getAvgTotalHemoglobinConc() {
|
||||
return (Float) getFieldByNumber(54);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getMinTotalHemoglobinConc() {
|
||||
final Object object = getFieldByNumber(55);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getMinTotalHemoglobinConc() {
|
||||
return (Float) getFieldByNumber(55);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getMaxTotalHemoglobinConc() {
|
||||
final Object object = getFieldByNumber(56);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getMaxTotalHemoglobinConc() {
|
||||
return (Float) getFieldByNumber(56);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getAvgSaturatedHemoglobinPercent() {
|
||||
final Object object = getFieldByNumber(57);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getAvgSaturatedHemoglobinPercent() {
|
||||
return (Float) getFieldByNumber(57);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getMinSaturatedHemoglobinPercent() {
|
||||
final Object object = getFieldByNumber(58);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getMinSaturatedHemoglobinPercent() {
|
||||
return (Float) getFieldByNumber(58);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number[] getMaxSaturatedHemoglobinPercent() {
|
||||
final Object object = getFieldByNumber(59);
|
||||
if (object == null)
|
||||
return null;
|
||||
if (!object.getClass().isArray()) {
|
||||
return new Number[]{(Number) object};
|
||||
}
|
||||
final Object[] objectsArray = (Object[]) object;
|
||||
final Number[] ret = new Number[objectsArray.length];
|
||||
for (int i = 0; i < objectsArray.length; i++) {
|
||||
ret[i] = (Number) objectsArray[i];
|
||||
}
|
||||
return ret;
|
||||
public Float getMaxSaturatedHemoglobinPercent() {
|
||||
return (Float) getFieldByNumber(59);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -792,33 +726,33 @@ public class FitRecord extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgTotalHemoglobinConc(final Number[] value) {
|
||||
setFieldByNumber(54, (Object[]) value);
|
||||
public Builder setAvgTotalHemoglobinConc(final Float value) {
|
||||
setFieldByNumber(54, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinTotalHemoglobinConc(final Number[] value) {
|
||||
setFieldByNumber(55, (Object[]) value);
|
||||
public Builder setMinTotalHemoglobinConc(final Float value) {
|
||||
setFieldByNumber(55, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMaxTotalHemoglobinConc(final Number[] value) {
|
||||
setFieldByNumber(56, (Object[]) value);
|
||||
public Builder setMaxTotalHemoglobinConc(final Float value) {
|
||||
setFieldByNumber(56, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAvgSaturatedHemoglobinPercent(final Number[] value) {
|
||||
setFieldByNumber(57, (Object[]) value);
|
||||
public Builder setAvgSaturatedHemoglobinPercent(final Float value) {
|
||||
setFieldByNumber(57, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMinSaturatedHemoglobinPercent(final Number[] value) {
|
||||
setFieldByNumber(58, (Object[]) value);
|
||||
public Builder setMinSaturatedHemoglobinPercent(final Float value) {
|
||||
setFieldByNumber(58, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMaxSaturatedHemoglobinPercent(final Number[] value) {
|
||||
setFieldByNumber(59, (Object[]) value);
|
||||
public Builder setMaxSaturatedHemoglobinPercent(final Float value) {
|
||||
setFieldByNumber(59, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+63
-2
@@ -1,3 +1,19 @@
|
||||
/* Copyright (C) 2024-2025 Daniele Gobbetti, José Rebelo, Thomas Kuehne
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@@ -6,6 +22,9 @@ import static org.hamcrest.Matchers.is;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
@@ -356,7 +375,7 @@ public class GarminSupportTest extends TestBase {
|
||||
|
||||
FitFile fitFile = FitFile.parseIncoming(fileContents);
|
||||
Assert.assertEquals(expectedOutput, fitFile.toString());
|
||||
|
||||
getAllFitFieldValues(fitFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -374,6 +393,7 @@ public class GarminSupportTest extends TestBase {
|
||||
|
||||
FitFile fitFile = FitFile.parseIncoming(fileContents);
|
||||
Assert.assertEquals(expectedOutput, fitFile.toString());
|
||||
getAllFitFieldValues(fitFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -994,7 +1014,7 @@ public class GarminSupportTest extends TestBase {
|
||||
"FitTrainingSettings{target_distance=1.0, target_speed=1.0, target_time=1, precise_target_speed=1.0}, " +
|
||||
"FitGoals{sport=1, sub_sport=1, start_date=1127433599, end_date=1127433599, type=distance, value=1, repeat=1, target_value=1, recurrence=1, recurrence_value=1, enabled=1, source=community, message_index=1}, " +
|
||||
"FitSession{2025-09-22 01:59:59.000, event=3, event_type=1, start_time=1127433599, start_latitude=8.381903171539307E-8, start_longitude=8.381903171539307E-8, sport=1, sub_sport=1, total_elapsed_time=1000, total_timer_time=1000, total_distance=100, total_cycles=1, total_calories=1, total_fat_calories=1, avg_speed=1.0, max_speed=1.0, average_heart_rate=1, max_heart_rate=1, avg_cadence=1, max_cadence=1, avg_power=1, max_power=1, total_ascent=1, total_descent=1, total_training_effect=1.0, first_lap_index=1, num_laps=1, event_group=1, trigger=1, nec_latitude=8.381903171539307E-8, nec_longitude=8.381903171539307E-8, swc_latitude=8.381903171539307E-8, swc_longitude=8.381903171539307E-8, num_lengths=1, normalized_power=1, training_stress_score=1.0, intensity_factor=1.0, left_right_balance=1, end_latitude=8.381903171539307E-8, end_longitude=8.381903171539307E-8, avg_stroke_count=10, avg_stroke_distance=1.0, swim_stroke=1, pool_length=1.0, threshold_power=1, pool_length_unit=1, num_active_lengths=1, total_work=1, avg_altitude=1.0, max_altitude=1.0, gps_accuracy=1, avg_grade=1.0, avg_pos_grade=1.0, avg_neg_grade=1.0, max_pos_grade=1.0, max_neg_grade=1.0, avg_temperature=1, max_temperature=1, total_moving_time=1.0, avg_pos_vertical_speed=1.0, avg_neg_vertical_speed=1.0, max_pos_vertical_speed=1.0, max_neg_vertical_speed=1.0, min_heart_rate=1, avg_lap_time=1.0, best_lap_index=1, min_altitude=1.0, player_score=1, opponent_score=1, opponent_name=a, max_ball_speed=1.0, avg_ball_speed=1.0, avg_vertical_oscillation=1.0, avg_stance_time_percent=1.0, avg_stance_time=1.0, avg_fractional_cadence=1.0, max_fractional_cadence=1.0, total_fractional_cycles=1.0, avg_left_torque_effectiveness=1.0, avg_right_torque_effectiveness=1.0, avg_left_pedal_smoothness=1.0, avg_right_pedal_smoothness=1.0, avg_combined_pedal_smoothness=1.0, sport_profile_name=a, sport_index=1, stand_time=1000, stand_count=1, avg_left_pco=1, avg_right_pco=1, enhanced_avg_speed=1.0, enhanced_max_speed=1.0, enhanced_avg_altitude=1.0, enhanced_min_altitude=1.0, enhanced_max_altitude=1.0, avg_lev_motor_power=1, max_lev_motor_power=1, lev_battery_consumption=1.0, avg_vertical_ratio=1.0, avg_stance_time_balance=1.0, avg_step_length=1.0, total_anaerobic_training_effect=1.0, avg_vam=1.0, avg_depth=1.0, max_depth=1.0, surface_interval=1, start_cns=1, end_cns=1, start_n2=1, end_n2=1, avg_respiration_rate=1, max_respiration_rate=1, min_respiration_rate=1, min_temperature=1, o2_toxicity=1, dive_number=1, training_load_peak=1.0, enhanced_avg_respiration_rate=1.0, enhanced_max_respiration_rate=1.0, enhanced_min_respiration_rate=1.0, total_grit=1.0, total_flow=1.0, jump_count=1, avg_grit=1.0, avg_flow=1.0, workout_feel=1, workout_rpe=1, avg_spo2=1, avg_stress=1, hrv_sdrr=1, hrv_rmssd=1, total_fractional_ascent=1.0, total_fractional_descent=1.0, avg_core_temperature=1.0, min_core_temperature=1.0, max_core_temperature=1.0, timestamp=1758499199, message_index=1}, " +
|
||||
"FitLap{2025-09-22 01:59:59.000, event=3, event_type=1, start_time=1127433599, start_lat=8.381903171539307E-8, start_long=8.381903171539307E-8, end_lat=8.381903171539307E-8, end_long=8.381903171539307E-8, total_elapsed_time=1.0, total_timer_time=1.0, total_distance=1.0, total_cycles=1, total_calories=1, total_fat_calories=1, avg_speed=1.0, max_speed=1.0, avg_heart_rate=1, max_heart_rate=1, avg_cadence=1, max_cadence=1, avg_power=1, max_power=1, total_ascent=1, total_descent=1, intensity=1, lap_trigger=1, sport=1, event_group=1, num_lengths=1, normalized_power=1, left_right_balance=1, first_length_index=1, avg_stroke_distance=100, swim_style=BACKSTROKE, sub_sport=1, num_active_lengths=1, total_work=1, avg_altitude=1.0, max_altitude=1.0, gps_accuracy=1, avg_grade=1.0, avg_pos_grade=1.0, avg_neg_grade=1.0, max_pos_grade=1.0, max_neg_grade=1.0, avg_temperature=1, max_temperature=1, total_moving_time=1.0, avg_pos_vertical_speed=1.0, avg_neg_vertical_speed=1.0, max_pos_vertical_speed=1.0, max_neg_vertical_speed=1.0, repetition_num=1, min_altitude=1.0, min_heart_rate=1, wkt_step_index=1, opponent_score=1, avg_vertical_oscillation=1.0, avg_stance_time_percen=1.0, avg_stance_time=1.0, avg_fractional_cadence=1.0, max_fractional_cadence=1.0, total_fractional_cycles=1.0, player_score=1, avg_left_torque_effectiveness=1.0, avg_right_torque_effectiveness=1.0, avg_left_pedal_smoothness=1.0, avg_right_pedal_smoothness=1.0, avg_combined_pedal_smoothness=1.0, time_standing=1.0, stand_count=1, avg_left_pco=1, avg_right_pco=1, enhanced_avg_speed=10.0, enhanced_max_speed=10.0, enhanced_avg_altitude=1.0, enhanced_min_altitude=1.0, enhanced_max_altitude=1.0, avg_lev_motor_power=1, max_lev_motor_power=1, lev_battery_consumption=1.0, avg_vertical_ratio=1.0, avg_stance_time_balance=1.0, avg_step_length=1.0, avg_vam=1.0, avg_depth=1.0, max_depth=1.0, min_temperature=1, enhanced_avg_respiration_rate=1.0, enhanced_max_respiration_rate=1.0, avg_respiration_rate=1, max_respiration_rate=1, total_grit=1.0, total_flow=1.0, jump_count=1, avg_grit=1.0, avg_flow=1.0, total_fractional_ascent=1.0, total_fractional_descent=1.0, avg_core_temperature=1.0, min_core_temperature=1.0, max_core_temperature=1.0, timestamp=1758499199, message_index=1}, " +
|
||||
"FitLap{2025-09-22 01:59:59.000, event=3, event_type=1, start_time=1127433599, start_lat=8.381903171539307E-8, start_long=8.381903171539307E-8, end_lat=8.381903171539307E-8, end_long=8.381903171539307E-8, total_elapsed_time=1.0, total_timer_time=1.0, total_distance=1.0, total_cycles=1, total_calories=1, total_fat_calories=1, avg_speed=1.0, max_speed=1.0, avg_heart_rate=1, max_heart_rate=1, avg_cadence=1, max_cadence=1, avg_power=1, max_power=1, total_ascent=1, total_descent=1, intensity=1, lap_trigger=1, sport=1, event_group=1, num_lengths=1, normalized_power=1, left_right_balance=1, first_length_index=1, avg_stroke_distance=100, swim_style=BACKSTROKE, sub_sport=1, num_active_lengths=1, total_work=1, avg_altitude=1.0, max_altitude=1.0, gps_accuracy=1, avg_grade=1.0, avg_pos_grade=1.0, avg_neg_grade=1.0, max_pos_grade=1.0, max_neg_grade=1.0, avg_temperature=1, max_temperature=1, total_moving_time=1.0, avg_pos_vertical_speed=1.0, avg_neg_vertical_speed=1.0, max_pos_vertical_speed=1.0, max_neg_vertical_speed=1.0, repetition_num=1, min_altitude=1.0, min_heart_rate=1, wkt_step_index=1, opponent_score=1, avg_vertical_oscillation=1.0, avg_stance_time_percent=1.0, avg_stance_time=1.0, avg_fractional_cadence=1.0, max_fractional_cadence=1.0, total_fractional_cycles=1.0, player_score=1, avg_left_torque_effectiveness=1.0, avg_right_torque_effectiveness=1.0, avg_left_pedal_smoothness=1.0, avg_right_pedal_smoothness=1.0, avg_combined_pedal_smoothness=1.0, time_standing=1.0, stand_count=1, avg_left_pco=1, avg_right_pco=1, enhanced_avg_speed=10.0, enhanced_max_speed=10.0, enhanced_avg_altitude=1.0, enhanced_min_altitude=1.0, enhanced_max_altitude=1.0, avg_lev_motor_power=1, max_lev_motor_power=1, lev_battery_consumption=1.0, avg_vertical_ratio=1.0, avg_stance_time_balance=1.0, avg_step_length=1.0, avg_vam=1.0, avg_depth=1.0, max_depth=1.0, min_temperature=1, enhanced_avg_respiration_rate=1.0, enhanced_max_respiration_rate=1.0, avg_respiration_rate=1, max_respiration_rate=1, total_grit=1.0, total_flow=1.0, jump_count=1, avg_grit=1.0, avg_flow=1.0, total_fractional_ascent=1.0, total_fractional_descent=1.0, avg_core_temperature=1.0, min_core_temperature=1.0, max_core_temperature=1.0, timestamp=1758499199, message_index=1}, " +
|
||||
"FitRecord{2025-09-22 01:59:59.000, latitude=8.381903171539307E-8, longitude=8.381903171539307E-8, altitude=1.0, heart_rate=1, cadence=1, distance=1.0, speed=1.0, power=1, grade=1.0, resistance=1, time_from_course=1.0, cycle_length=1.0, temperature=1, cycles=1, total_cycles=1, compressed_accumulated_power=1, accumulated_power=1, left_right_balance=1, gps_accuracy=1, vertical_speed=1.0, calories=1, oscillation=1.0, stance_time_percent=1.0, stance_time=1.0, activity=1, left_torque_effectiveness=1.0, right_torque_effectiveness=1.0, left_pedal_smoothness=1.0, right_pedal_smoothness=1.0, combined_pedal_smoothness=1.0, time128=1.0, stroke_type=1, zone=1, ball_speed=1.0, cadence256=1.0, fractional_cadence=1.0, avg_total_hemoglobin_conc=1.0, min_total_hemoglobin_conc=1.0, max_total_hemoglobin_conc=1.0, avg_saturated_hemoglobin_percent=1.0, min_saturated_hemoglobin_percent=1.0, max_saturated_hemoglobin_percent=1.0, device_index=1, left_pco=1, right_pco=1, enhanced_speed=1.0, enhanced_altitude=1.0, battery_soc=1.0, motor_power=1, vertical_ratio=1.0, stance_time_balance=1.0, step_length=1.0, cycle_length16=1.0, absolute_pressure=1, depth=1.0, next_stop_depth=1.0, next_stop_time=1, time_to_surface=1, ndl_time=1, cns_load=1, n2_load=1, respiration_rate=1, enhanced_respiration_rate=100, grit=1.0, flow=1.0, current_stress=1.0, ebike_travel_rang=1, ebike_battery_level=1, ebike_assist_mode=1, ebike_assist_level_percent=1, air_time_remaining=1, pressure_sac=1.0, volume_sac=1.0, rmv=1.0, ascent_rate=1.0, po2=1.0, core_temperature=1.0, timestamp=1758499199}, " +
|
||||
"FitEvent{2025-09-22 01:59:59.000, event=3, event_type=1, data16=1, data=1, event_group=1, score=1, opponent_score=1, front_gear_num=1, front_gear=1, rear_gear_num=1, rear_gear=1, device_index=1, activity_type=1, start_timestamp=1127433599, radar_threat_level_max=1, radar_threat_count=1, radar_threat_avg_approach_speed=1.0, radar_threat_max_approach_speed=1.0, timestamp=1758499199}, " +
|
||||
"FitDeviceInfo{2025-09-22 01:59:59.000, device_index=1, device_type=1, manufacturer=1, serial_number=1, product=1, software_version=100, hardware_version=1, cum_operating_time=1, battery_voltage=1.0, battery_status=1, sensor_position=1, descriptor=a, ant_transmission_type=1, ant_device_number=1, ant_network=1, source_type=1, product_name=a, battery_level=1, timestamp=1758499199}, " +
|
||||
@@ -1109,8 +1129,49 @@ public class GarminSupportTest extends TestBase {
|
||||
String expected = expectedOutput.replace("}, Fit", "},\nFit").replace("}, RecordData{", "},\nRecordData{");
|
||||
String actual = fitFile.toString().replace("}, Fit", "},\nFit").replace("}, RecordData{", "},\nRecordData{");
|
||||
assertThat(actual, is(expected));
|
||||
getAllFitFieldValues(fitFile);
|
||||
} finally {
|
||||
TimeZone.setDefault(defaultTimeZone);
|
||||
}
|
||||
}
|
||||
|
||||
// try to retrieve the value of each message's fields
|
||||
private static void getAllFitFieldValues(FitFile fitFile) {
|
||||
List<RecordData> records = fitFile.getRecords();
|
||||
if (records == null || records.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int recordIndex = 0; recordIndex < records.size(); recordIndex++) {
|
||||
RecordData record = records.get(recordIndex);
|
||||
Class<?> recordClass = record.getClass();
|
||||
Method[] methods = recordClass.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
String name = method.getName();
|
||||
if (!name.startsWith("get")) {
|
||||
continue;
|
||||
}
|
||||
int modifiers = method.getModifiers();
|
||||
if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) {
|
||||
continue;
|
||||
}
|
||||
Parameter[] parameters = method.getParameters();
|
||||
if (parameters.length != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
method.invoke(record);
|
||||
} catch (Exception e) {
|
||||
String message = name + " failed for " + record;
|
||||
if ("FitRecord".equals(recordClass.getSimpleName()) && "getLatitude".equals(name)){
|
||||
// TODO GarminSupportTest.TestFitFileDevelopersField -> FitRecord / getLatitude
|
||||
// FIXME java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Double
|
||||
continue;
|
||||
}
|
||||
throw new AssertionError(message, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user