Commit graph

21 commits

Author SHA1 Message Date
bcacd4b8a7 feat: racing line analysis, frame trimming, persistence fix
- Add analyze_racing_line(): lap-by-lap path extraction with speed data,
  downsampled to 400 pts/lap. Spline-sorted in spline mode for clean paths.
- Add complete_lap_frames() + split_by_lap() utilities: filters to laps
  whose spline spans >= 0.9 of [0,1], discarding partial out/in laps.
- Fix complete_lap_frames logic: was checking if segment STARTS at
  spline~0, but a full lap starting mid-track (joined before start/finish)
  also qualifies. Now checks spline span coverage instead.
- WOT window trimming in analyze_shift_points(): trims to first/last
  frame with throttle >= 0.9, filters rev-limiter plateau (acc_g < 0.01).
- Fix frame persistence race condition: persist_session now writes frames
  synchronously instead of spawning a thread. Multiple concurrent calls
  could race on the same temp file, with earlier calls (empty frames)
  overwriting later calls with correct data.
- atomic_write uses UUID-based temp file names as defense-in-depth.
- PositionMode now derives Deserialize for RacingLineAnalysis.
- Empty game/track_name validation in build_track() endpoint.
- Wired RacingLine use case into analysis dispatch.
2026-07-04 11:17:06 +02:00
d86a87ab7d refactor: fix all compiler + clippy warnings
- analysis.rs: use .clamp() instead of .max().min(), saturating_sub,
  inline corner_start into corner_start_s (dead assignment removed)
- binary_utils.rs, parser_pcars.rs: use std::array::from_fn for array reads
- recording.rs: std::io::Error::other() instead of Error::new(ErrorKind::Other),
  #[allow(dead_code)] on diagnostic methods (len, total_pushed, dropped_count, ring_stats)
- track_model.rs: prefix unused path vars with _, #[allow(dead_code)] on exists()
- parser_ksudp.rs: fix doc list item indentation
- session.rs: std::mem::take instead of mem::replace(..., Default::default())

cargo build: 0 warnings, clippy: 0 warnings, 33 tests pass
2026-06-25 11:40:38 +02:00
9a4ca18864 legal: add AGPL-3.0 license, copyright headers, commercial license info
- LICENSE: GNU AGPL-3.0 (full text)
- Copyright headers added to all 15 source files in src/
- COMMERCIAL_LICENSE.md: dual-license explanation (AGPL + commercial)
2026-06-25 11:09:04 +02:00
f576a45d8f docs: add car_grip use case and grip analysis response format to README 2026-06-24 10:21:38 +02:00
652d059b1d feat: car_grip use case — envelope extraction grip analysis
- New UseCase::CarGrip variant with race-pace guidance
- analyze_car_grip(): speed-binned envelope (peak lateral/accel/brake G),
  grip circle scatter, steering response scatter
- Envelope extraction: 10 km/h bins, max |G| per bin
- Scatter downsampled to ~800 points
- Dispatch wired in analyze()
- 33 tests pass
2026-06-24 10:18:23 +02:00
3985e81cdd docs: fix build track endpoint path in API table 2026-06-24 09:46:42 +02:00
ba84fc0a6b docs: update README and AGENTS.md for session persistence, characteristics, track endpoints
- Document session persistence model (split metadata/frames files, lazy load)
- Add characteristics API endpoints and response examples
- Add track API endpoints to endpoint table
- Fix use case name track_map → track_mapping
- Update architecture with characteristics.rs and track_model.rs
- Update test count to 33
- Rewrite AGENTS.md: accurate ports, persistence paths, tech stack
2026-06-24 09:40:13 +02:00
ed7dbcf1c9 feat: persistent sessions, remove track_map use case, car characteristics DB
- Remove obsolete TrackMap use case variant (superseded by TrackMapping)
- Add session/run/analysis persistence: metadata to data/sessions/<id>.json,
  frames to <id>.frames.json (split for lazy loading)
- Atomic writes (temp + rename), compact JSON, off-thread frame serialization
- load_all loads metadata only at startup; ensure_frames_loaded lazy-loads
  frames before analysis
