From 1650f86d2276c067cb610dedcbacaf902121b74b Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Mon, 2 Nov 2026 22:38:34 +0000 Subject: [PATCH] Qualify upstream compatibility --- .../opendbc/safety/modes/honda_stock_aol.h | 13 +++- opendbc_repo/opendbc/safety/modes/tesla.h | 2 +- .../opendbc/safety/modes/tesla_screen_aol.h | 14 ++--- opendbc_repo/opendbc/safety/modes/toyota.h | 4 +- opendbc_repo/opendbc/safety/modes/volvo_cma.h | 2 +- .../opendbc/safety/tests/test_tesla_hw1.py | 2 +- openpilot/common/tests/test_usb_host.py | 59 +++++++++++++++++++ .../ui/mici/onroad/augmented_road_view.py | 2 +- .../flm/producer_clock_equivalence.py | 2 +- .../tests/test_upstream_producer_transport.py | 2 +- openpilot/starpilot/replay/render.py | 2 +- openpilot/starpilot/ui/native/raylib_extra.cc | 6 +- .../starpilot/ui/tests/test_camera_display.py | 7 ++- .../tools/lib/tests/test_log_time_series.py | 31 ++++++++++ panda/board/crc.h | 2 +- tools/ci/schema-policy.json | 4 +- upstream-sync.json | 2 +- 17 files changed, 127 insertions(+), 29 deletions(-) create mode 100644 openpilot/common/tests/test_usb_host.py create mode 100644 openpilot/tools/lib/tests/test_log_time_series.py diff --git a/opendbc_repo/opendbc/safety/modes/honda_stock_aol.h b/opendbc_repo/opendbc/safety/modes/honda_stock_aol.h index f9260e1170..d122a8c403 100644 --- a/opendbc_repo/opendbc/safety/modes/honda_stock_aol.h +++ b/opendbc_repo/opendbc/safety/modes/honda_stock_aol.h @@ -149,9 +149,16 @@ static uint8_t honda_stock_aol_permission_mask(void) { static bool honda_stock_aol_selected(const CANPacket_t *msg, const RxCheck *check) { bool selected = false; - if ((check != NULL) && rx_status[check - honda_rx_workspace].msg_seen) { - const CanMsgCheck *source = &check->msg[rx_status[check - honda_rx_workspace].index]; - selected = msg_matches(msg, source->addr, source->bus, source->len); + if (check != NULL) { + for (int i = 0; i < current_safety_config.rx_checks_len; i++) { + if (check == &honda_rx_workspace[i]) { + if (rx_status[i].msg_seen) { + const CanMsgCheck *source = &check->msg[rx_status[i].index]; + selected = msg_matches(msg, source->addr, source->bus, source->len); + } + break; + } + } } return selected; } diff --git a/opendbc_repo/opendbc/safety/modes/tesla.h b/opendbc_repo/opendbc/safety/modes/tesla.h index 4d4b3db590..a843ac8e29 100644 --- a/opendbc_repo/opendbc/safety/modes/tesla.h +++ b/opendbc_repo/opendbc/safety/modes/tesla.h @@ -103,7 +103,7 @@ static void tesla_rx_hook(const CANPacket_t *msg) { const int angle_meas_new = (((msg->data[4] & 0x3FU) << 8) | msg->data[5]) - 8192U; update_sample(&angle_meas, angle_meas_new); - const int torsion_bar_torque = (((msg->data[2] & 0x0FU) << 8) | msg->data[3]) - 2050; + const int torsion_bar_torque = (int)(((msg->data[2] & 0x0FU) << 8) | msg->data[3]) - 2050; const int hands_on_level = msg->data[4] >> 6; // EPAS3S_handsOnLevel const int eac_status = msg->data[6] >> 5; // EPAS3S_eacStatus const int eac_error_code = msg->data[2] >> 4; // EPAS3S_eacErrorCode diff --git a/opendbc_repo/opendbc/safety/modes/tesla_screen_aol.h b/opendbc_repo/opendbc/safety/modes/tesla_screen_aol.h index 23a22ecea9..593c3d4c03 100644 --- a/opendbc_repo/opendbc/safety/modes/tesla_screen_aol.h +++ b/opendbc_repo/opendbc/safety/modes/tesla_screen_aol.h @@ -126,21 +126,21 @@ static void tesla_screen_rx(const CANPacket_t *msg, bool autopark) { } static bool tesla_screen_param_valid(uint16_t param) { - param &= ~256U; - bool valid = (param == 512U) || (param == 1536U); + const uint16_t screen_param = (uint16_t)(param & ~256U); + bool valid = (screen_param == 512U) || (screen_param == 1536U); #ifdef ALLOW_DEBUG - valid = valid || (param == 513U) || (param == 1537U); + valid = valid || (screen_param == 513U) || (screen_param == 1537U); #endif return valid; } static void tesla_screen_configure(uint16_t param) { - param &= ~256U; + const uint16_t screen_param = (uint16_t)(param & ~256U); tesla_screen_reset(); - tesla_screen_enabled = tesla_screen_param_valid(param); + tesla_screen_enabled = tesla_screen_param_valid(screen_param); tesla_screen_enabled = tesla_screen_enabled && ((unsigned int)alternative_experience == 32U); - tesla_screen_brake_disengage = (param == 1536U) || (param == 1537U); - tesla_screen_longitudinal = (param == 513U) || (param == 1537U); + tesla_screen_brake_disengage = (screen_param == 1536U) || (screen_param == 1537U); + tesla_screen_longitudinal = (screen_param == 513U) || (screen_param == 1537U); if (tesla_screen_enabled) { static const AolSafetyPolicy policy = { .reset = tesla_screen_reset, diff --git a/opendbc_repo/opendbc/safety/modes/toyota.h b/opendbc_repo/opendbc/safety/modes/toyota.h index f885f54387..687289ff76 100644 --- a/opendbc_repo/opendbc/safety/modes/toyota.h +++ b/opendbc_repo/opendbc/safety/modes/toyota.h @@ -820,8 +820,8 @@ static safety_config toyota_init(uint16_t param) { bool eps_required = false; bool main_required = false; for (int i = 0; i < ret.rx_checks_len; i++) { - eps_required |= toyota_rx_checks[i].msg[0].addr == 0x262; - main_required |= toyota_rx_checks[i].msg[0].addr == (toyota_alt_cruise ? 0x365 : 0x1D3); + eps_required |= toyota_rx_checks[i].msg[0].addr == 0x262U; + main_required |= toyota_rx_checks[i].msg[0].addr == (toyota_alt_cruise ? 0x365U : 0x1D3U); } if (!eps_required) { const bool eps5 = (toyota_dsu_bypass && toyota_bypass_eps5) || toyota_aol_rav4h_filter || diff --git a/opendbc_repo/opendbc/safety/modes/volvo_cma.h b/opendbc_repo/opendbc/safety/modes/volvo_cma.h index aad0b1aed4..60fa4b9612 100644 --- a/opendbc_repo/opendbc/safety/modes/volvo_cma.h +++ b/opendbc_repo/opendbc/safety/modes/volvo_cma.h @@ -613,7 +613,7 @@ static safety_config volvo_cma_init(uint16_t param) { } for (uint8_t i = 0U; i < VOLVO_CMA_RX_CHECK_COUNT; i++) { rx_workspace[i] = selected[i]; - if (volvo_cma_lca2_mod15 && (rx_workspace[i].msg[0].addr == (int)VOLVO_CMA_PORT_LCA_2)) { + if (volvo_cma_lca2_mod15 && (rx_workspace[i].msg[0].addr == (unsigned int)VOLVO_CMA_PORT_LCA_2)) { rx_workspace[i].msg[0].max_counter = 14U; } } diff --git a/opendbc_repo/opendbc/safety/tests/test_tesla_hw1.py b/opendbc_repo/opendbc/safety/tests/test_tesla_hw1.py index 5049020168..323fbbc75d 100644 --- a/opendbc_repo/opendbc/safety/tests/test_tesla_hw1.py +++ b/opendbc_repo/opendbc/safety/tests/test_tesla_hw1.py @@ -33,7 +33,7 @@ def reset(param=16): class TestModelSHW1Safety(unittest.TestCase): def test_all_16bit_profile_words_are_isolated(self): debug = lib.set_safety_hooks(CarParams.SafetyModel.allOutput, 0) == 0 - supported = {0, 1, 16, 17, 512, 1536} | ({513, 1537} if debug else set()) + supported = {0, 1, 16, 17, 256, 257, 512, 768, 1536, 1792} | ({513, 769, 1537, 1793} if debug else set()) for param in range(65536): result = lib.set_safety_hooks(10, param) expected = 0 if param in supported else -1 diff --git a/openpilot/common/tests/test_usb_host.py b/openpilot/common/tests/test_usb_host.py new file mode 100644 index 0000000000..dd1f37bddb --- /dev/null +++ b/openpilot/common/tests/test_usb_host.py @@ -0,0 +1,59 @@ +import ast +from pathlib import Path +from types import SimpleNamespace +from unittest.mock import Mock + +import pytest + +from openpilot.common.hardware import usb + + +@pytest.mark.parametrize('states,expected', ( + ([], False), (['not attached'], False), (['configured'], True), + (['suspended'], True), (['not attached', 'addressed'], True), +)) +def test_usb_host_detection_uses_actual_controller_state(tmp_path, monkeypatch, states, expected): + for number, state in enumerate(states): + controller = tmp_path / str(number) + controller.mkdir() + (controller / 'state').write_text(state + '\n') + monkeypatch.setattr(usb, 'UDC_PATH', tmp_path) + assert usb.usb_host_connected() is expected + + +def test_missing_controller_state_is_not_a_host(tmp_path, monkeypatch): + monkeypatch.setattr(usb, 'UDC_PATH', tmp_path / 'absent') + assert not usb.usb_host_connected() + + +@pytest.mark.parametrize('present,cable,link,host,available', ( + (False, False, False, False, False), + (False, True, False, False, True), + (False, True, False, True, False), + (False, True, True, False, False), + (False, True, True, True, False), + (True, True, False, True, True), + (True, False, True, False, True), +)) +def test_actual_modeld_startup_rejects_host_cable(monkeypatch, present, cable, link, host, available): + from openpilot.starpilot.models import manager + + class SelectionReached(Exception): + pass + + selection = Mock(side_effect=SelectionReached) + monkeypatch.setattr(manager, 'resolve_runtime', selection) + monkeypatch.delenv('STARPILOT_MODELD_RECOVERY_SMALL_ONLY', raising=False) + source = Path(__file__).resolve().parents[2] / 'selfdrive/modeld/modeld.py' + main = next(n for n in ast.parse(source.read_text()).body if isinstance(n, ast.FunctionDef) and n.name == 'main') + prefix = [] + for node in main.body: + prefix.append(node) + if isinstance(node, ast.Assign) and any(isinstance(t, ast.Name) and t.id == 'selection' for t in node.targets): + break + namespace = {'cloudlog': Mock(), 'ModelReceiptOwner': Mock(), 'chestnut_present': lambda: present, + 'cable_connected': lambda: cable, 'usb_host_connected': lambda: host, + 'jetlink_adapter': SimpleNamespace(link_on=lambda: link), 'os': __import__('os')} + with pytest.raises(SelectionReached): + exec(compile(ast.Module(body=prefix, type_ignores=[]), str(source), 'exec'), namespace) + selection.assert_called_once_with(chestnut_available=available, randomize=True) diff --git a/openpilot/selfdrive/ui/mici/onroad/augmented_road_view.py b/openpilot/selfdrive/ui/mici/onroad/augmented_road_view.py index a5c8ff8d99..5e246aeaf0 100644 --- a/openpilot/selfdrive/ui/mici/onroad/augmented_road_view.py +++ b/openpilot/selfdrive/ui/mici/onroad/augmented_road_view.py @@ -317,7 +317,7 @@ class AugmentedRoadView(CameraView): if not self._bookmark_icon.interacting(): super()._handle_mouse_release(mouse_pos) - def _render(self, rect: rl.Rectangle, /, *, paint: bool = True, poll_camera: bool = True): + def _render(self, rect: rl.Rectangle, *, paint: bool = True, poll_camera: bool = True): if not paint: super()._render(rect, paint=False, poll_camera=poll_camera) return diff --git a/openpilot/starpilot/flm/producer_clock_equivalence.py b/openpilot/starpilot/flm/producer_clock_equivalence.py index ba8614e4b1..9634a1f8bd 100644 --- a/openpilot/starpilot/flm/producer_clock_equivalence.py +++ b/openpilot/starpilot/flm/producer_clock_equivalence.py @@ -18,7 +18,7 @@ PRODUCER_SOURCE_HASHES = ( ('openpilot', 'system/camerad/cameras/spectra.cc', '4fa26c17f0fb792a4ab6815657beccddee1d641faa2fd02e5aa7393f717a2f3a'), ('openpilot', 'system/camerad/cameras/camera_qcom2.cc', 'b34c24c9984a0ac086f7b961cb7ff09d0501231da50aaad0e676bb3dc3f2edd9'), ('openpilot', 'system/camerad/cameras/camera_common.cc', 'bd9a416a6ee21047b4deec6df04276d8717cd92fe14de43f3e9daff86b62bb8f'), - ('openpilot', 'selfdrive/modeld/modeld.py', '4ffe0193c64acab99f47b594ed98164e7ab6285f04f18205525d1b9931b9a086'), + ('openpilot', 'selfdrive/modeld/modeld.py', '8aa09862919bd3900489b2444f03179661b62e45f683270abf8c50d1ae3173fa'), ('openpilot', 'selfdrive/modeld/fill_model_msg.py', 'b3916c34d1073d0c26a7a8adc51e7b148f63a1ac68b388226170fd0f8b8b56b4'), ('openpilot', 'system/sensord/sensord.py', '7c79ab07d775622a43001e5a9b9ccc9a7bafb065940185849b33eefc2fd26420'), ('openpilot', 'system/sensord/sensors/lsm6ds3_gyro.py', '3e561f3d8572e1477c9b4b810c7570837d51e81c5672fe21ec67a68cae00dd92'), diff --git a/openpilot/starpilot/flm/tests/test_upstream_producer_transport.py b/openpilot/starpilot/flm/tests/test_upstream_producer_transport.py index f81ed2a852..0b12ccf83f 100644 --- a/openpilot/starpilot/flm/tests/test_upstream_producer_transport.py +++ b/openpilot/starpilot/flm/tests/test_upstream_producer_transport.py @@ -9,7 +9,7 @@ from openpilot.starpilot.flm import producer_clock_equivalence as clock APPROVED = { - 'selfdrive/modeld/modeld.py': '4ffe0193c64acab99f47b594ed98164e7ab6285f04f18205525d1b9931b9a086', + 'selfdrive/modeld/modeld.py': '8aa09862919bd3900489b2444f03179661b62e45f683270abf8c50d1ae3173fa', 'visionipc/visionipc_py.cc': '6c131c4f5eccb9f822f1aaae63733f26b1427c52340b61c9cdaf6cd4aee2f89d', 'visionipc/visionipc_server.cc': 'a4325a5171eacb931eb271d06a992d2f27216040df113d92099f62cdfa67d81a', 'visionipc/visionipc_client.cc': 'd142cd60eedabfc581e9770fcd6f0ca81b762ba9dbc608b54dd20a27a317a52d', diff --git a/openpilot/starpilot/replay/render.py b/openpilot/starpilot/replay/render.py index 1f5b1e12f0..98af28b368 100644 --- a/openpilot/starpilot/replay/render.py +++ b/openpilot/starpilot/replay/render.py @@ -509,7 +509,7 @@ class Compositor: # Preserve the subscriber to avoid repeated seeks while paused. self.camera.client = client self.camera.frame = frame - self.camera.available_streams = available + self.camera.available_streams = list(available) if client is not None and client.is_connected(): self.camera._initialize_textures() pip_client = self.pip_stream._client diff --git a/openpilot/starpilot/ui/native/raylib_extra.cc b/openpilot/starpilot/ui/native/raylib_extra.cc index c9271d3d66..23412d3bb7 100644 --- a/openpilot/starpilot/ui/native/raylib_extra.cc +++ b/openpilot/starpilot/ui/native/raylib_extra.cc @@ -48,8 +48,8 @@ NB_MODULE(_raylib_extra, module) { }, nb::is_implicit()); nb::implicitly_convertible(); nb::implicitly_convertible(); - auto color = nb::borrow>(nb::type()); - color.def("__init__", [](Color *self, nb::sequence values) { + auto color_type = nb::borrow>(nb::type()); + color_type.def("__init__", [](Color *self, nb::sequence values) { if (nb::len(values) != 4) throw nb::value_error("Color requires four channels"); new (self) Color{nb::cast(values[0]), nb::cast(values[1]), nb::cast(values[2]), nb::cast(values[3])}; }, nb::is_implicit()); @@ -104,7 +104,7 @@ NB_MODULE(_raylib_extra, module) { if (!nb::hasattr(target, "init_audio_device")) target.def("init_audio_device", []() { symbol("InitAudioDevice")(); }); if (!nb::hasattr(target, "close_audio_device")) target.def("close_audio_device", []() { symbol("CloseAudioDevice")(); }); if (!nb::hasattr(target, "is_audio_device_ready")) target.def("is_audio_device_ready", []() { return symbol("IsAudioDeviceReady")(); }); - if (!nb::hasattr(target, "load_sound")) target.def("load_sound", [](const char *path) { return symbol("LoadSound")(path); }); + if (!nb::hasattr(target, "load_sound")) target.def("load_sound", [](const char *sound_path) { return symbol("LoadSound")(sound_path); }); if (!nb::hasattr(target, "unload_sound")) target.def("unload_sound", [](Sound sound) { symbol("UnloadSound")(sound); }); if (!nb::hasattr(target, "play_sound")) target.def("play_sound", [](Sound sound) { symbol("PlaySound")(sound); }); if (!nb::hasattr(target, "stop_sound")) target.def("stop_sound", [](Sound sound) { symbol("StopSound")(sound); }); diff --git a/openpilot/starpilot/ui/tests/test_camera_display.py b/openpilot/starpilot/ui/tests/test_camera_display.py index b04dcffa55..4d2a27deeb 100644 --- a/openpilot/starpilot/ui/tests/test_camera_display.py +++ b/openpilot/starpilot/ui/tests/test_camera_display.py @@ -4,6 +4,7 @@ from pathlib import Path from types import SimpleNamespace as NS import tempfile import unittest +import numpy as np from unittest.mock import Mock, patch from openpilot.starpilot.ui.raylib import rl @@ -250,10 +251,10 @@ class CameraDisplayTests(unittest.TestCase): camera = CameraViewWithoutResources.__new__(CameraViewWithoutResources) camera._stream_type = native_camera.NARROW_ROAD_CAM camera.client = object() - camera._engaged_val = [0] - camera._color_strength_val = [0.0] + camera._engaged_val = np.array([0], dtype=np.int32) + camera._color_strength_val = np.array([0.0], dtype=np.float32) camera._color_strength_loc = 3 - camera._enhance_driver_val = [0] + camera._enhance_driver_val = np.array([0], dtype=np.int32) camera._engaged_loc = 1 camera._enhance_driver_loc = 2 camera.shader = object() diff --git a/openpilot/tools/lib/tests/test_log_time_series.py b/openpilot/tools/lib/tests/test_log_time_series.py new file mode 100644 index 0000000000..40d11a3a51 --- /dev/null +++ b/openpilot/tools/lib/tests/test_log_time_series.py @@ -0,0 +1,31 @@ +import numpy as np + +from openpilot.cereal import messaging +from openpilot.tools.lib.log_time_series import msgs_to_time_series + + +def test_union_columns_keep_rows_aligned_when_controller_changes(): + messages = [] + for stamp, branch, output in [(3, 'pidState', 0.25), (1, 'torqueState', 0.5), (2, 'pidState', 0.75)]: + message = messaging.new_message('controlsState') + message.logMonoTime = stamp * 10**9 + getattr(message.controlsState.lateralControlState, 'init')(branch).output = output + messages.append(message) + group = msgs_to_time_series(messages)['controlsState'] + assert group['t'].tolist() == [1., 2., 3.] + assert group['lateralControlState/pidState/output'].tolist() == [None, 0.75, 0.25] + assert group['lateralControlState/torqueState/output'].tolist() == [0.5, None, None] + assert all(len(column) == 3 for column in group.values()) + + +def test_nested_values_and_ragged_lists_preserve_sort_order(): + messages = [] + for stamp, points in [(2, [1., 2.]), (1, [3.])]: + message = messaging.new_message('modelV2') + message.logMonoTime = stamp * 10**9 + message.modelV2.position.x = points + messages.append(message) + group = msgs_to_time_series(messages)['modelV2'] + assert group['t'].tolist() == [1., 2.] + np.testing.assert_array_equal(group['position/x'][0], [3.]) + np.testing.assert_array_equal(group['position/x'][1], [1., 2.]) diff --git a/panda/board/crc.h b/panda/board/crc.h index bbf350003e..661435e0f0 100644 --- a/panda/board/crc.h +++ b/panda/board/crc.h @@ -13,7 +13,7 @@ void crc32_init(void) { } } -uint32_t crc32_update(uint32_t crc, const uint8_t *dat, uint32_t len) { +static uint32_t crc32_update(uint32_t crc, const uint8_t *dat, uint32_t len) { uint32_t ret = crc; for (uint32_t i = 0U; i < len; i++) { ret = crc32_table[(ret ^ dat[i]) & 0xFFU] ^ (ret >> 8U); diff --git a/tools/ci/schema-policy.json b/tools/ci/schema-policy.json index 9aded19e64..7c8b066b36 100644 --- a/tools/ci/schema-policy.json +++ b/tools/ci/schema-policy.json @@ -1,6 +1,6 @@ { "schema_version": 2, - "upstream_commit": "2ab952d5eb16020116d3354b83f30303db5a99b4", + "upstream_commit": "ad4c9cdf1857034bb06c12e4b0cfba093e6ae3d6", "opendbc_commit": "35f7e0813462607ef1d703e52313e7571e31405d", "unchanged_schemas": { "openpilot/cereal/deprecated.capnp": "b3aa5c13de40001ed7376cef858500fb003f7698f96131cd0db18d878fa1af0d", @@ -9,7 +9,7 @@ "opendbc_repo/opendbc/car/include/c++.capnp": "fb306076cd38c27af1aed20fac6395e9a46fbe5b5df6a248b5f1b6845a079c44", "opendbc_repo/opendbc/car/rlog.capnp": "76331a09f36764d08228ba1ed6c03419cc8cdfcc797db98c4d56fab52a6ac050" }, - "log_sha256": "4036fc4a3e653d877eee57a902fe59776dca607d95c17d29ca46b0db4c9313d9", + "log_sha256": "8a2891925ca8a2d0a59d98fd4dbe3585c77e16a2e02db6c8029cb0964b2dce84", "custom_header": "using Cxx = import \"/include/c++.capnp\";\n$Cxx.namespace(\"cereal\");\nusing Car = import \"/car.capnp\";\n\n@0xb526ba661d550a59;\n\n# custom.capnp: a home for empty structs reserved for custom forks\n# These structs are guaranteed to remain reserved and empty in mainline\n# cereal, so use these if you want custom events in your fork.\n\n# DO rename the structs\n# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n# Automatic FLM adds children only to existing reserved fork carriers.\n# All evidence clocks are explicitly MONOTONIC; default/version0 is invalid.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n# Live tracking trials are a separate protocol, never ReplayValidation.\n\n\n\n\n\n\n\n\n", "historical_empty_slots": [], "historical_restored": { diff --git a/upstream-sync.json b/upstream-sync.json index 8e6196827d..c59e3619d9 100644 --- a/upstream-sync.json +++ b/upstream-sync.json @@ -2,7 +2,7 @@ "schema_version": 1, "upstream": { "url": "https://github.com/commaai/openpilot.git", - "commit": "2ab952d5eb16020116d3354b83f30303db5a99b4" + "commit": "ad4c9cdf1857034bb06c12e4b0cfba093e6ae3d6" }, "dependencies": [ {