mirror of
https://github.com/sstent/go-garminconnect.git
synced 2026-01-27 01:21:36 +00:00
sync
This commit is contained in:
111
internal/fit/decoder.go
Normal file
111
internal/fit/decoder.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package fit
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
headerSize = 12
|
||||
protocolMajor = 2
|
||||
)
|
||||
|
||||
// FileHeader represents the header of a FIT file
|
||||
type FileHeader struct {
|
||||
Size uint8
|
||||
Protocol uint8
|
||||
Profile [4]byte
|
||||
DataSize uint32
|
||||
Signature [4]byte
|
||||
}
|
||||
|
||||
// Activity represents activity data from a FIT file
|
||||
type Activity struct {
|
||||
Type string
|
||||
StartTime int64
|
||||
TotalDistance float64
|
||||
Duration float64
|
||||
}
|
||||
|
||||
// Decoder parses FIT files
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
// NewDecoder creates a new FIT decoder
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return &Decoder{r: r}
|
||||
}
|
||||
|
||||
// Parse decodes the FIT file and returns the activity data
|
||||
func (d *Decoder) Parse() (*Activity, error) {
|
||||
var header FileHeader
|
||||
if err := binary.Read(d.r, binary.LittleEndian, &header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Validate header
|
||||
if header.Protocol != protocolMajor {
|
||||
return nil, errors.New("unsupported FIT protocol version")
|
||||
}
|
||||
|
||||
// For simplicity, we'll just extract basic activity data
|
||||
activity := &Activity{}
|
||||
|
||||
// Skip to activity record (simplified for example)
|
||||
// In a real implementation, we would parse the file structure properly
|
||||
for {
|
||||
var recordHeader uint8
|
||||
if err := binary.Read(d.r, binary.LittleEndian, &recordHeader); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if recordHeader == 0x21 { // Activity record header (example value)
|
||||
var record struct {
|
||||
Type uint8
|
||||
StartTime int64
|
||||
TotalDistance float32
|
||||
Duration uint32
|
||||
}
|
||||
if err := binary.Read(d.r, binary.LittleEndian, &record); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
activity.Type = activityType(record.Type)
|
||||
activity.StartTime = record.StartTime
|
||||
activity.TotalDistance = float64(record.TotalDistance)
|
||||
activity.Duration = float64(record.Duration)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return activity, nil
|
||||
}
|
||||
|
||||
func activityType(t uint8) string {
|
||||
switch t {
|
||||
case 1:
|
||||
return "Running"
|
||||
case 2:
|
||||
return "Cycling"
|
||||
case 3:
|
||||
return "Swimming"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFile reads and parses a FIT file
|
||||
func ReadFile(path string) (*Activity, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return NewDecoder(file).Parse()
|
||||
}
|
||||
Reference in New Issue
Block a user