Files
fit-parser/QUICKSTART.md
Thomas Klaehn 2945d90d24 Initial commit
Signed-off-by: Thomas Klaehn <thomas.klaehn@perinet.io>
2026-02-08 07:30:31 +00:00

254 lines
6.7 KiB
Markdown

# Quick Start Guide
## Installation
```bash
# Get the module
go get git.blackfinn.de/go/fit-parser/fitparser
# Or clone and use locally
git clone https://git.blackfinn.de/go/fit-parser.git
```
## Quick Test
```bash
# Run the example
cd fitparser/example
go run main.go testdata/Activity.fit
# Run tests
cd fitparser
go test -v
```
## Basic Usage
### 1. Simple File Parsing
```go
package main
import (
"fmt"
"log"
"os"
"git.blackfinn.de/go/fit-parser/fitparser"
)
func main() {
// Read the FIT file
data, err := os.ReadFile("activity.fit")
if err != nil {
log.Fatal(err)
}
// Create decoder
decoder, err := fitparser.NewDecoder(data)
if err != nil {
log.Fatal(err)
}
// Decode messages
messages, err := decoder.Decode()
if err != nil {
log.Printf("Warning: %v", err)
// Continue anyway - CRC errors are non-fatal
}
fmt.Printf("Decoded %d messages\n", len(messages))
}
```
### 2. Processing Activity Data
```go
for _, msg := range messages {
switch msg.Num {
case fitparser.MesgNumFileId:
// File information
if fileType, ok := msg.GetFieldValueUint8(fitparser.FieldFileIdType); ok {
fmt.Printf("File Type: %s\n", fitparser.GetFileTypeName(fileType))
}
case fitparser.MesgNumRecord:
// GPS and sensor data points
if timestamp, ok := msg.GetFieldValueUint32(fitparser.FieldRecordTimestamp); ok {
t := fitparser.ConvertFITTimestamp(timestamp)
fmt.Printf("Time: %s\n", t)
}
if hr, ok := msg.GetFieldValueUint8(fitparser.FieldRecordHeartRate); ok {
if hr != fitparser.Uint8Invalid {
fmt.Printf("Heart Rate: %d bpm\n", hr)
}
}
case fitparser.MesgNumSession:
// Activity summary
if sport, ok := msg.GetFieldValueUint8(fitparser.FieldSessionSport); ok {
fmt.Printf("Sport: %s\n", fitparser.GetSportName(sport))
}
if totalTime, ok := msg.GetFieldValueUint32(fitparser.FieldSessionTotalTimerTime); ok {
minutes := float64(totalTime) / 1000.0 / 60.0
fmt.Printf("Duration: %.2f minutes\n", minutes)
}
}
}
```
### 3. GPS Coordinates
```go
for _, msg := range messages {
if msg.Num == fitparser.MesgNumRecord {
// Get latitude
if lat, ok := msg.Fields[fitparser.FieldRecordPositionLat]; ok {
if latInt, ok := lat.(int32); ok && latInt != fitparser.Sint32Invalid {
latDeg := fitparser.ConvertSemicirclesToDegrees(latInt)
// Get longitude
if lon, ok := msg.Fields[fitparser.FieldRecordPositionLong]; ok {
if lonInt, ok := lon.(int32); ok && lonInt != fitparser.Sint32Invalid {
lonDeg := fitparser.ConvertSemicirclesToDegrees(lonInt)
fmt.Printf("Position: %.6f, %.6f\n", latDeg, lonDeg)
}
}
}
}
}
}
```
## Running the Example
This repository includes a complete example application:
```bash
# From the example directory
cd example
go run main.go testdata/Activity.fit
go run main.go testdata/Settings.fit
go run main.go testdata/RealWorld_Cycling.fit
# Or from the repository root
go run example/main.go example/testdata/Activity.fit
```
## Testing
Run the test suite:
```bash
cd fitparser
go test -v
```
Run benchmarks:
```bash
cd fitparser
go test -bench=.
```
## Common Message Types
- **FileId** (0) - File metadata (type, manufacturer, product, serial number)
- **Record** (20) - Data points (GPS, heart rate, power, cadence, etc.)
- **Lap** (19) - Lap summaries
- **Session** (18) - Activity session summaries
- **Activity** (34) - Overall activity summaries
- **Event** (21) - Events (start, stop, lap button, etc.)
- **DeviceInfo** (23) - Device information
## Field Access Patterns
### Type-Safe Accessors
```go
// For common types
uint8Val, ok := msg.GetFieldValueUint8(fieldNum)
uint16Val, ok := msg.GetFieldValueUint16(fieldNum)
uint32Val, ok := msg.GetFieldValueUint32(fieldNum)
stringVal, ok := msg.GetFieldValueString(fieldNum)
```
### Direct Field Access
```go
// Access any field by number
if value, ok := msg.Fields[fieldNum]; ok {
// Type assert as needed
switch v := value.(type) {
case uint8:
fmt.Printf("Uint8: %d\n", v)
case uint32:
fmt.Printf("Uint32: %d\n", v)
case int32:
fmt.Printf("Sint32: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
case []uint8:
fmt.Printf("Byte array: %v\n", v)
}
}
```
## Performance Tips
1. **Disable CRC for faster parsing** (if you trust your files):
```go
decoder.EnableCRCCheck(false)
```
2. **Filter messages early** if you only need specific types:
```go
for _, msg := range messages {
if msg.Num != fitparser.MesgNumRecord {
continue // Skip non-record messages
}
// Process only records
}
```
3. **Use type-safe accessors** when possible - they're optimized
## Handling Invalid Values
FIT files use special "invalid" values to indicate missing data:
```go
// Always check for invalid values
if hr, ok := msg.GetFieldValueUint8(fitparser.FieldRecordHeartRate); ok {
if hr != fitparser.Uint8Invalid {
fmt.Printf("Heart Rate: %d bpm\n", hr)
} else {
fmt.Println("Heart Rate: not available")
}
}
```
Invalid value constants:
- `Uint8Invalid` = 0xFF
- `Uint16Invalid` = 0xFFFF
- `Uint32Invalid` = 0xFFFFFFFF
- `Sint8Invalid` = 0x7F
- `Sint16Invalid` = 0x7FFF
- `Sint32Invalid` = 0x7FFFFFFF
## Next Steps
- Read the full [README.md](README.md) for comprehensive documentation
- Explore the [example/main.go](example/main.go) for a complete working example
- Check the [fitparser/](fitparser/) directory for implementation details
- Try parsing your own FIT files!
## Troubleshooting
**CRC Validation Failures**: If CRC validation fails, the file may be corrupted. CRC checking is enabled by default and validates data integrity. You can disable it with `decoder.EnableCRCCheck(false)` if you trust the file source.
**Invalid Field Values**: Always check for invalid values using the provided constants (e.g., `Uint8Invalid`, `Uint32Invalid`). These indicate missing or unavailable data in the FIT file.
**Unknown Message Types**: Some proprietary message types may not have names in the profile. They'll show as "Unknown" but can still be accessed by their message number.