Initial commit

Signed-off-by: Thomas Klaehn <thomas.klaehn@perinet.io>
This commit is contained in:
Thomas Klaehn
2026-02-08 07:28:32 +00:00
commit 2945d90d24
25 changed files with 3177 additions and 0 deletions

346
fitparser/profile.go Normal file
View File

@@ -0,0 +1,346 @@
package fitparser
// Common message numbers
const (
MesgNumFileId = 0
MesgNumCapabilities = 1
MesgNumDeviceSettings = 2
MesgNumUserProfile = 3
MesgNumHrmProfile = 4
MesgNumSdmProfile = 5
MesgNumBikeProfile = 6
MesgNumZonesTarget = 7
MesgNumHrZone = 8
MesgNumPowerZone = 9
MesgNumMetZone = 10
MesgNumSport = 12
MesgNumGoal = 15
MesgNumSession = 18
MesgNumLap = 19
MesgNumRecord = 20
MesgNumEvent = 21
MesgNumDeviceInfo = 23
MesgNumWorkout = 26
MesgNumWorkoutStep = 27
MesgNumSchedule = 28
MesgNumActivity = 34
MesgNumSoftware = 35
MesgNumFileCapabilities = 37
MesgNumMesgCapabilities = 38
MesgNumFieldCapabilities = 39
MesgNumFileCreator = 49
MesgNumBloodPressure = 51
MesgNumSpeedZone = 53
MesgNumMonitoring = 55
MesgNumHrv = 78
MesgNumLength = 101
MesgNumMonitoringInfo = 103
MesgNumPad = 105
MesgNumSegmentLap = 142
)
// Common field numbers for FileId message
const (
FieldFileIdType = 0
FieldFileIdManufacturer = 1
FieldFileIdProduct = 2
FieldFileIdSerialNumber = 3
FieldFileIdTimeCreated = 4
FieldFileIdNumber = 5
)
// Common field numbers for Record message
const (
FieldRecordTimestamp = 253
FieldRecordPositionLat = 0
FieldRecordPositionLong = 1
FieldRecordAltitude = 2
FieldRecordHeartRate = 3
FieldRecordCadence = 4
FieldRecordDistance = 5
FieldRecordSpeed = 6
FieldRecordPower = 7
FieldRecordCompressedSpeedDistance = 8
FieldRecordGrade = 9
FieldRecordResistance = 10
FieldRecordTimeFromCourse = 11
FieldRecordCycleLength = 12
FieldRecordTemperature = 13
)
// Common field numbers for Lap message
const (
FieldLapTimestamp = 253
FieldLapEvent = 0
FieldLapEventType = 1
FieldLapStartTime = 2
FieldLapStartPositionLat = 3
FieldLapStartPositionLong = 4
FieldLapEndPositionLat = 5
FieldLapEndPositionLong = 6
FieldLapTotalElapsedTime = 7
FieldLapTotalTimerTime = 8
FieldLapTotalDistance = 9
FieldLapTotalCycles = 10
FieldLapTotalCalories = 11
FieldLapTotalFatCalories = 12
FieldLapAvgSpeed = 13
FieldLapMaxSpeed = 14
FieldLapAvgHeartRate = 15
FieldLapMaxHeartRate = 16
FieldLapAvgCadence = 17
FieldLapMaxCadence = 18
FieldLapAvgPower = 19
FieldLapMaxPower = 20
)
// Common field numbers for Session message
const (
FieldSessionTimestamp = 253
FieldSessionEvent = 0
FieldSessionEventType = 1
FieldSessionStartTime = 2
FieldSessionStartPositionLat = 3
FieldSessionStartPositionLong = 4
FieldSessionSport = 5
FieldSessionSubSport = 6
FieldSessionTotalElapsedTime = 7
FieldSessionTotalTimerTime = 8
FieldSessionTotalDistance = 9
FieldSessionTotalCycles = 10
FieldSessionTotalCalories = 11
FieldSessionTotalFatCalories = 13
FieldSessionAvgSpeed = 14
FieldSessionMaxSpeed = 15
FieldSessionAvgHeartRate = 16
FieldSessionMaxHeartRate = 17
FieldSessionAvgCadence = 18
FieldSessionMaxCadence = 19
FieldSessionAvgPower = 20
FieldSessionMaxPower = 21
)
// Common field numbers for Activity message
const (
FieldActivityTimestamp = 253
FieldActivityTotalTimerTime = 0
FieldActivityNumSessions = 1
FieldActivityType = 2
FieldActivityEvent = 3
FieldActivityEventType = 4
FieldActivityLocalTimestamp = 5
FieldActivityEventGroup = 6
)
// File types
const (
FileTypeDevice = 1
FileTypeSettings = 2
FileTypeSport = 3
FileTypeActivity = 4
FileTypeWorkout = 5
FileTypeCourse = 6
FileTypeSchedules = 7
FileTypeWeight = 9
FileTypeTotals = 10
FileTypeGoals = 11
FileTypeBloodPressure = 14
FileTypeMonitoringA = 15
FileTypeActivitySummary = 20
FileTypeMonitoringDaily = 28
FileTypeMonitoringB = 32
FileTypeSegment = 34
FileTypeSegmentList = 35
)
// Sport types
const (
SportGeneric = 0
SportRunning = 1
SportCycling = 2
SportTransition = 3
SportFitnessEquipment = 4
SportSwimming = 5
SportBasketball = 6
SportSoccer = 7
SportTennis = 8
SportAmericanFootball = 9
SportTraining = 10
SportWalking = 11
SportCrossCountrySkiing = 12
SportAlpineSkiing = 13
SportSnowboarding = 14
SportRowing = 15
SportMountaineering = 16
SportHiking = 17
SportMultisport = 18
SportPaddling = 19
)
// GetMessageName returns a human-readable name for a message number
func GetMessageName(mesgNum uint16) string {
switch mesgNum {
case MesgNumFileId:
return "FileId"
case MesgNumCapabilities:
return "Capabilities"
case MesgNumDeviceSettings:
return "DeviceSettings"
case MesgNumUserProfile:
return "UserProfile"
case MesgNumHrmProfile:
return "HrmProfile"
case MesgNumSdmProfile:
return "SdmProfile"
case MesgNumBikeProfile:
return "BikeProfile"
case MesgNumZonesTarget:
return "ZonesTarget"
case MesgNumHrZone:
return "HrZone"
case MesgNumPowerZone:
return "PowerZone"
case MesgNumMetZone:
return "MetZone"
case MesgNumSport:
return "Sport"
case MesgNumGoal:
return "Goal"
case MesgNumSession:
return "Session"
case MesgNumLap:
return "Lap"
case MesgNumRecord:
return "Record"
case MesgNumEvent:
return "Event"
case MesgNumDeviceInfo:
return "DeviceInfo"
case MesgNumActivity:
return "Activity"
case MesgNumSoftware:
return "Software"
case MesgNumFileCapabilities:
return "FileCapabilities"
case MesgNumMesgCapabilities:
return "MesgCapabilities"
case MesgNumFieldCapabilities:
return "FieldCapabilities"
case MesgNumFileCreator:
return "FileCreator"
case MesgNumBloodPressure:
return "BloodPressure"
case MesgNumSpeedZone:
return "SpeedZone"
case MesgNumMonitoring:
return "Monitoring"
case MesgNumHrv:
return "Hrv"
case MesgNumLength:
return "Length"
case MesgNumMonitoringInfo:
return "MonitoringInfo"
case MesgNumPad:
return "Pad"
case MesgNumSegmentLap:
return "SegmentLap"
default:
return "Unknown"
}
}
// GetFileTypeName returns a human-readable name for a file type
func GetFileTypeName(fileType uint8) string {
switch fileType {
case FileTypeDevice:
return "Device"
case FileTypeSettings:
return "Settings"
case FileTypeSport:
return "Sport"
case FileTypeActivity:
return "Activity"
case FileTypeWorkout:
return "Workout"
case FileTypeCourse:
return "Course"
case FileTypeSchedules:
return "Schedules"
case FileTypeWeight:
return "Weight"
case FileTypeTotals:
return "Totals"
case FileTypeGoals:
return "Goals"
case FileTypeBloodPressure:
return "BloodPressure"
case FileTypeMonitoringA:
return "MonitoringA"
case FileTypeActivitySummary:
return "ActivitySummary"
case FileTypeMonitoringDaily:
return "MonitoringDaily"
case FileTypeMonitoringB:
return "MonitoringB"
case FileTypeSegment:
return "Segment"
case FileTypeSegmentList:
return "SegmentList"
default:
return "Unknown"
}
}
// GetSportName returns a human-readable name for a sport type
func GetSportName(sport uint8) string {
switch sport {
case SportGeneric:
return "Generic"
case SportRunning:
return "Running"
case SportCycling:
return "Cycling"
case SportTransition:
return "Transition"
case SportFitnessEquipment:
return "FitnessEquipment"
case SportSwimming:
return "Swimming"
case SportBasketball:
return "Basketball"
case SportSoccer:
return "Soccer"
case SportTennis:
return "Tennis"
case SportAmericanFootball:
return "AmericanFootball"
case SportTraining:
return "Training"
case SportWalking:
return "Walking"
case SportCrossCountrySkiing:
return "CrossCountrySkiing"
case SportAlpineSkiing:
return "AlpineSkiing"
case SportSnowboarding:
return "Snowboarding"
case SportRowing:
return "Rowing"
case SportMountaineering:
return "Mountaineering"
case SportHiking:
return "Hiking"
case SportMultisport:
return "Multisport"
case SportPaddling:
return "Paddling"
default:
return "Unknown"
}
}
// ConvertSemicirclesToDegrees converts a position in semicircles to degrees
// FIT files store lat/long as semicircles (2^31 semicircles = 180 degrees)
func ConvertSemicirclesToDegrees(semicircles int32) float64 {
return float64(semicircles) * (180.0 / 2147483648.0)
}