commit eea5925b9021ac841cdced31f1de1f4c80bb3a32 Author: Eduardo Silva Date: Sat Oct 19 21:42:54 2024 +0100 Added an interface to support multiple games - In the same way, I expect the addition of the ability of holding multiple sinks in memory like outputting to a TUI, GUI and other hardware devices diff --git a/esdi.go b/esdi.go new file mode 100644 index 0000000..21aad8e --- /dev/null +++ b/esdi.go @@ -0,0 +1,35 @@ +package main + +import ( + "log" + + "github.com/tarm/serial" +) + +type ESDI struct { + SerialConfig *serial.Config + SerialConn *serial.Port + Source GameSource +} + +func (e *ESDI) Close() { + err := e.SerialConn.Close() + if err != nil { + log.Fatalf("couldn't close serial connection: %v", err) + } +} + +func ESDIInit(port string, baud int) (ESDI, error) { + sConfig := &serial.Config{ + Name: port, + Baud: baud, + } + + // Open the serial port + sPort, err := serial.OpenPort(sConfig) + if err != nil { + return ESDI{}, err + } + + return ESDI{sConfig, sPort, nil}, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..211c595 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module esdi + +go 1.22.0 + +require github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 + +require golang.org/x/sys v0.26.0 // indirect + +require esilva.org.localhost/bngsdk v0.1.0 + +replace esilva.org.localhost/bngsdk => ../pkg/bngsdk diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5f28ef9 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go new file mode 100644 index 0000000..6a85140 --- /dev/null +++ b/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "esdi/sources/beamng" + "fmt" + "log" + "strings" + "time" +) + +type GameSource interface { + GetData(string) (interface{}, error) + UpdateData() error +} + +func main() { + esdi, err := ESDIInit("COM10", 9600) + if err != nil { + log.Fatalf("Failed to get Desktop Interface: %v", err) + } + + bIF, err := beamng.Init("127.0.0.1", 4444) + if err != nil { + log.Fatalf("Failed to create BeamNG interface: %v", err) + } + + esdi.Source = &bIF + + lastTime := time.Now().UnixMilli() + lastDataSent := time.Now().UnixMilli() + for { + var err error + var buffer strings.Builder + buffer.WriteString("\033[?25l\033[2J\033[H") + + err = esdi.Source.UpdateData() + if err != nil { + fmt.Printf("could not update data: %v", err) + continue + } + + curGear, err := esdi.Source.GetData("Gear") + if err != nil { + log.Fatalf("could not get field `Gear`: %v", err) + } + + curRPM, err := esdi.Source.GetData("RPM") + if err != nil { + log.Fatalf("could not get field `RPM`: %v", err) + } + + gear := int(curGear.(int8)) + rpm := int(curRPM.(float32)) + + buffer.WriteString(fmt.Sprintf("Gear: %d, RPM: %d", gear, rpm)) + + curTime := time.Now().UnixMilli() + message := fmt.Sprintf("%d,%d\n", gear-1, rpm) + buffer.WriteString("\n" + message) + + messageWasSentMark := "N" + if curTime-lastDataSent > 75 { + _, err = esdi.SerialConn.Write([]byte(message)) + if err != nil { + log.Printf("Unable to write data: %v", err) + break + } + + messageWasSentMark = "Y" + lastDataSent = curTime + } + + buffer.WriteString(" -> " + messageWasSentMark) + if curTime-lastTime > 100 { + fmt.Print(buffer.String()) + lastTime = curTime + } + } + + esdi.Close() +} diff --git a/sources/beamng/beamngSink.go b/sources/beamng/beamngSink.go new file mode 100644 index 0000000..f31cf02 --- /dev/null +++ b/sources/beamng/beamngSink.go @@ -0,0 +1,40 @@ +package beamng + +import ( + "fmt" + + "esilva.org.localhost/bngsdk" +) + +// This will implement the GameSink interface from the main package +type BeamNG struct { + SDK *bngsdk.BNGSDK +} + +const ( + NAME = "BeamNG.Drive" +) + +func Init(ip string, port int) (BeamNG, error) { + var err error + + sdk, err := bngsdk.Init(ip, port) + if err != nil { + return BeamNG{}, err + } + + return BeamNG{SDK: &sdk}, nil +} + +// GetData will retrieve a given field by its name from the OutGauge data +func (b *BeamNG) GetData(fieldName string) (interface{}, error) { + if val, ok := b.SDK.DataDict[fieldName]; ok { + return val, nil + } + + return nil, fmt.Errorf("key `%s` doesn't exist", fieldName) +} + +func (b *BeamNG) UpdateData() error { + return b.SDK.ReadData() +} diff --git a/sources/iracing/iracingSink.go b/sources/iracing/iracingSink.go new file mode 100644 index 0000000..f26ff02 --- /dev/null +++ b/sources/iracing/iracingSink.go @@ -0,0 +1,33 @@ +package iracing + +import ( + "esilva.org.localhost/bngsdk" +) + +// This will implement the GameSink interface from the main package +type BeamNG struct { + SDK *bngsdk.BNGSDK +} + +const ( + NAME = "iRacing" +) + +func Init(ip string, port int) (BeamNG, error) { + var err error + + sdk, err := bngsdk.Init(ip, port) + if err != nil { + return BeamNG{}, err + } + + return BeamNG{SDK: &sdk}, nil +} + +func (b *BeamNG) GetData(fieldName string, out interface{}) error { + return nil +} + +func (b *BeamNG) UpdateData() error { + return b.SDK.ReadData() +}