From 05af404db133e5af971ea708f420c6478c941c55 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 11 Mar 2026 21:20:17 +0000 Subject: [PATCH] add the identification ID for a telemetry field we will use this so the serial device knows where to send the data --- providers/iracing/iracing.go | 5 +++-- telemetry/data.go | 12 ++++++++---- telemetry/data_test.go | 22 +++++++++++++++------- telemetry/provider.go | 2 +- tui/internal/controllers/streaming.go | 9 ++++++--- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/providers/iracing/iracing.go b/providers/iracing/iracing.go index 49d641c..f49050e 100644 --- a/providers/iracing/iracing.go +++ b/providers/iracing/iracing.go @@ -121,12 +121,12 @@ func (i *IRacing) Stream() (<-chan telem.TelemetryData, error) { return i.streamCh, nil } -func (i *IRacing) Subscribe(requestFields []telem.FieldID) { +func (i *IRacing) Subscribe(requestFields map[int16]telem.FieldID) { i.logger.Debug(fmt.Sprintf("Len Req: %d\n", len(requestFields))) i.data.ActiveBinds = make([]telem.BoundField, 0, len(requestFields)) - for _, id := range requestFields { + for winID, id := range requestFields { // Translate the UI FieldIDs to this provider's field names sdkKey, ok := internalToSDKFieldNames[id] if !ok { @@ -178,6 +178,7 @@ func (i *IRacing) Subscribe(requestFields []telem.FieldID) { } } + i.data.Values[id].ID = winID i.data.ActiveBinds = append(i.data.ActiveBinds, binding) } diff --git a/telemetry/data.go b/telemetry/data.go index 62f8e4e..5ff4ecb 100644 --- a/telemetry/data.go +++ b/telemetry/data.go @@ -47,6 +47,7 @@ const ( // application. // From my testing, using an uint64 bucket is around 50x faster than any type TelemetryField struct { + ID int16 // Identification: I have to learn how I will use this on other devices Type DataType Raw uint64 Str string // Only to be used with DataTypeSTRING @@ -54,17 +55,20 @@ type TelemetryField struct { // Pack will pack this current TelemetryField into bytes to send over the wire // Format: -// 0x00 - DataType -// 0x01 - if its a (u)int8 +// 0x00 - Field ID +// 0x00 | +// 0x01 - DataType +// 0x02 - if its a (u)int8 // or -// 0x01 - if its a (u)int16 - first byte -// 0x01 - if its a (u)int16 - second byte +// 0x02 - if its a (u)int16 - first byte +// 0x02 - if its a (u)int16 - second byte // or // 0x02 - str len max is 255 chars // [0x02] - str func (tf *TelemetryField) Pack(dest []byte) []byte { // NOTE: maybe we can have a pool of these so we don't have to create them here // or whatever + dest = append(dest, uint8(tf.ID), uint8(tf.ID>>8)) dest = append(dest, uint8(tf.Type)) switch tf.Type { diff --git a/telemetry/data_test.go b/telemetry/data_test.go index 95993c1..728cf77 100644 --- a/telemetry/data_test.go +++ b/telemetry/data_test.go @@ -17,51 +17,57 @@ func Test_TelemetryField(t *testing.T) { { name: "test_max_uint8", tf: TelemetryField{ + ID: 0x01, Type: DataTypeUINT8, Raw: uint64(math.MaxUint8), }, - expect: []byte{0x00, 0xFF}, + expect: []byte{0x01, 0x00, 0x00, 0xFF}, }, { name: "test_max_int8", tf: TelemetryField{ + ID: 0x02, Type: DataTypeINT8, Raw: uint64(math.MaxInt8), }, - expect: []byte{0x01, 0x7F}, + expect: []byte{0x02, 0x00, 0x01, 0x7F}, }, { name: "test_max_uint16", tf: TelemetryField{ + ID: 0x03, Type: DataTypeUINT16, Raw: uint64(math.MaxUint16), }, - expect: []byte{0x02, 0xFF, 0xFF}, + expect: []byte{0x03, 0x00, 0x02, 0xFF, 0xFF}, }, { name: "test_max_int16", tf: TelemetryField{ + ID: 0x04, Type: DataTypeINT16, Raw: uint64(math.MaxInt16), }, - expect: []byte{0x03, 0xFF, 0x7F}, + expect: []byte{0x04, 0x00, 0x03, 0xFF, 0x7F}, }, { name: "test_string", tf: TelemetryField{ + ID: 0x05, Type: DataTypeSTRING, Str: "a cool string!", }, - expect: []byte{0x08, 0x0E, 0x61, 0x20, 0x63, 0x6F, 0x6F, 0x6C, 0x20, 0x73, + expect: []byte{0x05, 0x00, 0x08, 0x0E, 0x61, 0x20, 0x63, 0x6F, 0x6F, 0x6C, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x21}, }, { name: "test_char", tf: TelemetryField{ + ID: 0x06, Type: DataTypeCHAR, Raw: uint64('R'), }, - expect: []byte{0x09, 0x52}, + expect: []byte{0x06, 0x00, 0x09, 0x52}, }, } @@ -92,16 +98,18 @@ func Test_TelemetryData(t *testing.T) { } data.Values[Speed] = TelemetryField{ + ID: 0x01, Type: DataTypeUINT16, Raw: uint64(254), } data.Values[Gear] = TelemetryField{ + ID: 0x02, Type: DataTypeCHAR, Raw: uint64('R'), } - expect := []byte{0x02, 0xFE, 0x00, 0x09, 0x52} + expect := []byte{0x01, 0x00, 0x02, 0xFE, 0x00, 0x02, 0x00, 0x09, 0x52} result := data.Pack() if !bytes.Equal(result, expect) { diff --git a/telemetry/provider.go b/telemetry/provider.go index 56675f7..785b2f6 100644 --- a/telemetry/provider.go +++ b/telemetry/provider.go @@ -3,5 +3,5 @@ package telemetry type TelemetryProvider interface { Stream() (<-chan TelemetryData, error) - Subscribe([]FieldID) + Subscribe(map[int16]FieldID) } diff --git a/tui/internal/controllers/streaming.go b/tui/internal/controllers/streaming.go index 1c5a54f..cc4c1f3 100644 --- a/tui/internal/controllers/streaming.go +++ b/tui/internal/controllers/streaming.go @@ -89,12 +89,15 @@ func (sc *StreamingCtrl) Start() { // goes into the layout tool, sets up the data to transmit to his devices and // then comes here to stream that data. We call this to set the fields the user // has subscrived to in his tooling +// +// Performance reasoning: this is not used during the high frequency data transmission +// so we can get away with using a map for convenience here func (sc *StreamingCtrl) SetInternalState() { - // Get the subscribed fields - fields := make([]telemetry.FieldID, 0, len(sc.Service.CDash.State.Layout.Windows)) + fields := make(map[int16]telemetry.FieldID, len(sc.Service.CDash.State.Layout.Windows)) + for _, w := range sc.Service.CDash.State.Layout.Windows { fieldID, _ := telemetry.GetFieldID(w.UIData.TelemetryField) - fields = append(fields, fieldID) + fields[w.UIData.IDX] = fieldID } sc.TelemServ.ActiveProvider.Subscribe(fields)