Compare commits

..

5 Commits

Author SHA1 Message Date
Jason Wen 813ef1ee65 cleanup 2026-03-04 23:23:49 -05:00
Jason Wen 3749b49186 Merge branch 'master' into fix_rivian_long 2026-03-04 23:15:19 -05:00
Jason Wen 6bea70ac86 pandad: gate unsupported pandas before flashing (#1754) 2026-03-04 23:15:10 -05:00
lukasloetkolben 25b6f84bb0 lets do it like that 2026-03-03 15:42:21 +01:00
lukasloetkolben 73092daefc fixed missing internal panda 2026-03-03 15:25:48 +01:00
10 changed files with 41 additions and 89 deletions
-1
View File
@@ -25,7 +25,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CarParamsPersistent", {PERSISTENT, BYTES}},
{"CarParamsPrevRoute", {PERSISTENT, BYTES}},
{"CompletedTrainingVersion", {PERSISTENT, STRING, "0"}},
{"ConfidenceVisual", {PERSISTENT | BACKUP, INT, "0"}},
{"ControlsReady", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"CurrentBootlog", {PERSISTENT, STRING}},
{"CurrentRoute", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}},
+21 -15
View File
@@ -32,8 +32,7 @@ def flash_panda(panda_serial: str) -> Panda:
raise
# skip flashing if the detected panda is not supported
supported_panda = check_panda_support(panda)
if not supported_panda:
if panda.get_type() not in Panda.SUPPORTED_DEVICES:
cloudlog.warning(f"Panda {panda_serial} is not supported (hw_type: {panda.get_type()}), skipping flash...")
return panda
@@ -69,10 +68,19 @@ def flash_panda(panda_serial: str) -> Panda:
return panda
def check_panda_support(panda) -> bool:
hw_type = panda.get_type()
if hw_type in Panda.SUPPORTED_DEVICES:
return True
def check_panda_support(panda_serials: list[str]) -> bool:
unsupported = []
for serial in panda_serials:
panda = Panda(serial)
hw_type = panda.get_type()
panda.close()
if hw_type in Panda.SUPPORTED_DEVICES:
return True
unsupported.append((serial, hw_type))
for serial, hw_type in unsupported:
cloudlog.warning(f"Panda {serial} is not supported (hw_type: {hw_type}), skipping...")
return False
@@ -126,13 +134,17 @@ def main() -> None:
cloudlog.info(f"{len(panda_serials)} panda(s) found, connecting - {panda_serials}")
# custom flasher for xnor's Rivian Longitudinal Upgrade Kit
flash_rivian_long(panda_serials)
# skip flashing and health check if no supported panda is detected
if not check_panda_support(panda_serials):
continue
# Flash the first panda
panda_serial = panda_serials[0]
panda = flash_panda(panda_serial)
# flash Rivian longitudinal upgrade panda
flash_rivian_long(panda)
# Ensure internal panda is present if expected
if HARDWARE.has_internal_panda() and not panda.is_internal():
cloudlog.error("Internal panda is missing, trying again")
@@ -143,12 +155,6 @@ def main() -> None:
# log panda fw version
params.put("PandaSignatures", panda.get_signature())
# skip health check if the detected panda is not supported
supported_panda = check_panda_support(panda)
if not supported_panda:
cloudlog.warning(f"Panda {panda.get_usb_serial()} is not supported (hw_type: {panda.get_type()}), skipping health check...")
continue
# check health for lost heartbeat
health = panda.health()
if health["heartbeat_lost"]:
+5 -8
View File
@@ -24,12 +24,10 @@ def draw_circle_gradient(center_x: float, center_y: float, radius: int,
class ConfidenceBall(Widget, ConfidenceBallSP):
def __init__(self, demo: bool = False, scale: float = 1.0, visual: int = 0):
def __init__(self, demo: bool = False):
Widget.__init__(self)
ConfidenceBallSP.__init__(self)
self._demo = demo
self._scale = scale
self._visual = visual
self._confidence_filter = FirstOrderFilter(-0.5, 0.5, 1 / gui_app.target_fps)
def update_filter(self, value: float):
@@ -56,7 +54,7 @@ class ConfidenceBall(Widget, ConfidenceBallSP):
self.rect.height,
)
status_dot_radius = int(24 * self._scale)
status_dot_radius = 24
dot_height = (1 - self._confidence_filter.x) * (content_rect.height - 2 * status_dot_radius) + status_dot_radius
dot_height = self._rect.y + dot_height
@@ -83,7 +81,6 @@ class ConfidenceBall(Widget, ConfidenceBallSP):
top_dot_color = rl.Color(50, 50, 50, 255)
bottom_dot_color = rl.Color(13, 13, 13, 255)
if not self.update_confidence_visual(content_rect, status_dot_radius, dot_height, top_dot_color, bottom_dot_color):
draw_circle_gradient(content_rect.x + content_rect.width - status_dot_radius,
dot_height, status_dot_radius,
top_dot_color, bottom_dot_color)
draw_circle_gradient(content_rect.x + content_rect.width - status_dot_radius,
dot_height, status_dot_radius,
top_dot_color, bottom_dot_color)
@@ -95,7 +95,6 @@ class AugmentedRoadView(CameraView, AugmentedRoadViewSP):
# Draw all UI overlays
self.model_renderer.render(self._content_rect)
AugmentedRoadViewSP.update_fade_out_bottom_overlay(self, self._content_rect)
self.update_confidence_visual(self._content_rect)
self._hud_renderer.render(self._content_rect)
self.alert_renderer.render(self._content_rect)
self.driver_state_renderer.render(self._content_rect)
@@ -120,18 +120,10 @@ class VisualsLayout(Widget):
button_width=350,
inline=False
)
self._confidence_visual = multiple_button_item_sp(
title=lambda: tr("Confidence Visual"),
description=lambda: tr("Display confidence ball or bar on the driving screen."),
buttons=[lambda: tr("Off"), lambda: tr("Ball"), lambda: tr("Bar")],
param="ConfidenceVisual",
inline=False
)
items = list(self._toggles.values()) + [
self._chevron_info,
self._dev_ui_info,
self._confidence_visual,
]
return items
@@ -143,8 +135,6 @@ class VisualsLayout(Widget):
self._dev_ui_info.action_item.set_selected_button(ui_state.params.get("DevUIInfo", return_default=True))
self._confidence_visual.action_item.set_selected_button(ui_state.params.get("ConfidenceVisual", return_default=True))
if ui_state.has_longitudinal_control:
self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["enabled"]))
self._chevron_info.action_item.set_selected_button(ui_state.params.get("ChevronInfo", return_default=True))
@@ -4,7 +4,7 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import pyray as rl
from openpilot.selfdrive.ui.onroad.augmented_road_view import BORDER_COLORS
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
@@ -19,26 +19,8 @@ class ConfidenceBallSP:
@staticmethod
def get_lat_long_dot_color():
from openpilot.selfdrive.ui.onroad.augmented_road_view import BORDER_COLORS
if ui_state.status == UIStatus.LAT_ONLY:
return BORDER_COLORS[UIStatus.LAT_ONLY]
# UIStatus.LONG_ONLY
return BORDER_COLORS[UIStatus.LONG_ONLY]
def update_confidence_visual(self, content_rect, status_dot_radius, dot_height, top_dot_color, bottom_dot_color) -> bool:
if self._visual == 2:
bar_width = int(20 * self._scale)
bar_x = content_rect.x + content_rect.width - bar_width
fill_h = int(content_rect.height * self._confidence_filter.x)
fill_y = int(content_rect.y + (content_rect.height - fill_h))
rl.draw_rectangle(int(bar_x), int(content_rect.y), bar_width, int(content_rect.height), rl.Color(20, 20, 20, 180))
rl.draw_rectangle_gradient_v(int(bar_x), fill_y, bar_width, fill_h, top_dot_color, bottom_dot_color)
return True
elif self._visual == 1:
rl.draw_circle_gradient(int(content_rect.x + content_rect.width - status_dot_radius),
int(dot_height), status_dot_radius,
top_dot_color, bottom_dot_color)
return True
return False
@@ -8,7 +8,6 @@ import pyray as rl
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.selfdrive.ui.ui_state import UIStatus, ui_state
from openpilot.system.ui.lib.application import gui_app
from openpilot.selfdrive.ui.mici.onroad.confidence_ball import ConfidenceBall
BORDER_COLORS_SP = {
UIStatus.LAT_ONLY: rl.Color(0x00, 0xC8, 0xC8, 0xFF), # Cyan for lateral-only state
@@ -20,7 +19,6 @@ class AugmentedRoadViewSP:
def __init__(self):
self._fade_texture = gui_app.texture("icons_mici/onroad/onroad_fade.png")
self._fade_alpha_filter = FirstOrderFilter(0, 0.1, 1 / gui_app.target_fps)
self._confidence_visual = ConfidenceBall(scale=1.5)
def update_fade_out_bottom_overlay(self, _content_rect):
# Fade out bottom of overlays for looks (only when engaged)
@@ -31,9 +29,3 @@ class AugmentedRoadViewSP:
rl.Rectangle(0, 0, self._fade_texture.width, self._fade_texture.height),
_content_rect, rl.Vector2(0, 0), 0.0,
rl.Color(255, 255, 255, int(255 * fade_alpha)))
def update_confidence_visual(self, _content_rect):
mode = ui_state.confidence_visual
if mode in (1, 2):
self._confidence_visual._visual = mode
self._confidence_visual.render(_content_rect)
-1
View File
@@ -143,7 +143,6 @@ class UIStateSP:
self.true_v_ego_ui = self.params.get_bool("TrueVEgoUI")
self.turn_signals = self.params.get_bool("ShowTurnSignals")
self.boot_offroad_mode = self.params.get("DeviceBootMode", return_default=True)
self.confidence_visual = self.params.get("ConfidenceVisual", return_default=True)
class DeviceSP:
@@ -74,7 +74,7 @@ def _flash_panda(panda: Panda) -> None:
panda.reconnect()
def flash_rivian_long(panda: Panda) -> None:
def flash_rivian_long(panda_serials: list[str]) -> None:
if not os.path.isfile(FW_PATH):
cloudlog.error(f"Rivian longitudinal upgrade firmware not found at {FW_PATH}")
return
@@ -83,13 +83,19 @@ def flash_rivian_long(panda: Panda) -> None:
cloudlog.info("Not a Rivian, skipping longitudinal upgrade...")
return
# only flash external black pandas (HW_TYPE_BLACK = 0x03)
if panda.get_type() == b'\x03' and not panda.is_internal():
try:
_flash_panda(panda)
except Exception:
cloudlog.exception(f"Failed to flash F4 panda {panda.get_usb_serial()}")
for serial in panda_serials:
panda = Panda(serial)
# only flash external black pandas (HW_TYPE_BLACK = 0x03)
if panda.get_type() == b'\x03' and not panda.is_internal():
try:
_flash_panda(panda)
cloudlog.info(f"Successfully flashed xnor's Rivian Longitudinal Upgrade Kit: {serial}")
except Exception:
cloudlog.exception(f"Failed to flash xnor's Rivian Longitudinal Upgrade Kit: {serial}")
panda.close()
return
if __name__ == '__main__':
flash_rivian_long(Panda())
flash_rivian_long(Panda.list())
-18
View File
@@ -186,24 +186,6 @@
"title": "Completed Training Version",
"description": ""
},
"ConfidenceVisual": {
"title": "Confidence Visual",
"description": "Display confidence ball or bar on the driving screen.",
"options": [
{
"value": 0,
"label": "Off"
},
{
"value": 1,
"label": "Ball"
},
{
"value": 2,
"label": "Bar"
}
]
},
"ControlsReady": {
"title": "Controls Ready",
"description": ""