Moved the data streaming thing to a controller for now
This commit is contained in:
@@ -27,22 +27,24 @@ type Ctrls struct {
|
||||
}
|
||||
|
||||
type MainController struct {
|
||||
Logger *slog.Logger
|
||||
App *tview.Application
|
||||
Dom *dom.DOM
|
||||
EvBus *events.Bus
|
||||
DevClerk *peripheral.PeripheralDeviceClerk
|
||||
CDash *cdashdisplay.CDashDisplay
|
||||
Logger *slog.Logger
|
||||
App *tview.Application
|
||||
Dom *dom.DOM
|
||||
EvBus *events.Bus
|
||||
DevClerk *peripheral.PeripheralDeviceClerk
|
||||
CDash *cdashdisplay.CDashDisplay
|
||||
StreamStrl *StreamingCtrl
|
||||
}
|
||||
|
||||
func NewMainController(logger *slog.Logger) *MainController {
|
||||
pLogger = logger
|
||||
mc := &MainController{
|
||||
App: tview.NewApplication(),
|
||||
Dom: dom.NewDOM(),
|
||||
EvBus: events.NewBus(),
|
||||
DevClerk: peripheral.NewPeripheralDeviceClerk(),
|
||||
CDash: nil,
|
||||
App: tview.NewApplication(),
|
||||
Dom: dom.NewDOM(),
|
||||
EvBus: events.NewBus(),
|
||||
DevClerk: peripheral.NewPeripheralDeviceClerk(),
|
||||
CDash: nil,
|
||||
StreamStrl: NewStreamingCtrl(),
|
||||
}
|
||||
|
||||
mc.EvBus.On(ui.RedrawEv{}, func(e any) {
|
||||
@@ -186,5 +188,13 @@ func NewMainController(logger *slog.Logger) *MainController {
|
||||
mc.App.Draw()
|
||||
})
|
||||
|
||||
mc.EvBus.On(ui.StartStreamingReqEv{}, func(e any) {
|
||||
mc.StreamStrl.Start(mc.EvBus)
|
||||
})
|
||||
|
||||
mc.EvBus.On(ui.StopStreamingReqEv{}, func(e any) {
|
||||
mc.StreamStrl.Stop(mc.EvBus)
|
||||
})
|
||||
|
||||
return mc
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package controllers
|
||||
@@ -0,0 +1,189 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
esdi "esdi/oldEsdi"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"esdi/tui/internal/events"
|
||||
"esdi/tui/internal/ui"
|
||||
|
||||
"github.com/ESilva15/goirsdk"
|
||||
)
|
||||
|
||||
// Car data lengths
|
||||
const (
|
||||
SpeedLen = 5
|
||||
GearLen = 3
|
||||
RpmLen = 6
|
||||
BrakeBiasLen = 6
|
||||
)
|
||||
|
||||
type StreamingCtrl struct {
|
||||
LastMessageTime time.Time
|
||||
Data *esdi.SimulationData
|
||||
DataView *esdi.DataPacket
|
||||
InitialTime time.Time
|
||||
LastTime time.Time
|
||||
Mut sync.Mutex
|
||||
Irsdk *goirsdk.IBT
|
||||
}
|
||||
|
||||
func NewStreamingCtrl() *StreamingCtrl {
|
||||
return &StreamingCtrl{
|
||||
Data: &esdi.SimulationData{},
|
||||
DataView: &esdi.DataPacket{},
|
||||
InitialTime: time.Now(),
|
||||
LastTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *StreamingCtrl) Stop(bus *events.Bus) {
|
||||
}
|
||||
|
||||
func (sc *StreamingCtrl) Start(bus *events.Bus) {
|
||||
// Open the telemetry file
|
||||
file, err := os.Open("/home/esilva/Desktop/projetos/simracing_peripherals/testTelemetry/supercars_indianapolis.ibt")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open IBT file: %v", err)
|
||||
}
|
||||
|
||||
sc.Irsdk, err = goirsdk.Init(file, "./out.ibt", "./out.yaml")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load iRacing data")
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
go sc.ReadData()
|
||||
|
||||
// global irsdk is now here
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second / 60)
|
||||
defer ticker.Stop()
|
||||
|
||||
counter := 0
|
||||
for t := range ticker.C {
|
||||
// whatever
|
||||
currentTime := time.Now()
|
||||
|
||||
delta := currentTime.Sub(startTime)
|
||||
|
||||
str := sc.Stringified() + fmt.Sprintf("%v - %7d\n%5f - %5f",
|
||||
t.UTC(), counter, delta.Seconds(), delta.Seconds()/float64(counter))
|
||||
|
||||
bus.Emit(ui.StreamDataEv{Str: str})
|
||||
counter++
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (sc *StreamingCtrl) ReadData() {
|
||||
dataReaderTicker := time.NewTicker(time.Second / 60)
|
||||
defer dataReaderTicker.Stop()
|
||||
|
||||
sc.InitialTime = time.Now()
|
||||
for _ = range dataReaderTicker.C {
|
||||
var err error
|
||||
|
||||
sc.Mut.Lock()
|
||||
_, err = sc.Irsdk.Update(time.Millisecond * 100)
|
||||
if err != nil {
|
||||
fmt.Printf("could not update data: %v", err)
|
||||
continue
|
||||
}
|
||||
sc.Mut.Unlock()
|
||||
|
||||
sc.getVehicleData()
|
||||
|
||||
// Test the actual dataPacket we are sending over the wire
|
||||
copyBytes(sc.DataView.Speed[:], SpeedLen, fmt.Sprintf("%3d", sc.Data.Speed))
|
||||
copyBytes(sc.DataView.Gear[:], GearLen, fmt.Sprintf("%2d", sc.Data.Gear))
|
||||
copyBytes(sc.DataView.RPM[:], RpmLen, fmt.Sprintf("%3d", sc.Data.RPM))
|
||||
|
||||
sc.LastMessageTime = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *StreamingCtrl) getVehicleData() {
|
||||
sc.Mut.Lock()
|
||||
curGear := sc.Irsdk.Vars.Vars["Gear"].Value
|
||||
curRPM := sc.Irsdk.Vars.Vars["RPM"].Value
|
||||
curSpeed := sc.Irsdk.Vars.Vars["Speed"].Value
|
||||
|
||||
sc.Data.Gear = int32(curGear.(int))
|
||||
sc.Data.RPM = int32(curRPM.(float32))
|
||||
sc.Data.Speed = int32(msToKph(curSpeed.(float32)))
|
||||
sc.Mut.Unlock()
|
||||
}
|
||||
|
||||
func copyBytes(dest []byte, destSize int, src string) {
|
||||
copy(dest[:], []byte(src))
|
||||
dest[min(destSize-1, len(src))] = '\x00'
|
||||
}
|
||||
|
||||
func msToKph(v float32) int {
|
||||
return int((3600 * v) / 1000)
|
||||
}
|
||||
|
||||
// Move this function to the views
|
||||
func (sc *StreamingCtrl) Stringified() string {
|
||||
var buffer strings.Builder
|
||||
|
||||
sc.Mut.Lock()
|
||||
sessionTimeR := sc.Irsdk.Vars.Vars["SessionTime"].Value
|
||||
sessionTime := float64(sessionTimeR.(float64))
|
||||
|
||||
currTime := time.Now()
|
||||
delta := currTime.Sub(sc.LastTime)
|
||||
buffer.WriteString(fmt.Sprintf("[%s]\n", currTime.Format("2006/01/02 15:04:05.000")))
|
||||
buffer.WriteString(fmt.Sprintf("Delta: %d [%f]\n\n", delta.Milliseconds(), 1000.0/60.0))
|
||||
sc.LastTime = currTime
|
||||
|
||||
elapsed := currTime.Sub(sc.InitialTime)
|
||||
softwareElapsed := time.Unix(0, 0).Add(elapsed).Format("04:05.000")
|
||||
sessionElapsed := time.Unix(0, 0).
|
||||
Add(time.Duration(sessionTime * float64(time.Second))).
|
||||
Format("04:05.000")
|
||||
|
||||
buffer.WriteString(fmt.Sprintf("Elapsed (software): %s\n",
|
||||
softwareElapsed))
|
||||
buffer.WriteString(fmt.Sprintf("Elapsed (session): %s\n\n",
|
||||
sessionElapsed))
|
||||
|
||||
// buffer.WriteString("Car data:\n")
|
||||
buffer.WriteString(fmt.Sprintf("Gear: %d, RPM: %d, Speed: %d\n\n",
|
||||
sc.Data.Gear, sc.Data.RPM, sc.Data.Speed))
|
||||
|
||||
// buffer.WriteString("Fuel data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Fuel Est: %s\n\n", e.dataPacket.FuelEst))
|
||||
|
||||
// buffer.WriteString("Lap data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Delta: [%s] [%f] [%s]\n", e.dataPacket.DeltaToBestLap,
|
||||
// e.data.LapDeltaFloat, lapTimeDeltaRepresentation(e.data.LapDeltaFloat)))
|
||||
// buffer.WriteString(fmt.Sprintf("LapTime: %s\n", e.dataPacket.CurrLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("Best Lap Time: %s\n", e.dataPacket.BestLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("Last Lap Time: %s\n", e.dataPacket.LastLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("LapBestNLapTi: %f\n\n", e.data.LapBestNLapTime))
|
||||
|
||||
// buffer.WriteString("Position data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Pos: %d\n", e.dataPacket.Position))
|
||||
|
||||
// for p, v := range e.dataPacket.Standings {
|
||||
// s := fmt.Sprintf("[%2d] %s %-16s %-16s\n",
|
||||
// p+1, v.Lap, string(bytes.Trim(v.DriverName[:], "\x00")), v.TimeBehindString)
|
||||
// buffer.WriteString(s)
|
||||
// }
|
||||
|
||||
// buffer.WriteString(fmt.Sprintf("Size: %v\n", binary.Size(DataPacket{})))
|
||||
// buffer.WriteString(fmt.Sprintf("Recv: %d\n", e.data.Recv))
|
||||
// buffer.WriteString(fmt.Sprintf("Recv Err: %v\n", e.data.ReadError))
|
||||
|
||||
sc.Mut.Unlock()
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
@@ -93,3 +93,14 @@ type ErrorFormParseEv struct {
|
||||
type FindCDashDisplay struct{}
|
||||
|
||||
// Device events --------------------------------------------------------------
|
||||
|
||||
// + Stream events ------------------------------------------------------------
|
||||
|
||||
type StartStreamingReqEv struct{}
|
||||
type StopStreamingReqEv struct{}
|
||||
|
||||
type StreamDataEv struct {
|
||||
Str string
|
||||
}
|
||||
|
||||
// - Stream events ------------------------------------------------------------
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
esdi "esdi/oldEsdi"
|
||||
"esdi/tui/internal/dom"
|
||||
"esdi/tui/internal/events"
|
||||
"esdi/tui/internal/ui"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ESilva15/goirsdk"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
@@ -29,54 +22,6 @@ const (
|
||||
streamingBoxID = "streaming-box"
|
||||
)
|
||||
|
||||
var (
|
||||
lastMessageTime time.Time
|
||||
data *esdi.SimulationData = &esdi.SimulationData{}
|
||||
dataView *esdi.DataPacket = &esdi.DataPacket{}
|
||||
initialTime = time.Now()
|
||||
lastTime = time.Now()
|
||||
mu sync.Mutex
|
||||
irsdk *goirsdk.IBT
|
||||
)
|
||||
|
||||
func setUpSource(bus *events.Bus, doc *dom.DOM, tv *tview.TextView) {
|
||||
// Open the telemetry file
|
||||
file, err := os.Open("/home/esilva/Desktop/projetos/simracing_peripherals/testTelemetry/supercars_indianapolis.ibt")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open IBT file: %v", err)
|
||||
}
|
||||
|
||||
irsdk, err = goirsdk.Init(file, "./out.ibt", "./out.yaml")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load iRacing data")
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
go readData()
|
||||
|
||||
// global irsdk is now here
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second / 60)
|
||||
defer ticker.Stop()
|
||||
|
||||
counter := 0
|
||||
for t := range ticker.C {
|
||||
// whatever
|
||||
currentTime := time.Now()
|
||||
|
||||
delta := currentTime.Sub(startTime)
|
||||
|
||||
str := stringified() + fmt.Sprintf("%v - %7d\n%5f - %5f",
|
||||
t.UTC(), counter, delta.Seconds(), delta.Seconds()/float64(counter))
|
||||
|
||||
tv.SetText(str)
|
||||
bus.Emit(ui.ForceRedraw{})
|
||||
counter++
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func streamingWindow(bus *events.Bus, doc *dom.DOM) {
|
||||
bus.Emit(ui.LogEv{Log: "creating streaming window"})
|
||||
|
||||
@@ -84,9 +29,9 @@ func streamingWindow(bus *events.Bus, doc *dom.DOM) {
|
||||
box := tview.NewTextView()
|
||||
box.SetBorder(true).SetTitle("STREAMING")
|
||||
box.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
switch ev.Rune() {
|
||||
case 'q':
|
||||
// well, I really need to design the UI to work properly
|
||||
switch ev.Key() {
|
||||
case tcell.KeyEsc:
|
||||
// well, I really need to design the UI (as if lmao) better
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -119,148 +64,12 @@ func streamingWindow(bus *events.Bus, doc *dom.DOM) {
|
||||
// Add it to the action pages and view it
|
||||
AddAndShowPage(bus, doc, actionPages, boxNode, true)
|
||||
|
||||
setUpSource(bus, doc, box)
|
||||
}
|
||||
bus.Emit(ui.StartStreamingReqEv{})
|
||||
|
||||
func stringified() string {
|
||||
var buffer strings.Builder
|
||||
bus.On(ui.StreamDataEv{}, func(e any) {
|
||||
sd := e.(ui.StreamDataEv)
|
||||
box.SetText(sd.Str)
|
||||
|
||||
mu.Lock()
|
||||
sessionTimeR := irsdk.Vars.Vars["SessionTime"].Value
|
||||
sessionTime := float64(sessionTimeR.(float64))
|
||||
|
||||
currTime := time.Now()
|
||||
delta := currTime.Sub(lastTime)
|
||||
buffer.WriteString(fmt.Sprintf("[%s]\n", currTime.Format("2006/01/02 15:04:05.000")))
|
||||
buffer.WriteString(fmt.Sprintf("Delta: %d [%f]\n\n", delta.Milliseconds(), 1000.0/60.0))
|
||||
lastTime = currTime
|
||||
|
||||
elapsed := currTime.Sub(initialTime)
|
||||
softwareElapsed := time.Unix(0, 0).Add(elapsed).Format("04:05.000")
|
||||
sessionElapsed := time.Unix(0, 0).
|
||||
Add(time.Duration(sessionTime * float64(time.Second))).
|
||||
Format("04:05.000")
|
||||
|
||||
buffer.WriteString(fmt.Sprintf("Elapsed (software): %s\n",
|
||||
softwareElapsed))
|
||||
buffer.WriteString(fmt.Sprintf("Elapsed (session): %s\n\n",
|
||||
sessionElapsed))
|
||||
|
||||
// buffer.WriteString("Car data:\n")
|
||||
buffer.WriteString(fmt.Sprintf("Gear: %d, RPM: %d, Speed: %d\n\n",
|
||||
data.Gear, data.RPM, data.Speed))
|
||||
|
||||
// buffer.WriteString("Fuel data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Fuel Est: %s\n\n", e.dataPacket.FuelEst))
|
||||
|
||||
// buffer.WriteString("Lap data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Delta: [%s] [%f] [%s]\n", e.dataPacket.DeltaToBestLap,
|
||||
// e.data.LapDeltaFloat, lapTimeDeltaRepresentation(e.data.LapDeltaFloat)))
|
||||
// buffer.WriteString(fmt.Sprintf("LapTime: %s\n", e.dataPacket.CurrLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("Best Lap Time: %s\n", e.dataPacket.BestLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("Last Lap Time: %s\n", e.dataPacket.LastLapTime))
|
||||
// buffer.WriteString(fmt.Sprintf("LapBestNLapTi: %f\n\n", e.data.LapBestNLapTime))
|
||||
|
||||
// buffer.WriteString("Position data:\n")
|
||||
// buffer.WriteString(fmt.Sprintf("Pos: %d\n", e.dataPacket.Position))
|
||||
|
||||
// for p, v := range e.dataPacket.Standings {
|
||||
// s := fmt.Sprintf("[%2d] %s %-16s %-16s\n",
|
||||
// p+1, v.Lap, string(bytes.Trim(v.DriverName[:], "\x00")), v.TimeBehindString)
|
||||
// buffer.WriteString(s)
|
||||
// }
|
||||
|
||||
// buffer.WriteString(fmt.Sprintf("Size: %v\n", binary.Size(DataPacket{})))
|
||||
// buffer.WriteString(fmt.Sprintf("Recv: %d\n", e.data.Recv))
|
||||
// buffer.WriteString(fmt.Sprintf("Recv Err: %v\n", e.data.ReadError))
|
||||
|
||||
mu.Unlock()
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func msToKph(v float32) int {
|
||||
return int((3600 * v) / 1000)
|
||||
}
|
||||
|
||||
func lapTimeRepresentation(t float32, f string) string {
|
||||
if t < 0 {
|
||||
t = 0
|
||||
}
|
||||
|
||||
wholeSeconds := int64(t)
|
||||
lapTime := time.Unix(wholeSeconds, int64((t-float32(wholeSeconds))*1e9))
|
||||
|
||||
return lapTime.Format(f)
|
||||
}
|
||||
|
||||
func lapTimeDeltaRepresentation(t float32) string {
|
||||
sign := '-'
|
||||
if t < 0 {
|
||||
sign = '+'
|
||||
t = -t
|
||||
}
|
||||
|
||||
// Cap to 99.9 max
|
||||
if t > 99.9 {
|
||||
t = 99.9
|
||||
}
|
||||
|
||||
if t >= 1 {
|
||||
// Round to nearest tenth
|
||||
rounded := float32(int(t*10+0.5)) / 10
|
||||
return fmt.Sprintf("%c%.1f", sign, rounded)
|
||||
}
|
||||
|
||||
// t < 1: round to nearest tenth and remove leading zero (e.g., "0.1" → ".1")
|
||||
rounded := float32(int(t*10+0.5)) / 10
|
||||
s := fmt.Sprintf("%.1f", rounded)
|
||||
if strings.HasPrefix(s, "0") {
|
||||
s = s[1:]
|
||||
}
|
||||
return fmt.Sprintf("%c%s", sign, s)
|
||||
}
|
||||
|
||||
func readData() {
|
||||
dataReaderTicker := time.NewTicker(time.Second / 60)
|
||||
defer dataReaderTicker.Stop()
|
||||
|
||||
initialTime = time.Now()
|
||||
for _ = range dataReaderTicker.C {
|
||||
var err error
|
||||
|
||||
mu.Lock()
|
||||
_, err = irsdk.Update(time.Millisecond * 100)
|
||||
if err != nil {
|
||||
fmt.Printf("could not update data: %v", err)
|
||||
continue
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
getVehicleData()
|
||||
|
||||
// Test the actual dataPacket we are sending over the wire
|
||||
copyBytes(dataView.Speed[:], SpeedLen, fmt.Sprintf("%3d", data.Speed))
|
||||
copyBytes(dataView.Gear[:], GearLen, fmt.Sprintf("%2d", data.Gear))
|
||||
copyBytes(dataView.RPM[:], RpmLen, fmt.Sprintf("%3d", data.RPM))
|
||||
|
||||
lastMessageTime = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func getVehicleData() {
|
||||
mu.Lock()
|
||||
curGear := irsdk.Vars.Vars["Gear"].Value
|
||||
curRPM := irsdk.Vars.Vars["RPM"].Value
|
||||
curSpeed := irsdk.Vars.Vars["Speed"].Value
|
||||
|
||||
data.Gear = int32(curGear.(int))
|
||||
data.RPM = int32(curRPM.(float32))
|
||||
data.Speed = int32(msToKph(curSpeed.(float32)))
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func copyBytes(dest []byte, destSize int, src string) {
|
||||
copy(dest[:], []byte(src))
|
||||
dest[min(destSize-1, len(src))] = '\x00'
|
||||
bus.Emit(ui.ForceRedraw{})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user