/
gt7communication.go
145 lines (128 loc) · 3.19 KB
/
gt7communication.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package gt7
import (
"encoding/binary"
"fmt"
"golang.org/x/crypto/salsa20"
"net"
"time"
)
type Session struct {
SpecialPacketTime int64
BestLap int32
MinBodyHeight int
MaxSpeed int
}
type GT7Communication struct {
playstationIP string
sendPort, receivePort int
lastTimeDataReceived time.Time
currentLap Lap
session Session
laps []Lap
LastData GTData
alwaysRecordData bool
shallRun, shallRestart bool
}
func (gt7c *GT7Communication) SendHB(conn *net.UDPConn) error {
_, err := conn.WriteToUDP([]byte("A"), &net.UDPAddr{
IP: net.ParseIP(gt7c.playstationIP),
Port: gt7c.sendPort,
})
if err != nil {
return fmt.Errorf("error sending heart beat: %v", err)
}
err = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
if err != nil {
return fmt.Errorf("error setting read deadline: %v", err)
}
return nil
}
func salsa20Dec(dat []byte) []byte {
var key [32]byte
key = [32]byte([]byte("Simulator Interface Packet GT7 ver 0.0"))
oiv := dat[0x40:0x44]
iv1 := binary.LittleEndian.Uint32(oiv)
iv2 := iv1 ^ 0xDEADBEAF
iv := make([]byte, 8)
binary.LittleEndian.PutUint32(iv, iv2)
binary.LittleEndian.PutUint32(iv[4:], iv1)
ddata := make([]byte, len(dat))
salsa20.XORKeyStream(ddata, dat, iv, &key)
magic := binary.LittleEndian.Uint32(ddata[:4])
if magic != 0x47375330 {
return nil
}
return ddata
}
func (gt7c *GT7Communication) Start() error {
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.IPv4zero,
Port: 5055,
})
if err != nil {
return fmt.Errorf("error starting connection: %v", err)
}
defer conn.Close()
return nil
}
type Lap struct {
}
func NewGT7Communication(playstationIP string) *GT7Communication {
return >7Communication{
playstationIP: playstationIP,
sendPort: 33739,
receivePort: 33740,
LastData: GTData{},
shallRun: true,
shallRestart: false,
}
}
func (gt7c *GT7Communication) Stop() {
gt7c.shallRun = false
}
func (gt7c *GT7Communication) Run() error {
for gt7c.shallRun {
s := &net.UDPConn{}
gt7c.shallRestart = false
addr, err := net.ResolveUDPAddr("udp", ":33740")
if err != nil {
return fmt.Errorf("error resolving address: %v", err)
}
s, err = net.ListenUDP("udp", addr)
if err != nil {
return fmt.Errorf("error listening on udp %s: %v", addr, err)
}
defer s.Close()
gt7c.SendHB(s)
if err != nil {
return fmt.Errorf("error sending heart beat: %v", addr)
}
packageID := 0
packageNr := 0
for !gt7c.shallRestart && gt7c.shallRun {
buffer := make([]byte, 4096)
n, _, err := s.ReadFromUDP(buffer)
if err != nil {
gt7c.SendHB(s)
packageNr = 0
continue
}
packageNr++
ddata := salsa20Dec(buffer[:n])
if len(ddata) > 0 && int(binary.LittleEndian.Uint32(ddata[0x70:0x70+4])) > packageID {
gt7c.lastTimeDataReceived = time.Now()
packageID = int(binary.LittleEndian.Uint32(ddata[0x70 : 0x70+4]))
curlap := int(binary.LittleEndian.Uint16(ddata[0x74 : 0x74+2]))
gt7c.LastData = NewGTData(ddata)
if curlap == 0 {
gt7c.session.SpecialPacketTime = 0
}
if packageNr > 100 {
gt7c.SendHB(s)
packageNr = 0
}
}
}
}
return nil
}