Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65f03fd4c9 | ||
|
|
20025dae1b | ||
|
|
03d0f8aefc | ||
|
|
df99994a75 | ||
|
|
80651c21cf | ||
|
|
528c62288a | ||
|
|
196e1d8916 | ||
|
|
decd91c406 | ||
|
|
b8e632d3eb | ||
|
|
d8589394f6 | ||
|
|
76f2e265d7 | ||
|
|
7c03088470 | ||
|
|
0006b649f3 | ||
|
|
3493a73a82 | ||
|
|
f4bde52f40 |
@@ -1,17 +1,20 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"esdi/logger"
|
||||
esdi "esdi/oldEsdi"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func liveTelemetryCmdAction(cmd *cobra.Command, args []string) {
|
||||
log := logger.GetInstance()
|
||||
|
||||
ddPort, _ := cmd.Flags().GetString("port")
|
||||
outputFile, _ := cmd.Flags().GetString("out")
|
||||
sessionFile, _ := cmd.Flags().GetString("session")
|
||||
|
||||
// log.Printf("Called `live`:\nPort: '%s'\nOutFile: '%s'\n", ddPort, outputFile)
|
||||
log.Printf("Called `live`:\nPort: '%s'\nOutFile: '%s'\n", ddPort, outputFile)
|
||||
|
||||
esdi.RunLiveTelemetry(ddPort, outputFile, sessionFile)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"esdi/logger"
|
||||
esdi "esdi/oldEsdi"
|
||||
|
||||
// "github.com/ESilva15/goirsdk"
|
||||
@@ -9,14 +10,14 @@ import (
|
||||
)
|
||||
|
||||
func offlineTelemetryCmdAction(cmd *cobra.Command, args []string) {
|
||||
// log := logger.GetInstance()
|
||||
log := logger.GetInstance()
|
||||
|
||||
ddPort, _ := cmd.Flags().GetString("port")
|
||||
inFile, _ := cmd.Flags().GetString("in")
|
||||
outFile, _ := cmd.Flags().GetString("out")
|
||||
sessionFile, _ := cmd.Flags().GetString("session")
|
||||
|
||||
// log.Printf("Called `offline`:\nPort: '%s'\nSource: '%s'\nOutFile: '%s'\n", ddPort, inFile, outFile)
|
||||
log.Printf("Called `offline`:\nPort: '%s'\nSource: '%s'\nOutFile: '%s'\n", ddPort, inFile, outFile)
|
||||
|
||||
esdi.RunOfflineTelemetry(ddPort, inFile, outFile, sessionFile)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package cdashdisplay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"esdi/peripheral/communication"
|
||||
"esdi/peripheral/communication/packets"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tarm/serial"
|
||||
portp "go.bug.st/serial"
|
||||
@@ -48,11 +46,11 @@ func findDisplayPort() (*communication.WalkieTalkie, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("Looking into %v", ports))
|
||||
pLogger.Info(fmt.Sprintf("Looking into %v", ports))
|
||||
|
||||
var wt *communication.WalkieTalkie
|
||||
for _, port := range ports {
|
||||
slog.Info(fmt.Sprintf("Trying port %s", port))
|
||||
pLogger.Info(fmt.Sprintf("Trying port %s", port))
|
||||
|
||||
wt = &communication.WalkieTalkie{
|
||||
Cfg: &serial.Config{
|
||||
@@ -62,7 +60,7 @@ func findDisplayPort() (*communication.WalkieTalkie, error) {
|
||||
},
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("Started probing port %s", port))
|
||||
pLogger.Info(fmt.Sprintf("Started probing port %s", port))
|
||||
|
||||
probeResult := make(chan error, 1)
|
||||
|
||||
@@ -78,14 +76,14 @@ func findDisplayPort() (*communication.WalkieTalkie, error) {
|
||||
err = fmt.Errorf("probe completely hung/timed out: %s", port)
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("Finished probing port %s", port))
|
||||
pLogger.Info(fmt.Sprintf("Finished probing port %s", port))
|
||||
|
||||
if err == nil {
|
||||
slog.Info(fmt.Sprintf("Success probing port %s: %+v", port, err))
|
||||
pLogger.Info(fmt.Sprintf("Success probing port %s: %+v", port, err))
|
||||
break
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("wasn't port %s", port))
|
||||
pLogger.Info(fmt.Sprintf("wasn't port %s", port))
|
||||
wt = nil
|
||||
}
|
||||
|
||||
@@ -93,6 +91,6 @@ func findDisplayPort() (*communication.WalkieTalkie, error) {
|
||||
return nil, fmt.Errorf("couldn't find cdashdisplay")
|
||||
}
|
||||
|
||||
slog.Info(fmt.Sprintf("found cdashdisplay on port: %s", wt.Cfg.Name))
|
||||
pLogger.Info(fmt.Sprintf("found cdashdisplay on port: %s", wt.Cfg.Name))
|
||||
return wt, nil
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
helper "esdi/helpers"
|
||||
@@ -20,6 +19,13 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// TODO: remove this logger. It should be on the device struct
|
||||
var pLogger *slog.Logger
|
||||
|
||||
func SetLogger(l *slog.Logger) {
|
||||
pLogger = l
|
||||
}
|
||||
|
||||
// I have to move this to some kind of configuration place
|
||||
const (
|
||||
layoutsDir = "./layouts/"
|
||||
@@ -109,56 +115,26 @@ func NewCDashState() *CDashState {
|
||||
type CDashDisplay struct {
|
||||
WT *communication.WalkieTalkie
|
||||
State *CDashState
|
||||
fieldToWindows map[telemetry.FieldID][]int16
|
||||
bufPool sync.Pool
|
||||
}
|
||||
|
||||
// Connect will try to find and connect to the CDashDisplay
|
||||
func NewCDashDisplay() (*CDashDisplay, error) {
|
||||
func Discover() (*CDashDisplay, error) {
|
||||
// Look for the port
|
||||
p, err := findDisplayPort()
|
||||
if err != nil {
|
||||
slog.Info("failed to find cdashdisplay port: %s", err.Error())
|
||||
pLogger.Info("failed to find cdashdisplay port: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CDashDisplay{
|
||||
WT: p,
|
||||
State: NewCDashState(),
|
||||
fieldToWindows: make(map[telemetry.FieldID][]int16),
|
||||
bufPool: sync.Pool{
|
||||
New: func() any {
|
||||
b := make([]byte, 0, telemetry.MaxFields*8)
|
||||
return &b
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) SendCommand() {
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) RegisterFieldMapping(fieldID telemetry.FieldID, winID int16) {
|
||||
d.fieldToWindows[fieldID] = append(d.fieldToWindows[fieldID], winID)
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) UnregisterFieldMapping(winID int16) {
|
||||
for fieldID, windows := range d.fieldToWindows {
|
||||
updated := windows[:0]
|
||||
for _, w := range windows {
|
||||
if w != winID {
|
||||
updated = append(updated, w)
|
||||
}
|
||||
|
||||
if len(updated) == 0 {
|
||||
delete(d.fieldToWindows, fieldID)
|
||||
} else {
|
||||
d.fieldToWindows[fieldID] = updated
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) CreateWindow(win *DesktopUIWindow) (*DesktopUIWindow, error) {
|
||||
bytes, err := helper.StructToBytes(win.UIWindow)
|
||||
if err != nil {
|
||||
@@ -174,12 +150,9 @@ func (d *CDashDisplay) CreateWindow(win *DesktopUIWindow) (*DesktopUIWindow, err
|
||||
|
||||
win.UIData.IDX = wID.ID
|
||||
|
||||
slog.Info(fmt.Sprintf("Recived ID message: %v", wID))
|
||||
pLogger.Info(fmt.Sprintf("Recived ID message: %v", wID))
|
||||
|
||||
d.State.Layout.AddWindow(win)
|
||||
if fieldID, ok := telemetry.GetFieldID(win.UIData.TelemetryField); ok {
|
||||
d.RegisterFieldMapping(fieldID, win.UIData.IDX)
|
||||
}
|
||||
|
||||
return win, nil
|
||||
}
|
||||
@@ -205,14 +178,12 @@ func (d *CDashDisplay) UpdateWindow(win *DesktopUIWindow) error {
|
||||
// I get it and update it in the controller
|
||||
// I send the pointer here
|
||||
// -> it should be the same pointer then right?
|
||||
slog.Debug(fmt.Sprintf("PreUpdate ID: %p", win))
|
||||
pLogger.Debug(fmt.Sprintf("PreUpdate ID: %p", win))
|
||||
d.State.Layout.Windows[win.UIData.IDX] = win
|
||||
slog.Debug(fmt.Sprintf("PostUpdate ID: %p", win))
|
||||
pLogger.Debug(fmt.Sprintf("PostUpdate ID: %p", win))
|
||||
// Yeah, same address as suspected
|
||||
// I can't think about it right now. I'll think about that tomorrow
|
||||
|
||||
// TODO: need to update the field mappings here!
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -235,15 +206,14 @@ func (d *CDashDisplay) DestroyWindow(wID int16) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// NOTE: add this
|
||||
d.UnregisterFieldMapping(wID)
|
||||
// NODE: add this
|
||||
d.State.Layout.RemoveWindow(wID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) updateWindowDimensions(win *UIWindow, packet UpdateDimsPacket) error {
|
||||
slog.Debug(fmt.Sprintf("UPDATE: %v", packet))
|
||||
pLogger.Debug(fmt.Sprintf("UPDATE: %v", packet))
|
||||
|
||||
bytes, err := helper.StructToBytes(packet)
|
||||
if err != nil {
|
||||
@@ -257,9 +227,9 @@ func (d *CDashDisplay) updateWindowDimensions(win *UIWindow, packet UpdateDimsPa
|
||||
}
|
||||
|
||||
// Nothing bad happened afaik
|
||||
slog.Debug(fmt.Sprintf("cur dims: %v", win.Dims))
|
||||
pLogger.Debug(fmt.Sprintf("cur dims: %v", win.Dims))
|
||||
win.Dims = packet.Dims
|
||||
slog.Debug(fmt.Sprintf("new dims: %v", win.Dims))
|
||||
pLogger.Debug(fmt.Sprintf("new dims: %v", win.Dims))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -375,18 +345,18 @@ func (d *CDashDisplay) LoadLayout(layoutName string) error {
|
||||
func (d *CDashDisplay) UnloadLayout() error {
|
||||
var err error
|
||||
for _, w := range d.State.Layout.Windows {
|
||||
slog.Debug(fmt.Sprintf("= Removing %d ==============================================",
|
||||
pLogger.Debug(fmt.Sprintf("= Removing %d ==============================================",
|
||||
w.UIData.IDX))
|
||||
|
||||
err = d.DestroyWindow(w.UIData.IDX)
|
||||
time.Sleep(75 * time.Millisecond)
|
||||
if err != nil {
|
||||
slog.Error(fmt.Sprintf("failed to destroy window: %+v", err))
|
||||
pLogger.Error(fmt.Sprintf("failed to destroy window: %+v", err))
|
||||
// NOTE: Add a way to handle multiple errors ?
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Debug(fmt.Sprintf("= Removing %d ==============================================",
|
||||
pLogger.Debug(fmt.Sprintf("= Removing %d ==============================================",
|
||||
w.UIData.IDX))
|
||||
}
|
||||
|
||||
@@ -394,7 +364,7 @@ func (d *CDashDisplay) UnloadLayout() error {
|
||||
}
|
||||
|
||||
func (d *CDashDisplay) SendData(data *telemetry.TelemetryData) {
|
||||
packet := d.encodePacket(data)
|
||||
packet := data.Pack()
|
||||
|
||||
bytes, err := helper.StructToBytes(packet)
|
||||
if err != nil {
|
||||
@@ -408,7 +378,7 @@ func (d *CDashDisplay) SendData(data *telemetry.TelemetryData) {
|
||||
curStr += fmt.Sprintf("%02x ", byte)
|
||||
|
||||
if byteCount == 8 {
|
||||
// slog.Debug(curStr)
|
||||
// pLogger.Debug(curStr)
|
||||
curStr = ""
|
||||
byteCount = 0
|
||||
}
|
||||
|
||||
@@ -15,13 +15,12 @@ func (cds *CDashDisplay) Name() string {
|
||||
return NAME
|
||||
}
|
||||
|
||||
func (cds *CDashDisplay) RequiredFields() []telemetry.FieldID {
|
||||
fields := make([]telemetry.FieldID, 0, len(cds.State.Layout.Windows))
|
||||
func (cds *CDashDisplay) RequiredFields() map[int16]telemetry.FieldID {
|
||||
fields := make(map[int16]telemetry.FieldID, len(cds.State.Layout.Windows))
|
||||
|
||||
for _, w := range cds.State.Layout.Windows {
|
||||
if fieldID, ok := telemetry.GetFieldID(w.UIData.TelemetryField); ok {
|
||||
fields = append(fields, fieldID)
|
||||
}
|
||||
fieldID, _ := telemetry.GetFieldID(w.UIData.TelemetryField)
|
||||
fields[w.UIData.IDX] = fieldID
|
||||
}
|
||||
|
||||
return fields
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package cdashdisplay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
)
|
||||
import "fmt"
|
||||
|
||||
type LayoutTree struct {
|
||||
Windows map[int16]*DesktopUIWindow `yaml:"Windows"`
|
||||
@@ -16,13 +13,13 @@ func NewLayoutTree() *LayoutTree {
|
||||
}
|
||||
|
||||
func (l *LayoutTree) AddWindow(w *DesktopUIWindow) {
|
||||
slog.Debug(fmt.Sprintf("adding window '%d' - %v", w.UIData.IDX))
|
||||
pLogger.Debug(fmt.Sprintf("adding window '%d' - %v", w.UIData.IDX))
|
||||
l.Windows[w.UIData.IDX] = w
|
||||
slog.Debug(fmt.Sprintf("new map - %v", l.Windows))
|
||||
pLogger.Debug(fmt.Sprintf("new map - %v", l.Windows))
|
||||
}
|
||||
|
||||
func (l *LayoutTree) RemoveWindow(idx int16) {
|
||||
slog.Debug(fmt.Sprintf("removing window '%d'", idx))
|
||||
pLogger.Debug(fmt.Sprintf("removing window '%d'", idx))
|
||||
delete(l.Windows, idx)
|
||||
slog.Debug(fmt.Sprintf("new map - %v", l.Windows))
|
||||
pLogger.Debug(fmt.Sprintf("new map - %v", l.Windows))
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package cdashdisplay
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"esdi/telemetry"
|
||||
)
|
||||
|
||||
// In this file we will place all structs that are 1:1 representation of the
|
||||
// types in the device transport layer ->
|
||||
|
||||
@@ -71,71 +65,6 @@ type UIWindowUpdatePacket struct {
|
||||
Window UIWindow
|
||||
}
|
||||
|
||||
// TODO: this is here because this is the only device I use like this
|
||||
// once I add another serial device I will move this somewhere else that can
|
||||
// be reused by all devices but still is decoupled from the telemetry package
|
||||
func (cds *CDashDisplay) encodePacket(td *telemetry.TelemetryData) []byte {
|
||||
bufPtr := cds.bufPool.Get().(*[]byte)
|
||||
buf := (*bufPtr)[:0]
|
||||
|
||||
for fieldID, windowIDs := range cds.fieldToWindows {
|
||||
if int(fieldID) >= len(td.Values) || len(windowIDs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tf := &td.Values[fieldID]
|
||||
|
||||
for _, winID := range windowIDs {
|
||||
buf = packField(winID, tf, buf)
|
||||
}
|
||||
}
|
||||
|
||||
// We have to copy here because we have to return the buffer
|
||||
result := make([]byte, len(buf))
|
||||
copy(result, buf)
|
||||
|
||||
cds.bufPool.Put(&buf)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Pack will pack this current TelemetryField into bytes to send over the wire
|
||||
// Format:
|
||||
// 0x00 - Field ID
|
||||
// 0x00 |
|
||||
// 0x01 - DataType
|
||||
// 0x02 - if its a (u)int8
|
||||
// or
|
||||
// 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 packField(winID int16, tf *telemetry.TelemetryField, 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(winID), uint8(winID>>8))
|
||||
dest = append(dest, uint8(tf.Type))
|
||||
|
||||
switch tf.Type {
|
||||
case telemetry.DataTypeINT8, telemetry.DataTypeUINT8, telemetry.DataTypeCHAR:
|
||||
dest = append(dest, uint8(tf.Raw))
|
||||
case telemetry.DataTypeINT16, telemetry.DataTypeUINT16:
|
||||
dest = append(dest, uint8(tf.Raw), uint8(tf.Raw>>8))
|
||||
case telemetry.DataTypeINT32, telemetry.DataTypeUINT32:
|
||||
dest = append(dest, uint8(tf.Raw), uint8(tf.Raw>>8), uint8(tf.Raw>>16), uint8(tf.Raw>>24))
|
||||
case telemetry.DataTypeINT64, telemetry.DataTypeUINT64:
|
||||
dest = append(
|
||||
dest, uint8(tf.Raw), uint8(tf.Raw>>8), uint8(tf.Raw>>16),
|
||||
uint8(tf.Raw>>24), uint8(tf.Raw>>32), uint8(tf.Raw>>40), uint8(tf.Raw>>48),
|
||||
uint8(tf.Raw>>56),
|
||||
)
|
||||
case telemetry.DataTypeSTRING:
|
||||
l := min(len(tf.Str), math.MaxUint8)
|
||||
|
||||
dest = append(dest, uint8(l))
|
||||
dest = append(dest, tf.Str[:l]...)
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
// func getUIWindowDTO(w *DesktopWindowData) *UIWindow {
|
||||
//
|
||||
// }
|
||||
|
||||
+24
-7
@@ -2,6 +2,8 @@
|
||||
package devices
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"esdi/devices/cdashdisplay"
|
||||
"esdi/devices/uidevice"
|
||||
"esdi/peripheral"
|
||||
@@ -33,11 +35,26 @@ func DiscoverUIDevice() (peripheral.Peripheral, error) {
|
||||
}
|
||||
|
||||
func DiscoverCDashDisplay() (peripheral.Peripheral, error) {
|
||||
// Create a cdashdisplay
|
||||
display, err := cdashdisplay.NewCDashDisplay()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return display, nil
|
||||
// // Find CDashDisplay
|
||||
// {
|
||||
// ds.Messages <- "looking for " + cdashdisplay.Name + "...\n"
|
||||
// ds.Logger.Info("Looking for " + cdashdisplay.Name)
|
||||
//
|
||||
// cdashdisplay.SetLogger(ds.Logger.With("[device]", cdashdisplay.Name))
|
||||
//
|
||||
// // Create a cdashdisplay
|
||||
// display, err := cdashdisplay.Discover()
|
||||
// if err == nil {
|
||||
// ds.Devices[cdashdisplay.Name] = display
|
||||
// ds.Logger.Info("found " + cdashdisplay.Name + " on: " + display.WT.Cfg.Name)
|
||||
// ds.Messages <- "found " + cdashdisplay.Name + " on: " + display.WT.Cfg.Name + "\n"
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ds.Logger.Info("didn't find " + cdashdisplay.Name)
|
||||
// ds.Messages <- "didn't find " + cdashdisplay.Name + "\n"
|
||||
// // No CDashDisplay available for one reason or another, so we don't set the
|
||||
// // key
|
||||
// }
|
||||
return nil, errors.New("not implemented yet")
|
||||
}
|
||||
|
||||
@@ -37,10 +37,17 @@ func (uid *UIDevice) DataChannel() <-chan telemetry.TelemetryData {
|
||||
return uid.dataChan
|
||||
}
|
||||
|
||||
func (uid *UIDevice) RequiredFields() []telemetry.FieldID {
|
||||
return []telemetry.FieldID{
|
||||
func (uid *UIDevice) RequiredFields() map[int16]telemetry.FieldID {
|
||||
subscribeTo := []telemetry.FieldID{
|
||||
telemetry.Speed,
|
||||
telemetry.Gear,
|
||||
telemetry.RPM,
|
||||
}
|
||||
|
||||
fields := make(map[int16]telemetry.FieldID, len(subscribeTo))
|
||||
for k, field := range subscribeTo {
|
||||
fields[int16(k)] = field
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var l *log.Logger
|
||||
var once sync.Once
|
||||
|
||||
func createLogger() {
|
||||
l = log.New(os.Stdout, "[esdi] ", log.LstdFlags | log.Lshortfile)
|
||||
}
|
||||
|
||||
func GetInstance() *log.Logger {
|
||||
once.Do(func() {
|
||||
createLogger()
|
||||
})
|
||||
|
||||
return l
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"esdi/cmd"
|
||||
"esdi/config"
|
||||
"esdi/telemetry"
|
||||
|
||||
"github.com/arl/statsviz"
|
||||
)
|
||||
@@ -41,6 +42,9 @@ func initApplication() {
|
||||
slog.Error(fmt.Sprintf("failed to setup metrics server: %+v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Setting up some internal data structures
|
||||
telemetry.Init()
|
||||
}
|
||||
|
||||
func setupLogger() error {
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
type Peripheral interface {
|
||||
Name() string
|
||||
SendData(*telemetry.TelemetryData)
|
||||
RequiredFields() []telemetry.FieldID
|
||||
RequiredFields() map[int16]telemetry.FieldID
|
||||
}
|
||||
|
||||
type PeripheralDeviceClerk struct {
|
||||
|
||||
@@ -115,7 +115,7 @@ func (b *BeamNG) Stream() (<-chan telemetry.TelemetryData, error) {
|
||||
return b.streamCh, nil
|
||||
}
|
||||
|
||||
func (b *BeamNG) Subscribe(requestFields []telemetry.FieldID) {
|
||||
func (b *BeamNG) Subscribe(requestFields map[int16]telemetry.FieldID) {
|
||||
// NOTE: document how the Subscribe funtion works
|
||||
slog.Debug(fmt.Sprintf("Len Req: %d\n", len(requestFields)))
|
||||
|
||||
@@ -125,7 +125,9 @@ func (b *BeamNG) Subscribe(requestFields []telemetry.FieldID) {
|
||||
// we will add their dependencies and the primitives to a slice
|
||||
pendingBinds := make([]telemetry.FieldID, telemetry.MaxFields)
|
||||
|
||||
for _, id := range requestFields {
|
||||
for winID, id := range requestFields {
|
||||
b.data.Values[id].IDs = append(b.data.Values[id].IDs, winID)
|
||||
|
||||
switch id {
|
||||
case telemetry.RPMStateColour:
|
||||
b.data.VirtualBinds = append(b.data.VirtualBinds, telemetry.NewRPMLights())
|
||||
|
||||
@@ -220,7 +220,7 @@ func (i *IRacing) StopStream() {
|
||||
i.streamCancel = nil
|
||||
}
|
||||
|
||||
func (i *IRacing) Subscribe(requestFields []telemetry.FieldID) {
|
||||
func (i *IRacing) Subscribe(requestFields map[int16]telemetry.FieldID) {
|
||||
i.logger.Debug(fmt.Sprintf("Len Req: %d\n", len(requestFields)))
|
||||
|
||||
i.data.ActiveBinds = make([]telemetry.BoundField, 0, len(requestFields))
|
||||
@@ -229,7 +229,9 @@ func (i *IRacing) Subscribe(requestFields []telemetry.FieldID) {
|
||||
// we will add their dependencies and the primitives to a slice
|
||||
pendingBinds := make([]telemetry.FieldID, 0, telemetry.MaxFields)
|
||||
|
||||
for _, id := range requestFields {
|
||||
for winID, id := range requestFields {
|
||||
i.data.Values[id].IDs = append(i.data.Values[id].IDs, winID)
|
||||
|
||||
switch id {
|
||||
case telemetry.RPMStateColour:
|
||||
i.data.VirtualBinds = append(i.data.VirtualBinds, telemetry.NewRPMLights())
|
||||
|
||||
+5
-13
@@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"esdi/providers"
|
||||
"esdi/telemetry"
|
||||
telem "esdi/telemetry"
|
||||
)
|
||||
|
||||
@@ -204,20 +203,13 @@ func (t *TelemetryService) UnsubscribeListener(id string) {
|
||||
}
|
||||
|
||||
func (t *TelemetryService) SubscribeToFields() {
|
||||
seen := make(map[telemetry.FieldID]struct{})
|
||||
var allFields []telemetry.FieldID
|
||||
|
||||
// _ = t.devService.SubscribeFields()
|
||||
// TODO: we need to find a way of requesting devices to send all subscribed fields
|
||||
// instead of going through the devices on DevService here
|
||||
for _, dev := range t.devService.Devices {
|
||||
for _, field := range dev.RequiredFields() {
|
||||
if _, exists := seen[field]; !exists {
|
||||
seen[field] = struct{}{}
|
||||
allFields = append(allFields, field)
|
||||
fields := dev.RequiredFields()
|
||||
t.activeProvider.Subscribe(fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.logger.Debug("requested fields", "fields", allFields)
|
||||
t.activeProvider.Subscribe(allFields)
|
||||
}
|
||||
|
||||
func (t *TelemetryService) StartStream() {
|
||||
|
||||
+75
-8
@@ -1,18 +1,12 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fieldNameToID = make(map[string]FieldID, MaxFields)
|
||||
for id, name := range FieldNames {
|
||||
fieldNameToID[name] = FieldID(id)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: allow the user to create custom data things. For example, iRacing provides
|
||||
// multiple surface temps, but I guess the user doesn't want all of them at once.
|
||||
// allow him to make something that allows some data transformation to occur.
|
||||
@@ -70,7 +64,7 @@ const (
|
||||
// NOTE: we can optimize this via a special command that says a given piece of data
|
||||
// is for multiple targets
|
||||
type TelemetryField struct {
|
||||
// IDs []int16 // Identification for the serial device
|
||||
IDs []int16 // Identification for the serial device
|
||||
Type DataType
|
||||
Raw uint64
|
||||
Str string // Only to be used with DataTypeSTRING
|
||||
@@ -81,6 +75,49 @@ func (tf *TelemetryField) Unused() {
|
||||
tf.Raw = uint64('-')
|
||||
}
|
||||
|
||||
// Pack will pack this current TelemetryField into bytes to send over the wire
|
||||
// Format:
|
||||
// 0x00 - Field ID
|
||||
// 0x00 |
|
||||
// 0x01 - DataType
|
||||
// 0x02 - if its a (u)int8
|
||||
// or
|
||||
// 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
|
||||
for _, id := range tf.IDs {
|
||||
dest = append(dest, uint8(id), uint8(id>>8))
|
||||
dest = append(dest, uint8(tf.Type))
|
||||
|
||||
switch tf.Type {
|
||||
case DataTypeINT8, DataTypeUINT8, DataTypeCHAR:
|
||||
dest = append(dest, uint8(tf.Raw))
|
||||
case DataTypeINT16, DataTypeUINT16:
|
||||
dest = append(dest, uint8(tf.Raw), uint8(tf.Raw>>8))
|
||||
case DataTypeINT32, DataTypeUINT32:
|
||||
dest = append(dest, uint8(tf.Raw), uint8(tf.Raw>>8), uint8(tf.Raw>>16), uint8(tf.Raw>>24))
|
||||
case DataTypeINT64, DataTypeUINT64:
|
||||
dest = append(
|
||||
dest, uint8(tf.Raw), uint8(tf.Raw>>8), uint8(tf.Raw>>16),
|
||||
uint8(tf.Raw>>24), uint8(tf.Raw>>32), uint8(tf.Raw>>40), uint8(tf.Raw>>48),
|
||||
uint8(tf.Raw>>56),
|
||||
)
|
||||
case DataTypeSTRING:
|
||||
l := min(len(tf.Str), math.MaxUint8)
|
||||
|
||||
dest = append(dest, uint8(l))
|
||||
dest = append(dest, tf.Str[:l]...)
|
||||
}
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
func (tf *TelemetryField) String() string {
|
||||
switch tf.Type {
|
||||
case DataTypeSTRING:
|
||||
@@ -222,6 +259,13 @@ func GetFieldName(id FieldID) string {
|
||||
|
||||
var fieldNameToID map[string]FieldID
|
||||
|
||||
func initFieldNamesMap() {
|
||||
fieldNameToID = make(map[string]FieldID, MaxFields)
|
||||
for id, name := range FieldNames {
|
||||
fieldNameToID[name] = FieldID(id)
|
||||
}
|
||||
}
|
||||
|
||||
func GetFieldID(name string) (FieldID, bool) {
|
||||
id, ok := fieldNameToID[name]
|
||||
return id, ok
|
||||
@@ -241,3 +285,26 @@ type TelemetryData struct {
|
||||
func NewTelemetryData() *TelemetryData {
|
||||
return &TelemetryData{}
|
||||
}
|
||||
|
||||
func (td *TelemetryData) Pack() []byte {
|
||||
bufPtr := bufferPool.Get().(*[]byte)
|
||||
buf := (*bufPtr)[:0]
|
||||
|
||||
// for _, bind := range td.ActiveBinds {
|
||||
// buf = td.Values[bind.ID].Pack(buf)
|
||||
// }
|
||||
|
||||
for k := range td.Values {
|
||||
if len(td.Values[k].IDs) > 0 {
|
||||
buf = td.Values[k].Pack(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// We have to copy here because we have to return the buffer
|
||||
result := make([]byte, len(buf))
|
||||
copy(result, buf)
|
||||
|
||||
bufferPool.Put(&buf)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import "time"
|
||||
type TelemetryProvider interface {
|
||||
StopStream()
|
||||
Stream() (<-chan TelemetryData, error)
|
||||
Subscribe([]FieldID)
|
||||
Subscribe(map[int16]FieldID)
|
||||
IsAlive(time.Duration) bool
|
||||
Name() string
|
||||
Close()
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
package telemetry
|
||||
|
||||
func Init() {
|
||||
initFieldNamesMap()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user