178 lines
3.9 KiB
Go
178 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"math"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
VarHeaderSize = 144
|
|
IRSDK_char = 0
|
|
IRSDK_bool = 1
|
|
IRSDK_int = 2
|
|
IRSDK_bitField = 3
|
|
IRSDK_float = 4
|
|
IRSDK_double = 5
|
|
)
|
|
|
|
// I think I can make an interface if IRSDK types with available types and
|
|
// that they need a parser (reads and type coerces I guess)
|
|
var (
|
|
VarTypes = map[int]VarType{
|
|
IRSDK_char: {1, "irsdk_char"},
|
|
IRSDK_bool: {1, "irsdk_bool"},
|
|
IRSDK_int: {4, "irsdk_int"},
|
|
IRSDK_bitField: {4, "irsdk_bitField"},
|
|
IRSDK_float: {4, "irsdk_float"},
|
|
IRSDK_double: {8, "irsdk_double"},
|
|
}
|
|
)
|
|
|
|
type VarType struct {
|
|
Size int // Size is the var type size in bytes
|
|
Name string // Name is the irsdk var name
|
|
}
|
|
|
|
type IBTVar struct {
|
|
Type int32
|
|
Offset int32
|
|
Count int32
|
|
CountAsTime bool
|
|
Padding [3]byte
|
|
Name [32]byte
|
|
Description [64]byte
|
|
Unit [32]byte
|
|
}
|
|
|
|
type Var struct {
|
|
Type int32
|
|
Offset int32
|
|
Count int32
|
|
CountAsTime bool
|
|
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{}
|
|
}
|
|
|
|
func (v *IBTVar) ToString() string {
|
|
return fmt.Sprintf(
|
|
"Type: %5d (0x%08x)\n"+
|
|
"Offset: %5d (0x%08x)\n"+
|
|
"Count: %5d (0x%08x)\n"+
|
|
"CountAsTime: %5t\n"+
|
|
"Name: %s\n"+
|
|
"Description: %s\n"+
|
|
"Unit: %s",
|
|
v.Type, v.Type, v.Offset, v.Offset, v.Count, v.Count,
|
|
v.CountAsTime, v.Name, v.Description, v.Unit,
|
|
)
|
|
}
|
|
|
|
type varBuffer struct {
|
|
tickCount int
|
|
bufOffset int
|
|
}
|
|
|
|
type TelemetryVars struct {
|
|
LastVersion int
|
|
Vars map[string]Var
|
|
}
|
|
|
|
func (i *IBT) readVariablerHeaders() error {
|
|
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, VarHeaderSize)
|
|
|
|
_, err := i.File.ReadAt(rbuf, int64(i.Headers.VarHeaderOffset+k*VarHeaderSize))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var dst IBTVar
|
|
err = binary.Read(bytes.NewBuffer(rbuf[:]), binary.LittleEndian, &dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|