Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature add live telemetry functionality #9

Merged
merged 12 commits into from
Aug 31, 2024
Merged
Binary file added .testing/live_test_file.ibt
Binary file not shown.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

![ibt logo](assets/ibt_mascot.png)


[![Go Reference](https://pkg.go.dev/badge/github.com/teamjorge/ibt.svg)](https://pkg.go.dev/github.com/teamjorge/ibt)
[![Go Report Card](https://goreportcard.com/badge/github.com/teamjorge/ibt)](https://goreportcard.com/report/github.com/teamjorge/ibt)
[![codecov](https://codecov.io/gh/teamjorge/ibt/branch/main/graph/badge.svg?token=08QVKSEPXT)](https://codecov.io/gh/teamjorge/ibt)


## Install

`go get github.com/teamjorge/ibt`
Expand Down Expand Up @@ -40,4 +38,4 @@ git clone https://github.com/teamjorge/ibt
git clone [email protected]:teamjorge/ibt.git
```

Please have a look at the instructors in the examples [`README`](./examples/README.md) for details on how to run each example.
Please have a look at the instructions in the examples [`README`](./examples/README.md) for details on how to run each example.
4 changes: 2 additions & 2 deletions examples/track_temp/processors.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ func (t *trackTempProcessor) Name() string { return "Track Temp" }

// Method used for processing every tick of telemetry
func (t *trackTempProcessor) Process(input ibt.Tick, hasNext bool, session *headers.Session) error {
trackTemp, err := ibt.GetVariableValue[float32](input, "TrackTempCrew")
trackTemp, err := ibt.GetTickValue[float32](input, "TrackTempCrew")
if err != nil {
return err
}

lap, err := ibt.GetVariableValue[int](input, "Lap")
lap, err := ibt.GetTickValue[int](input, "Lap")
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/teamjorge/ibt

go 1.22.4
go 1.22

require (
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8
Expand Down
14 changes: 8 additions & 6 deletions headers/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package headers

import (
"fmt"
"io"
"math"
"time"

"github.com/teamjorge/ibt/utilities"
Expand Down Expand Up @@ -37,9 +37,9 @@ type DiskHeader struct {
func ReadDiskHeader(reader Reader) (*DiskHeader, error) {
diskHeaderBuf := make([]byte, DISK_HEADER_BYTES_SIZE)

_, err := io.ReadAtLeast(reader, diskHeaderBuf, DISK_HEADER_BYTES_SIZE)
_, err := reader.ReadAt(diskHeaderBuf, int64(TELEMETRY_HEADER_BYTES_SIZE))
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to read disk header buffer: %v", err)
}

h := DiskHeader{
Expand All @@ -50,14 +50,16 @@ func ReadDiskHeader(reader Reader) (*DiskHeader, error) {
RecordCount: utilities.Byte4ToInt(diskHeaderBuf[28:32]),
}

if h.EndTime == 0.0 || h.RecordCount == 0 || h.StartTime == 0 {
return nil, fmt.Errorf("invalid disk header detected. values received: %v", h)
if h.EndTime < 0 || h.StartTime < 0 || h.EndTime > math.Pow(10, 20) || h.StartTime > math.Pow(10, 20) ||
h.RecordCount == 0 {
return nil, fmt.Errorf("invalid disk header detected. values received: %+v", h)
}

// Determine if StartDate is an invalid time value
parsedTime := time.Unix(h.StartDate, 0)
currentYear := time.Now().Year()
if parsedTime.Year() < currentYear-20 || currentYear > parsedTime.Year() {

if parsedTime.Year() < currentYear-20 || parsedTime.Year() > currentYear+20 {
return nil, fmt.Errorf("invalid StartDate detected: %v", parsedTime)
}

Expand Down
64 changes: 47 additions & 17 deletions headers/disk_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package headers

import (
"fmt"
"os"
"reflect"
"testing"
Expand All @@ -16,20 +15,27 @@ var expectedDiskHeader = DiskHeader{
}

func TestDiskHeaders(t *testing.T) {
t.Run("valid header file", func(t *testing.T) {
f, err := os.Open("../.testing/valid_test_file.ibt")
if err != nil {
t.Errorf("failed to open testing file - %v", err)
return
}
defer f.Close()
validF, err := os.Open("../.testing/valid_test_file.ibt")
if err != nil {
t.Errorf("failed to open testing file - %v", err)
return
}
defer validF.Close()

invalidF, err := os.Open("../.testing/invalid_test_file.ibt")
if err != nil {
t.Errorf("failed to open testing file - %v", err)
return
}
defer invalidF.Close()

t.Run("valid header file", func(t *testing.T) {
// Read telemetry header to move buffer along
if _, err := f.Seek(int64(TELEMETRY_HEADER_BYTES_SIZE), 0); err != nil {
if _, err := validF.Seek(int64(TELEMETRY_HEADER_BYTES_SIZE), 0); err != nil {
t.Errorf("failed to read telemetry header to move buffer along: %v", err)
}

output, err := ReadDiskHeader(f)
output, err := ReadDiskHeader(validF)
if err != nil {
t.Errorf("failed to parse disk header for testing file - %v", err)
return
Expand All @@ -40,19 +46,38 @@ func TestDiskHeaders(t *testing.T) {
}
})

t.Run("invalid header file", func(t *testing.T) {
f, err := os.Open("../.testing/invalid_test_file.ibt")
t.Run("invalid header file invalid end/start time", func(t *testing.T) {
_, err := ReadDiskHeader(invalidF)

if err != nil && err.Error()[:46] != "invalid disk header detected. values received:" {
t.Errorf("expected invalid disk header detected error. received: %v", err.Error()[:46])
}

if err == nil {
t.Error("expected diskHeader parsing of invalid file to return an error")
}
})

t.Run("invalid header file invalid parsed date", func(t *testing.T) {
mock, err := newMockReader(
validF,
TELEMETRY_HEADER_BYTES_SIZE+DISK_HEADER_BYTES_SIZE,
TELEMETRY_HEADER_BYTES_SIZE,
TELEMETRY_HEADER_BYTES_SIZE+8,
)
if err != nil {
t.Errorf("failed to open testing file - %v", err)
return
t.Errorf("failed to initialize a test mockReader - %v", err)
}

_, err = ReadDiskHeader(mock)

if err != nil && err.Error()[:27] != "invalid StartDate detected:" {
t.Errorf("expected invalid StartDate error. received: %v. full error: %v", err.Error()[:27], err)
}
defer f.Close()

a, err := ReadDiskHeader(f)
if err == nil {
t.Error("expected diskHeader parsing of invalid file to return an error")
}
fmt.Println(a)
})

t.Run("empty file", func(t *testing.T) {
Expand All @@ -64,6 +89,11 @@ func TestDiskHeaders(t *testing.T) {
defer f.Close()

_, err = ReadDiskHeader(f)

if err != nil && err.Error()[:34] != "failed to read disk header buffer:" {
t.Errorf("expected read disk header error. received: %v. full error: %v", err.Error()[:34], err)
}

if err == nil {
t.Error("expected diskHeader parsing of empty file to return an error")
}
Expand Down
73 changes: 34 additions & 39 deletions headers/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,56 @@ import "fmt"

// Header contains all sub-headers present in the ibt file.
type Header struct {
telemHeader *TelemetryHeader
diskHeader *DiskHeader
varHeader map[string]VarHeader
sessionInfo *Session
TelemetryHeader *TelemetryHeader
DiskHeader *DiskHeader
VarHeader map[string]VarHeader
SessionInfo *Session
VarBuffers []VarBuffer
}

func NewHeader(telemHeader *TelemetryHeader, diskHeader *DiskHeader, varHeader map[string]VarHeader, sessionInfo *Session) Header {
return Header{
telemHeader: telemHeader,
diskHeader: diskHeader,
varHeader: varHeader,
sessionInfo: sessionInfo,
}
}

// TelemetryHeader returns the loaded telemetry sub-header.
func (h *Header) TelemetryHeader() *TelemetryHeader { return h.telemHeader }

// DiskHeader returns the loaded disk sub-header.
func (h *Header) DiskHeader() *DiskHeader { return h.diskHeader }

// VarHeader returns the loaded variable sub-header.
func (h *Header) VarHeader() map[string]VarHeader { return h.varHeader }

// SessionInfo returns the parsed session information.
func (h *Header) SessionInfo() *Session { return h.sessionInfo }

// ParseHeader parses each of the required sub-headers of the ibt file in sequence.
func ParseHeaders(r Reader) (Header, error) {
var header Header

func ParseHeaders(r Reader) (*Header, error) {
telemHeader, err := ReadTelemetryHeader(r)
if err != nil {
return header, fmt.Errorf("failed to parse telemetry header: %v", err)
return nil, fmt.Errorf("failed to parse telemetry header: %v", err)
}

diskHeader, err := ReadDiskHeader(r)
if err != nil {
return header, fmt.Errorf("failed to parse disk header: %v", err)
return nil, fmt.Errorf("failed to parse disk header: %v", err)
}

sessionInfo, err := ReadSessionInfo(r, telemHeader.SessionInfoOffset, telemHeader.SessionInfoLength)
varHeader, err := ReadVarHeader(r, telemHeader.NumVars, telemHeader.VarHeaderOffset)
if err != nil {
return header, fmt.Errorf("failed to parse session info: %v", err)
return nil, fmt.Errorf("failed to parse variable header: %v", err)
}

varHeader, err := ReadVarHeader(r, telemHeader.NumVars, telemHeader.VarHeaderOffset)
varBuffers, err := ReadVarBufferHeaders(r, telemHeader.NumBuf)
if err != nil {
return header, fmt.Errorf("failed to parse variable header: %v", err)
return nil, fmt.Errorf("failed to parse var buffer header: %v", err)
}

return Header{
telemHeader: telemHeader,
diskHeader: diskHeader,
sessionInfo: sessionInfo,
varHeader: varHeader,
sessionInfo, err := ReadSessionInfo(r, telemHeader.SessionInfoOffset, telemHeader.SessionInfoLength)
if err != nil {
return nil, fmt.Errorf("failed to parse session info: %v", err)
}

return &Header{
TelemetryHeader: telemHeader,
DiskHeader: diskHeader,
VarHeader: varHeader,
SessionInfo: sessionInfo,
VarBuffers: varBuffers,
}, nil
}

func (h *Header) UpdateVarBuffer(r Reader) error {
varBuffers, err := ReadVarBufferHeaders(r, h.TelemetryHeader.NumBuf)
if err != nil {
return fmt.Errorf("failed to parse var buffer header: %v", err)
}

h.VarBuffers = varBuffers

return nil
}
Loading
Loading