feat: #1 telemetry record/playback with auto-race detection
- TelemetryRecorder: manual + auto mode (IsRaceOn edge detection) - TelemetryPlayer: timed packet replay into _handle_packet pipeline - .tsr format: [uint32 elapsed_ms][uint32 len][bytes] - Settings UI: start/stop, auto toggle, recording list, play button - API: /record/*, /playback/*, /recordings
This commit is contained in:
@@ -422,3 +422,50 @@ async def api_update_forward_targets(data: dict[str, Any]):
|
||||
save_config(cfg)
|
||||
telemetry_listener.forwarder.reload_targets()
|
||||
return {"ok": True, "active": telemetry_listener.forwarder.active}
|
||||
|
||||
|
||||
# ---- Record & Playback ----
|
||||
from server.recorder import TelemetryRecorder, TelemetryPlayer
|
||||
|
||||
_recorder = None
|
||||
_player = None
|
||||
|
||||
def _get_recorder():
|
||||
global _recorder
|
||||
if _recorder is None: _recorder = TelemetryRecorder(telemetry_listener)
|
||||
return _recorder
|
||||
|
||||
def _get_player():
|
||||
global _player
|
||||
if _player is None: _player = TelemetryPlayer(telemetry_listener)
|
||||
return _player
|
||||
|
||||
@router.post("/record/start")
|
||||
async def api_start_record():
|
||||
_get_recorder().start()
|
||||
return {"ok": True, "recording": True}
|
||||
|
||||
@router.post("/record/stop")
|
||||
async def api_stop_record():
|
||||
_get_recorder().stop()
|
||||
return {"ok": True, "recording": False}
|
||||
|
||||
@router.get("/record/status")
|
||||
async def api_record_status():
|
||||
return {"recording": _get_recorder().is_recording, "playing": _get_player().is_playing}
|
||||
|
||||
@router.get("/recordings")
|
||||
async def api_list_recordings():
|
||||
return TelemetryPlayer.list_recordings()
|
||||
|
||||
@router.post("/playback/start")
|
||||
async def api_start_playback(data: dict):
|
||||
filename = data.get("filename", "")
|
||||
if not filename: raise HTTPException(400, "filename required")
|
||||
_get_player().start(filename)
|
||||
return {"ok": True, "playing": True}
|
||||
|
||||
@router.post("/playback/stop")
|
||||
async def api_stop_playback():
|
||||
_get_player().stop()
|
||||
return {"ok": True, "playing": False}
|
||||
|
||||
Reference in New Issue
Block a user