5 Commits
11 changed files with 294 additions and 280 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
coverage* coverage*
*.txt *.txt
+3 -3
View File
@@ -1,3 +1,3 @@
test: test:
go test -coverprofile=coverage.out ./... -cover -bench= go test -coverprofile=coverage.out ./... -cover -bench=
go tool cover -html=coverage.out -o coverage.html go tool cover -html=coverage.out -o coverage.html
+17 -17
View File
@@ -1,17 +1,17 @@
# About # About
This project will be able to parse `.ibt` files, read live data from races and This project will be able to parse `.ibt` files, read live data from races and
broadcast messages to the service. Its still not very mature at all, but after broadcast messages to the service. Its still not very mature at all, but after
this commit I will turn it into a package instead and give it a stable API. this commit I will turn it into a package instead and give it a stable API.
Will also put some examples then. Will also put some examples then.
## The SDK ## The SDK
I used various sources to develop and understand how `iRacing` works, and learn I used various sources to develop and understand how `iRacing` works, and learn
a lot with it. Once I have matured this project a bit I will document its a lot with it. Once I have matured this project a bit I will document its
inner workings too. inner workings too.
## SharedMem ## SharedMem
I vendored in the code from [hidez8891/shm](https://github.com/hidez8891/shm) I vendored in the code from [hidez8891/shm](https://github.com/hidez8891/shm)
since the repo has been archived. I took the opportunity to update some of its since the repo has been archived. I took the opportunity to update some of its
code. code.
+38 -38
View File
@@ -1,38 +1,38 @@
package goirsdk package goirsdk
import ( import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
// TestParseTelemetrySubHeader_WithGoodBuffer // TestParseTelemetrySubHeader_WithGoodBuffer
// Given a well structured buffer it will output the expected // Given a well structured buffer it will output the expected
// DiskSubHeader struct // DiskSubHeader struct
func TestParseTelemetrySubHeader_WithGoodBuffer(t *testing.T) { func TestParseTelemetrySubHeader_WithGoodBuffer(t *testing.T) {
// Arrange // Arrange
header := [32]byte{ header := [32]byte{
0x54, 0x1e, 0x14, 0x67, 0x00, 0x00, 0x00, 0x00, 0x54, 0x09, 0x00, 0xf0, 0x54, 0x1e, 0x14, 0x67, 0x00, 0x00, 0x00, 0x00, 0x54, 0x09, 0x00, 0xf0,
0xee, 0x7e, 0x6b, 0x40, 0x53, 0x74, 0x88, 0x44, 0x44, 0x86, 0x8f, 0x40, 0xee, 0x7e, 0x6b, 0x40, 0x53, 0x74, 0x88, 0x44, 0x44, 0x86, 0x8f, 0x40,
0x08, 0x00, 0x00, 0x00, 0xe1, 0xb8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe1, 0xb8, 0x00, 0x00,
} }
expectedHeader := DiskSubHeader{ expectedHeader := DiskSubHeader{
StartDate: 1729371732, StartDate: 1729371732,
StartTime: 219.96666717536084, StartTime: 219.96666717536084,
EndTime: 1008.7833338413715, EndTime: 1008.7833338413715,
LapCount: 8, LapCount: 8,
RecordCount: 47329, RecordCount: 47329,
} }
// Act // Act
headers, err := parseTelemetrySubHeader(header) headers, err := parseTelemetrySubHeader(header)
// Assert // Assert
if err != nil { if err != nil {
t.Fatalf("Error parsing buffer: %v", err) t.Fatalf("Error parsing buffer: %v", err)
} }
if !cmp.Equal(&expectedHeader, headers) { if !cmp.Equal(&expectedHeader, headers) {
t.Fatalf("Expected:\n%#v\nGot:\n%#v\n", expectedHeader, headers) t.Fatalf("Expected:\n%#v\nGot:\n%#v\n", expectedHeader, headers)
} }
} }
+10 -10
View File
@@ -1,10 +1,10 @@
module github.com/ESilva15/goirsdk module github.com/ESilva15/goirsdk
go 1.23.2 go 1.23.2
require ( require (
github.com/google/go-cmp v0.6.0 github.com/google/go-cmp v0.6.0
golang.org/x/sys v0.26.0 golang.org/x/sys v0.26.0
golang.org/x/text v0.19.0 golang.org/x/text v0.19.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
+10 -10
View File
@@ -1,10 +1,10 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+52 -52
View File
@@ -1,52 +1,52 @@
package goirsdk package goirsdk
import ( import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
// TestParseTelemetryHeader_WithGoodBuffer // TestParseTelemetryHeader_WithGoodBuffer
// Given a well structured buffer it will output the expected // Given a well structured buffer it will output the expected
// TelemetryHeaders struct // TelemetryHeaders struct
func TestParseTelemetryHeader_WithGoodBuffer(t *testing.T) { func TestParseTelemetryHeader_WithGoodBuffer(t *testing.T) {
// Arrange // Arrange
header := [112]byte{ header := [112]byte{
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x3f, 0x00, 0x00, 0x90, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x3f, 0x00, 0x00, 0x90, 0x99, 0x00, 0x00,
0x10, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x1d, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x2b, 0x00, 0x00, 0x95, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x2b, 0x00, 0x00, 0x95, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} }
expectedHeader := TelemetryHeaders{ expectedHeader := TelemetryHeaders{
Version: 2, Version: 2,
Status: 1, Status: 1,
TickRate: 60, TickRate: 60,
SessionInfoUpdate: 0, SessionInfoUpdate: 0,
SessionInfoLength: 16133, SessionInfoLength: 16133,
SessionInfoOffset: 39312, SessionInfoOffset: 39312,
NumVars: 272, NumVars: 272,
VarHeaderOffset: 144, VarHeaderOffset: 144,
NumBuf: 1, NumBuf: 1,
BufLen: 1053, BufLen: 1053,
Padding: [12]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x2b, 0x0, 0x0}, Padding: [12]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x2b, 0x0, 0x0},
BufOffset: 55445, BufOffset: 55445,
} }
// Act // Act
headers, err := parseTelemetryHeader(header) headers, err := parseTelemetryHeader(header)
// Assert // Assert
if err != nil { if err != nil {
t.Fatalf("Error parsing buffer: %v", err) t.Fatalf("Error parsing buffer: %v", err)
} }
if !cmp.Equal(&expectedHeader, headers) { if !cmp.Equal(&expectedHeader, headers) {
t.Fatalf("Expected:\n%#v\nGot:\n%#v\n", expectedHeader, headers) t.Fatalf("Expected:\n%#v\nGot:\n%#v\n", expectedHeader, headers)
} }
} }
+62 -86
View File
@@ -2,22 +2,25 @@
package goirsdk package goirsdk
import ( import (
"github.com/ESilva15/goirsdk/logger"
"fmt" "fmt"
"log"
"os" "os"
// "os"
"io" "io"
// "log"
// "time"
// conv "ibtReader/conversions"
"github.com/ESilva15/goirsdk/winutils" "github.com/ESilva15/goirsdk/winutils"
"gopkg.in/yaml.v3"
) )
const ( const (
ibtFile = "./telemetryFiles/mx5_2016Okayama_full_2024_10_19_22_02_12.ibt" ibtFile = "./telemetryFiles/mx5_2016Okayama_full_2024_10_19_22_02_12.ibt"
) )
func msToKph(v float32) int {
return int((3600 * v) / 1000)
}
// Reader is an interface to represent the readable data that can be either // Reader is an interface to represent the readable data that can be either
// a .ibt file (or live data, hopefully) // a .ibt file (or live data, hopefully)
type Reader interface { type Reader interface {
@@ -29,7 +32,8 @@ type Reader interface {
// IBT struct will hold the relevant data for a given IBT file // IBT struct will hold the relevant data for a given IBT file
type IBT struct { type IBT struct {
File Reader // Source of the data File Reader // Source of the data
FileToExport string // If set, it will export the IBT data to the file FileToExport *os.File // If set, it will export the IBT data to the file
YAMLExport *os.File // If set, it will export the session YAML to the file
Headers *TelemetryHeaders // IBT file Headers Headers *TelemetryHeaders // IBT file Headers
SubHeaders *DiskSubHeader // IBT file Sub Headers SubHeaders *DiskSubHeader // IBT file Sub Headers
SessionInfo *SessionInfoYAML // IBT file Session Info SessionInfo *SessionInfoYAML // IBT file Session Info
@@ -50,28 +54,43 @@ func (i *IBT) IsConnected() bool {
return false return false
} }
func (i *IBT) ExportToIBT(filepath string) { func (i *IBT) exportYAML(path string) error {
rbuf := make([]byte, fileMapSize) file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
_, err := i.File.ReadAt(rbuf, 0)
if err != nil { if err != nil {
log.Fatal(err) return fmt.Errorf("failed to open output file for YAML: %v", err)
}
defer file.Close()
enc := yaml.NewEncoder(file)
err = enc.Encode(i.SessionInfo)
if err != nil {
return fmt.Errorf("failed to write YAML contents to file: %v", err)
} }
err = os.WriteFile(filepath, rbuf, 0644) return nil
if err != nil {
log.Fatal(err)
}
} }
// Init serves to initialize and get a hold of a IBT struct // Init serves to initialize and get a hold of a IBT struct
func Init(f Reader) (*IBT, error) { func Init(f Reader, exportTelem string, exportYAML string) (*IBT, error) {
log := logger.GetInstance()
// Read the header of the file // Read the header of the file
var err error var err error
ibt := IBT{ ibt := IBT{
File: f, File: f,
Vars: &TelemetryVars{}, FileToExport: nil,
winUtils: nil, YAMLExport: nil,
Vars: &TelemetryVars{},
winUtils: nil,
}
// If requested to output to a telemetry file
if exportTelem != "" {
ibt.FileToExport, err = os.OpenFile(exportTelem, os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
return nil, fmt.Errorf("failed to open ibt export file: %v", err)
}
} }
if ibt.File == nil { if ibt.File == nil {
@@ -112,10 +131,15 @@ func Init(f Reader) (*IBT, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to read headers from file: %v", err) return nil, fmt.Errorf("Unable to read headers from file: %v", err)
} }
// Write to the output file
_, err = ibt.FileToExport.WriteAt(headerRaw[:], 0)
if err != nil {
log.Fatal(err)
}
// Read the disk sub headers // Read the disk sub headers
var subheaderRaw [SubHeaderSize]byte var subheaderRaw [SubHeaderSize]byte
_, err = ibt.File.ReadAt(subheaderRaw[:], 112) _, err = ibt.File.ReadAt(subheaderRaw[:], HeaderSize)
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to read disk subheaders from file: %v", err) return nil, fmt.Errorf("Failed to read disk subheaders from file: %v", err)
} }
@@ -123,6 +147,11 @@ func Init(f Reader) (*IBT, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to parse disk subheaders from file: %v", err) return nil, fmt.Errorf("Unable to parse disk subheaders from file: %v", err)
} }
// Write to the output file
_, err = ibt.FileToExport.WriteAt(subheaderRaw[:], HeaderSize)
if err != nil {
log.Fatal(err)
}
// Read session info string // Read session info string
sessionInfoStringRaw := make([]byte, ibt.Headers.SessionInfoLength) sessionInfoStringRaw := make([]byte, ibt.Headers.SessionInfoLength)
@@ -130,10 +159,23 @@ func Init(f Reader) (*IBT, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to read sessionInfoString from file: %v", err) return nil, fmt.Errorf("Failed to read sessionInfoString from file: %v", err)
} }
// Write to the output file
_, err = ibt.FileToExport.WriteAt(sessionInfoStringRaw[:], int64(ibt.Headers.SessionInfoOffset))
if err != nil {
log.Fatal(err)
}
ibt.SessionInfo, err = parseSessionInfo(sessionInfoStringRaw, ibt.Headers.SessionInfoLength) ibt.SessionInfo, err = parseSessionInfo(sessionInfoStringRaw, ibt.Headers.SessionInfoLength)
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to parse SessionInfoString from file: %v", err) return nil, fmt.Errorf("Unable to parse SessionInfoString from file: %v", err)
} }
// Write to YAML output file
if exportYAML != "" {
err := ibt.exportYAML(exportYAML)
if err != nil {
return nil, err
}
}
// Read the telemetry vars info // Read the telemetry vars info
err = ibt.readVariablerHeaders() err = ibt.readVariablerHeaders()
@@ -151,69 +193,3 @@ func (i *IBT) Close() {
i.winUtils.Close() i.winUtils.Close()
} }
} }
// func main() {
// fmt.Println("================== IBT FILE PARSER ==================")
//
// file, err := os.Open(ibtFile)
// if err != nil {
// log.Fatalf("Failed to open IBT file: %v", err)
// }
//
// ibt, err := Init(file)
// if err != nil {
// log.Fatalf("Failed to create irsdk instance: %v", err)
// }
// // fmt.Printf("%s\n", ibt.Headers.ToString())
// // fmt.Printf("%s\n", ibt.SubHeaders.ToString())
// // fmt.Printf("%s\n", ibt.SessionInfo.ToString())
//
// // Display the human readable start date
// // unixStartDate := time.Unix(ibt.SubHeaders.StartDate, 0)
// // startDate := unixStartDate.Format("2006/01/02 15:04:05 -0700 MST")
// // fmt.Println("StartDate:", startDate)
//
// // Display the human readable version of start time
// // unixStartTime := time.Unix(ibt.SubHeaders.StartDate+int64(ibt.SubHeaders.StartTime), 0)
// // startTime := unixStartTime.Format("2006/01/02 15:04:05 -0700 MST")
// // fmt.Println("StartTime:", startTime)
//
// // Display the human readable version of end time
// // unixEndTime := time.Unix(ibt.SubHeaders.StartDate+int64(ibt.SubHeaders.EndTime), 0)
// // endTime := unixEndTime.Format("2006/01/02 15:04:05 -0700 MST")
// // fmt.Println("EndTime: ", endTime)
//
// last := time.Now().UnixMilli()
// for {
// time.Sleep(time.Second / 60)
// res, err := ibt.Update(100 * time.Millisecond)
// if res == Unknown {
// log.Fatalf("Some unknown error occurred: %v\n", err)
// }
//
// if res == Paused {
// fmt.Printf("\r \r")
// fmt.Println("GAME IS PAUSED")
// continue
// }
//
// curTime := time.Now().UnixMilli()
//
// if curTime-last > 250 {
// fmt.Printf(" \r")
// if val, ok := ibt.Vars.Vars["Speed"]; ok {
// fmt.Printf("\r%d %d", ibt.Vars.Tick/60, conv.MsToKph(val.Value.(float32)))
// } else {
// fmt.Printf("\r%d %s", ibt.Vars.Tick/60, "KEY DOESN'T EXIST")
// }
// }
//
// if res == Ended {
// fmt.Println("\nEnd of file found...")
// break
// }
// }
// fmt.Printf("%d\n", ibt.Vars.Tick)
//
// ibt.Close()
// }
+23
View File
@@ -0,0 +1,23 @@
package logger
import (
"log"
"os"
"sync"
)
var l *log.Logger
var once sync.Once
func createLogger() {
l = log.New(os.Stdout, "[ibtReader] ", log.LstdFlags | log.Lshortfile)
}
func GetInstance() *log.Logger {
once.Do(func() {
createLogger()
})
return l
}
+24 -9
View File
@@ -91,8 +91,9 @@ type varBuffer struct {
} }
type TelemetryVars struct { type TelemetryVars struct {
Tick int32 Tick int32 // Keeps track of the current data buffer tick
Vars map[string]Var RecorderTick int32 // Counts from 0 when creating a telemetry file from a replay or live data
Vars map[string]Var // Variables content
} }
func (i *IBT) readVariablerHeaders() error { func (i *IBT) readVariablerHeaders() error {
@@ -107,6 +108,11 @@ func (i *IBT) readVariablerHeaders() error {
return err return err
} }
_, err = i.FileToExport.WriteAt(rbuf, int64(i.Headers.VarHeaderOffset+k*VarHeaderSize))
if err != nil {
log.Fatal(err)
}
var dst IBTVar var dst IBTVar
err = binary.Read(bytes.NewBuffer(rbuf[:]), binary.LittleEndian, &dst) err = binary.Read(bytes.NewBuffer(rbuf[:]), binary.LittleEndian, &dst)
if err != nil { if err != nil {
@@ -197,6 +203,11 @@ func (i *IBT) Update(timeout time.Duration) (IRacingState, error) {
return Failed, err return Failed, err
} }
_, err = i.FileToExport.WriteAt(buf, int64(i.Headers.BufOffset+i.Vars.RecorderTick*i.Headers.BufLen))
if err != nil {
log.Fatalf("Failed to write to file [2]: %v", err)
}
err = i.readData(buf) err = i.readData(buf)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return Unknown, err return Unknown, err
@@ -205,11 +216,21 @@ func (i *IBT) Update(timeout time.Duration) (IRacingState, error) {
if err == io.EOF { if err == io.EOF {
return Ended, nil return Ended, nil
} }
i.Vars.RecorderTick++
} else { } else {
// This will get the dataframe corresponding to a give tick // This will get the dataframe corresponding to a given tick
start := i.Headers.BufOffset + i.Vars.Tick*i.Headers.BufLen start := i.Headers.BufOffset + i.Vars.Tick*i.Headers.BufLen
buf := make([]byte, i.Headers.BufLen) buf := make([]byte, i.Headers.BufLen)
_, err := i.File.ReadAt(buf, int64(start)) _, err := i.File.ReadAt(buf, int64(start))
// Make this happen in a different thread, or have this send to a queue that has a thread
// writing to a file
_, err = i.FileToExport.WriteAt(buf, int64(start))
if err != nil {
log.Fatalf("Failed to write to file [1]: %v\n", err)
}
if err == io.EOF { if err == io.EOF {
return Ended, nil return Ended, nil
} }
@@ -226,11 +247,5 @@ func (i *IBT) Update(timeout time.Duration) (IRacingState, error) {
i.Vars.Tick++ i.Vars.Tick++
} }
// Make this happen in a different thread, or have this send to a queue that has a thread
// writing to a file
if i.FileToExport != "" {
i.ExportToIBT(i.FileToExport)
}
return Running, nil return Running, nil
} }
+53 -53
View File
@@ -1,53 +1,53 @@
//go:build (linux && cgo) || (darwin && cgo) //go:build (linux && cgo) || (darwin && cgo)
// +build linux,cgo darwin,cgo // +build linux,cgo darwin,cgo
package winutils package winutils
import ( import (
"errors" "errors"
"sync" "sync"
"time" "time"
) )
const ( const (
WAIT_OBJECT_0 = 0 WAIT_OBJECT_0 = 0
WAIT_TIMEOUT = 258 WAIT_TIMEOUT = 258
) )
var ( var (
once sync.Once once sync.Once
ErrUnsupportedOS = errors.New("not found") ErrUnsupportedOS = errors.New("not found")
) )
type utils struct { type utils struct {
} }
// INITIALIZATION // INITIALIZATION
func newUtils() (*utils, error) { func newUtils() (*utils, error) {
return nil, ErrUnsupportedOS return nil, ErrUnsupportedOS
} }
func (u *utils) Close() { func (u *utils) Close() {
} }
// openEvent opens a windows.Handle for a given event // openEvent opens a windows.Handle for a given event
func (u *utils) OpenEvent(eventName string) error { func (u *utils) OpenEvent(eventName string) error {
return ErrUnsupportedOS return ErrUnsupportedOS
} }
// OpenBroadcastChannel opens up a broadcast channel to send commands to iracing // OpenBroadcastChannel opens up a broadcast channel to send commands to iracing
func (u *utils) OpenBroadcastChannel(name string) error { func (u *utils) OpenBroadcastChannel(name string) error {
return ErrUnsupportedOS return ErrUnsupportedOS
} }
// INITIALIZATION // INITIALIZATION
// openEvent waits for a good response for some given time // openEvent waits for a good response for some given time
func (u *utils) CheckValidDataEvent(timeout time.Duration) bool { func (u *utils) CheckValidDataEvent(timeout time.Duration) bool {
return false return false
} }
// SendBroadcastMessage sends a message trough the broadcast channel // SendBroadcastMessage sends a message trough the broadcast channel
func (u *utils) SendBroadcastMessage(id, p1, p2 uintptr) error { func (u *utils) SendBroadcastMessage(id, p1, p2 uintptr) error {
return ErrUnsupportedOS return ErrUnsupportedOS
} }