mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-04 19:43:49 +08:00
Report how the channel was found and what the ladder tried; wait longer for a slow car
Reports carry the SDP outcome (where the RFCOMM channel came from and how many retries it took). The Discord post names the handshake options tried and how each ended. A car that once needed 70 s to be ready now gets that many stage timeouts to answer the Wi-Fi handshake, never fewer than the standard wait and capped at nine.
This commit is contained in:
@@ -104,10 +104,22 @@ def _setup(log_dir: Path | None, logs_to_check: int = 3) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def _handshake(log_dir: Path | None, logs_to_check: int = 3) -> str:
|
||||
"""What the setup ladder tried in the newest log that recorded it, e.g. "standard (advanced) > other_reply (worked)"."""
|
||||
from openpilot.starpilot.system.starport import compat_report
|
||||
from openpilot.starpilot.system.starport.bugsink_report import session_ladder
|
||||
for path in compat_report.session_logs(log_dir or identity_store.LOG_DIR)[:logs_to_check]:
|
||||
tried = session_ladder(compat_report.load_events(path))
|
||||
if tried:
|
||||
return " > ".join(f"{item['rung']}{' learned' if item.get('learned') else ''} ({item.get('outcome', 'tried')})" for item in tried[-6:])
|
||||
return ""
|
||||
|
||||
|
||||
def device_summary(log_dir: Path | None = None) -> dict:
|
||||
from openpilot.starpilot.system.starport.bugsink_transport import device_metadata
|
||||
summary = device_metadata()
|
||||
for key, read in (("car_fingerprint", _car_fingerprint), ("head_unit", lambda: _head_unit(log_dir)), ("setup", lambda: _setup(log_dir))):
|
||||
for key, read in (("car_fingerprint", _car_fingerprint), ("head_unit", lambda: _head_unit(log_dir)), ("setup", lambda: _setup(log_dir)),
|
||||
("handshake", lambda: _handshake(log_dir))):
|
||||
try:
|
||||
summary[key] = read()
|
||||
except Exception as error:
|
||||
@@ -163,6 +175,7 @@ def send(data: bytes, name: str, note: str, summary: dict, url: str | None = Non
|
||||
f"Car: {summary.get('car_fingerprint') or 'unknown'}",
|
||||
f"Head unit: {summary.get('head_unit') or 'unknown'}",
|
||||
f"Setup: {summary.get('setup') or 'unknown'}",
|
||||
f"Handshake: {summary.get('handshake') or 'unknown'}",
|
||||
f"Branch {summary.get('branch', '?')} @ {str(summary.get('commit', '?'))[:10]}",
|
||||
f"Note: {note.strip() or '(none)'}"]
|
||||
payload = {"content": "\n".join(lines)[:1900], "username": "StarPilot diagnostics", "allowed_mentions": {"parse": []}}
|
||||
|
||||
@@ -61,6 +61,7 @@ class SendTest(unittest.TestCase):
|
||||
self.assertIn("Note: Dropped at the light", call["payload"]["content"])
|
||||
self.assertIn("Head unit: Honda Display Audio", call["payload"]["content"])
|
||||
self.assertIn("Setup: unknown", call["payload"]["content"]) # no session log recorded a setup in this fixture
|
||||
self.assertIn("Handshake: unknown", call["payload"]["content"])
|
||||
self.assertNotIn(SUMMARY["device_id"], call["payload"]["content"])
|
||||
self.assertEqual(query(call), {"wait": "true"})
|
||||
self.assertEqual(call["files"]["files[0]"], ("logs.zip", b"zip", "application/zip"))
|
||||
|
||||
@@ -190,6 +190,17 @@ def offered_modes(events: list[dict]) -> list[str]:
|
||||
return modes[:MAX_OFFERED_MODES]
|
||||
|
||||
|
||||
def session_sdp(events: list[dict]) -> dict:
|
||||
"""How the car's Android Auto RFCOMM channel was found: where it came from, and how many SDP retries it took."""
|
||||
found = next((event for event in events if event["event"] == "rfcomm_channel"), {})
|
||||
retries = sum(1 for event in events if event["event"] == "sdp_retry")
|
||||
if not found and not retries:
|
||||
return {}
|
||||
return {key: value for key, value in (("channel", found.get("channel") if isinstance(found.get("channel"), int) else None),
|
||||
("source", str(found["source"])[:12] if found.get("source") else None),
|
||||
("retries", retries or None)) if value is not None}
|
||||
|
||||
|
||||
def session_setup(events: list[dict]) -> dict:
|
||||
"""The setup type and profile the owner chose, as recorded when the session started."""
|
||||
start = next((event for event in events if event["event"] == "session_start"), {})
|
||||
@@ -265,6 +276,7 @@ def session_record(path: Path) -> dict:
|
||||
"phone_address_sent": bool(opened.get("phone_address")) if opened is not None else None,
|
||||
"strategy": session_strategy(events, setup),
|
||||
"ladder": session_ladder(events),
|
||||
"sdp": session_sdp(events),
|
||||
"software": {key: str(software.get(key) or "unknown") for key in ("commit", "branch")} if isinstance(software, dict) else {},
|
||||
"settings": settings if isinstance(settings, dict) else {},
|
||||
"seq": _session_number(path),
|
||||
|
||||
@@ -239,6 +239,14 @@ class SetupLadder:
|
||||
entry["t_ready"] = (entry["t_ready"] + [round(float(t_ready_s), 1)])[-8:]
|
||||
self.save()
|
||||
|
||||
def ready_patience(self, address: str, stage_timeout: float = 20.0) -> int:
|
||||
"""Stage timeouts a slow car needs: it was ready after t_ready_s once, so the bootstrap must be willing to wait that long.
|
||||
|
||||
Never less than the standard patience, and 0 (no opinion) for a car nothing is known about."""
|
||||
entry = self.cars.get(address.upper())
|
||||
times = entry["t_ready"] if entry else []
|
||||
return min(9, int(-(-max(times) // stage_timeout))) if times else 0
|
||||
|
||||
def snapshot(self, address: str, adapter: bool = False) -> dict:
|
||||
"""What the setup screen and the reports show: every rung, its state, and whether this car has a learned strategy."""
|
||||
entry = self.cars.get(address.upper()) if address else None
|
||||
|
||||
@@ -1341,7 +1341,9 @@ class Supervisor:
|
||||
boot = WirelessBootstrap(rfcomm, self._bootstrap_log, device_serial=config["device_name"],
|
||||
version_status=int(config.get("version_status", 0)),
|
||||
experiment="all" if car_profiles.tuning(config)["bootstrap_experiments"] or strategy.experiments else "",
|
||||
modern_reply=strategy.modern_reply, patience=strategy.patience, channel_override=strategy.channel_type)
|
||||
modern_reply=strategy.modern_reply, channel_override=strategy.channel_type,
|
||||
# a car that once took 70 s to be ready gets more than the standard wait for the Wi-Fi handshake
|
||||
patience=max(strategy.patience, self._ladder.ready_patience(address, 20.0)))
|
||||
self._set(state="wifi_start")
|
||||
result = boot.run(lambda credentials: lease.acquire(credentials, cancelled=boot.join_is_cancelled), cancelled=self._stop.is_set)
|
||||
except Exception as error:
|
||||
|
||||
@@ -506,3 +506,11 @@ def test_report_shows_what_the_ladder_tried_and_what_worked(tmp_path):
|
||||
tags = br.drive_event([record])["tags"]
|
||||
assert (tags["aa.ladder_rung"], tags["aa.ladder_learned"]) == ("other_reply", "no")
|
||||
assert br.session_record(write_session(tmp_path, 2, STREAMED))["ladder"] == [] # older logs report nothing, without error
|
||||
|
||||
|
||||
def test_report_says_how_the_rfcomm_channel_was_found(tmp_path):
|
||||
events = [list(item) for item in STREAMED]
|
||||
events.insert(1, (0, 1, "sdp_retry", {"error": "x"}))
|
||||
events.insert(2, (0, 2, "rfcomm_channel", {"channel": 8, "source": "sdp"}))
|
||||
assert br.session_record(write_session(tmp_path, 1, events))["sdp"] == {"channel": 8, "source": "sdp", "retries": 1}
|
||||
assert br.session_record(write_session(tmp_path, 2, STREAMED))["sdp"] == {}
|
||||
|
||||
@@ -211,3 +211,13 @@ def test_forgetting_a_car_forgets_what_was_learned_about_it(sup):
|
||||
sup._ladder.worked(RECEIVER, sl.resolve("patient", False), 10.0)
|
||||
assert sup.forget_receiver(RECEIVER) is True
|
||||
assert not sup._ladder.snapshot(RECEIVER)["learned"] and RECEIVER not in sup._ladder.cars
|
||||
|
||||
|
||||
def test_a_slow_car_gets_the_patience_it_once_needed_and_an_unknown_car_gets_no_opinion(ladder):
|
||||
assert ladder.ready_patience(CAR) == 0
|
||||
ladder.worked(CAR, sl.resolve("standard", False), 14.0)
|
||||
assert ladder.ready_patience(CAR) == 1
|
||||
ladder.worked(CAR, sl.resolve("standard", False), 70.0)
|
||||
assert ladder.ready_patience(CAR) == 4 # 70 s at 20 s per stage timeout
|
||||
ladder.worked(CAR, sl.resolve("standard", False), 3000.0)
|
||||
assert ladder.ready_patience(CAR) == 9 # capped
|
||||
|
||||
Reference in New Issue
Block a user