mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Garmin: extend FIT file parsing 14 - COURSE_POINT 32 / type 4
based on https://github.com/muktihari/fit
This commit is contained in:
committed by
José Rebelo
parent
62b324ec90
commit
a28ed02534
+4
-1
@@ -6,6 +6,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefi
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionArray;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionBoolean;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoordinate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoursePoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionDayOfWeek;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionExerciseCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionFileType;
|
||||
@@ -52,6 +53,7 @@ public class FieldDefinitionFactory {
|
||||
case COORDINATE -> new FieldDefinitionCoordinate(localNumber, size, baseType, name);
|
||||
case SWIM_STYLE -> new FieldDefinitionSwimStyle(localNumber, size, baseType, name);
|
||||
case LOCATION_SYMBOL -> new FieldDefinitionLocationSymbol(localNumber, size, baseType, name, scale, offset);
|
||||
case COURSE_POINT -> new FieldDefinitionCoursePoint(localNumber, size, baseType, name, scale, offset);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,6 +79,7 @@ public class FieldDefinitionFactory {
|
||||
WEATHER_AQI,
|
||||
COORDINATE,
|
||||
SWIM_STYLE,
|
||||
LOCATION_SYMBOL
|
||||
LOCATION_SYMBOL,
|
||||
COURSE_POINT
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -736,7 +736,7 @@ public class GlobalFITMessage {
|
||||
new FieldDefinitionPrimitive(2, BaseType.SINT32, "position_lat", FieldDefinitionFactory.FIELD.COORDINATE),
|
||||
new FieldDefinitionPrimitive(3, BaseType.SINT32, "position_long", FieldDefinitionFactory.FIELD.COORDINATE),
|
||||
new FieldDefinitionPrimitive(4, BaseType.UINT32, "distance", 100, 0), // m
|
||||
new FieldDefinitionPrimitive(5, BaseType.ENUM, "type"),
|
||||
new FieldDefinitionPrimitive(5, BaseType.ENUM, "type", FieldDefinitionFactory.FIELD.COURSE_POINT),
|
||||
new FieldDefinitionPrimitive(6, BaseType.STRING, 16, "name"),
|
||||
new FieldDefinitionPrimitive(8, BaseType.ENUM, "favorite"),
|
||||
new FieldDefinitionPrimitive(254, BaseType.UINT16, "message_index")
|
||||
|
||||
+2
@@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordDef
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.RecordHeader;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionAlarmLabel;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionCoursePoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionExerciseCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalSource;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionGoalType;
|
||||
@@ -365,6 +366,7 @@ public class FitCodeGen {
|
||||
case COORDINATE -> Double.class;
|
||||
case SWIM_STYLE -> FieldDefinitionSwimStyle.SwimStyle.class;
|
||||
case LOCATION_SYMBOL -> FieldDefinitionLocationSymbol.LocationSymbol.class;
|
||||
case COURSE_POINT -> FieldDefinitionCoursePoint.CoursePoint.class;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/* Copyright (C) 2025 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.fit.fieldDefinitions;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FieldDefinition;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.baseTypes.BaseType;
|
||||
|
||||
public class FieldDefinitionCoursePoint extends FieldDefinition {
|
||||
|
||||
public FieldDefinitionCoursePoint(int localNumber, int size, BaseType baseType, String name, int scale, int offset) {
|
||||
super(localNumber, size, baseType, name, scale, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(ByteBuffer byteBuffer) {
|
||||
final Object rawObj = baseType.decode(byteBuffer, scale, offset);
|
||||
if (rawObj != null) {
|
||||
final Number raw = (Number) rawObj;
|
||||
return CoursePoint.fromId(raw.intValue());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuffer byteBuffer, Object o) {
|
||||
if (o instanceof CoursePoint coursePoint) {
|
||||
baseType.encode(byteBuffer, coursePoint.getId(), scale, offset);
|
||||
return;
|
||||
}
|
||||
baseType.encode(byteBuffer, o, scale, offset);
|
||||
}
|
||||
|
||||
public enum CoursePoint {
|
||||
GENERIC(0, "generic"),
|
||||
SUMMIT(1, "summit"),
|
||||
VALLEY(2, "valley"),
|
||||
WATER(3, "water"),
|
||||
FOOD(4, "food"),
|
||||
DANGER(5, "danger"),
|
||||
LEFT(6, "left"),
|
||||
RIGHT(7, "right"),
|
||||
STRAIGHT(8, "straight"),
|
||||
FIRST_AID(9, "first_aid"),
|
||||
FOURTH_CATEGORY(10, "fourth_category"),
|
||||
THIRD_CATEGORY(11, "third_category"),
|
||||
SECOND_CATEGORY(12, "second_category"),
|
||||
FIRST_CATEGORY(13, "first_category"),
|
||||
HORS_CATEGORY(14, "hors_category"),
|
||||
SPRINT(15, "sprint"),
|
||||
LEFT_FORK(16, "left_fork"),
|
||||
RIGHT_FORK(17, "right_fork"),
|
||||
MIDDLE_FORK(18, "middle_fork"),
|
||||
SLIGHT_LEFT(19, "slight_left"),
|
||||
SHARP_LEFT(20, "sharp_left"),
|
||||
SLIGHT_RIGHT(21, "slight_right"),
|
||||
SHARP_RIGHT(22, "sharp_right"),
|
||||
U_TURN(23, "u_turn"),
|
||||
SEGMENT_START(24, "segment_start"),
|
||||
SEGMENT_END(25, "segment_end"),
|
||||
CAMPSITE(27, "campsite"),
|
||||
AID_STATION(28, "aid_station"),
|
||||
REST_AREA(29, "rest_area"),
|
||||
GENERAL_DISTANCE(30, "general_distance"),
|
||||
SERVICE(31, "service"),
|
||||
ENERGY_GEL(32, "energy_gel"),
|
||||
SPORTS_DRINK(33, "sports_drink"),
|
||||
MILE_MARKER(34, "mile_marker"),
|
||||
CHECKPOINT(35, "checkpoint"),
|
||||
SHELTER(36, "shelter"),
|
||||
MEETING_SPOT(37, "meeting_spot"),
|
||||
OVERLOOK(38, "overlook"),
|
||||
TOILET(39, "toilet"),
|
||||
SHOWER(40, "shower"),
|
||||
GEAR(41, "gear"),
|
||||
SHARP_CURVE(42, "sharp_curve"),
|
||||
STEEP_INCLINE(43, "steep_incline"),
|
||||
TUNNEL(44, "tunnel"),
|
||||
BRIDGE(45, "bridge"),
|
||||
OBSTACLE(46, "obstacle"),
|
||||
CROSSING(47, "crossing"),
|
||||
STORE(48, "store"),
|
||||
TRANSITION(49, "transition"),
|
||||
NAVAID(50, "navaid"),
|
||||
TRANSPORT(51, "transport"),
|
||||
ALERT(52, "alert"),
|
||||
INFO(53, "info");
|
||||
|
||||
private final int id;
|
||||
|
||||
@NonNull
|
||||
private final String name;
|
||||
|
||||
CoursePoint(int id, @NonNull String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CoursePoint fromId(int id) {
|
||||
for (CoursePoint symbol : values()) {
|
||||
if (id == symbol.id) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CoursePoint fromName(String name) {
|
||||
for (CoursePoint symbol : values()) {
|
||||
if (symbol.name.equals(name)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -22,6 +22,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.FitRecord
|
||||
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.fieldDefinitions.FieldDefinitionCoursePoint.CoursePoint;
|
||||
|
||||
/**
|
||||
* WARNING: This class was auto-generated, please avoid modifying it directly.
|
||||
@@ -60,8 +61,8 @@ public class FitCoursePoint extends RecordData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getType() {
|
||||
return (Integer) getFieldByNumber(5);
|
||||
public CoursePoint getType() {
|
||||
return (CoursePoint) getFieldByNumber(5);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -107,7 +108,7 @@ public class FitCoursePoint extends RecordData {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setType(final Integer value) {
|
||||
public Builder setType(final CoursePoint value) {
|
||||
setFieldByNumber(5, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ FitWorkoutStep{2025-09-21 23:59:59.000, wkt_step_name=a, duration_type=1, durati
|
||||
FitSchedule{2025-09-21 23:59:59.000, manufacturer=1, product=1, serial_number=1, time_created=1127433599, completed=true, type=1, scheduled_time=1},
|
||||
FitWeightScale{2025-09-21 23:59:59.000, weight=1.0, percent_fat=1.0, percent_hydration=1.0, visceral_fat_mass=1.0, bone_mass=1.0, muscle_mass=1.0, basal_met=1.0, physique_rating=1, active_met=1.0, metabolic_age=1, visceral_fat_rating=1, user_profile_index=1, bmi=1.0, timestamp=1758499199},
|
||||
FitCourse{2025-09-21 23:59:59.000, sport=1, name=a, capabilities=1, sub_sport=1},
|
||||
FitCoursePoint{2025-09-21 23:59:59.000, timestamp=1758499199, position_lat=8.381903171539307E-8, position_long=8.381903171539307E-8, distance=1.0, type=1, name=a, favorite=1, message_index=1},
|
||||
FitCoursePoint{2025-09-21 23:59:59.000, timestamp=1758499199, position_lat=8.381903171539307E-8, position_long=8.381903171539307E-8, distance=1.0, type=summit, name=a, favorite=1, message_index=1},
|
||||
FitTotals{2025-09-21 23:59:59.000, timer_time=1, distance=1, calories=1, sport=1, elapsed_time=1, sessions=1, active_time=1, sport_index=1, timestamp=1758499199, message_index=1},
|
||||
FitActivity{2025-09-21 23:59:59.000, total_timer_time=1000, num_sessions=1, type=1, event=3, event_type=1, local_timestamp=1, event_group=1, timestamp=1758499199},
|
||||
FitSoftware{2025-09-21 23:59:59.000, version=1.0, part_number=a, message_index=1},
|
||||
|
||||
Reference in New Issue
Block a user