Organized the code a bit better and it works now
This is a basic functioning version of an IBT file parser Currently it can only parse a file, but I do want to support live data
This commit is contained in:
+16
-16
@@ -7,23 +7,23 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
SubHeaderSize = 32 // SubHeaderSize is the size of the subheader
|
||||
SubHeaderSize = 32 // SubHeaderSize is the size of the subheader
|
||||
)
|
||||
|
||||
// DiskSubHeader represents the IBT sub headers
|
||||
type DiskSubHeader struct {
|
||||
StartDate float64 // StartDate represents the start data of the telemetry
|
||||
StartTime float64 // StartTime ...
|
||||
EndTime float64 // EndTime ...
|
||||
StartDate int64 // StartDate represents the start date of the telemetry
|
||||
StartTime float64 // StartTime of file relative to start of session
|
||||
EndTime float64 // EndTime of file relative to start of session
|
||||
LapCount int32 // LapCount represents the total number laps
|
||||
RecordCount int32 // RecordCount ...
|
||||
RecordCount int32 // RecordCount holds the number of data frames
|
||||
}
|
||||
|
||||
// parseTelemetrySubHeader will return a pointer to a DiskSubHeader variable
|
||||
// or nil if an error occurs. In which case the error return value is more
|
||||
// valuable
|
||||
func parseTelemetrySubHeader(buf [SubHeaderSize]byte) (*DiskSubHeader, error) {
|
||||
dst := DiskSubHeader{}
|
||||
dst := DiskSubHeader{}
|
||||
err := binary.Read(bytes.NewBuffer(buf[:]), binary.LittleEndian, &dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -34,14 +34,14 @@ func parseTelemetrySubHeader(buf [SubHeaderSize]byte) (*DiskSubHeader, error) {
|
||||
|
||||
// ToString renders a string showing the values of the struct
|
||||
func (d *DiskSubHeader) ToString() string {
|
||||
return fmt.Sprintf(
|
||||
"StartDate: %13f (0x%04x)\n" +
|
||||
"StartTime: %13f (0x%08x)\n" +
|
||||
"EndTime: %13f (0x%08x)\n" +
|
||||
"LapCount: %13d (0x%04x)\n" +
|
||||
"RecordCount: %13d (0x%04x)\n",
|
||||
d.StartDate, d.StartDate, d.StartTime, d.StartTime,
|
||||
d.EndTime, d.EndTime, d.LapCount, d.LapCount,
|
||||
d.RecordCount, d.RecordCount,
|
||||
)
|
||||
return fmt.Sprintf(
|
||||
"StartDate: %13d (0x%04x)\n"+
|
||||
"StartTime: %13f (0x%08x)\n"+
|
||||
"EndTime: %13f (0x%08x)\n"+
|
||||
"LapCount: %13d (0x%04x)\n"+
|
||||
"RecordCount: %13d (0x%04x)\n",
|
||||
d.StartDate, d.StartDate, d.StartTime, d.StartTime,
|
||||
d.EndTime, d.EndTime, d.LapCount, d.LapCount,
|
||||
d.RecordCount, d.RecordCount,
|
||||
)
|
||||
}
|
||||
|
||||
+12
-12
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
FileHeaderSize = 56 // FileHeaderSize is the size of the headers
|
||||
FileHeaderSize = 112 // FileHeaderSize is the size of the headers
|
||||
HeaderSize = 4 // HeaderSize is the size of a single header
|
||||
)
|
||||
|
||||
@@ -42,17 +42,17 @@ type TelemetryHeaders struct {
|
||||
// ToString renders a string showing the values of the struct
|
||||
func (th *TelemetryHeaders) ToString() string {
|
||||
return fmt.Sprintf(
|
||||
"Version: %5d (0x%04x)\n"+
|
||||
"Status: %5d (0x%04x)\n"+
|
||||
"TickRate: %5d (0x%04x)\n"+
|
||||
"SIUpdate: %5d (0x%04x)\n"+
|
||||
"SILength: %5d (0x%04x)\n"+
|
||||
"SIOffset: %5d (0x%04x)\n"+
|
||||
"NumVars: %5d (0x%04x)\n"+
|
||||
"VarHeaderOffset: %5d (0x%04x)\n"+
|
||||
"NumBuf: %5d (0x%04x)\n"+
|
||||
"BufLen: %5d (0x%04x)\n"+
|
||||
"BufOffset: %5d (0x%04x)\n",
|
||||
"Version: %5d (0x%04x)\n"+
|
||||
"Status: %5d (0x%04x)\n"+
|
||||
"TickRate: %5d (0x%04x)\n"+
|
||||
"SIUpdate: %5d (0x%04x)\n"+
|
||||
"SILength: %5d (0x%04x)\n"+
|
||||
"SIOffset: %5d (0x%04x)\n"+
|
||||
"NumVars: %5d (0x%04x)\n"+
|
||||
"VarHeaderOffset: %5d (0x%04x)\n"+
|
||||
"NumBuf: %5d (0x%04x)\n"+
|
||||
"BufLen: %5d (0x%04x)\n"+
|
||||
"BufOffset: %5d (0x%04x)\n",
|
||||
th.Version, th.Version, th.Status, th.Status, th.TickRate, th.TickRate,
|
||||
th.SessionInfoUpdate, th.SessionInfoUpdate,
|
||||
th.SessionInfoLength, th.SessionInfoLength,
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
// Package IbtParser is all you need for you iRacing telemetry parsing
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ibtFile = "./telemetryFiles/mx5_2016Okayama_full_2024_10_19_22_02_12.ibt"
|
||||
// ibtFile = "./telemetryFiles/sample.ibt"
|
||||
)
|
||||
|
||||
// Reader is an interface to represent the readable data that can be either
|
||||
// a .ibt file (or live data, hopefully)
|
||||
type Reader interface {
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
// IBT struct will hold the relevant data for a given IBT file
|
||||
type IBT struct {
|
||||
File Reader // Source of the data
|
||||
Headers *TelemetryHeaders // IBT file Headers
|
||||
SubHeaders *DiskSubHeader // IBT file Sub Headers
|
||||
SessionInfo *SessionInfoYAML // IBT file Session Info
|
||||
Vars *TelemetryVars // Vars will hold the telemetry data
|
||||
Tick int32 // Tick holds the cound of the reads
|
||||
}
|
||||
|
||||
// Init serves to initialize and get a hold of a IBT struct
|
||||
func Init(f Reader) (*IBT, error) {
|
||||
// Read the header of the file
|
||||
var err error
|
||||
ibt := IBT{
|
||||
File: f,
|
||||
Vars: &TelemetryVars{},
|
||||
}
|
||||
|
||||
// Read the file headers
|
||||
var headerRaw [FileHeaderSize]byte
|
||||
_, err = ibt.File.ReadAt(headerRaw[:], 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read from file: %v", err)
|
||||
}
|
||||
ibt.Headers, err = parseTelemetryHeader(headerRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to read headers from file: %v", err)
|
||||
}
|
||||
|
||||
// Read the disk sub headers
|
||||
var subheaderRaw [SubHeaderSize]byte
|
||||
_, err = ibt.File.ReadAt(subheaderRaw[:], 112)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read subheader from file: %v", err)
|
||||
}
|
||||
ibt.SubHeaders, err = parseTelemetrySubHeader(subheaderRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse subheaders from file: %v", err)
|
||||
}
|
||||
|
||||
// Read session info string
|
||||
sessionInfoStringRaw := make([]byte, ibt.Headers.SessionInfoLength)
|
||||
_, err = ibt.File.ReadAt(sessionInfoStringRaw, int64(ibt.Headers.SessionInfoOffset))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read sessionInfoString from file: %v", err)
|
||||
}
|
||||
ibt.SessionInfo, err = parseSessionInfo(sessionInfoStringRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse Session Info from file: %v", err)
|
||||
}
|
||||
|
||||
// Read the telemetry vars info
|
||||
ibt.readVariablerHeaders()
|
||||
|
||||
return &ibt, nil
|
||||
}
|
||||
|
||||
func msToKph(v float32) int {
|
||||
return int((3600 * v) / 1000)
|
||||
}
|
||||
|
||||
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)
|
||||
fmt.Printf("%s\n", ibt.Headers.ToString())
|
||||
fmt.Printf("%s\n", ibt.SubHeaders.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 := ibt.Update()
|
||||
|
||||
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.Tick/60, msToKph(val.Value.(float32)))
|
||||
} else {
|
||||
fmt.Printf("\r%d %s", ibt.Tick/60, "KEY DOESN'T EXIST")
|
||||
}
|
||||
}
|
||||
|
||||
if !res {
|
||||
fmt.Println("\nEnd of file found...")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%d\n", ibt.Tick)
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
// Package IbtParser is all you need for you iRacing telemetry parsing
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
ibtFile = "./telemetryFiles/mx5_2016Okayama_full_2024_10_19_22_02_12.ibt"
|
||||
)
|
||||
|
||||
// Reader is an interface (??? very useful)
|
||||
type Reader interface {
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
// IBT struct will hold the relevant data for a given IBT file
|
||||
type IBT struct {
|
||||
File Reader // Source of the data
|
||||
Headers *TelemetryHeaders // IBT file Headers
|
||||
SubHeaders *DiskSubHeader // IBT file Sub Headers
|
||||
SessionInfo *SessionInfoYAML // IBT file Session Info
|
||||
Vars *TelemetryVars
|
||||
LastValidData int64
|
||||
Tick int32
|
||||
}
|
||||
|
||||
// Init serves to initialize and get a hold of a IBT struct
|
||||
func Init(f Reader) (*IBT, error) {
|
||||
// Read the header of the file
|
||||
var err error
|
||||
ibt := IBT{
|
||||
File: f,
|
||||
Vars: &TelemetryVars{},
|
||||
}
|
||||
|
||||
// Read the file headers
|
||||
var headerRaw [FileHeaderSize]byte
|
||||
_, err = ibt.File.ReadAt(headerRaw[:], 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read from file: %v", err)
|
||||
}
|
||||
ibt.Headers, err = parseTelemetryHeader(headerRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to read headers from file: %v", err)
|
||||
}
|
||||
|
||||
// Read the disk sub headers
|
||||
var subheaderRaw [SubHeaderSize]byte
|
||||
_, err = ibt.File.ReadAt(subheaderRaw[:], FileHeaderSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read subheader from file: %v", err)
|
||||
}
|
||||
ibt.SubHeaders, err = parseTelemetrySubHeader(subheaderRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse subheaders from file: %v", err)
|
||||
}
|
||||
|
||||
// Read session info string
|
||||
sessionInfoStringRaw := make([]byte, ibt.Headers.SessionInfoLength)
|
||||
_, err = ibt.File.ReadAt(sessionInfoStringRaw, int64(ibt.Headers.SessionInfoOffset))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read sessionInfoString from file: %v", err)
|
||||
}
|
||||
ibt.SessionInfo, err = parseSessionInfo(sessionInfoStringRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to parse Session Info from file: %v", err)
|
||||
}
|
||||
|
||||
return &ibt, nil
|
||||
}
|
||||
|
||||
func (i *IBT) readVariablerHeaders() {
|
||||
i.Vars = &TelemetryVars{Vars: make(map[string]Var, i.Headers.NumVars)}
|
||||
|
||||
var k int32
|
||||
for k = 0; k < i.Headers.NumVars; k++ {
|
||||
rbuf := make([]byte, VarSize)
|
||||
|
||||
_, err := i.File.ReadAt(rbuf, int64(i.Headers.VarHeaderOffset+k*VarSize))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var dst IBTVar
|
||||
err = binary.Read(bytes.NewBuffer(rbuf[:]), binary.LittleEndian, &dst)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
v := Var{
|
||||
Type: dst.Type,
|
||||
Offset: dst.Offset,
|
||||
Count: dst.Count,
|
||||
CountAsTime: dst.CountAsTime,
|
||||
Name: strings.TrimLeft(strings.TrimRight(string(dst.Name[:]), "\x00"), "\x00"),
|
||||
Description: strings.TrimLeft(strings.TrimRight(string(dst.Description[:]), "\x00"), "\x00"),
|
||||
Unit: strings.TrimLeft(strings.TrimRight(string(dst.Unit[:]), "\x00"), "\x00"),
|
||||
Value: nil,
|
||||
}
|
||||
|
||||
// fmt.Println(dst.Name)
|
||||
// fmt.Println(v.Name)
|
||||
|
||||
i.Vars.Vars[v.Name] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IBT) readData() error {
|
||||
start := i.Headers.BufOffset + i.Tick*i.Headers.BufLen
|
||||
buf := make([]byte, i.Headers.BufLen)
|
||||
_, err := i.File.ReadAt(buf, int64(start))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range i.Vars.Vars {
|
||||
rbuf := buf[v.Offset : v.Offset+int32(VarTypes[int(v.Type)].Size)]
|
||||
|
||||
// Read the value
|
||||
switch v.Type {
|
||||
case IRSDK_char:
|
||||
v.Value = string(rbuf[0])
|
||||
case IRSDK_bool:
|
||||
v.Value = int(rbuf[0]) > 0
|
||||
case IRSDK_int:
|
||||
v.Value = int(binary.LittleEndian.Uint32(rbuf))
|
||||
case IRSDK_bitField:
|
||||
v.Value = fmt.Sprintf("0x%x", int(binary.LittleEndian.Uint32(rbuf)))
|
||||
case IRSDK_float:
|
||||
v.Value = math.Float32frombits(uint32(binary.LittleEndian.Uint32(rbuf)))
|
||||
case IRSDK_double:
|
||||
v.Value = math.Float64frombits(uint64(binary.LittleEndian.Uint64(rbuf)))
|
||||
}
|
||||
// --------------
|
||||
|
||||
i.Vars.Vars[k] = v
|
||||
}
|
||||
|
||||
i.Tick++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IBT) Update() bool {
|
||||
err := i.readData()
|
||||
if err != nil && err != io.EOF {
|
||||
log.Fatalf("What happened?\n%v\n", err)
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func msToKph(v float32) int {
|
||||
return int((3600 * v) / 1000)
|
||||
}
|
||||
|
||||
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)
|
||||
fmt.Printf("%s\n", ibt.Headers.ToString())
|
||||
fmt.Printf("%s", ibt.SubHeaders.ToString())
|
||||
// fmt.Println(ibt.SessionInfo.ToString())
|
||||
|
||||
// last := time.Now().Unix()
|
||||
ibt.readVariablerHeaders()
|
||||
ibt.Update()
|
||||
|
||||
last := time.Now().UnixMilli()
|
||||
for {
|
||||
time.Sleep(time.Second / 60)
|
||||
res := ibt.Update()
|
||||
|
||||
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.Tick/60, msToKph(val.Value.(float32)))
|
||||
} else {
|
||||
fmt.Printf("\r%d %s", ibt.Tick/60, "KEY DOESN'T EXIST")
|
||||
}
|
||||
}
|
||||
|
||||
if !res {
|
||||
fmt.Println("\nEnd of file found...")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
+96
-86
@@ -1,7 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"math"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -37,7 +43,7 @@ type IBTVar struct {
|
||||
Offset int32
|
||||
Count int32
|
||||
CountAsTime bool
|
||||
Padding [0]byte
|
||||
Padding [3]byte
|
||||
Name [32]byte
|
||||
Description [64]byte
|
||||
Unit [32]byte
|
||||
@@ -51,11 +57,11 @@ type Var struct {
|
||||
Name string
|
||||
Description string
|
||||
Unit string
|
||||
// TODO
|
||||
// Create an interface for this value
|
||||
// Represent the IRSDK var types with a struct each that implements the Parse
|
||||
// method or something like that I guess
|
||||
Value interface{}
|
||||
// TODO
|
||||
// Create an interface for this value
|
||||
// Represent the IRSDK var types with a struct each that implements the Parse
|
||||
// method or something like that I guess
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (v *IBTVar) ToString() string {
|
||||
@@ -82,86 +88,90 @@ type TelemetryVars struct {
|
||||
Vars map[string]Var
|
||||
}
|
||||
|
||||
// func findLatestBuffer(i *IBT) varBuffer {
|
||||
// var vb varBuffer
|
||||
// foundTickCount := 0
|
||||
// for k := 0; k < int(i.Headers.NumBuf); k++ {
|
||||
// rbuf := make([]byte, 16)
|
||||
// _, err := i.File.ReadAt(rbuf, int64(48+k*16))
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// currentVb := varBuffer{
|
||||
// int(binary.LittleEndian.Uint32(rbuf[0:4])),
|
||||
// int(binary.LittleEndian.Uint32(rbuf[4:8])),
|
||||
// }
|
||||
//
|
||||
// if foundTickCount < currentVb.tickCount {
|
||||
// foundTickCount = currentVb.tickCount
|
||||
// vb = currentVb
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return vb
|
||||
// }
|
||||
func (i *IBT) readVariablerHeaders() {
|
||||
i.Vars = &TelemetryVars{Vars: make(map[string]Var, i.Headers.NumVars)}
|
||||
|
||||
// func (i *IBT) parseVariableHeaders(offset int32) (int32, error) {
|
||||
// if i.Vars.Vars == nil {
|
||||
// i.Vars.Vars = make(map[string]*Variable, i.Headers.NumVars)
|
||||
// }
|
||||
//
|
||||
// var size int32 = 0
|
||||
// for k := range i.Headers.NumVars {
|
||||
// start := k * VarSize + offset
|
||||
// size += start
|
||||
//
|
||||
// buf := make([]byte, VarSize)
|
||||
// _, err := i.File.ReadAt(buf, int64(start))
|
||||
// if err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
//
|
||||
// newVar, err := parseVariable(buf)
|
||||
// i.Vars.Vars[string(newVar.Name[:])] = newVar
|
||||
// }
|
||||
//
|
||||
// return size, nil
|
||||
// }
|
||||
var k int32
|
||||
for k = 0; k < i.Headers.NumVars; k++ {
|
||||
rbuf := make([]byte, VarSize)
|
||||
|
||||
// This function will read a single variable
|
||||
// func parseVariable(buf []byte) (*Variable, error) {
|
||||
// if len(buf)%VarSize != 0 {
|
||||
// return nil, fmt.Errorf("buffer must be multiple of size: %d", VarSize)
|
||||
// }
|
||||
//
|
||||
// dst := Variable{}
|
||||
// err := binary.Read(bytes.NewBuffer(buf[:]), binary.LittleEndian, &dst)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return &dst, nil
|
||||
// }
|
||||
_, err := i.File.ReadAt(rbuf, int64(i.Headers.VarHeaderOffset+k*VarSize))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// this function will read the variables
|
||||
// func parseVariables(i *IBT) error {
|
||||
// i.parseVariableHeaders(0)
|
||||
// vb := findLatestBuffer(i)
|
||||
// fmt.Printf("%+v\n", vb)
|
||||
// if i.Vars.LastVersion < vb.tickCount {
|
||||
// // Then we have new data
|
||||
// i.Vars.LastVersion = vb.tickCount
|
||||
// i.LastValidData = time.Now().Unix()
|
||||
// for _, v := range i.Vars.Vars {
|
||||
// // fmt.Printf("%s\n", v.ToString())
|
||||
// rbuf := make([]byte, VarTypes[int(v.Type)].Size)
|
||||
// _, err := i.File.ReadAt(rbuf, int64(vb.bufOffset + int(v.Offset)))
|
||||
// if err != nil {
|
||||
// log.Fatalf("Reading values: %v\n", err)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
// }
|
||||
var dst IBTVar
|
||||
err = binary.Read(bytes.NewBuffer(rbuf[:]), binary.LittleEndian, &dst)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(dst.Name)
|
||||
|
||||
v := Var{
|
||||
Type: dst.Type,
|
||||
Offset: dst.Offset,
|
||||
Count: dst.Count,
|
||||
CountAsTime: dst.CountAsTime,
|
||||
Name: strings.TrimRight(string(dst.Name[:]), "\x00"),
|
||||
Description: strings.TrimRight(string(dst.Description[:]), "\x00"),
|
||||
Unit: strings.TrimRight(string(dst.Unit[:]), "\x00"),
|
||||
Value: nil,
|
||||
}
|
||||
|
||||
i.Vars.Vars[v.Name] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IBT) readData() error {
|
||||
// I think that we can add one extra check or verification here
|
||||
// The file headers tells us how many data frames there are, we can probably
|
||||
// cap it at that instead of waiting for the read to fail
|
||||
// Probably wouldn't work on live data tho
|
||||
start := i.Headers.BufOffset + i.Tick*i.Headers.BufLen
|
||||
buf := make([]byte, i.Headers.BufLen)
|
||||
_, err := i.File.ReadAt(buf, int64(start))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range i.Vars.Vars {
|
||||
rbuf := buf[v.Offset : v.Offset+int32(VarTypes[int(v.Type)].Size)]
|
||||
|
||||
// Read the value
|
||||
switch v.Type {
|
||||
case IRSDK_char:
|
||||
v.Value = string(rbuf[0])
|
||||
case IRSDK_bool:
|
||||
v.Value = int(rbuf[0]) > 0
|
||||
case IRSDK_int:
|
||||
v.Value = int(binary.LittleEndian.Uint32(rbuf))
|
||||
case IRSDK_bitField:
|
||||
v.Value = fmt.Sprintf("0x%x", int(binary.LittleEndian.Uint32(rbuf)))
|
||||
case IRSDK_float:
|
||||
v.Value = math.Float32frombits(uint32(binary.LittleEndian.Uint32(rbuf)))
|
||||
case IRSDK_double:
|
||||
v.Value = math.Float64frombits(uint64(binary.LittleEndian.Uint64(rbuf)))
|
||||
}
|
||||
// --------------
|
||||
|
||||
i.Vars.Vars[k] = v
|
||||
}
|
||||
|
||||
i.Tick++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IBT) Update() bool {
|
||||
err := i.readData()
|
||||
if err != nil && err != io.EOF {
|
||||
log.Fatalf("What happened?\n%v\n", err)
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user