Documentation
¶
Overview ¶
Package decoder provides a handler to decode fit files.
Decoder supports decoding chained fit files for all fit protocol versions.
Index ¶
- Variables
- type AccumulatedValue
- type Accumulator
- type Decoder
- func (d *Decoder) CheckIntegrity() (seq int, err error)
- func (d *Decoder) Decode() (fit *proto.Fit, err error)
- func (d *Decoder) DecodeWithContext(ctx context.Context) (fit *proto.Fit, err error)
- func (d *Decoder) Discard() error
- func (d *Decoder) Next() bool
- func (d *Decoder) PeekFileId() (fileId *mesgdef.FileId, err error)
- func (d *Decoder) Reset(r io.Reader, opts ...Option)
- type Factory
- type Option
- type RawDecoder
- type RawFlag
Constants ¶
This section is empty.
Variables ¶
var ( // Integrity errors ErrNotAFitFile = errors.New("not a fit file") ErrDataSizeZero = errors.New("data size zero") ErrCRCChecksumMismatch = errors.New("crc checksum mismatch") // Message-field related errors ErrMesgDefMissing = errors.New("message definition missing") ErrFieldValueTypeMismatch = errors.New("field value type mismatch") ErrByteSizeMismatch = errors.New("byte size mismath") )
Functions ¶
This section is empty.
Types ¶
type AccumulatedValue ¶
func (*AccumulatedValue) Accumulate ¶
func (a *AccumulatedValue) Accumulate(value uint32, bits byte) uint32
type Accumulator ¶
type Accumulator struct {
AccumulatedValues []AccumulatedValue // use slice over map since len(values) is relatively small
}
func NewAccumulator ¶
func NewAccumulator() *Accumulator
func (*Accumulator) Accumulate ¶
func (*Accumulator) Collect ¶
func (a *Accumulator) Collect(mesgNum typedef.MesgNum, destFieldNum byte, value uint32)
func (*Accumulator) Reset ¶ added in v0.4.2
func (a *Accumulator) Reset()
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder is Fit file decoder. See New() for details.
func New ¶
New returns a FIT File Decoder to decode given r.
The FIT protocol allows for multiple FIT files to be chained together in a single FIT file. Each FIT file in the chain must be a properly formatted FIT file (header, data records, CRC).
To decode chained FIT files, use Next() to check if r hasn't reach EOF and next bytes are still a valid FIT sequences.
for dec.Next() { fit, err := dec.Decode() }
Note: We encourage wrapping r into a buffered reader such as bufio.NewReader(r), decode process requires byte by byte reading and having frequent read on non-buffered reader might impact performance, especially if it involves syscall such as reading a file.
func (*Decoder) CheckIntegrity ¶ added in v0.7.0
CheckIntegrity checks all FIT sequences of given reader are valid determined by these following checks:
- Has valid FileHeader's size and bytes 8–11 of the FileHeader is “.FIT”
- FileHeader's DataSize > 0
- CRC checksum of messages should match with File's CRC value.
It returns the number of sequences completed and any error encountered. The number of sequences completed can help recovering valid FIT sequences in a chained FIT that contains invalid or corrupted data.
After invoking this method, the underlying reader should be reset afterward as the reader has been fully read. If the underlying reader implements io.Seeker, we can do reader.Seek(0, io.SeekStart).
func (*Decoder) Decode ¶
Decode method decodes `r` into Fit data. One invocation will produce one valid Fit data or an error if it occurs. To decode a chained Fit file that contains more than one Fit data, this decode method should be invoked multiple times. It is recommended to wrap it with the Next() method when you are uncertain if it's a chained fit file.
for dec.Next() { fit, err := dec.Decode() if err != nil { return err } }
func (*Decoder) DecodeWithContext ¶
DecodeWithContext is similar to Decode but with respect to context propagation.
func (*Decoder) Discard ¶ added in v0.11.0
Discard discards a single FIT file sequence and returns any error encountered. This method directs the Decoder to point to the byte sequence of the next valid FIT file sequence, discarding the current FIT file sequence.
Example: - A chained FIT file consist of Activity, Course, Workout and Settings. And we only want to decode Course.
for dec.Next() { fileId, err := dec.PeekFileId() if err != nil { return err } if fileId.Type != typedef.FileCourse { if err := dec.Discard(); err != nil { return err } continue } fit, err := dec.Decode() if err != nil { return err } }
func (*Decoder) Next ¶
Next checks whether next bytes are still a valid Fit File sequence. Return false when invalid or reach EOF.
func (*Decoder) PeekFileId ¶
PeekFileId decodes only up to FileId message without decoding the whole reader. FileId message should be the first message of any Fit file, otherwise return an error.
After this method is invoked, Decode picks up where this left then continue decoding next messages instead of starting from zero. This method is idempotent and can be invoked even after Decode has been invoked.
func (*Decoder) Reset ¶ added in v0.9.0
Reset resets the Decoder to read its input from r, clear any error and reset previous options to default options so any options needs to be inputed again. It is similar to New() but it retains the underlying storage for use by future decode to reduce memory allocs (except messages need to be re-allocated).
type Factory ¶
type Factory interface { // CreateMesgOnly create new message with Fields and DeveloperFields are being nil. If not found, it returns new message with "unknown" name. CreateMesgOnly(mesgNum typedef.MesgNum) proto.Message // CreateField create new field based on defined messages in the factory. If not found, it returns new field with "unknown" name. CreateField(mesgNum typedef.MesgNum, num byte) proto.Field }
Factory defines a contract that any Factory containing these method can be used by the Decoder.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
func WithBroadcastOnly ¶
func WithBroadcastOnly() Option
WithBroadcastOnly directs the Decoder to only broadcast the messages without retaining them, reducing memory usage when it's not going to be used anyway. This option is intended to be used with WithMesgListener and WithMesgDefListener. When this option is specified, the Decode will return a fit with empty messages.
func WithIgnoreChecksum ¶
func WithIgnoreChecksum() Option
WithIgnoreChecksum directs the Decoder to not checking data integrity (CRC Checksum).
func WithMesgDefListener ¶
func WithMesgDefListener(listeners ...listener.MesgDefListener) Option
WithMesgDefListener adds listeners to the listener pool, where each listener is broadcasted every message definition. The listeners will be appended not replaced. If users need to reset use Reset().
func WithMesgListener ¶
func WithMesgListener(listeners ...listener.MesgListener) Option
WithMesgListener adds listeners to the listener pool, where each listener is broadcasted every message. The listeners will be appended not replaced. If users need to reset use Reset().
func WithNoComponentExpansion ¶
func WithNoComponentExpansion() Option
WithNoComponentExpansion directs the Decoder to not expand the components.
type RawDecoder ¶ added in v0.8.0
type RawDecoder struct { // [MesgDef: 6 + 255 * 3 = 771] < [Mesg: 1 + (255 * 255 * 2) = 130051]. Use bigger capacity. // // This is exported to allow the unused space to be utilized in a tight RAM, for instance, an embedded device. // Using Index >= len(b) is safe on each Decode's callback function call. BytesArray [1 + (255 * 255 * 2)]byte // contains filtered or unexported fields }
RawDecoder is a sequence of FIT bytes decoder. See NewRaw() for details.
func NewRaw ¶ added in v0.8.0
func NewRaw() *RawDecoder
NewRaw creates new RawDecoder which provides low-level building block to work with FIT bytes for the maximum performance gain. RawDecoder will split bytes by its corresponding RawFlag (FileHeader, MessageDefinition, MessageData and CRC) for scoping the operation.
However, this is still considered unsafe operation since we work with bytes directly and the responsibility for validation now placed on the user-space. The only thing that this validates is the reader should be a FIT (FileHeader: has valid Size and bytes 8-12 is ".FIT").
The idea is to allow us to use a minimal viable decoder for performance and memory-critical situations, where every computation or memory usage is constrained. RawDecoder itself is using constant memory < 131 KB and the Decode method has zero heap alloc (except errors) while it may use additional small stack memory. The implementation of the callback function is also expected to have minimal overhead.
For general purpose usage, use Decoder instead.
func (*RawDecoder) Decode ¶ added in v0.8.0
func (d *RawDecoder) Decode(r io.Reader, fn func(flag RawFlag, b []byte) error) (n int64, err error)
Decode decodes r reader into sequence of FIT bytes splitted by its corresponding RawFlag (FileHeader, MessageDefinition, MessageData and CRC) for every FIT sequences in the reader, until it reaches EOF. It returns the number of bytes read and any error encountered. When fn returns an error, Decode will immediately return the error.
For performance, the b is not copied and the underlying array's values will be replaced each fn call. If you need to work with b in its slice form later on, it should be copied.
Note: We encourage wrapping r into a buffered reader such as bufio.NewReader(r), decode process requires byte by byte reading and having frequent read on non-buffered reader might impact performance, especially if it involves syscall such as reading a file.
type RawFlag ¶ added in v0.8.0
type RawFlag byte
RawFlag is the kind of the incomming bytes, the size of the incomming bytes is vary but the the size is guaranteed by the corresponding RawFlag.
const ( // RawFlagFileHeader is guaranteed to have either 12 or 14 bytes (all in little-endian byte order): // Size + ProtocolVersion + ProfileVersion (2 bytes) + DataSize (4 bytes) + DataType (4 bytes) + // (only if Size is 14) CRC (2 bytes) RawFlagFileHeader RawFlag = iota // RawFlagMesgDef is guaranteed to have: // Header + Reserved + Architecture + MesgNum (2 bytes) + n FieldDefinitions + (n FieldDefinitions * 3) + // (only if Header & 0b00100000 == 0b00100000) n DeveloperFieldDefinitions + (n DeveloperFieldDefinitions * 3) RawFlagMesgDef // RawFlagMesgData is guaranteed to have: // Header + Fields' value represented by its Message Definition + (only if it has developer fields) // Developer Fields' value. RawFlagMesgData // RawFlagCRC is guaranteed to have: // 2 bytes (in little-endian byte order) as the checksum of the messages. RawFlagCRC )