347 lines
8.8 KiB
Go
347 lines
8.8 KiB
Go
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)
|
|
}
|