Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: remove not particularly useful features #418

Merged
merged 22 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8ad4e1f
proto: remove CreateMessageDefinition, CreateMessageDefinitionTo and …
muktihari Sep 10, 2024
d727a77
proto: remove Message's WithFields and WithDeveloperFields method
muktihari Sep 10, 2024
e1c5036
remove internal/kit
muktihari Sep 10, 2024
439812a
remove (Message) WithFieldValues
muktihari Sep 11, 2024
51e3b70
remove all Clone() method
muktihari Sep 11, 2024
fc93dee
encoder: add unit test for newMessageDefinition
muktihari Sep 11, 2024
328efc4
remove factory CreateMesgOnly
muktihari Sep 11, 2024
a76a593
decoder: make Accumulator values private and update docs
muktihari Sep 11, 2024
b6becfc
encoder: allocate mesgDef fields and developerFields upfront size 255
muktihari Sep 11, 2024
f39e616
proto: remove constant MaxBytesPerMessage and MaxBytesPerMessageDefin…
muktihari Sep 11, 2024
89cdb27
proto: change FileHeader.ProtocolVersion type to proto.Version instea…
muktihari Sep 11, 2024
8ac7805
chore: update Factory interface code docs
muktihari Sep 11, 2024
c787d2d
decoder: rename ErrNotAFitFile to ErrNotFITFile
muktihari Sep 11, 2024
f053e10
decoder: remove idempotent guarantee for PeekFileHeader and PeekFileI…
muktihari Sep 11, 2024
fdce53a
docs: update documentation
muktihari Sep 11, 2024
d919b60
fuzz: ignore mesgDef reserved
muktihari Sep 12, 2024
9990347
basetype: remove IsInteger() EndianAbility() method, add EndianAbilit…
muktihari Sep 12, 2024
097b558
remove: Reserved and Architecture fields from Message
muktihari Sep 12, 2024
5a65535
proto: move LocalMesgNum and NewMessageDefinition functions to bottom
muktihari Sep 12, 2024
b796c2d
chore: clean up proto_marshal_test.go code
muktihari Sep 12, 2024
b75f50d
encoder: simplify encodeCRC
muktihari Sep 12, 2024
1961084
decoder: reset on Decode, make Next as optional
muktihari Sep 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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