- Normalize Recording runs to Stopped on reload (stale ring-buffer markers)
- Cache car_name on UseCaseSession during run finalization
- Add characteristics.rs: aggregate shift-point data per car across sessions
- New API: GET /api/characteristics/cars, GET /api/characteristics/cars/{car}
- Add Deserialize to TelemetryFrame and FeedSource for session round-trip
2026-06-24 09:32:16 +02:00
937090681f feat: add track map implementation — persistent TrackModel, dual position mode, boundary recording, track API endpoints
Backend tasks A→B→C→F→E→D from the Track Map Implementation plan:

A. PCARS V1 position data: read world_position (3×i16) and current_lap_distance
   from viewed participant entry, compute derived spline_position, add unit tests.

B. Dual position mode: auto-detect spline vs coordinate mode in track map analysis,
   compute cumulative 2D distance as pseudo-spline for PCARS/future games.

C. Persistent TrackModel: Corner, Sector, TrackModel data structures with serde,
   TrackModelStore with async CRUD at data/tracks/<game>/<track_name>.json.

F. Track model building algorithm: resample boundaries, compute center line,
   track width, heading, curvature, auto-detect corners (κ > 0.005), 3 sectors,
   coordinate normalization to [0,1]².

E. TrackMapping use case: new boundary recording workflow with step-by-step
   guidance, session integration.

D. Track API endpoints: GET/DELETE /api/tracks/{game}/{track_name},
   GET /api/tracks, GET .../corners, POST /api/tracks/build.
2026-06-08 14:17:39 +02:00
9fae8ba9d8 feat: add run deletion, session reopen, and feed merging (v0.6.0)
- DELETE /api/sessions/{id}/runs/{run_id} removes stopped runs
- POST /api/sessions/{id}/reopen transitions Completed → Active
- Optional merge_feeds field on POST /api/sessions/{id}/runs combines
  frames from multiple feeds with priority-based deduplication
- In-place merge_frames() avoids 2× peak memory
- All new fields use #[serde(default)] for backward compatibility
- Updated README.md with new endpoints and feed merging docs
2026-06-06 09:38:42 +02:00
e3aa511ac7 feat: KSUDP parser fix, warnings system, shift point rewrite, code quality (v0.5.1)
Bug Fixes:
- Fixed KSUDP binary parser offsets from packed (323B) to natural C
  alignment (328B) — 3 bytes padding after char identifier, 2 bytes
  after 6 bools
- Fixed setup_terminal() leaving terminal in raw mode on early exit

New Features:
- Thread-safe warning buffer (warnings.rs) with TUI bar + stderr fallback
- Rewrote shift point analysis per AC forum methodology: per-gear
  acceleration curves, crossover detection, same-gear merging
- UseCase::guidance() — step-by-step recording instructions
- Recording metadata enrichment in analysis responses
- recording_id field on sessions

Code Quality:
- Extracted finalize_run() helper (session.rs)
- Extracted execute_and_store_analysis() helper (api.rs)
- Extracted lerp_search<T>() generic helper (analysis.rs)

Breaking API Changes:
- GET /api/use-cases: string[] -> [{id, name, guidance}[]]
- Shift point analysis: gear_ranges/shift_events -> gear_curves/crossover_points

Updated README.md with new API response examples and TUI warning bar.
2026-06-05 21:12:57 +02:00
090ab7e559 docs: add Web Client section to README 2026-06-05 16:12:34 +02:00
dc10627842 docs: update README.md and project plan for session management and analysis 2026-06-05 10:48:07 +02:00
47a0896134 feat: add use-case session management, analysis algorithms, and REST API (v0.5.0)
- Add session layer with UseCaseSession, SessionRun, SessionManager
  for use-case driven telemetry analysis (shift points, track mapping)
- Add analysis module with shift point detection (gear RPM ranges,
  upshift events, recommended shift RPM) and track map reconstruction
  (spline-aligned interpolation for center line from boundary runs)
