From 111609f1b52196ee3a91e3f78fa998f316704829 Mon Sep 17 00:00:00 2001 From: Benjamin Tamasi Date: Fri, 11 Aug 2023 11:22:44 +0200 Subject: [PATCH] updates to how calculations work when event counter doesn't change --- ant/powerProfile.go | 8 +- ant/speedAndCadenceProfile.go | 53 +++++-------- cmd/server/server.go | 143 ---------------------------------- go.mod | 10 +-- go.sum | 8 -- 5 files changed, 23 insertions(+), 199 deletions(-) delete mode 100644 cmd/server/server.go diff --git a/ant/powerProfile.go b/ant/powerProfile.go index 08c9b5a..5f23fab 100644 --- a/ant/powerProfile.go +++ b/ant/powerProfile.go @@ -66,13 +66,11 @@ func (m PowerMessage) InstantaneousPower() (num uint16) { // In conditions where packets are lost, average power accurately calculates power over the interval // between the received messages. func (m PowerMessage) AveragePower(prev PowerMessage) float32 { - if prev == nil { - return float32(m.InstantaneousPower()) - } + eventCountDiff := m.eventCountDiff(prev) - if prev.EventCount() == m.EventCount() { + if eventCountDiff == 0 { return float32(m.InstantaneousPower()) } - return float32(m.accumulatedPowerDiff(prev)) / float32(m.eventCountDiff(prev)) + return float32(m.accumulatedPowerDiff(prev)) / float32(eventCountDiff) } diff --git a/ant/speedAndCadenceProfile.go b/ant/speedAndCadenceProfile.go index 2582203..5de1cd5 100644 --- a/ant/speedAndCadenceProfile.go +++ b/ant/speedAndCadenceProfile.go @@ -36,17 +36,11 @@ func (m SpeedAndCadenceMessage) CumulativeSpeedRevolutionCount() (num uint16) { return } -func (m SpeedAndCadenceMessage) SpeedEventTimeDiff(prev SpeedAndCadenceMessage) uint16 { - if prev == nil { - return 0 - } +func (m SpeedAndCadenceMessage) speedEventTimeDiff(prev SpeedAndCadenceMessage) uint16 { return m.SpeedEventTime() - prev.SpeedEventTime() } -func (m SpeedAndCadenceMessage) CadenceEventTimeDiff(prev SpeedAndCadenceMessage) uint16 { - if prev == nil { - return 0 - } +func (m SpeedAndCadenceMessage) cadenceEventTimeDiff(prev SpeedAndCadenceMessage) uint16 { return m.CadenceEventTime() - prev.CadenceEventTime() } @@ -54,49 +48,40 @@ func (m SpeedAndCadenceMessage) speedRevolutionCountDiff(prev SpeedAndCadenceMes return m.CumulativeSpeedRevolutionCount() - prev.CumulativeSpeedRevolutionCount() } -func (m SpeedAndCadenceMessage) CadenceRevolutionCountDiff(prev SpeedAndCadenceMessage) uint16 { +func (m SpeedAndCadenceMessage) cadenceRevolutionCountDiff(prev SpeedAndCadenceMessage) uint16 { return m.CumulativeCadenceRevolutionCount() - prev.CumulativeCadenceRevolutionCount() } -// Returns the cadence calculated from the previous message (0 if previous message is nil) -// The second parameter "nochange" indicates that the EventTime counter has not changed since the -// previous message, which means a complete rotation has not yet occurred. You should use this value -// to handle cases where the pedal stops: "coasting" (EventTime counter does not change) +// Cadence Returns the cadence calculated from the previous message +// If the "ok" parameter is false, this indicates that a complete rotation has not yet occurred. +// In this case the cadence has not changed, but it is impossible to calculate from these two messages. +// We can use this to also handle cases where the pedal stops: "coasting" (EventTime counter does not change) // Cadence: (RPM) -func (m SpeedAndCadenceMessage) Cadence(prev SpeedAndCadenceMessage) (cadence float32, nochange bool) { - if prev == nil { +func (m SpeedAndCadenceMessage) Cadence(prev SpeedAndCadenceMessage) (cadence float32, ok bool) { + eventCountDiff := m.cadenceEventTimeDiff(prev) + if eventCountDiff == 0 { return 0, false } - if m.CadenceEventTimeDiff(prev) == 0 { - return 0, true - } - - return float32(m.CadenceRevolutionCountDiff(prev)) * 1024 * 60 / float32(m.CadenceEventTimeDiff(prev)), false + return float32(m.cadenceRevolutionCountDiff(prev)) * 1024 * 60 / float32(eventCountDiff), true } // Distance travelled since the last message: (m) // circumference: Circumference of the wheel (m) func (m SpeedAndCadenceMessage) Distance(prev SpeedAndCadenceMessage, circumference float32) float32 { - if prev == nil { - return 0 - } return float32(m.speedRevolutionCountDiff(prev)) * circumference } -// Speed: (m/s) +// Speed in (m/s) // circumference: Circumference of the wheel (m) -// The second parameter "nochange" indicates that the EventTime counter has not changed since the -// previous message, which means a complete rotation has not yet occurred. You should use this value -// to handle cases where the pedal stops: "coasting" (EventTime counter does not change) -func (m SpeedAndCadenceMessage) Speed(prev SpeedAndCadenceMessage, circumference float32) (speed float32, nochange bool) { - if prev == nil { +// If the "ok" parameter is false, this indicates that a complete rotation has not yet occurred. +// In this case the speed has not changed, but it is impossible to calculate from these two messages. +// We can use this to also handle cases where the pedal stops: "coasting" (EventTime counter does not change) +func (m SpeedAndCadenceMessage) Speed(prev SpeedAndCadenceMessage, circumference float32) (speed float32, ok bool) { + eventCountDiff := m.speedEventTimeDiff(prev) + if eventCountDiff == 0 { return 0, false } - if m.SpeedEventTimeDiff(prev) == 0 { - return 0, true - } - - return m.Distance(prev, circumference) * 1024 / float32(m.SpeedEventTimeDiff(prev)), false + return m.Distance(prev, circumference) * 1024 / float32(eventCountDiff), true } diff --git a/cmd/server/server.go b/cmd/server/server.go deleted file mode 100644 index 9a0e27f..0000000 --- a/cmd/server/server.go +++ /dev/null @@ -1,143 +0,0 @@ -package main - -import ( - "bufio" - "context" - "fmt" - "github.com/half2me/antgo/ant" - "github.com/redis/go-redis/v9" - "log" - "net" - "time" -) - -const ( - HOST = "localhost" - PORT = "9999" - TYPE = "tcp" -) - -func main() { - // redis://:@localhost:6379/ - opt, err := redis.ParseURL("redis://localhost:6379/0") - if err != nil { - panic(err) - } - - client := redis.NewClient(opt) - - listen, err := net.Listen(TYPE, HOST+":"+PORT) - if err != nil { - log.Fatal(err) - } - // close listener - defer listen.Close() - - // Write to Redis - ch := make(chan ant.BroadcastMessage) - go redisWriter(client, ch) - - // Server loop - for { - conn, err := listen.Accept() - if err != nil { - log.Fatal(err) - } - go handle(conn, ch) - } -} - -func handle(conn net.Conn, ch chan ant.BroadcastMessage) { - log.Println("New connection!") - defer conn.Close() - r := bufio.NewReader(conn) - - for { - msg, err := ant.ReadMsg(r) - if err != nil { - break - } - // skip non-broadcast messages - if msg.Class() != ant.MESSAGE_TYPE_BROADCAST { - continue - } - ch <- ant.BroadcastMessage(msg) - - } - log.Println("Client disconnected!") -} - -func redisWriter(client *redis.Client, ch chan ant.BroadcastMessage) { - ctx := context.Background() - for msg := range ch { - // deduplicate: TODO: replace with lua script? - hash := "dedup:" + string(hashAntMsg(msg)) - res, err := client.SetNX(ctx, "dedup:"+string(hash), "", time.Second*5).Result() - if err != nil { - log.Fatal(err.Error()) - } - if !res { - continue - } - - key := fmt.Sprintf("antcmp:%d:%s", msg.DeviceNumber(), msg.DeviceTypeString()) - result, err := client.GetSet(ctx, key, []byte(msg)).Result() // TODO: replace with SetArgs to have TTL here - switch { - case err == redis.Nil: - continue - case err != nil: - log.Fatal(err.Error()) - } - - old := ant.BroadcastMessage(result) - hkey := fmt.Sprintf("ant:%d", msg.DeviceNumber()) - switch msg.DeviceType() { - case ant.DEVICE_TYPE_POWER: - pow := ant.PowerMessage(msg) - oldPow := ant.PowerMessage(old) - power := pow.AveragePower(oldPow) - err := client.HSet(ctx, hkey, "power", power).Err() - if err != nil { - log.Fatal(err.Error()) - } - fmt.Printf("%5d %.2fW\n", msg.DeviceNumber(), power) - err = client.Publish(ctx, hkey+":power", power).Err() - if err != nil { - log.Fatal(err.Error()) - } - case ant.DEVICE_TYPE_SPEED_AND_CADENCE: - s := ant.SpeedAndCadenceMessage(msg) - oldS := ant.SpeedAndCadenceMessage(old) - cadence, _ := s.Cadence(oldS) - speed, _ := s.Speed(oldS, 0.98) - delta := s.Distance(oldS, 0.98) - - err := client.HSet(ctx, hkey, "speed", speed, "cadence", cadence).Err() - if err != nil { - log.Fatal(err.Error()) - } - distance, err := client.HIncrByFloat(ctx, hkey, "distance", float64(delta)).Result() - if err != nil { - return - } - fmt.Printf("%5d %.2frpm %.2fm/s %.2fm\n", msg.DeviceNumber(), cadence, speed, distance) - err = client.Publish(ctx, hkey+":speed", speed).Err() - if err != nil { - log.Fatal(err.Error()) - } - err = client.Publish(ctx, hkey+":cadence", cadence).Err() - if err != nil { - log.Fatal(err.Error()) - } - err = client.Publish(ctx, hkey+":distance", distance).Err() - if err != nil { - log.Fatal(err.Error()) - } - } - } -} - -func hashAntMsg(msg ant.BroadcastMessage) []byte { - // content + extended content: device number [:2] & type [2] - return append(msg.Content(), msg.ExtendedContent()[:3]...) -} diff --git a/go.mod b/go.mod index 7e00096..afe796c 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,4 @@ module github.com/half2me/antgo go 1.20 -require ( - github.com/google/gousb v1.1.2 - github.com/redis/go-redis/v9 v9.0.3 -) - -require ( - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect -) +require github.com/google/gousb v1.1.2 diff --git a/go.sum b/go.sum index 2ffda70..a51fb85 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,2 @@ -github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= -github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/google/gousb v1.1.2 h1:1BwarNB3inFTFhPgUEfah4hwOPuDz/49I0uX8XNginU= github.com/google/gousb v1.1.2/go.mod h1:GGWUkK0gAXDzxhwrzetW592aOmkkqSGcj5KLEgmCVUg= -github.com/redis/go-redis/v9 v9.0.3 h1:+7mmR26M0IvyLxGZUHxu4GiBkJkVDid0Un+j4ScYu4k= -github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=