refactor: extract test data generator to server/test_mode.py
- TestDataGenerator class: builds 324-byte Forza packets, runs async loop at 30fps - Simulated data passes through _handle_packet (parser -> WS -> forwarder) - Listener delegates to test_mode.get_generator() - Cleaner separation: listener.py no longer contains test logic
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import random
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
from typing import Any, Callable
|
||||
|
||||
@@ -60,7 +58,6 @@ class TelemetryListener:
|
||||
self._last_packet_time: float = 0.0
|
||||
self._packet_count: int = 0
|
||||
self.forwarder = DataForwarder()
|
||||
self._test_task: asyncio.Task | None = None
|
||||
|
||||
@property
|
||||
def is_running(self) -> bool:
|
||||
@@ -126,92 +123,17 @@ class TelemetryListener:
|
||||
|
||||
@property
|
||||
def is_testing(self) -> bool:
|
||||
return self._test_task is not None and not self._test_task.done()
|
||||
from server.test_mode import _test_generator
|
||||
return _test_generator.running
|
||||
|
||||
def start_test_mode(self):
|
||||
if self._test_task and not self._test_task.done():
|
||||
return
|
||||
self._test_task = asyncio.ensure_future(self._test_loop())
|
||||
logger.info("UI test mode started")
|
||||
from server.test_mode import _test_generator
|
||||
_test_generator.listener = self
|
||||
_test_generator.start()
|
||||
|
||||
def stop_test_mode(self):
|
||||
if self._test_task and not self._test_task.done():
|
||||
self._test_task.cancel()
|
||||
self._test_task = None
|
||||
logger.info("UI test mode stopped")
|
||||
|
||||
async def _test_loop(self):
|
||||
import math
|
||||
phase = 0.0
|
||||
gear = 1
|
||||
gear_timer = 0
|
||||
while True:
|
||||
await asyncio.sleep(1.0 / 30.0)
|
||||
phase += 0.06
|
||||
gear_timer += 1
|
||||
if gear_timer > 50:
|
||||
gear_timer = 0
|
||||
gear = (gear % 6) + 1
|
||||
|
||||
max_rpm = 8000.0
|
||||
rpm = max_rpm * (0.15 + 0.55 * abs(math.sin(phase)))
|
||||
speed_kmh = rpm / max_rpm * 320.0 + random.uniform(-5, 5)
|
||||
throttle = max(0.0, min(1.0, 0.15 + 0.65 * abs(math.sin(phase + 0.5))))
|
||||
brake = max(0.0, min(1.0, random.uniform(0, 0.4) if random.random() > 0.75 else 0))
|
||||
steering = math.sin(phase * 0.25) * 0.5
|
||||
fuel = max(0.0, 1.0 - phase * 0.008)
|
||||
best_lap = 92.0 + random.uniform(-1, 1)
|
||||
last_lap = best_lap + random.uniform(0.3, 2.5)
|
||||
lap_time = last_lap * random.uniform(0.2, 0.85)
|
||||
|
||||
td = TelemetryData(
|
||||
game_id=get_config().get("selected_game_id", "test"),
|
||||
timestamp=time.time(),
|
||||
speed_kmh=speed_kmh, speed_mph=speed_kmh * 0.621371,
|
||||
rpm=rpm, max_rpm=max_rpm, gear=gear,
|
||||
throttle=throttle, brake=brake, clutch=0.0, steering=steering,
|
||||
lap_time=lap_time, best_lap=best_lap, last_lap=last_lap,
|
||||
lap_number=int(phase) % 15, fuel=fuel,
|
||||
boost=random.uniform(0, 1.5),
|
||||
horsepower=rpm / max_rpm * 400, torque=rpm / max_rpm * 500,
|
||||
engine_temp=80 + random.uniform(-10, 20),
|
||||
oil_temp=90 + random.uniform(-5, 15),
|
||||
raw={"test_mode": True},
|
||||
)
|
||||
|
||||
self._last_packet_time = time.time()
|
||||
self._packet_count += 1
|
||||
self._latest_data = td
|
||||
|
||||
from server.websocket import ws_manager
|
||||
ws_manager.push_telemetry(td)
|
||||
|
||||
if self.forwarder._sock and self.forwarder._targets:
|
||||
buf = bytearray(324)
|
||||
struct.pack_into("<i", buf, 0, 1)
|
||||
struct.pack_into("<I", buf, 4, int(time.time() * 1000))
|
||||
struct.pack_into("<f", buf, 8, max_rpm)
|
||||
struct.pack_into("<f", buf, 12, 800.0)
|
||||
struct.pack_into("<f", buf, 16, rpm)
|
||||
struct.pack_into("<f", buf, 256, speed_kmh / 3.6)
|
||||
struct.pack_into("<f", buf, 260, rpm / max_rpm * 400000)
|
||||
struct.pack_into("<f", buf, 264, torque)
|
||||
struct.pack_into("<f", buf, 284, boost)
|
||||
struct.pack_into("<f", buf, 288, fuel)
|
||||
struct.pack_into("<f", buf, 296, best_lap)
|
||||
struct.pack_into("<f", buf, 300, last_lap)
|
||||
struct.pack_into("<f", buf, 304, lap_time)
|
||||
struct.pack_into("<H", buf, 312, int(phase) % 15)
|
||||
struct.pack_into("<B", buf, 314, 1)
|
||||
struct.pack_into("<B", buf, 315, int(throttle * 255))
|
||||
struct.pack_into("<B", buf, 316, int(brake * 255))
|
||||
struct.pack_into("<B", buf, 319, gear)
|
||||
struct.pack_into("<b", buf, 320, int(steering * 127))
|
||||
self.forwarder.forward(bytes(buf))
|
||||
|
||||
for cb in self._callbacks:
|
||||
try: cb(td)
|
||||
except Exception: pass
|
||||
from server.test_mode import _test_generator
|
||||
_test_generator.stop()
|
||||
|
||||
def _get_parser(self, key: str) -> BaseParser:
|
||||
if key not in self._parser_cache:
|
||||
|
||||
Reference in New Issue
Block a user