- Add 9 REST API endpoints for session CRUD, run management, and
  analysis triggers under /api/sessions/*
- Add RecordingManager with always-on ring buffers (5 min, 18k frames)
  replacing raw binary file dumps
- Wire SessionManager in main.rs with Arc<Mutex> shared state
- Add TelemetryFrame Serialize derives for JSON API output
- Fix stop_recording race: hold active lock across flush I/O
- Fix flush: separate ring buffer lock from JSON serialization
- Fix flush failure propagation: errors prevent Stopped status
- Add data_truncated flag on SessionRun for ring buffer wrap detection
- Deduplicate gear_display into shared free function
- Deduplicate session_display into closure
- Mutex poisoning recovery on all session API handlers
2026-06-05 10:40:17 +02:00
56d3169033 fix: resolve 7 code review issues from v0.4.x
- Fix KSUDP clutch field reading fuel at offset 59 (KSUDP has no clutch input)
- Replace Notify with watch::channel for reliable shutdown (no missed wakeups)
- Deduplicate read_u16 from parser_pcars into shared binary_utils
- Remove dead Display impl for FeedSource
- Remove unused read_i8 helper from binary_utils
- Change Vec<Instant> to [Instant; 50] in FeedState (eliminate heap alloc)
- Cache rarely-changing strings by driver_id in Telemetry Tool parser
2026-06-04 11:12:55 +02:00
8f50302a78 docs: rewrite README.md, add remote operation docs, bump v0.4.1
- Complete README rewrite covering all three feeds (KSUDP, Telemetry Tool, PCARS)
- Document environment variables (GAME_HOST, LISTEN, BIND)
- Add same-machine and remote setup examples
- Document TUI layout, data capture format, architecture, testing
- Bump version 0.3.0 → 0.4.1
2026-06-04 10:39:00 +02:00
6732ff0199 refactor: split network config into game_host and listen_addr
Replace RUSTY_TELEMETRY_BIND with two env vars:
- RUSTY_TELEMETRY_GAME_HOST: IP of the machine running the sim (for
  KSUDP handshake target). Default: 127.0.0.1
- RUSTY_TELEMETRY_LISTEN: local address to bind for incoming feeds
  (Telemetry Tool, PCARS). Default: 0.0.0.0 (accept from any interface)

Both fall back to RUSTY_TELEMETRY_BIND for backward compatibility.
This enables running rusty-telemetry on a separate machine from the game.
2026-06-04 10:28:52 +02:00
a50d3af290 feat: add PCARS 1 & 2 UDP telemetry parser (port 5606)
- Auto-detect PCARS1 (1367-byte V1) vs PCARS2 (559-byte V2) packet format
- Parse speed, RPM, gear, inputs, tyres, engine temps, damage, weather
- Map PCARS-specific fields to TelemetryFrame (oil/water temp, damage, etc.)
- Add FeedSource::Pcars + 16 PCARS-specific Option fields to TelemetryFrame
- Port 5606 as optional bind-listen feed (like Telemetry Tool)
- 5 new unit tests for PCARS parser (32 total)
- Shared binary_utils module for all parsers
2026-06-04 09:49:00 +02:00
7a1c37fc86 refactor: TUI multi-feed monitor with binary parsers
- Add ratatui/crossterm TUI replacing stdout data dump
- Add binary parsers for KSUDP RTCarInfo (port 9996) and Telemetry Tool (port 10101)
- Add shared binary_utils module for safe packet reading
- Add ring-buffer frequency calculation and feed health state machine
- Add parse_first_driver() to avoid unnecessary multi-driver allocation
- Add 27 unit tests (14 feed_state + 6 ksudp + 7 telemetry_tool)
- Move parsing outside mutex lock to minimize TUI contention
- Replace expect() on env var with graceful error handling
- Remove unused serde dependency
- Delete obsolete stats.rs and telemetry.rs
2026-06-04 08:48:35 +02:00
1731495197 feat: multi-port UDP listener with data dump
Listen on three AC telemetry ports simultaneously (9996, 10101, 5005).
Dump received data to per-feed files under ./data/<session>/.
Notify on console for each received packet.

- Port 9996: AC built-in (ksudp), binary with 4-byte length framing
- Port 10101: Telemetry Tool plugin, binary with 4-byte length framing
- Port 5005: AC Lua plugin, JSON with newline-separated records
- Configurable bind address via RUSTY_TELEMETRY_BIND (default 127.0.0.1)
- Buffered file I/O via tokio BufWriter
- Graceful shutdown with flush on Ctrl+C
- Startup banner showing feed status
- Bumped version to 0.2.0, added futures dependency
2026-06-03 11:50:06 +02:00
30543fd0ba feat: initial rusty-telemetry UDP listener
- Async UDP listener on configurable bind address (default 127.0.0.1:5005)
- RUSTY_TELEMETRY_BIND env var for cross-machine deployment
- Deserializes JSON telemetry frames with serde
- deny_unknown_fields for schema drift detection
- ReceiveStats tracker with packet rate and data rate
- Locked stdout writes for efficient output
- .gitignore for /target/ and .idea/
2026-06-01 15:13:13 +02:00