Skip to content

Commit

Permalink
refactor!: remove not particularly useful features (#418)
Browse files Browse the repository at this point in the history
* proto: remove CreateMessageDefinition, CreateMessageDefinitionTo and WithMessages

* proto: remove Message's WithFields and WithDeveloperFields method

* remove internal/kit

* remove (Message) WithFieldValues

* remove all Clone() method

* encoder: add unit test for newMessageDefinition

* remove factory CreateMesgOnly

* decoder: make Accumulator values private and update docs

* encoder: allocate mesgDef fields and developerFields upfront size 255

* proto: remove constant MaxBytesPerMessage and MaxBytesPerMessageDefinition

* proto: change FileHeader.ProtocolVersion type to proto.Version instead of byte

* chore: update Factory interface code docs

* decoder: rename ErrNotAFitFile to ErrNotFITFile

* decoder: remove idempotent guarantee for PeekFileHeader and PeekFileId as we might change the behavior later

* docs: update documentation

* fuzz: ignore mesgDef reserved

* basetype: remove IsInteger() EndianAbility() method, add EndianAbilityMask

* remove: Reserved and Architecture fields from Message

* proto: move LocalMesgNum and NewMessageDefinition functions to bottom

* chore: clean up proto_marshal_test.go code

* encoder: simplify encodeCRC

* decoder: reset on Decode, make Next as optional
  • Loading branch information
muktihari authored Sep 12, 2024
1 parent c1bf3fa commit 3e5a59e
Show file tree
Hide file tree
Showing 59 changed files with 1,704 additions and 1,850 deletions.
3 changes: 2 additions & 1 deletion cmd/fitactivity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Output:
```sh
About:
fitactivity is a program to handle FIT files based on provided command.
fitactivity is a program to manage FIT files based on provided command.
Usage:
fitactivity [command]
Expand Down Expand Up @@ -228,6 +228,7 @@ Subcommand Flags (only if subcommand is provided):
--rdp float64 reduce method: RDP [Ramer-Douglas-Peucker] based on GPS points, epsilon > 0
--distance float64 reduce method: distance interval in meters
--time uint32 reduce method: time interval in seconds
remove: (select at least one)
--unknown bool remove unknown messages
--nums string remove message numbers (value separated by comma)
Expand Down
8 changes: 4 additions & 4 deletions cmd/fitactivity/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ loop:
return err
}

fit.FileHeader.ProtocolVersion = byte(latestProtocolVersion(fits))
fit.FileHeader.ProtocolVersion = latestProtocolVersion(fits)
fit.FileHeader.ProfileVersion = latestProfileVersion(fits)

for _, subcommand := range subcommands {
Expand Down Expand Up @@ -1050,14 +1050,14 @@ func formatThousand(v int) string {
return result.String()
}

func latestProtocolVersion(fits []*proto.FIT) byte {
var version = byte(proto.V1)
func latestProtocolVersion(fits []*proto.FIT) proto.Version {
var version = proto.V1
for i := range fits {
if fits[i].FileHeader.ProtocolVersion > version {
version = fits[i].FileHeader.ProtocolVersion
}
}
return byte(proto.Version(version))
return version
}

func latestProfileVersion(fits []*proto.FIT) uint16 {
Expand Down
64 changes: 40 additions & 24 deletions cmd/fitprint/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func Print(path string) error {
defer p.Close()

dec := decoder.New(f,
decoder.WithMesgDefListener(p),
decoder.WithMesgListener(p),
decoder.WithBroadcastOnly(),
decoder.WithIgnoreChecksum(),
Expand Down Expand Up @@ -127,16 +128,23 @@ File Header:
const channelBuffer = 1000

type printer struct {
w io.Writer
poolc chan proto.Message
mesgc chan proto.Message
done chan struct{}
active bool
count int
w io.Writer
localMessageDefinitions [proto.LocalMesgNumMask + 1]proto.MessageDefinition
poolc chan proto.Message
messagec chan message
done chan struct{}
active bool
count int

fieldDescriptions []*mesgdef.FieldDescription
}

type message struct {
proto.Message
Reserved byte
Architecture byte
}

func New(w io.Writer) *printer {
p := &printer{w: w}
p.reset()
Expand All @@ -151,20 +159,20 @@ func New(w io.Writer) *printer {
}

func (p *printer) loop() {
for mesg := range p.mesgc {
switch mesg.Num {
for m := range p.messagec {
switch m.Num {
case mesgnum.FieldDescription:
p.fieldDescriptions = append(p.fieldDescriptions, mesgdef.NewFieldDescription(&mesg))
p.fieldDescriptions = append(p.fieldDescriptions, mesgdef.NewFieldDescription(&m.Message))
}
p.print(mesg)
p.poolc <- mesg
p.print(m)
p.poolc <- m.Message
p.count++
}
close(p.done)
}

func (p *printer) reset() {
p.mesgc = make(chan proto.Message, channelBuffer)
p.messagec = make(chan message, channelBuffer)
p.done = make(chan struct{})
p.count = 0
p.active = true
Expand All @@ -174,7 +182,7 @@ func (p *printer) Wait() {
if !p.active {
return
}
close(p.mesgc)
close(p.messagec)
<-p.done
p.active = false
}
Expand All @@ -184,6 +192,12 @@ func (p *printer) Close() {
close(p.poolc)
}

var _ decoder.MesgDefListener = (*printer)(nil)

func (p *printer) OnMesgDef(mesgDef proto.MessageDefinition) {
p.localMessageDefinitions[proto.LocalMesgNum(mesgDef.Header)] = mesgDef
}

var _ decoder.MesgListener = (*printer)(nil)

func (p *printer) OnMesg(mesg proto.Message) {
Expand All @@ -192,10 +206,10 @@ func (p *printer) OnMesg(mesg proto.Message) {
go p.loop()
p.active = true
}
p.mesgc <- p.prep(mesg)
p.messagec <- p.prep(mesg)
}

func (p *printer) prep(mesg proto.Message) proto.Message {
func (p *printer) prep(mesg proto.Message) message {
m := <-p.poolc

if cap(m.Fields) < len(mesg.Fields) {
Expand All @@ -212,20 +226,22 @@ func (p *printer) prep(mesg proto.Message) proto.Message {
copy(m.DeveloperFields, mesg.DeveloperFields)
mesg.DeveloperFields = m.DeveloperFields

return mesg
mesgDef := p.localMessageDefinitions[proto.LocalMesgNum(mesg.Header)]

return message{Message: mesg, Reserved: mesgDef.Reserved, Architecture: mesgDef.Architecture}
}

func (p *printer) print(mesg proto.Message) {
numstr := mesg.Num.String()
func (p *printer) print(m message) {
numstr := m.Num.String()
if strings.HasPrefix(numstr, "MesgNumInvalid") {
numstr = factory.NameUnknown
}

fmt.Fprintf(p.w, "%s (num: %d, arch: %d, fields[-]: %d, developerFields[+]: %d) [%d]:\n",
numstr, mesg.Num, mesg.Architecture, len(mesg.Fields), len(mesg.DeveloperFields), p.count)
numstr, m.Num, m.Architecture, len(m.Fields), len(m.DeveloperFields), p.count)

for j := range mesg.Fields {
field := &mesg.Fields[j]
for j := range m.Fields {
field := &m.Fields[j]

var (
isDynamicField = false
Expand All @@ -237,7 +253,7 @@ func (p *printer) print(mesg proto.Message) {
units = field.Units
)

if subField := field.SubFieldSubtitution(&mesg); subField != nil {
if subField := field.SubFieldSubtitution(&m.Message); subField != nil {
isDynamicField = true
name = subField.Name
baseType = subField.Type.BaseType()
Expand Down Expand Up @@ -291,8 +307,8 @@ func (p *printer) print(mesg proto.Message) {
)
}

for i := range mesg.DeveloperFields {
devField := &mesg.DeveloperFields[i]
for i := range m.DeveloperFields {
devField := &m.DeveloperFields[i]
fieldDesc := p.getFieldDescription(devField.DeveloperDataIndex, devField.Num)
if fieldDesc == nil {
continue
Expand Down
65 changes: 36 additions & 29 deletions decoder/accumulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,60 @@ import (
"github.com/muktihari/fit/profile/typedef"
)

// Accumulator is value accumulator.
type Accumulator struct {
AccumulatedValues []AccumulatedValue // use slice over map since len(values) is relatively small
values []value // use slice over map since len(values) is relatively small
}

// NewAccumulator creates new accumulator.
func NewAccumulator() *Accumulator {
return &Accumulator{} // No need to make AccumulatedValues as it will be created on append anyway.
return &Accumulator{}
}

func (a *Accumulator) Collect(mesgNum typedef.MesgNum, destFieldNum byte, value uint32) {
for i := range a.AccumulatedValues {
field := &a.AccumulatedValues[i]
if field.MesgNum == mesgNum && field.DestFieldNum == destFieldNum {
field.Value = value
field.Last = value
// Collect collects value, it will either append the value when not exist or replace existing one.
func (a *Accumulator) Collect(mesgNum typedef.MesgNum, destFieldNum byte, val uint32) {
for i := range a.values {
av := &a.values[i]
if av.mesgNum == mesgNum && av.fieldNum == destFieldNum {
av.value = val
av.last = val
return
}
}
a.AccumulatedValues = append(a.AccumulatedValues, AccumulatedValue{
MesgNum: mesgNum,
DestFieldNum: destFieldNum,
Value: value,
Last: value,
a.values = append(a.values, value{
mesgNum: mesgNum,
fieldNum: destFieldNum,
value: val,
last: val,
})
}

func (a *Accumulator) Accumulate(mesgNum typedef.MesgNum, destFieldNum byte, value uint32, bits byte) uint32 {
for i := range a.AccumulatedValues {
av := &a.AccumulatedValues[i]
if av.MesgNum == mesgNum && av.DestFieldNum == destFieldNum {
return av.Accumulate(value, bits)
// Accumulate calculates the accumulated value and update accordingly. It returns the original value
// when the corresponding value does not exist.
func (a *Accumulator) Accumulate(mesgNum typedef.MesgNum, destFieldNum byte, val uint32, bits byte) uint32 {
for i := range a.values {
av := &a.values[i]
if av.mesgNum == mesgNum && av.fieldNum == destFieldNum {
return av.accumulate(val, bits)
}
}
return value
return val
}

func (a *Accumulator) Reset() { a.AccumulatedValues = a.AccumulatedValues[:0] }
// Reset resets the accumulator. Tt retains the underlying storage for use by
// future use to reduce memory allocs.
func (a *Accumulator) Reset() { a.values = a.values[:0] }

type AccumulatedValue struct {
MesgNum typedef.MesgNum
DestFieldNum byte
Last uint32
Value uint32
type value struct {
mesgNum typedef.MesgNum
fieldNum byte
last uint32
value uint32
}

func (a *AccumulatedValue) Accumulate(value uint32, bits byte) uint32 {
func (a *value) accumulate(val uint32, bits byte) uint32 {
var mask uint32 = (1 << bits) - 1
a.Value += (value - a.Last) & mask
a.Last = value
return a.Value
a.value += (val - a.last) & mask
a.last = val
return a.value
}
8 changes: 4 additions & 4 deletions decoder/accumulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ func TestAccumulatorReset(t *testing.T) {
accumu := NewAccumulator()
accumu.Collect(mesgnum.Record, fieldnum.RecordSpeed, 1000)

if len(accumu.AccumulatedValues) != 1 {
t.Fatalf("expected AccumulatedValues is 1, got: %d", len(accumu.AccumulatedValues))
if len(accumu.values) != 1 {
t.Fatalf("expected AccumulatedValues is 1, got: %d", len(accumu.values))
}

accumu.Reset()

if len(accumu.AccumulatedValues) != 0 {
t.Fatalf("expected AccumulatedValues is 0 after reset, got: %d", len(accumu.AccumulatedValues))
if len(accumu.values) != 0 {
t.Fatalf("expected AccumulatedValues is 0 after reset, got: %d", len(accumu.values))
}
}
Loading

0 comments on commit 3e5a59e

Please sign in to comment.