├── .gitignore ├── LICENSE ├── README.md ├── examples ├── simpleserialprint.ino └── simulatorflags.ino └── src ├── GT7UDPParser.cpp ├── GT7UDPParser.h ├── Main.cpp ├── Salsa20.h ├── Salsa20.inl └── library.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 MacManley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gran Turismo 7 UDP | Library for use on ESP 32 / ESP8266 devices 2 | **Data Output from the Gran Turismo 7 Game** 3 | 4 | This program captures and parses packets that are sent by UDP from the Gran Turismo 7 game on PS4/PS5. This library is written specifically for usage on the ESP32 and ESP8266. 5 | 6 | # Usage: 7 | ```C++ 8 | #include "GT7UDPParser.h" 9 | GT7_UDP_Parser gt7Telem; 10 | Packet packetContent; 11 | 12 | void setup() 13 | { 14 | gt7Telem.begin(); 15 | gt7Telem.sendHeartbeat(); 16 | } 17 | 18 | void loop() 19 | { 20 | packetContent = gt7Telem.read(); 21 | } 22 | ``` 23 | 24 | ### Packet 25 | 26 | The following data types are used in the structure: 27 | 28 | | Type | Description | 29 | | ------ | ----------------------- | 30 | | uint8 | Unsigned 8-bit integer | 31 | | int8 | Signed 8-bit integer | 32 | | uint16 | Unsigned 16-bit integer | 33 | | int16 | Signed 16-bit integer | 34 | | uint32 | Unsigned 32-bit integer | 35 | | float | Floating point (32-bit) | 36 | | uint64 | Unsigned 64-bit integer | 37 | 38 | There is a singular encrypted packet sent out by GT7. The packet is encrypted in the Salsa20 stream cipher. The packets will only be sent from the console if there is a heartbeat sent from a device (in our case an ESP8266/ESP32). Once the console receives a heartbeat, it then establishes a connection with the ESP8266/ESP32 and sends the data to the IP address that was used to send the heartbeat. The console will expect a heartbeat every 100 packets (around 1.6 seconds) or else the connection will cease. 39 | 40 | ## The Packet: 41 | 42 | This singular packet details many different telemetry points such as positioning, car telemetry, laptimes and more. 43 | 44 | Size: 296 bytes 45 | 46 | Frequency: 60Hz (60 times a second) 47 | 48 | ```c# 49 | struct Packet { 50 | int32 magic; // Magic, different value defines what game is being played 51 | float position[3]; // Position on Track in meters in each axis 52 | float worldVelocity[3]; // Velocity in meters for each axis 53 | float rotation[3]; // Rotation (Pitch/Yaw/Roll) (RANGE: -1 -> 1) 54 | float orientationRelativeToNorth; // Orientation to North (RANGE: 1.0 (North) -> 0.0 (South)) 55 | float angularVelocity[3]; // Speed at which the car turns around axis in rad/s (RANGE: -1 -> 1) 56 | float bodyHeight; // Body height 57 | float EngineRPM; // Engine revolutions per minute 58 | uint8 iv[4]; // IV for Salsa20 encryption/decryption 59 | float fuelLevel; // Fuel level of car in liters 60 | float fuelCapacity; // Max fuel capacity for current car (RANGE: 100 (most cars) -> 5 (karts) -> 0 (electric cars)) 61 | float speed; // Speed in m/s 62 | float boost; // Offset by +1 (EXAMPLE: 1.0 = 0 X 100kPa, 2.0 = 1 x 100kPa) 63 | float oilPressure; // Oil pressure in bars 64 | float waterTemp; // Always 85 65 | float oilTemp; // Always 110 66 | float tyreTemp[4]; // Tyre temp for all 4 tires (FL -> FR -> RL -> RR) 67 | int32 packetId; // ID of packet 68 | int16 lapCount; // Lap count 69 | int16 totalLaps; // Laps to finish 70 | int32 bestLaptime; // Best lap time, defaults to -1 if not set 71 | int32 lastLaptime; // Previous lap time, defaults to -1 if not set 72 | int32 dayProgression; // Current time of day on track in ms 73 | int16 RaceStartPosition; // Position of the car before the start of the race, defaults to -1 after race start 74 | int16 preRaceNumCars; // Number of cars before the race start, defaults to -1 after start of the race 75 | int16 minAlertRPM; // Minimum RPM that the rev limiter displays an alert 76 | int16 maxAlertRPM; // Maximum RPM that the rev limiter displays an alert 77 | int16 calcMaxSpeed; // Highest possible speed achievable of the current transmission settings 78 | SimulatorFlags flags; // Packet flags 79 | uint8 gears; // First 4 bits: Current Gear, Last 4 bits: Suggested Gear, see appendices (getCurrentGearFromByte and getSuggestedGearFromByte) 80 | uint8 throttle; // Throttle (RANGE: 0 -> 255) 81 | uint8 brake; // Brake (RANGE: 0 -> 255) 82 | uint8 UNKNOWNBYTE1; // Padding byte 83 | float roadPlane[3]; // Banking of the road 84 | float roadPlaneDistance; // Distance above or below the plane, e.g a dip in the road is negative, hill is positive. 85 | float wheelRPS[4]; // Revolutions per second of tyres in rads 86 | float tyreRadius[4]; // Radius of the tyre in meters 87 | float suspHeight[4]; // Suspension height of the car 88 | uint32 UNKNOWNFLOAT2; // Unknown float 89 | uint32 UNKNOWNFLOAT3; // Unknown float 90 | uint32 UNKNOWNFLOAT4; // Unknown float 91 | uint32 UNKNOWNFLOAT5; // Unknown float 92 | uint32 UNKNOWNFLOAT6; // Unknown float 93 | uint32 UNKNOWNFLOAT7; // Unknown float 94 | uint32 UNKNOWNFLOAT8; // Unknown float 95 | uint32 UNKNOWNFLOAT9; // Unknown float 96 | float clutch; // Clutch (RANGE: 0.0 -> 1.0) 97 | float clutchEngagement; // Clutch Engangement (RANGE: 0.0 -> 1.0) 98 | float RPMFromClutchToGearbox; // Pretty much same as engine RPM, is 0 when clutch is depressed 99 | float transmissionTopSpeed; // Top speed as gear ratio value 100 | float gearRatios[8]; // Gear ratios of the car up to 8 101 | int32 carCode; // This value may be overriden if using a car with more then 9 gears, see appendices 102 | }; 103 | 104 | struct PacketInfo 105 | { 106 | Packet m_packet; 107 | }; 108 | ``` 109 | 110 | 111 | ## Encryption 112 | 113 | The packet is encrypted in the Salsa20 cipher stream with a 32 byte key and 8 byte nonce. 114 | 115 | ### ***Key*** 116 | 117 | ``` 118 | Simulator Interface Packet GT7 ver 0.0 119 | ``` 120 | 121 | This key is 39 bytes long. Each character in the string has to be converted into a byte slice of length 32, so the first 32 characters are used. Each character converted of the string will be represented by its corresponding ASCII value. 122 | 123 | ### ***Nonce*** 124 | 125 | The beginnings of the 8 byte nonce can be located at position \[0x40:0x44]. 4 bytes are extracted from the buffer. The extracted value is interpreted as a 32-bit integer, denoted as `iv1`. This value also undergoes an XOR operation with the constant `0xDEADBEAF`, producing a new integer value called `iv2`. These byte slices are then combined into the full 8 byte nonce, with the first 4 bytes initialized as `iv2`, and the last 4 bytes as `iv1`. 126 | 127 | 128 | # **Appendices** 129 | 130 | Here are some extra functions and also values used for some of the parameters in the UDP output 131 | 132 | ## Additional Functions 133 | 134 | These are the current additional functions needed to retrieve additional information not immediately present in the packet 135 | 136 | ```c# 137 | uint8 getCurrentGearFromByte() // Get the currently selected gear, Using gears 138 | uint8 getSuggestedGearFromByte() // Get the currently suggested gear, Using gears (Will be 15 if no gear is currently suggested) 139 | uint8 getPowertrainType() // Get the powertrain type, Using fuelCapacity, 0: Combustion Engine, 1: Electric, 2: Karts 140 | float getTyreSpeed() // Get linear tyre speed, using tyreRPS and tyreRadius 141 | float getTyreSlipRatio() // Get the tyre slip ratio, using speed and tyreSpeed 142 | ``` 143 | 144 | Here is how you can use them in your program: 145 | 146 | ```C++ 147 | #include "GT7UDPParser.h" 148 | GT7_UDP_Parser gt7Telem; 149 | Packet packetContent; 150 | 151 | void setup() 152 | { 153 | gt7Telem.begin(); 154 | gt7Telem.sendHeartbeat(); 155 | } 156 | 157 | void loop() 158 | { 159 | packetContent = gt7Telem.read(); 160 | currentGear = gt7Telem.getCurrentGearFromByte(); 161 | } 162 | ``` 163 | 164 | 165 | ## Simulator Flags 166 | 167 | 168 | There are bit flags sent out in the packet that detail game and car state. flags is a signed 16 bit integer. 169 | 170 | |ID |Name |Operation| 171 | |----|----------------------|---------------| 172 | |0 |None (No Active Flags)|flags == 0 | 173 | |1 |Car On Track |flags & 1 << 0 | 174 | |2 |Paused |flags & 1 << 1 | 175 | |3 |Loading Or Processing |flags & 1 << 2 | 176 | |4 |In Gear |flags & 1 << 3 | 177 | |5 |Has Turbo |flags & 1 << 4 | 178 | |6 |Rev Limit Alert Active|flags & 1 << 5 | 179 | |7 |Handbrake Active |flags & 1 << 6 | 180 | |8 |Lights Active |flags & 1 << 7 | 181 | |9 |High Beams Active |flags & 1 << 8 | 182 | |10 |Low Beams Active |flags & 1 << 9 | 183 | |11 |ASM Active |flags & 1 << 10| 184 | |12 |TCS Active |flags & 1 << 11| 185 | 186 | These bit flags can be accessed using the getFlag() function as shown below: 187 | 188 | ```C++ 189 | #include "GT7UDPParser.h" 190 | GT7_UDP_Parser gt7Telem; 191 | Packet packetContent; 192 | 193 | void loop() 194 | { 195 | packetContent = gt7Telem.read(); 196 | uint8_t TCSActive = gt7Telem.getFlag(12); 197 | if (TCSActive) { 198 | Serial.println("TCS: Active"); 199 | } else { 200 | Serial.println("TCS: Not Active"); 201 | } 202 | } 203 | ``` 204 | 205 | 206 | 207 | ## Car and Manufacturer IDs 208 | 209 | 210 | |ID |Name |Manufacturer| 211 | |----|-----------------------------------------------|-----| 212 | |24 |180SX Type X '96 |28 | 213 | |31 |Camaro Z28 '69 |7 | 214 | |36 |Chevelle SS 454 Sport Coupé |7 | 215 | |41 |Corvette Stingray (C3) '69 |7 | 216 | |48 |Fairlady 240ZG (HS30) '71 |28 | 217 | |63 |Corolla Levin 1600GT APEX (AE86) '83 |43 | 218 | |78 |Silvia K's Aero (S14) '96 |28 | 219 | |82 |Supra RZ '97 |43 | 220 | |104 |Sileighty '98 |28 | 221 | |105 |205 Turbo 16 Evolution 2 '86 |32 | 222 | |116 |GT-One (TS020) '99 |43 | 223 | |135 |S800 '66 |15 | 224 | |137 |Beat '91 |15 | 225 | |145 |Copen '02 |10 | 226 | |173 |R5 Turbo '80 |34 | 227 | |187 |Tuscan Speed 6 '00 |44 | 228 | |201 |Eunos Roadster (NA) '89 |21 | 229 | |203 |Integra Type R (DC2) '98 |15 | 230 | |204 |Civic Type R (EK) '98 |15 | 231 | |205 |RX-7 Spirit R Type A (FD) '02 |21 | 232 | |207 |MR2 GT-S '97 |43 | 233 | |210 |R34 GT-R V-spec II Nur '02 |28 | 234 | |211 |Lancer Evolution V GSR '98 |25 | 235 | |216 |McLaren F1 GTR Race Car '97 |6 | 236 | |293 |NSX Type R '92 |15 | 237 | |296 |787B '91 |21 | 238 | |301 |Lancer Evolution IV GSR '96 |25 | 239 | |315 |Cobra 427 '66 |36 | 240 | |334 |Clio V6 24V '00 |34 | 241 | |345 |Sprinter Trueno 1600GT APEX (S.Shigeno Version)|43 | 242 | |365 |155 2.5 V6 TI '93 |3 | 243 | |374 |RX-7 GT-X (FC) '90 |21 | 244 | |379 |Impreza Coupe WRX Type R STi Ver.VI '99 |38 | 245 | |387 |300 SL Coupe '54 |22 | 246 | |396 |NSX Type R '02 |15 | 247 | |451 |Impreza 22B-STi '98 |38 | 248 | |485 |GT-R GT500 '99 |28 | 249 | |489 |R33 GT-R V-spec '97 |28 | 250 | |514 |S2000 '99 |15 | 251 | |533 |Stratos '73 |18 | 252 | |543 |XJ220 '92 |17 | 253 | |575 |190 E 2.5-16 Evolution II '91 |22 | 254 | |604 |2000GT '67 |43 | 255 | |665 |Superbird '70 |55 | 256 | |688 |Integra Type R (DC2) '95 |15 | 257 | |709 |Fairlady Z 300ZX TT 2seater '89 |28 | 258 | |773 |R32 GT-R V-spec II '94 |28 | 259 | |779 |Cappuccino (EA11R) '91 |39 | 260 | |781 |Celica GT-FOUR Rally Car (ST205) '95 |43 | 261 | |799 |Lancer Evolution VIII MR GSR '04 |25 | 262 | |808 |V6 Escudo Pikes Peak Special spec.98 |39 | 263 | |810 |Sprinter Trueno 1600GT APEX (AE86) '83 |43 | 264 | |818 |Corvette (C2) '63 |7 | 265 | |821 |Civic Type R (EK) '97 |15 | 266 | |829 |Delta HF Integrale Evoluzione '91 |18 | 267 | |836 |Skyline 2000GT-R (KPGC110) '73 |28 | 268 | |837 |Skyline Hard Top 2000GT-R (KPGC10) '70 |28 | 269 | |843 |Supra 3.0GT Turbo A '88 |43 | 270 | |919 |Silvia Q's (S13) '88 |28 | 271 | |931 |Lancer Evolution III GSR '95 |25 | 272 | |942 |Corvette ZR-1 (C4) '89 |7 | 273 | |954 |R92CP '92 |28 | 274 | |959 |TT Coupe 3.2 quattro '03 |5 | 275 | |998 |Sauber Mercedes C9 '89 |22 | 276 | |1027|DeLorean S2 '04 |65 | 277 | |1040|Ford GT LM Race Car Spec II |13 | 278 | |1044|Sports 800 '65 |43 | 279 | |1067|XJR-9 '88 |17 | 280 | |1069|2J '70 |93 | 281 | |1365|R8 4.2 '07 |5 | 282 | |1370|MINI Cooper S '05 |51 | 283 | |1373|Viper GTS '02 |11 | 284 | |1378|F430 '06 |110 | 285 | |1384|Fairlady Z Version S (Z33) '07 |28 | 286 | |1385|Swift Sport '07 |39 | 287 | |1399|M3 '07 |6 | 288 | |1402|Viper SRT10 Coupe '06 |11 | 289 | |1409|F40 '92 |110 | 290 | |1410|512 BB '76 |110 | 291 | |1425|Ford GT LM Spec II Test Car |13 | 292 | |1426|Ford GT '06 |13 | 293 | |1431|RE Amemiya FD3S RX-7 |87 | 294 | |1433|Amuse S2000 GT1 Turbo |59 | 295 | |1448|SILVIA spec-R Aero (S15) '02 |28 | 296 | |1458|Fairlady Z (Z34) '08 |28 | 297 | |1461|Silvia K's Dia Selection (S13) '90 |28 | 298 | |1466|GT-R GT500 '08 |28 | 299 | |1470|Supra GT500 '97 |43 | 300 | |1474|Enzo Ferrari '02 |110 | 301 | |1480|Corvette ZR1 (C6) '09 |7 | 302 | |1481|Countach 25th Anniversary '88 |112 | 303 | |1484|Countach LP400 '74 |112 | 304 | |1504|458 Italia '09 |110 | 305 | |1506|Gallardo LP 560-4 '08 |112 | 306 | |1507|SLS AMG '10 |153 | 307 | |1508|Lancer Evolution VI GSR T.M. SCP '99 |25 | 308 | |1510|NSX GT500 '08 |15 | 309 | |1516|SC430 GT500 '08 |50 | 310 | |1523|500 F '68 |12 | 311 | |1527|500 1.2 8V Lounge SS '08 |12 | 312 | |1528|SLR McLaren '09 |22 | 313 | |1536|Zonda R '09 |30 | 314 | |1537|Prius G '09 |43 | 315 | |1539|GranTurismo S '08 |116 | 316 | |1540|McLaren F1 '94 |117 | 317 | |1541|TTS Coupe '09 |5 | 318 | |1542|Corvette Convertible (C3) '69 |7 | 319 | |1543|Challenger R/T '70 |11 | 320 | |1544|430 Scuderia '07 |110 | 321 | |1545|Murcielago LP 640 '09 |112 | 322 | |1549|Amuse NISMO 380RS Super Leggera |59 | 323 | |1551|330 P4 '67 |110 | 324 | |1553|XJ13 '66 |17 | 325 | |1562|LFA '10 |50 | 326 | |1563|Megane Trophy '11 |34 | 327 | |1565|Mark IV Race Car '67 |13 | 328 | |1578|8C Competizione '08 |3 | 329 | |1581|GT by Citroen Road Car |9 | 330 | |1582|Miura P400 Bertone Prototype '67 |112 | 331 | |1645|GIULIA TZ2 carrozzata da ZAGATO '65 |3 | 332 | |1646|908 HDi FAP '10 |32 | 333 | |1671|Sambabus Typ 2 '62 |46 | 334 | |1689|Civic Type R (EK) Touring Car |15 | 335 | |1722|MP4-12C '10 |117 | 336 | |1729|Mustang Mach 1 '71 |13 | 337 | |1746|Roadster Touring Car |21 | 338 | |1770|Aventador LP 700-4 '11 |112 | 339 | |1773|Scirocco R '10 |46 | 340 | |1778|Volkswagen 1200 '66 |46 | 341 | |1796|A110 '72 |86 | 342 | |1797|SLS AMG GT3 '11 |153 | 343 | |1893|Z8 '01 |6 | 344 | |1895|Dino 246 GT '71 |110 | 345 | |1896|Model S Signature Performance '12 |119 | 346 | |1898|One-77 '11 |4 | 347 | |1900|XNR Ghia Roadster '60 |55 | 348 | |1902|Z4 GT3 '11 |6 | 349 | |1904|M3 GT '11 |6 | 350 | |1905|GT-R NISMO GT3 '13 |28 | 351 | |1907|X-BOW R '12 |121 | 352 | |1916|Corvette C7 '14 |7 | 353 | |1925|G.T.350 '65 |36 | 354 | |1926|Cobra Daytona Coupe '64 |36 | 355 | |1927|Sport quattro S1 Pikes Peak '87 |5 | 356 | |1931|250 GT Berlinetta passo corto '61 |110 | 357 | |1932|1500 Biposto Bertone B.A.T 1 '52 |125 | 358 | |1933|MiTo '09 |3 | 359 | |1935|GT40 Mark I '66 |13 | 360 | |1956|Viper GTS '13 |11 | 361 | |1965|R18 TDI '11 |5 | 362 | |1973|Abarth 500 '09 |125 | 363 | |1975|RX500 '70 |21 | 364 | |1984|McLaren F1 GTR - BMW '95 |117 | 365 | |1985|Firebird Trans Am '78 |52 | 366 | |1986|R8 Gordini '66 |34 | 367 | |1987|Megane R.S. Trophy '11 |34 | 368 | |1990|Diablo GT '00 |112 | 369 | |2010|250 GTO '62 |110 | 370 | |2011|500 Mondial Pinin Farina Coupe '54 |110 | 371 | |2017|GTO '84 |110 | 372 | |2018|365 GTB4 '71 |110 | 373 | |2026|Aqua S '11 |43 | 374 | |2049|Veyron 16.4 '13 |113 | 375 | |2050|Huayra '13 |30 | 376 | |2051|Genesis Coupe 3.8 '13 |16 | 377 | |2055|Mercedes-Benz AMG VGT |153 | 378 | |2059|Corvette Stingray Racer Concept '59 |7 | 379 | |2060|Racing Kart 125 Shifter |33 | 380 | |2074|M4 '14 |6 | 381 | |2076|Mercedes-Benz AMG VGT Racing Series |153 | 382 | |2077|Red Bull X2014 Standard |33 | 383 | |2078|Red Bull X2014 Junior |33 | 384 | |2080|FT-1 |43 | 385 | |2087|BMW VGT |6 | 386 | |2095|Concept XR-PHEV EVOLUTION VGT |25 | 387 | |2098|GTI Roadster VGT |46 | 388 | |2099|VIZIV GT VGT |38 | 389 | |2101|TS030 Hybrid '12 |43 | 390 | |2103|DP-100 VGT |4 | 391 | |2106|FT-1 VGT |43 | 392 | |2107|Chaparral 2X VGT |93 | 393 | |2108|SRT Tomahawk X VGT |11 | 394 | |2109|MINI Clubman VGT |51 | 395 | |2110|SRT Tomahawk GTS-R VGT |11 | 396 | |2111|SRT Tomahawk S VGT |11 | 397 | |2112|Alpine VGT |86 | 398 | |2113|PEUGEOT VGT |32 | 399 | |2116|Alpine VGT Race |86 | 400 | |2117|INFINITI CONCEPT VGT |49 | 401 | |2118|LM55 VGT |21 | 402 | |2119|Italdesign VGT Street Mode |135 | 403 | |2120|Italdesign VGT Off-road Mode |135 | 404 | |2121|Honda Sports VGT |15 | 405 | |2122|IsoRivolta Zagato VGT |134 | 406 | |2123|LF-LC GT VGT |50 | 407 | |2124|GTI Supersport VGT |46 | 408 | |2127|GT-R LM NISMO '15 |28 | 409 | |2131|V12 Vantage GT3 '12 |4 | 410 | |2134|Bugatti VGT |113 | 411 | |2135|HYUNDAI N 2025 VGT |16 | 412 | |2136|4C '14 |3 | 413 | |2138|Mustang GT '15 |13 | 414 | |2139|RC F '14 |50 | 415 | |2141|Golf VII GTI '14 |46 | 416 | |2142|NISSAN CONCEPT 2020 VGT |28 | 417 | |2143|R8 LMS '15 |5 | 418 | |2144|S-FR '15 |43 | 419 | |2145|Focus ST '15 |13 | 420 | |2146|F-type R '14 |17 | 421 | |2147|Veneno '14 |112 | 422 | |2148|Roadster S (ND) '15 |21 | 423 | |2149|Mercedes-AMG GT S '15 |153 | 424 | |2150|Lancer Evolution Final '15 |25 | 425 | |2152|Charger SRT Hellcat '15 |11 | 426 | |2153|WRX STI Type S '14 |38 | 427 | |2154|86 GT '15 |43 | 428 | |2155|Polo GTI '14 |46 | 429 | |2156|2&4 powered by RC213V |15 | 430 | |2157|V8 Vantage Gr.4 |4 | 431 | |2158|458 Italia GT3 '13 |110 | 432 | |2159|Mustang Gr.3 |13 | 433 | |2160|Genesis Gr.3 |16 | 434 | |2161|GT-R Gr.4 |28 | 435 | |2162|LaFerrari '13 |110 | 436 | |2163|Genesis Gr.4 |16 | 437 | |2164|Mustang Gr.4 |13 | 438 | |2166|4C Gr.4 |3 | 439 | |2167|GT-R '17 |28 | 440 | |2169|TTS Coupe '14 |5 | 441 | |2170|A 45 AMG '13 |153 | 442 | |2171|Huracan LP 610-4 '15 |112 | 443 | |2172|DS 3 Racing '11 |154 | 444 | |2173|Atenza Sedan XD L Package '15 |21 | 445 | |2174|650S '14 |117 | 446 | |2175|V8 Vantage S '15 |4 | 447 | |2176|RCZ GT Line '15 |32 | 448 | |2177|Huracan GT3 '15 |112 | 449 | |2178|S-FR Racing Concept '16 |43 | 450 | |2179|Bugatti VGT (Gr.1) |113 | 451 | |2180|HYUNDAI N 2025 VGT (Gr.1) |16 | 452 | |2181|LM55 VGT (Gr.1) |21 | 453 | |2182|650S GT3 '15 |117 | 454 | |2183|Corvette C7 Gr.3 |7 | 455 | |2184|F-type Gr.3 |17 | 456 | |2185|Lancer Evolution Final Gr.3 |25 | 457 | |2186|WRX Gr.3 |38 | 458 | |2187|FT-1 VGT (Gr.3) |43 | 459 | |2188|R.S.01 GT3 '16 |34 | 460 | |2190|GT by Citroen Race Car (Gr.3) |9 | 461 | |2192|Volkswagen GTI VGT (Gr.3) |46 | 462 | |3183|PEUGEOT VGT (Gr.3) |32 | 463 | |3185|4C Gr.3 |3 | 464 | |3187|Alpine VGT '17 |86 | 465 | |3188|SRT Tomahawk VGT (Gr.1) |11 | 466 | |3192|SLS AMG Gr.4 |153 | 467 | |3209|M4 Safety Car |6 | 468 | |3210|Mercedes-AMG GT Safety Car |153 | 469 | |3214|Civic Type R (FK2) '15 |15 | 470 | |3215|208 GTi by Peugeot Sport '14 |32 | 471 | |3216|R.S.01 '16 |34 | 472 | |3217|Camaro SS '16 |7 | 473 | |3218|M6 GT3 Endurance Model '16 |6 | 474 | |3219|NSX '17 |15 | 475 | |3220|Clio R.S. 220 Trophy '15 |34 | 476 | |3221|M6 GT3 Sprint Model '16 |6 | 477 | |3222|86 GRMN '16 |43 | 478 | |3223|Viper SRT GT3-R '15 |11 | 479 | |3224|Mercedes-AMG GT3 '16 |153 | 480 | |3225|GT-R Safety Car |28 | 481 | |3227|LC500 '17 |50 | 482 | |3228|RC F GT3 prototype '16 |50 | 483 | |3229|Mustang Gr.B Rally Car |13 | 484 | |3230|Lancer Evolution Final Gr.B Rally Car |25 | 485 | |3231|Scirocco Gr.4 |46 | 486 | |3232|WRX Gr.B Rally Car |38 | 487 | |3234|Genesis Gr.B Rally Car |16 | 488 | |3235|NSX Gr.3 |15 | 489 | |3237|Atenza Gr.3 |21 | 490 | |3238|RCZ Gr.3 |32 | 491 | |3239|NSX Gr.B Rally Car |15 | 492 | |3241|GT-R Gr.B Rally Car |28 | 493 | |3242|RCZ Gr.B Rally Car |32 | 494 | |3245|M4 Gr.4 |6 | 495 | |3246|Veyron Gr.4 |113 | 496 | |3247|Corvette C7 Gr.4 |7 | 497 | |3248|GT by Citroen Gr.4 |9 | 498 | |3249|Viper Gr.4 |11 | 499 | |3251|NSX Gr.4 |15 | 500 | |3252|F-type Gr.4 |17 | 501 | |3253|Huracan Gr.4 |112 | 502 | |3254|RC F Gr.4 |50 | 503 | |3256|Atenza Gr.4 |21 | 504 | |3257|650S Gr.4 |117 | 505 | |3258|Lancer Evolution Final Gr.4 |25 | 506 | |3259|RCZ Gr.4 |32 | 507 | |3260|Megane Gr.4 |34 | 508 | |3261|WRX Gr.4 |38 | 509 | |3262|86 Gr.4 |43 | 510 | |3263|458 Italia Gr.4 |110 | 511 | |3264|Focus Gr.B Rally Car |13 | 512 | |3265|86 Gr.B Rally Car |43 | 513 | |3266|i3 '15 |6 | 514 | |3267|F12berlinetta '12 |110 | 515 | |3268|911 GT3 RS (991) '16 |136 | 516 | |3295|86 GT 'Limited' '16 |43 | 517 | |3296|Corvette C7 Gr.3 Road Car |7 | 518 | |3297|WRX STI Isle of Man '16 |38 | 519 | |3298|TT Cup '16 |5 | 520 | |3299|4C Gr.3 Road Car |3 | 521 | |3300|Mustang Gr.3 Road Car |13 | 522 | |3301|Lancer Evolution Final Gr.B Road Car |25 | 523 | |3303|RCZ Gr.3 Road Car |32 | 524 | |3304|WRX Gr.B Road Car |38 | 525 | |3305|Beetle Gr.3 |46 | 526 | |3306|Atenza Gr.3 Road Car |21 | 527 | |3309|Vulcan '16 |4 | 528 | |3310|Cayman GT4 Clubsport '16 |136 | 529 | |3311|911 RSR (991) '17 |136 | 530 | |3312|TS050 - Hybrid '16 |43 | 531 | |3313|919 Hybrid '16 |136 | 532 | |3314|Audi VGT |5 | 533 | |3315|McLaren VGT |117 | 534 | |3316|COPEN RJ VGT |10 | 535 | |3332|L500R HYbrid VGT 2017 |32 | 536 | |3333|L750R HYbrid VGT 2017 |32 | 537 | |3334|R18 '16 |5 | 538 | |3335|McLaren VGT (Gr.1) |117 | 539 | |3336|F-150 SVT Raptor '11 |13 | 540 | |3337|A110 '17 |86 | 541 | |3338|CHC 1967 Chevy Nova |147 | 542 | |3339|BRZ Drift Car '17 |38 | 543 | |3340|RC F GT3 '17 |50 | 544 | |3341|Pantera '71 |140 | 545 | |3342|F1500T-A |33 | 546 | |3343|DB11 '16 |4 | 547 | |3344|M3 Sport Evolution '89 |6 | 548 | |3345|GT-R NISMO '17 |28 | 549 | |3346|Mach Forty |148 | 550 | |3348|NSX CONCEPT-GT '16 |15 | 551 | |3349|RC F GT500 '16 |50 | 552 | |3350|GT-R NISMO GT500 '16 |28 | 553 | |3351|Audi e-tron VGT |5 | 554 | |3352|GR Supra Racing Concept '18 |43 | 555 | |3353|Clio R.S. 220 Trophy '16 |34 | 556 | |3354|BRZ S '15 |38 | 557 | |3356|Mini-Cooper 'S' '65 |51 | 558 | |3357|S660 '15 |15 | 559 | |3358|911 GT3 (996) '01 |136 | 560 | |3359|911 GT3 (997) '09 |136 | 561 | |3360|McLaren P1 GTR '16 |117 | 562 | |3361|E-type Coupe '61 |17 | 563 | |3362|F50 '95 |110 | 564 | |3363|DB3S '53 |4 | 565 | |3364|Greddy Fugu Z |149 | 566 | |3365|356 A/1500 GS GT Carrera Speedster '56 |136 | 567 | |3367|GR Supra RZ '19 |43 | 568 | |3368|Tundra TRD Pro '19 |43 | 569 | |3369|SR3 SL '13 |141 | 570 | |3370|Fit Hybrid '14 |15 | 571 | |3371|SF19 Super Formula / Toyota '19 |143 | 572 | |3372|SF19 Super Formula / Honda '19 |143 | 573 | |3373|962 C '88 |136 | 574 | |3374|Red Bull X2019 Competition |33 | 575 | |3375|356 A/1500 GS Carrera '56 |136 | 576 | |3376|D-type '54 |17 | 577 | |3377|Super Bee '70 |11 | 578 | |3383|Demio XD Touring '15 |21 | 579 | |3384|GTO Twin Turbo '91 |25 | 580 | |3385|911 Turbo (930) '81 |136 | 581 | |3387|Camaro ZL1 1LE Package '18 |7 | 582 | |3388|300 SEL 6.8 AMG '71 |153 | 583 | |3389|M3 '03 |6 | 584 | |3390|Taycan Turbo S '19 |136 | 585 | |3391|Shelby GT350R '16 |13 | 586 | |3392|Aventador LP 750-4 SV '15 |112 | 587 | |3393|Carrera GT '04 |136 | 588 | |3394|DBR9 GT1 '10 |4 | 589 | |3396|Jaguar VGT Coupe |17 | 590 | |3397|CLK-LM '98 |22 | 591 | |3398|CTR3 '07 |35 | 592 | |3399|GR Supra Race Car '19 |43 | 593 | |3400|911 GT1 Strassenversion '97 |136 | 594 | |3401|Crown Athlete G '13 |43 | 595 | |3402|Ford GT '17 |13 | 596 | |3403|Golf I GTI '83 |46 | 597 | |3404|911 Carrera RS CS (993) '95 |136 | 598 | |3405|R8 LMS Evo '19 |5 | 599 | |3406|Charger SRT Hellcat Safety Car |11 | 600 | |3407|Megane R.S. Trophy Safety Car |34 | 601 | |3408|Crown Athlete G Safety Car |43 | 602 | |3409|Mono '16 |144 | 603 | |3410|917K '70 |136 | 604 | |3411|Giulia GTAm '20 |3 | 605 | |3412|R8 Coupé V10 plus '16 |5 | 606 | |3413|BRZ STI Sport '18 |38 | 607 | |3414|Lambo V12 VGT |112 | 608 | |3415|8C 2900B Touring Berlinetta '38 |3 | 609 | |3416|Mercedes-AMG GT R '17 |153 | 610 | |3417|Jaguar VGT SV |17 | 611 | |3418|GR Supra RZ '20 |43 | 612 | |3419|RX-VISION GT3 CONCEPT |21 | 613 | |3420|Focus RS '18 |13 | 614 | |3421|Merak SS '80 |116 | 615 | |3422|3.0 CSL '73 |6 | 616 | |3423|Wicked Fabrication GT 51 |150 | 617 | |3424|Lancer Evolution IX MR GSR '06 |25 | 618 | |3426|Roadster Shop Rampage |151 | 619 | |3427|RX-8 Spirit R '12 |21 | 620 | |3428|S Barker Tourer '29 |22 | 621 | |3429|Fairlady Z 432 '69 |28 | 622 | |3430|Willys MB '45 |146 | 623 | |3431|911 Carrera RS (964) '92 |136 | 624 | |3432|Impreza Sedan WRX STi '04 |38 | 625 | |3433|FXX K '14 |110 | 626 | |3434|Testarossa '91 |110 | 627 | |3436|Ford GT Race Car '18 |13 | 628 | |3437|Mangusta '69 |140 | 629 | |3438|Abarth 595 SS '70 |125 | 630 | |3439|911 Carrera RS (993) '95 |136 | 631 | |3441|300 SL (W194) '52 |22 | 632 | |3442|A112 Abarth '85 |57 | 633 | |3443|308 GTB '75 |110 | 634 | |3444|1932 Ford Roadster Hot Rod |13 | 635 | |3445|DB5 '64 |4 | 636 | |3446|Spyder type 550/1500RS '55 |136 | 637 | |3449|Corvette C7 ZR1 '19 |7 | 638 | |3450|GT-R NISMO GT3 '18 |28 | 639 | |3451|GR Yaris RZ 'High performance' '20 |43 | 640 | |3452|917 LIVING LEGEND |136 | 641 | |3453|M3 '89 |6 | 642 | |3454|3.0 CSL '71 |6 | 643 | |3456|Swift Sport '17 |39 | 644 | |3457|A220 Race Car '68 |86 | 645 | |3458|Mercedes-AMG C 63 S '15 |153 | 646 | |3459|918 Spyder '13 |136 | 647 | |3462|GTO 'The Judge' '69 |52 | 648 | |3464|Corvette (C1) '58 |7 | 649 | |3466|Sierra RS 500 Cosworth '87 |13 | 650 | |3467|Civic Type R Limited Edition (FK8) '20 |15 | 651 | |3468|RGT 4.2 '16 |35 | 652 | |3469|F8 Tributo '19 |110 | 653 | |3471|Celica GT-Four (ST205) '94 |43 | 654 | |3473|Chiron '16 |113 | 655 | |3474|BRZ GT300 '21 |38 | 656 | |3475|MP4/4 '88 |117 | 657 | |3476|Suzuki Vision Gran Turismo |39 | 658 | |3477|Silvia spec-R Aero (S15) Touring Car |28 | 659 | |3478|Porsche VGT |136 | 660 | |3479|Jaguar VGT Roadster |17 | 661 | |3480|Swift Sport Gr.4 |39 | 662 | |3481|GR86 RZ '21 |43 | 663 | |3483|M2 Competition '18 |6 | 664 | |3485|Mercedes-AMG GT Black Series '20 |153 | 665 | |3486|Challenger SRT Demon '18 |11 | 666 | |3487|Mustang Boss 429 '69 |13 | 667 | |3488|Cayman GT4 '16 |136 | 668 | |3489|A6GCS/53 Spyder '54 |116 | 669 | |3490|Carrera GTS (904) '64 |136 | 670 | |3493|Skyline Super Silhouette Group 5 '84 |28 | 671 | |3494|Alphard Executive Lounge '18 |43 | 672 | |3495|RX-VISION '15 |21 | 673 | |3499|GR010 HYBRID '21 |43 | 674 | |3500|G70 3.3T AWD Prestige Package '22 |152 | 675 | |3501|G70 GR4 |152 | 676 | |3502|Genesis X GR3 |152 | 677 | |3503|RX-VISION GT3 CONCEPT Stealth Model |21 | 678 | |3504|Z Performance '23 |28 | 679 | |3505|Mangusta (Christian Dior) |140 | 680 | |3506|BRZ S '21 |38 | 681 | |3507|Porsche VGT Spyder |136 | 682 | |3508|SUZUKI Vision Gran Turismo (Gr.3 Version) |39 | 683 | |3509|911 Carrera RS (901) '73 |136 | 684 | |3510|Ferrari Vision Gran Turismo |110 | 685 | |3511|ID.R '19 |46 | 686 | |3512|Roadster NR-A (ND) '22 |21 | 687 | |3513|Silvia K's Type S (S14) '94 |28 | 688 | |3514|DS 21 Pallas '70 |9 | 689 | |3515|GR010 HYBRID (Olympic Esports Series) '21 |43 | 690 | |3517|Red Bull X2019 25th Anniversary |33 | 691 | |3518|Corvette C8 Stingray '20 |7 | 692 | |3519|959 '87 |136 | 693 | |3520|400R '95 |155 | 694 | |3521|Mazda3 '19 |21 | 695 | |3522|Maverick |156 | 696 | |3523|RS 5 Turbo DTM '19 |5 | 697 | |3524|GT-R NISMO (R32) '90 |28 | 698 | |3525|RA272 '65 |15 | 699 | |3526|Civic |157 | 700 | |3528|SF23 Super Formula / Honda '23 |143 | 701 | |3529|SF23 Super Formula / Toyota '23 |143 | 702 | |3530|Giulia Sprint GT Veloce '67 |3 | 703 | |3531|GT3 '20 |153 | 704 | |3532|Valkyrie '21 |4 | 705 | |3533|MC20 '20 |116 | 706 | |3534|Ambulance Himedic '21 |43 | 707 | |3535|GR Corolla MORIZO Edition '22 |43 | 708 | |3536|Civic Type R (FL5) '22 |15 | 709 | |3537|MAZDA3 Gr.4 |21 | 710 | |3538|Charger R/T 426 Hemi '68 |11 | 711 | |3539|911 GT3 RS (992) '22 |136 | 712 | |3540|Model 3 Performance '23 |119 | 713 | |3541|BVLGARI Aluminium VGT |158 | 714 | |3542|SKODA Vision Gran Turismo |159 | 715 | |3543|Genesis X Gran Berlinetta VGT Concept |152 | 716 | |3544|Genesis X Gran Racer Vision Gran Turismo Concept|152 | 717 | |3545|Jimny XC '18 |39 | 718 | |3546|AFEELA Prototype 2024 |160 | 719 | |3547|R4 GTL '85 |34 | 720 | |3548|Urus '18 |112 | 721 | |3550|Impreza Rally Car '98 |38 | 722 | |3551|M3 '97 |6 | 723 | |3553|GT-R Premium edition T-spec '24 |28 | 724 | |3554|Hiace Van DX '16 |43 | 725 | 726 | ## Credits 727 | 728 | Credit to [everard](https://github.com/everard/Salsa20) for the C++11 implementation of the stream cipher Salsa20. 729 | 730 | Credit to [Nenkai](https://github.com/Nenkai/PDTools) for help with IV setup and their work on GT7 UDP Capabilities. 731 | 732 | Credit to [ddm999](https://github.com/ddm999/gt7info) for CSV file of car and manufacturer IDs (I converted it into a markdown table). 733 | 734 | Thanks to members of GTPlanet for their findings on this hidden gem in GT7, find the thread [here](https://www.gtplanet.net/forum/threads/gt7-is-compatible-with-motion-rig.410728/). 735 | 736 | -------------------------------------------------------------------------------- /examples/simpleserialprint.ino: -------------------------------------------------------------------------------- 1 | //File: simpleserialprint.ino 2 | 3 | //#include "Wifi.h" // ESP32 WiFi include 4 | #include // ESP8266 WiFi include 5 | #include 6 | 7 | const char *SSID = "Your WiFi SSID"; 8 | const char *Password = "Your WiFi Password"; 9 | const IPAddress ip(..., ..., ., ..); // Insert your PS4/5 IP address here 10 | 11 | void startWiFi(); 12 | 13 | unsigned long previousT = 0; 14 | const long interval = 500; 15 | 16 | GT7_UDP_Parser gt7Telem; 17 | Packet packetContent; 18 | 19 | void setup() 20 | { 21 | Serial.begin(115200); 22 | startWiFi(); 23 | gt7Telem.begin(ip); 24 | gt7Telem.sendHeartbeat(); 25 | } 26 | 27 | void loop() 28 | { 29 | unsigned long currentT = millis(); 30 | packetContent= gt7Telem.readData(); 31 | 32 | float speed = (packetContent.packetContent.speed) * 3.6; // Times by 3.6 to convert from m/s to km/h 33 | 34 | Serial.print("Speed: "); 35 | Serial.println(speed); 36 | 37 | if (currentT - previousT >= interval) 38 | { // Send heartbeat every 500ms 39 | previousT = currentT; 40 | gt7Telem.sendHeartbeat(); 41 | //Serial.println("Pckt sent"); 42 | } 43 | } 44 | 45 | void startWiFi() 46 | { 47 | WiFi.mode(WIFI_STA); 48 | WiFi.begin(SSID, Password); 49 | Serial.print("Attempting to connect to "); 50 | Serial.println(SSID); 51 | 52 | uint8_t i = 0; 53 | while (WiFi.status() != WL_CONNECTED) 54 | { 55 | Serial.print('.'); 56 | delay(250); 57 | 58 | if ((++i % 16) == 0) 59 | { 60 | Serial.println(F(" still trying to connect")); 61 | } 62 | } 63 | 64 | Serial.print(F("Connection Successful | IP Address: ")); 65 | Serial.println(WiFi.localIP()); 66 | } 67 | -------------------------------------------------------------------------------- /examples/simulatorflags.ino: -------------------------------------------------------------------------------- 1 | //File: simulatorflags.ino 2 | 3 | //#include "Wifi.h" // ESP32 WiFi include 4 | #include // ESP8266 WiFi include 5 | #include 6 | 7 | const char *SSID = "Your WiFi SSID"; 8 | const char *Password = "Your WiFi Password"; 9 | const IPAddress ip(..., ..., ., ..); // Enter your Playstations IP here 10 | 11 | void startWiFi(); 12 | 13 | unsigned long previousT = 0; 14 | const long interval = 500; 15 | 16 | GT7_UDP_Parser gt7Telem; 17 | Packet packetContent; 18 | 19 | void setup() 20 | { 21 | Serial.begin(115200); 22 | startWiFi(); 23 | gt7Telem.begin(ip); 24 | gt7Telem.sendHeartbeat(); 25 | } 26 | 27 | void loop() 28 | { 29 | unsigned long currentT = millis(); 30 | packetContent = gt7Telem.readData(); 31 | 32 | for (int i = 0; i < 13; ++i) 33 | { 34 | uint8_t flag = gt7Telem.getFlag(i); 35 | Serial.print("Flag "); 36 | Serial.print(i); 37 | Serial.print(": "); 38 | Serial.println(flag); 39 | } 40 | 41 | if (currentT - previousT >= interval) 42 | { 43 | previousT = currentT; 44 | gt7Telem.sendHeartbeat(); 45 | } 46 | } 47 | 48 | void startWiFi() 49 | { 50 | WiFi.mode(WIFI_STA); 51 | WiFi.begin(SSID, Password); 52 | Serial.print("Attempting to connect to "); 53 | Serial.println(SSID); 54 | 55 | uint8_t i = 0; 56 | while (WiFi.status() != WL_CONNECTED) 57 | { 58 | Serial.print('.'); 59 | delay(250); 60 | 61 | if ((++i % 16) == 0) 62 | { 63 | Serial.println(F(" still trying to connect")); 64 | } 65 | } 66 | 67 | Serial.print(F("Connection Successful | IP Address: ")); 68 | Serial.println(WiFi.localIP()); 69 | } 70 | -------------------------------------------------------------------------------- /src/GT7UDPParser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "GT7UDPParser.h" 3 | #include "Salsa20.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | constexpr unsigned int localPort = 33740; 10 | constexpr unsigned int remotePort = 33739; 11 | constexpr char heartbeatMsg = 'A'; 12 | const std::string Key = "Simulator Interface Packet GT7 ver 0.0"; 13 | 14 | Packet packet; 15 | 16 | union IntToBytes { 17 | uint32_t integer; 18 | uint8_t bytes[4]; 19 | }; 20 | 21 | std::array GT7_UDP_Parser::getAsciiBytes(const std::string& inputString) { 22 | std::array asciiBytes = {}; 23 | for (size_t i = 0; i < inputString.size() && i < asciiBytes.size(); ++i) { 24 | asciiBytes[i] = static_cast(inputString[i]); 25 | } 26 | return asciiBytes; 27 | } 28 | 29 | void GT7_UDP_Parser::begin(const IPAddress playstationIP) { 30 | Udp.begin(localPort); 31 | remoteIP = playstationIP; 32 | dKey = getAsciiBytes(Key); 33 | } 34 | 35 | void GT7_UDP_Parser::sendHeartbeat(void) { 36 | Udp.beginPacket(remoteIP, remotePort); 37 | Udp.write(heartbeatMsg); 38 | Udp.endPacket(); 39 | } 40 | 41 | uint8_t GT7_UDP_Parser::getCurrentGearFromByte(void) { 42 | return packet.packetContent.gears & 0b00001111; // Extract the lower 4 bits for gears 43 | } 44 | 45 | // Function to extract suggested gear from the byte 46 | uint8_t GT7_UDP_Parser::getSuggestedGearFromByte(void) { 47 | return packet.packetContent.gears >> 4; // Shift right by 4 bits to get the upper 4 bits for suggested gear 48 | } 49 | 50 | 51 | uint8_t GT7_UDP_Parser::getPowertrainType(void) { 52 | if (static_cast(packet.packetContent.fuelCapacity) > 10) { 53 | return 0; 54 | } else { 55 | switch(static_cast(packet.packetContent.fuelCapacity)) { 56 | case 0: return 1; 57 | break; 58 | case 5: return 2; 59 | break; 60 | default: return 255; 61 | } 62 | } 63 | } 64 | 65 | float GT7_UDP_Parser::getTyreSpeed(int index) { 66 | if (index >= 0 && index < 4) { 67 | return abs(3.6f * packet.packetContent.tyreRadius[index] * packet.packetContent.wheelRPS[index]); 68 | } else return 0.0f; 69 | } 70 | 71 | float GT7_UDP_Parser::getTyreSlipRatio(int index) { 72 | float carSpeed = (packet.packetContent.speed * 3.6); 73 | float tyreSpeed = getTyreSpeed(index); 74 | if (carSpeed != 0.0f) { 75 | return tyreSpeed / carSpeed; 76 | } else return 0.0f; 77 | } 78 | 79 | uint8_t GT7_UDP_Parser::getFlag(int index) { 80 | SimulatorFlags flags = packet.packetContent.flags; 81 | int16_t indexAdjusted = index - 1; 82 | if (index < 0 || index > 13) { 83 | return 0; 84 | } 85 | 86 | if (index == 0) { 87 | return (static_cast(flags) == 0) ? 1 : 0; 88 | } else { 89 | return (index >= 1 && static_cast(flags) & (1 << indexAdjusted)) ? 1 : 0; 90 | } 91 | } 92 | 93 | Packet GT7_UDP_Parser::readData(void) { 94 | uint8_t recvBuffer[sizeof(packet.packetContent)]; 95 | memset(recvBuffer, 0, sizeof(packet.packetContent)); 96 | Udp.parsePacket(); 97 | if (Udp.read(recvBuffer, sizeof(recvBuffer)) == sizeof(packet.packetContent)) { 98 | int iv1 = *reinterpret_cast(&recvBuffer[0x40]); // Seed IV is always located there 99 | int iv2 = iv1 ^ 0xDEADBEAF; 100 | IntToBytes iv1Bytes, iv2Bytes; 101 | iv1Bytes.integer = iv1; 102 | iv2Bytes.integer = iv2; 103 | 104 | // Construct the 8-byte initialization vector 105 | uint8_t iv[8] = { 106 | iv2Bytes.bytes[0], iv2Bytes.bytes[1], iv2Bytes.bytes[2], iv2Bytes.bytes[3], 107 | iv1Bytes.bytes[0], iv1Bytes.bytes[1], iv1Bytes.bytes[2], iv1Bytes.bytes[3] 108 | }; 109 | 110 | ucstk::Salsa20 salsa20(dKey.data()); 111 | salsa20.setIv(iv); 112 | 113 | std::vector decryptedData(sizeof(recvBuffer)); 114 | salsa20.processBytes((recvBuffer), decryptedData.data(), 0x128); 115 | memcpy(&packet.packetContent, decryptedData.data(), sizeof(packet.packetContent)); 116 | } 117 | return packet; 118 | } -------------------------------------------------------------------------------- /src/GT7UDPParser.h: -------------------------------------------------------------------------------- 1 | #ifndef GT7UDPPARSER_H 2 | #define GT7UDPPARSER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #pragma pack(push, 1) 10 | 11 | enum class SimulatorFlags : int16_t { 12 | None = 0, 13 | 14 | CarOnTrack = 1 << 0, 15 | 16 | Paused = 1 << 1, 17 | 18 | LoadingOrProcessing = 1 << 2, 19 | 20 | InGear = 1 << 3, 21 | 22 | HasTurbo = 1 << 4, 23 | 24 | RevLimiterBlinkAlertActive = 1 << 5, 25 | 26 | HandBrakeActive = 1 << 6, 27 | 28 | LightsActive = 1 << 7, 29 | 30 | HighBeamActive = 1 << 8, 31 | 32 | LowBeamActive = 1 << 9, 33 | 34 | ASMActive = 1 << 10, 35 | 36 | TCSActive = 1 << 11 37 | }; 38 | 39 | struct GT7Packet { 40 | int32_t magic; // Magic, different value defines what game is being played 41 | float position[3]; // Position on Track in meters in each axis 42 | float worldVelocity[3]; // Velocity in meters for each axis 43 | float rotation[3]; // Rotation (Pitch/Yaw/Roll) (RANGE: -1 -> 1) 44 | float orientationRelativeToNorth; // Orientation to North (RANGE: 1.0 (North) -> 0.0 (South)) 45 | float angularVelocity[3]; // Speed at which the car turns around axis in rad/s (RANGE: -1 -> 1) 46 | float bodyHeight; // Body height 47 | float EngineRPM; // Engine revolutions per minute 48 | uint8_t iv[4]; // IV for Salsa20 encryption/decryption 49 | float fuelLevel; // Fuel level of car in liters 50 | float fuelCapacity; // Max fuel capacity for current car (RANGE: 100 (most cars) -> 5 (karts) -> 0 (electric cars)) 51 | float speed; // Speed in m/s 52 | float boost; // Offset by +1 (EXAMPLE: 1.0 = 0 X 100kPa, 2.0 = 1 x 100kPa) // TODO apply -1 offset 53 | float oilPressure; // Oil pressure in bars 54 | float waterTemp; // Constantly 85 55 | float oilTemp; // Constantly 110 56 | float tyreTemp[4]; // Tyre temp for all 4 tires (FL -> FR -> RL -> RR) 57 | int32_t packetId; // ID of packet 58 | int16_t lapCount; // Lap count 59 | int16_t totalLaps; // Laps to finish 60 | int32_t bestLaptime; // Best lap time, defaults to -1 if not set 61 | int32_t lastLaptime; // Previous lap time, defaults to -1 if not set 62 | int32_t dayProgression; // Current time of day on track in ms 63 | int16_t RaceStartPosition; // Position of the car before the start of the race, defaults to -1 after race start 64 | int16_t preRaceNumCars; // Number of cars before the race start, defaults to -1 after start of the race 65 | int16_t minAlertRPM; // Minimum RPM that the rev limiter displays an alert 66 | int16_t maxAlertRPM; // Maximum RPM that the rev limiter displays an alert 67 | int16_t calcMaxSpeed; // Highest possible speed achievable of the current transmission settings 68 | SimulatorFlags flags; // Packet flags // TODO: Get working 69 | uint8_t gears; // First 4 bits: Current Gear, Last 4 bits: Suggested Gear, see getCurrentGearFromByte and getSuggestedGearFromByte 70 | uint8_t throttle; // Throttle (RANGE: 0 -> 255) 71 | uint8_t brake; // Brake (RANGE: 0 -> 255) 72 | uint8_t PADDING; // Padding byte 73 | float roadPlane[3]; // Banking of the road 74 | float roadPlaneDistance; // Distance above or below the plane, e.g a dip in the road is negative, hill is positive. 75 | float wheelRPS[4]; // Revolutions per second of tyres in rads 76 | float tyreRadius[4]; // Radius of the tyre in meters 77 | float suspHeight[4]; // Suspension height of the car 78 | uint32_t UNKNOWNFLOATS[8]; // Unknown float 79 | float clutch; // Clutch (RANGE: 0.0 -> 1.0) 80 | float clutchEngagement; // Clutch Engangement (RANGE: 0.0 -> 1.0) 81 | float RPMFromClutchToGearbox; // Pretty much same as engine RPM, is 0 when clutch is depressed 82 | float transmissionTopSpeed; // Top speed as gear ratio value 83 | float gearRatios[8]; // Gear ratios of the car up to 8 84 | int32_t carCode; // This value may be overriden if using a car with more then 9 gears 85 | // 86 | }; 87 | 88 | struct Packet { 89 | GT7Packet packetContent; 90 | }; 91 | 92 | #pragma pack(pop) 93 | 94 | class GT7_UDP_Parser { 95 | public: 96 | void begin(const IPAddress playstationIP); 97 | void sendHeartbeat(); 98 | uint8_t getFlag(int index); 99 | uint8_t getCurrentGearFromByte(void); 100 | uint8_t getSuggestedGearFromByte(void); 101 | uint8_t getPowertrainType(void); 102 | float getTyreSpeed(int index); 103 | float getTyreSlipRatio(int index); 104 | Packet readData(); 105 | private: 106 | WiFiUDP Udp; 107 | IPAddress remoteIP; 108 | std::array dKey; 109 | std::array getAsciiBytes(const std::string& inputString); 110 | }; 111 | 112 | #endif -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 Nezametdinov E. Ildus 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include "Salsa20.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace ucstk; 31 | 32 | /** 33 | * Represents program. 34 | */ 35 | class Program 36 | { 37 | public: 38 | Program(): inputFileName_(), outputFileName_(), shouldShowHelp_(false) 39 | { 40 | std::memset(key_, 0, sizeof(key_)); 41 | } 42 | Program(const Program&) = delete; 43 | Program(Program&&) = delete; 44 | ~Program() {} 45 | Program& operator =(const Program&) = delete; 46 | Program& operator =(Program&&) = delete; 47 | 48 | /** 49 | * \brief Reads parameters from command line and validates them. 50 | * \param[in] argc number of command line arguments passed 51 | * \param[in] argv array of command line arguments 52 | * \return true on success 53 | */ 54 | bool initialize(int argc, char* argv[]) 55 | { 56 | std::string key; 57 | shouldShowHelp_ = false; 58 | 59 | for(int i = 0; i < argc; ++i) 60 | { 61 | std::string parameter = argv[i]; 62 | 63 | if(parameter == "-p") 64 | { 65 | if((argc - i - 1) != 3) 66 | break; 67 | 68 | inputFileName_ = argv[++i]; 69 | outputFileName_ = argv[++i]; 70 | key = argv[++i]; 71 | break; 72 | } 73 | 74 | if(parameter == "-h") 75 | { 76 | shouldShowHelp_ = true; 77 | return true; 78 | } 79 | } 80 | 81 | if(inputFileName_.empty()) 82 | { 83 | std::cout << "E: Input file name was not specified." << std::endl; 84 | return false; 85 | } 86 | 87 | if(outputFileName_.empty()) 88 | { 89 | std::cout << "E: Output file name was not specified." << std::endl; 90 | return false; 91 | } 92 | 93 | if(inputFileName_ == outputFileName_) 94 | { 95 | std::cout << "E: Input and output files should be distinct." << std::endl; 96 | return false; 97 | } 98 | 99 | if(key.empty()) 100 | { 101 | std::cout << "E: Key was not specified." << std::endl; 102 | return false; 103 | } 104 | 105 | if(!readKeyFromString(key)) 106 | { 107 | std::cout << "E: Invalid key value." << std::endl; 108 | return false; 109 | } 110 | 111 | return true; 112 | } 113 | 114 | /** 115 | * \brief Encrypts or decrypts the file. 116 | * \return true on success 117 | */ 118 | bool execute() 119 | { 120 | if(shouldShowHelp_) 121 | { 122 | std::cout << "Usage: salsa20 -p INPUT OUTPUT KEY" << std::endl; 123 | std::cout << " salsa20 -h" << std::endl; 124 | std::cout << std::endl << "Salsa20 is a stream cypher (see http://cr.yp.to/snuffle.html)."; 125 | std::cout << std::endl << std::endl; 126 | std::cout << "Options:" << std::endl; 127 | std::cout << " -h Shows this help text." << std::endl; 128 | std::cout << " -p Encrypts or decrypts file INPUT with KEY and outputs result to file OUTPUT."; 129 | std::cout << std::endl; 130 | std::cout << " KEY is a 32-byte key concatenated with 8-byte IV written in HEX."; 131 | std::cout << std::endl; 132 | return true; 133 | } 134 | 135 | std::ifstream inputStream(inputFileName_, std::ios_base::binary); 136 | if(!inputStream) 137 | { 138 | std::cout << "E: Could not open input file." << std::endl; 139 | return false; 140 | } 141 | 142 | std::ofstream outputStream(outputFileName_, std::ios_base::binary); 143 | if(!outputStream) 144 | { 145 | std::cout << "E: Could not create output file." << std::endl; 146 | return false; 147 | } 148 | 149 | const auto chunkSize = NUM_OF_BLOCKS_PER_CHUNK * Salsa20::BLOCK_SIZE; 150 | uint8_t chunk[chunkSize]; 151 | 152 | // determine size of the file 153 | inputStream.seekg(0, std::ios_base::end); 154 | auto fileSize = inputStream.tellg(); 155 | inputStream.seekg(0, std::ios_base::beg); 156 | 157 | // compute number of chunks and size of the remainder 158 | auto numChunks = fileSize / chunkSize; 159 | auto remainderSize = fileSize % chunkSize; 160 | 161 | // process file 162 | Salsa20 salsa20(key_); 163 | salsa20.setIv(&key_[IV_OFFSET]); 164 | std::cout << "Processing file \"" << inputFileName_ << '"' << std::endl; 165 | 166 | for(decltype(numChunks) i = 0; i < numChunks; ++i) 167 | { 168 | inputStream.read(reinterpret_cast(chunk), sizeof(chunk)); 169 | salsa20.processBlocks(chunk, chunk, NUM_OF_BLOCKS_PER_CHUNK); 170 | outputStream.write(reinterpret_cast(chunk), sizeof(chunk)); 171 | 172 | float percentage = 100.0f * static_cast(i + 1) / static_cast(numChunks); 173 | std::printf("[%3.2f]\r", percentage); 174 | } 175 | 176 | if(remainderSize != 0) 177 | { 178 | inputStream.read(reinterpret_cast(chunk), remainderSize); 179 | salsa20.processBytes(chunk, chunk, remainderSize); 180 | outputStream.write(reinterpret_cast(chunk), remainderSize); 181 | std::cout << "[100.00]"; 182 | } 183 | 184 | std::cout << std::endl << "OK" << std::endl; 185 | return true; 186 | } 187 | 188 | private: 189 | /// Helper constants 190 | enum: size_t 191 | { 192 | NUM_OF_BLOCKS_PER_CHUNK = 8192, 193 | IV_OFFSET = Salsa20::KEY_SIZE, 194 | KEY_SIZE = Salsa20::KEY_SIZE + Salsa20::IV_SIZE 195 | }; 196 | 197 | /** 198 | * \brief Reads byte from string. 199 | * \param[in] string string 200 | * \param[out] byte byte 201 | * \return true on success 202 | */ 203 | bool readByte(const char* string, uint8_t& byte) 204 | { 205 | byte = 0; 206 | 207 | for(uint32_t i = 0; i < 2; ++i) 208 | { 209 | uint8_t value = 0; 210 | char c = string[i]; 211 | 212 | if(c >= '0' && c <= '9') 213 | value = c - '0'; 214 | else if(c >= 'A' && c <= 'F') 215 | value = c - 'A' + 0x0A; 216 | else if(c >= 'a' && c <= 'f') 217 | value = c - 'a' + 0x0A; 218 | else 219 | return false; 220 | 221 | byte |= (value << (4 - i * 4)); 222 | } 223 | 224 | return true; 225 | } 226 | 227 | /** 228 | * \brief Reads key from string. 229 | * \param[in] string string 230 | * \return true on success 231 | */ 232 | bool readKeyFromString(const std::string& string) 233 | { 234 | auto stringLength = string.length(); 235 | 236 | if(stringLength != 2 * KEY_SIZE) 237 | return false; 238 | 239 | for(decltype(stringLength) i = 0; i < stringLength; i += 2) 240 | { 241 | if(!readByte(&string[i], key_[i / 2])) 242 | return false; 243 | } 244 | 245 | return true; 246 | } 247 | 248 | // Data members 249 | std::string inputFileName_, outputFileName_; 250 | uint8_t key_[KEY_SIZE]; 251 | bool shouldShowHelp_; 252 | 253 | }; 254 | 255 | // Entry point 256 | int main(int argc, char* argv[]) 257 | { 258 | Program program; 259 | 260 | if(!program.initialize(argc, argv)) 261 | return 1; 262 | 263 | if(!program.execute()) 264 | return 2; 265 | 266 | return 0; 267 | } -------------------------------------------------------------------------------- /src/Salsa20.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 Nezametdinov E. Ildus 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef SALSA20_H 24 | #define SALSA20_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace ucstk 32 | { 33 | 34 | using std::size_t; 35 | using std::int32_t; 36 | using std::uint8_t; 37 | using std::uint32_t; 38 | 39 | /** 40 | * Represents Salsa20 cypher. Supports only 256-bit keys. 41 | */ 42 | class Salsa20 43 | { 44 | public: 45 | /// Helper constants 46 | enum: size_t 47 | { 48 | VECTOR_SIZE = 16, 49 | BLOCK_SIZE = 64, 50 | KEY_SIZE = 32, 51 | IV_SIZE = 8 52 | }; 53 | 54 | /** 55 | * \brief Constructs cypher with given key. 56 | * \param[in] key 256-bit key 57 | */ 58 | inline Salsa20(const uint8_t* key = nullptr); 59 | Salsa20(const Salsa20&) = default; 60 | Salsa20(Salsa20&&) = default; 61 | ~Salsa20() = default; 62 | Salsa20& operator =(const Salsa20&) = default; 63 | Salsa20& operator =(Salsa20&&) = default; 64 | 65 | /** 66 | * \brief Sets key. 67 | * \param[in] key 256-bit key 68 | */ 69 | inline void setKey(const uint8_t* key); 70 | 71 | /** 72 | * \brief Sets IV. 73 | * \param[in] iv 64-bit IV 74 | */ 75 | inline void setIv(const uint8_t* iv); 76 | 77 | /** 78 | * \brief Generates key stream. 79 | * \param[out] output generated key stream 80 | */ 81 | inline void generateKeyStream(uint8_t output[BLOCK_SIZE]); 82 | 83 | /** 84 | * \brief Processes blocks. 85 | * \param[in] input input 86 | * \param[out] output output 87 | * \param[in] numBlocks number of blocks 88 | */ 89 | inline void processBlocks(const uint8_t* input, uint8_t* output, size_t numBlocks); 90 | 91 | /** 92 | * \brief Processes bytes. 93 | * 94 | * This function should be used carefully. If number of bytes is not multiple of 95 | * block size, then next call to the processBlocks function will be invalid. 96 | * Normally this function should be used once at the end of encryption or 97 | * decryption. 98 | * \param[in] input input 99 | * \param[out] output output 100 | * \param[in] numBytes number of bytes 101 | */ 102 | inline void processBytes(const uint8_t* input, uint8_t* output, size_t numBytes); 103 | 104 | private: 105 | /** 106 | * \brief Rotates value. 107 | * \param[in] value value 108 | * \param[in] numBits number of bits to rotate 109 | * \return result of the rotation 110 | */ 111 | inline uint32_t rotate(uint32_t value, uint32_t numBits); 112 | 113 | /** 114 | * \brief Converts 32-bit unsigned integer value to the array of bytes. 115 | * \param[in] value 32-bit unsigned integer value 116 | * \param[out] array array of bytes 117 | */ 118 | inline void convert(uint32_t value, uint8_t* array); 119 | 120 | /** 121 | * \brief Converts array of bytes to the 32-bit unsigned integer value. 122 | * \param[in] array array of bytes 123 | * \return 32-bit unsigned integer value 124 | */ 125 | inline uint32_t convert(const uint8_t* array); 126 | 127 | // Data members 128 | uint32_t vector_[VECTOR_SIZE]; 129 | 130 | }; 131 | 132 | } 133 | 134 | #include "Salsa20.inl" 135 | #endif -------------------------------------------------------------------------------- /src/Salsa20.inl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 Nezametdinov E. Ildus 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include "Salsa20.h" 24 | 25 | namespace ucstk 26 | { 27 | 28 | Salsa20::Salsa20(const uint8_t* key) 29 | { 30 | std::memset(vector_, 0, sizeof(vector_)); 31 | setKey(key); 32 | } 33 | 34 | //---------------------------------------------------------------------------------- 35 | void Salsa20::setKey(const uint8_t* key) 36 | { 37 | static const char constants[] = "expand 32-byte k"; 38 | 39 | if(key == nullptr) 40 | return; 41 | 42 | vector_[0] = convert(reinterpret_cast(&constants[0])); 43 | vector_[1] = convert(&key[0]); 44 | vector_[2] = convert(&key[4]); 45 | vector_[3] = convert(&key[8]); 46 | vector_[4] = convert(&key[12]); 47 | vector_[5] = convert(reinterpret_cast(&constants[4])); 48 | 49 | std::memset(&vector_[6], 0, 4 * sizeof(uint32_t)); 50 | 51 | vector_[10] = convert(reinterpret_cast(&constants[8])); 52 | vector_[11] = convert(&key[16]); 53 | vector_[12] = convert(&key[20]); 54 | vector_[13] = convert(&key[24]); 55 | vector_[14] = convert(&key[28]); 56 | vector_[15] = convert(reinterpret_cast(&constants[12])); 57 | } 58 | 59 | //---------------------------------------------------------------------------------- 60 | void Salsa20::setIv(const uint8_t* iv) 61 | { 62 | if(iv == nullptr) 63 | return; 64 | 65 | vector_[6] = convert(&iv[0]); 66 | vector_[7] = convert(&iv[4]); 67 | vector_[8] = vector_[9] = 0; 68 | } 69 | 70 | //---------------------------------------------------------------------------------- 71 | void Salsa20::generateKeyStream(uint8_t output[BLOCK_SIZE]) 72 | { 73 | uint32_t x[VECTOR_SIZE]; 74 | std::memcpy(x, vector_, sizeof(vector_)); 75 | 76 | for(int32_t i = 20; i > 0; i -= 2) 77 | { 78 | x[4 ] ^= rotate(static_cast(x[0 ] + x[12]), 7); 79 | x[8 ] ^= rotate(static_cast(x[4 ] + x[0 ]), 9); 80 | x[12] ^= rotate(static_cast(x[8 ] + x[4 ]), 13); 81 | x[0 ] ^= rotate(static_cast(x[12] + x[8 ]), 18); 82 | x[9 ] ^= rotate(static_cast(x[5 ] + x[1 ]), 7); 83 | x[13] ^= rotate(static_cast(x[9 ] + x[5 ]), 9); 84 | x[1 ] ^= rotate(static_cast(x[13] + x[9 ]), 13); 85 | x[5 ] ^= rotate(static_cast(x[1 ] + x[13]), 18); 86 | x[14] ^= rotate(static_cast(x[10] + x[6 ]), 7); 87 | x[2 ] ^= rotate(static_cast(x[14] + x[10]), 9); 88 | x[6 ] ^= rotate(static_cast(x[2 ] + x[14]), 13); 89 | x[10] ^= rotate(static_cast(x[6 ] + x[2 ]), 18); 90 | x[3 ] ^= rotate(static_cast(x[15] + x[11]), 7); 91 | x[7 ] ^= rotate(static_cast(x[3 ] + x[15]), 9); 92 | x[11] ^= rotate(static_cast(x[7 ] + x[3 ]), 13); 93 | x[15] ^= rotate(static_cast(x[11] + x[7 ]), 18); 94 | x[1 ] ^= rotate(static_cast(x[0 ] + x[3 ]), 7); 95 | x[2 ] ^= rotate(static_cast(x[1 ] + x[0 ]), 9); 96 | x[3 ] ^= rotate(static_cast(x[2 ] + x[1 ]), 13); 97 | x[0 ] ^= rotate(static_cast(x[3 ] + x[2 ]), 18); 98 | x[6 ] ^= rotate(static_cast(x[5 ] + x[4 ]), 7); 99 | x[7 ] ^= rotate(static_cast(x[6 ] + x[5 ]), 9); 100 | x[4 ] ^= rotate(static_cast(x[7 ] + x[6 ]), 13); 101 | x[5 ] ^= rotate(static_cast(x[4 ] + x[7 ]), 18); 102 | x[11] ^= rotate(static_cast(x[10] + x[9 ]), 7); 103 | x[8 ] ^= rotate(static_cast(x[11] + x[10]), 9); 104 | x[9 ] ^= rotate(static_cast(x[8 ] + x[11]), 13); 105 | x[10] ^= rotate(static_cast(x[9 ] + x[8 ]), 18); 106 | x[12] ^= rotate(static_cast(x[15] + x[14]), 7); 107 | x[13] ^= rotate(static_cast(x[12] + x[15]), 9); 108 | x[14] ^= rotate(static_cast(x[13] + x[12]), 13); 109 | x[15] ^= rotate(static_cast(x[14] + x[13]), 18); 110 | } 111 | 112 | for(size_t i = 0; i < VECTOR_SIZE; ++i) 113 | { 114 | x[i] += vector_[i]; 115 | convert(x[i], &output[4 * i]); 116 | } 117 | 118 | ++vector_[8]; 119 | vector_[9] += vector_[8] == 0 ? 1 : 0; 120 | } 121 | 122 | //---------------------------------------------------------------------------------- 123 | void Salsa20::processBlocks(const uint8_t* input, uint8_t* output, size_t numBlocks) 124 | { 125 | assert(input != nullptr && output != nullptr); 126 | 127 | uint8_t keyStream[BLOCK_SIZE]; 128 | 129 | for(size_t i = 0; i < numBlocks; ++i) 130 | { 131 | generateKeyStream(keyStream); 132 | 133 | for(size_t j = 0; j < BLOCK_SIZE; ++j) 134 | *(output++) = keyStream[j] ^ *(input++); 135 | } 136 | } 137 | 138 | //---------------------------------------------------------------------------------- 139 | void Salsa20::processBytes(const uint8_t* input, uint8_t* output, size_t numBytes) 140 | { 141 | assert(input != nullptr && output != nullptr); 142 | 143 | uint8_t keyStream[BLOCK_SIZE]; 144 | size_t numBytesToProcess; 145 | 146 | while(numBytes != 0) 147 | { 148 | generateKeyStream(keyStream); 149 | numBytesToProcess = numBytes >= BLOCK_SIZE ? BLOCK_SIZE : numBytes; 150 | 151 | for(size_t i = 0; i < numBytesToProcess; ++i, --numBytes) 152 | *(output++) = keyStream[i] ^ *(input++); 153 | } 154 | } 155 | 156 | //---------------------------------------------------------------------------------- 157 | uint32_t Salsa20::rotate(uint32_t value, uint32_t numBits) 158 | { 159 | return (value << numBits) | (value >> (32 - numBits)); 160 | } 161 | 162 | //---------------------------------------------------------------------------------- 163 | void Salsa20::convert(uint32_t value, uint8_t* array) 164 | { 165 | array[0] = static_cast(value >> 0); 166 | array[1] = static_cast(value >> 8); 167 | array[2] = static_cast(value >> 16); 168 | array[3] = static_cast(value >> 24); 169 | } 170 | 171 | //---------------------------------------------------------------------------------- 172 | uint32_t Salsa20::convert(const uint8_t* array) 173 | { 174 | return ((static_cast(array[0]) << 0) | 175 | (static_cast(array[1]) << 8) | 176 | (static_cast(array[2]) << 16) | 177 | (static_cast(array[3]) << 24)); 178 | } 179 | 180 | } -------------------------------------------------------------------------------- /src/library.properties: -------------------------------------------------------------------------------- 1 | name=GT7 UDP Telemetry Parser 2 | version=1.4.9 3 | author=MacManley 4 | maintainer=MacManley 5 | sentence=UDP Telemetry Parser for Gran Turismo 7 6 | paragraph=UDP Telemetry Parser for Gran Turismo 7 7 | category=Communication 8 | depends=WiFiUDP, Salsa20 9 | url=https://github.com/MacManley/gt7-udp 10 | architectures=* 11 | --------------------------------------------------------------------------------