Documentation
¶
Overview ¶
Package encoder provides a handler to encode data into FIT file binary form.
Encoder supports encoding multiple data into a single chained FIT file.
Index ¶
Constants ¶
const ( ErrNilWriter = errorString("nil writer") ErrEmptyMessages = errorString("empty messages") ErrMissingFileId = errorString("missing file_id mesg") ErrWriterAtOrWriteSeekerIsExpected = errorString("io.WriterAt or io.WriteSeeker is expected") )
const ( ErrInvalidUTF8String = errorString("invalid UTF-8 string") ErrValueTypeMismatch = errorString("value type mismatch") ErrNoFields = errorString("no fields") ErrMissingDeveloperDataId = errorString("missing developer data id") ErrMissingFieldDescription = errorString("missing field description") ErrExceedMaxAllowed = errorString("exceed max allowed") )
const ( // The 5-bit time offset rolls over every 32 seconds. // When an incoming time offset is less than previous time offset, rollover event has occurred. RolloverEvent = 32 )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder is FIT file encoder. See New() for details.
func New ¶
New returns a FIT File Encoder to encode FIT data to given w.
Encoding Strategy ¶
Since an invalid FileHeader means an invalid FIT file, we need to ensure that the FileHeader is correct, specifically the FileHeader's DataSize (size of messages in bytes) and FileHeader's CRC checksum should be correct after everything is written.
There are two strategies to achieve that and it depends on what kind of io.Writer is provided:
- io.WriterAt or io.WriteSeeker: Encoder can update the FileHeader's DataSize and CRC after the encoding process is completed since we can write at a specific byte position, making it more ideal and efficient.
- io.Writer: Encoder needs to iterate through the messages once to calculate the FileHeader's DataSize and CRC by writing to io.Discard, then re-iterate through the messages again for the actual writing.
Loading everything in memory and then writing it all later should preferably be avoided. While a FIT file is commonly small-sized, but by design, it can hold up to approximately 4GB. This is because the DataSize is of type uint32, and its maximum value is around that number. And also 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 (FileHeader, Messages, CRC), making it more dynamic in size.
Note: We encourage wrapping w into a buffered writer such as bufferedwriter.New(w) that maintain io.WriteAt or io.WriteSeeker method (bufio.Writer does not). Encode process requires small bytes writing and having frequent write on non-buffered writer might impact performance, especially if it involves syscall such as writing a file. If you do wrap, don't forget to Flush() the buffered writer after encode is completed.
func (*Encoder) Encode ¶
Encode encodes FIT into the dest writer. Only FIT's Messages is required, while FileHeader and CRC will be filled automatically by the Encoder. However, we allow for custom FileHeader, such as when a user intentionally specifies a FileHeader's Size as 12 (legacy) or a custom FileHeader's ProfileVersion. In these cases, those two values will be encoded as-is, irrespective of the current SDK profile version.
Multiple FIT files can be chained together into a single FIT file by calling Encode for each FIT data.
for _, fit := range fits { err := enc.Encode(fit) }
Encode chooses which strategy to use for encoding the data based on given writer.
func (*Encoder) EncodeWithContext ¶
EncodeWithContext is similar to Encode but with respect to context propagation.
func (*Encoder) Reset ¶ added in v0.9.0
Reset resets the Encoder to write its output to w 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 encode to reduce memory allocs.
func (*Encoder) StreamEncoder ¶ added in v0.6.0
func (e *Encoder) StreamEncoder() (*StreamEncoder, error)
StreamEncoder turns this Encoder into StreamEncoder to encode per message basis or in streaming fashion. It returns an error if the Encoder's Writer does not implement io.WriterAt or io.WriteSeeker. After invoking this method, it is recommended not to use the Encoder to avoid undefined behavior.
type Factory ¶ added in v0.13.0
type Factory interface { // 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 Encoder's Validator.
type MessageValidator ¶
type MessageValidator interface { // Validate performs message validation before encoding to avoid resulting a corrupt FIT file. // // The validation process includes: // 1. Removing fields created during component expansion. // 2. Removing fields with invalid values. // 3. Restoring float64-scaled field values to their binary forms (sint, uint, etc.). // 4. Verifying whether the type and value are in alignment. Validate(mesg *proto.Message) error // Reset the message validator. Reset() }
MessageValidator is an interface for implementing message validation before encoding the message.
func NewMessageValidator ¶
func NewMessageValidator(opts ...ValidatorOption) MessageValidator
NewMessageValidator creates new message validator. The validator is mainly used to validate message before encoding. This receives options that direct the message validator how it should behave in certain way.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
func WithBigEndian ¶
func WithBigEndian() Option
WithBigEndian directs the Encoder to encode values in Big-Endian bytes order (default: Little-Endian).
func WithCompressedTimestampHeader ¶
func WithCompressedTimestampHeader() Option
WithCompressedTimestampHeader directs the Encoder to compress timestamp in header to reduce file size. Saves 7 bytes per message: 3 bytes for field definition and 4 bytes for the uint32 timestamp value.
func WithMessageValidator ¶
func WithMessageValidator(validator MessageValidator) Option
WithMessageValidator directs the Encoder to use this message validator instead of the default one.
func WithNormalHeader ¶
WithNormalHeader directs the Encoder to use NormalHeader for encoding the message using multiple local message types. By default, the Encoder uses local message type 0. This option allows users to specify values between 0-15 (while entering zero is equivalent to using the default option, nothing is changed). Using multiple local message types optimizes file size by avoiding the need to interleave different message definition.
Note: To minimize the required RAM for decoding, it's recommended to use a minimal number of local message types. For instance, embedded devices may only support decoding data from local message type 0. Additionally, multiple local message types should be avoided in file types like settings, where messages of the same type can be grouped together.
func WithProtocolVersion ¶
WithProtocolVersion directs the Encoder to use specific Protocol Version (default: proto.V1). If the given protocolVersion is not supported, the Protocol Version will not be changed. Please validate using proto.Validate when putting user-defined Protocol Version to check whether it is supported or not. Or just use predefined Protocol Version constants such as proto.V1, proto.V2, etc, which the validity is ensured.
type StreamEncoder ¶ added in v0.6.0
type StreamEncoder struct {
// contains filtered or unexported fields
}
StreamEncoder is one layer above Encoder to enable encoding in streaming fashion. This will only valid when the Writer given to the Encoder should either implement io.WriterAt or io.WriteSeeker. This can only be created using (*Encoder).StreamEncoder() method.
func (*StreamEncoder) Reset ¶ added in v0.9.0
func (e *StreamEncoder) Reset(w io.Writer, opts ...Option) error
Reset resets the Stream Encoder and the underlying Encoder to write its output to w 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 encode to reduce memory allocs. If w does not implement io.WriterAt or io.WriteSeeker, error will be returned.
func (*StreamEncoder) SequenceCompleted ¶ added in v0.6.0
func (e *StreamEncoder) SequenceCompleted() error
SequenceCompleted finalises the FIT File by updating its FileHeader's DataSize & CRC, as well as the File's CRC. This will also reset variables so that the StreamEncoder can be used for the next sequence of FIT file.
func (*StreamEncoder) WriteMessage ¶ added in v0.6.0
func (e *StreamEncoder) WriteMessage(mesg *proto.Message) error
WriteMessage writes message to the writer, it will auto write FileHeader when
- This method is invoked on the first time of use.
- This method is called right after SequenceCompleted method has been called.
type ValidatorOption ¶
type ValidatorOption interface {
// contains filtered or unexported methods
}
ValidatorOptions is message validator's option.
func ValidatorWithFactory ¶ added in v0.13.0
func ValidatorWithFactory(factory Factory) ValidatorOption
ValidatorWithFactory directs the message validator to use this factory instead of standard factory. The factory is only used for validating developer fields that have valid native data.
func ValidatorWithPreserveInvalidValues ¶
func ValidatorWithPreserveInvalidValues() ValidatorOption
ValidatorWithPreserveInvalidValues directs the message validator to preserve invalid value instead of omit it.