Merge qualified HKG and MQB source

This commit is contained in:
firestar5683
2026-10-22 20:15:07 -05:00
10 changed files with 124 additions and 13 deletions
@@ -244,7 +244,13 @@ class PEPendingStartup:
self._tester()
self.check()
self.thread = self.thread_factory(target=self._loop, name='pe-startup-tester', daemon=True)
self.thread.start()
try:
self.thread.start()
except BaseException:
self.stop_event.set()
if getattr(self.thread, 'ident', None) is None:
self.thread = None
raise
except BaseException:
self.owner.phase = Phase.ABORT
self._restore()
@@ -183,11 +183,28 @@ def test_actual_card_publisher_keeps_sibling_diagnostics_until_sent(identity, pa
@pytest.mark.parametrize('identity', [CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_KONA_EV_2ND_GEN])
def test_existing_keeper_owners_close_after_real_thread_launch_failure(identity):
from opendbc.car.hyundai.tests.test_ioniq5pe_stock import params as ev9_params
from openpilot.starpilot.vehicle_startup import VehicleStartupOwner
if identity == CAR.KIA_EV9:
cp = ev9_params(candidate=identity)
import threading
from opendbc.car.hyundai.tests.test_ev9_pending_startup import pending_startup_fixture
with pending_startup_fixture() as (fixture, owner, ci, packer):
fixture.warm(owner, ci, packer)
published = ci.CP.to_dict()
owner.thread_factory = threading.Thread
with patch('threading.Thread.start', side_effect=OSError('launch failed')):
with pytest.raises(OSError, match='launch failed'):
try:
fixture.commit(owner, ci)
finally:
owner.close()
assert owner.closed and owner.restored and owner.close_completed
assert owner.thread is None and owner.stop_event.is_set()
assert owner.fault and not owner.owner.active() and not owner.can_emit(ci.CC)
assert owner.owner.published and ci.CP.to_dict() == published
assert [request for request, _ in fixture.queries[-3:]] == [b'\x10\x03', b'\x28\x00\x01', b'\x10\x01']
return
else:
fp = gen_empty_fingerprint()
fp[2].update({0x50: 16, 0x2A4: 24})
@@ -197,8 +214,6 @@ def test_existing_keeper_owners_close_after_real_thread_launch_failure(identity)
sent = []
owner = CarInterface.startup_owner(cp, (list, sent.extend), requested=True)
assert owner is not None
if identity == CAR.KIA_EV9:
owner._ready = lambda: False
requests = []
def query(send, recv, bus, addresses, commands, responses):
@@ -507,9 +507,16 @@ class TestHyundaiLongitudinalSafetyCameraSCCRefreshHybrid(HyundaiRefreshHybridGa
self.packer = CANPackerSafety("hyundai_can_refresh_generated")
self.safety = libsafety_py.libsafety
flags = HyundaiSafetyFlags.CAMERA_SCC | HyundaiSafetyFlags.CAN_REFRESH_MSGS | HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.LONG
self.safety.set_alternative_experience(0)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, flags)
self.safety.init_tests()
def test_set_resume_buttons(self):
self.assertFalse(self.safety.get_controls_allowed())
self.assertTrue(self._rx(self._button_msg(0, main_button=1)))
self.assertTrue(self._rx(self._button_msg(0, main_button=0)))
super().test_set_resume_buttons()
def test_hybrid_long_refresh_length_and_acc_allowlist(self):
self.assertTrue(self._tx(common.make_msg(0, 0x485, 8)))
self.assertFalse(self._tx(common.make_msg(0, 0x485, 4)))
@@ -37,7 +37,8 @@ class TestBlendedCruiseAcknowledgment(unittest.TestCase):
helper.v_cruise_kph = helper.v_cruise_kph_last = 90.
instance = SimpleNamespace(sm={'carControl': SimpleNamespace(enabled=True)},
CC_prev=SimpleNamespace(enabled=False), CS_prev=previous,
experimental_mode=False, is_metric=True, vehicle_startup=holder, v_cruise_helper=helper)
experimental_mode=False, is_metric=True, initial_cruise_speed=V_CRUISE_INITIAL,
vehicle_startup=holder, v_cruise_helper=helper)
Car.update_cruise_speed(cast(Car, instance), previous)
self.assertIsNone(holder.consume_cruise_resume())
return helper.v_cruise_kph
@@ -1,4 +1,5 @@
import unittest
from functools import cache
from opendbc.can import CANPacker
from opendbc.car.structs import CarParams
@@ -8,7 +9,16 @@ from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests.test_hyundai_ev9_long import Ev9LongFixture
@cache
def release_safety():
default = libsafety_py.libsafety
library = libsafety_py.ffi.dlopen(libsafety_py._build_libsafety(release=True))
assert libsafety_py.libsafety is default
return library
class PEFixture:
RELEASE_NATIVE = False
packet = Ev9LongFixture.packet
feed = Ev9LongFixture.feed
@@ -16,7 +26,7 @@ class PEFixture:
ready = Ev9LongFixture.ready
def setUp(self):
self.safety = libsafety_py.libsafety
self.safety = release_safety() if self.RELEASE_NATIVE else libsafety_py.libsafety
self.packer = CANPacker('hyundai_canfd_generated')
self.safety.init_tests()
self.safety.set_alternative_experience(0)
@@ -177,6 +187,8 @@ class TestPELongDebug(PEFixture, unittest.TestCase):
class TestPELongReleaseDenied(PEFixture, unittest.TestCase):
RELEASE_NATIVE = True
def test_release_never_admits_proposed_pe_long_profile(self):
for _ in range(6):
@@ -8,6 +8,8 @@ from opendbc.safety.tests.test_hyundai_ev9_long import Ev9LongFixture
class TestPECombinedReleaseDenied(PEFixture, unittest.TestCase):
RELEASE_NATIVE = True
def test_combined_pe_profile_has_no_transmit_authority_in_release(self):
self.safety.set_alternative_experience(32)
self.assertEqual(self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, 0x5495), 0)
@@ -29,7 +29,7 @@ from openpilot.cereal import log
disable_ecu_module = importlib.import_module('opendbc.car.disable_ecu')
def classic_frames(ci, tick, *, main=0, lkas=0, button=0, engaged=False):
def classic_frames(ci, tick, *, main=0, main_button=0, lkas=0, button=0, engaged=False):
assert ci.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID
packer = CANPacker('hyundai_can_generated')
@@ -52,7 +52,7 @@ def classic_frames(ci, tick, *, main=0, lkas=0, button=0, engaged=False):
counter = tick // period
values = {}
if name == 'CLU11':
values.update(CF_Clu_AliveCnt1=counter%16, CF_Clu_CruiseSwState=button, CF_Clu_CruiseSwMain=main)
values.update(CF_Clu_AliveCnt1=counter%16, CF_Clu_CruiseSwState=button, CF_Clu_CruiseSwMain=main_button)
elif name == 'E_EMS11':
values.update(CR_Vcu_AccPedDep_Pos=0)
elif name == 'WHL_SPD11':
@@ -204,7 +204,7 @@ def test_full_engagement_arms_aol_through_stock_off_with_main_on(raw_fault, with
return send(service, raw)
local.setattr(card.pm, 'send', capture)
def step(*, main=1, lkas=0, button=0, engaged=False, withdraw_request=False, bad_checksum=False,
def step(*, main=1, main_button=0, lkas=0, button=0, engaged=False, withdraw_request=False, bad_checksum=False,
heartbeat_override=None, inject_relay=False, drop_wheel=False):
nonlocal tick
tick += 1
@@ -219,7 +219,7 @@ def test_full_engagement_arms_aol_through_stock_off_with_main_on(raw_fault, with
native.set_timer(source_ns // 1000)
native.set_aol_test_heartbeat(heartbeat if heartbeat_override is None else heartbeat_override)
native.aol_set_host_request(request)
frames = classic_frames(card.CI, tick, main=main, lkas=lkas, button=button, engaged=engaged)
frames = classic_frames(card.CI, tick, main=main, main_button=main_button, lkas=lkas, button=button, engaged=engaged)
if drop_wheel:
frames = [frame for frame in frames if frame[0] != 0x386]
if bad_checksum:
@@ -352,6 +352,10 @@ def test_full_engagement_arms_aol_through_stock_off_with_main_on(raw_fault, with
assert card.aol_card_intent.allowed_latch and not card.aol_card_intent.pause_lateral
assert not state.cruiseState.enabled and state.cruiseState.available
assert native_counts['lateral_only_nonzero'] > 0
assert not card.aol_card_intent._main_held
if withdrawal == 'main-off':
for _ in range(2):
step(main=0, main_button=1, engaged=False)
if withdrawal == 'lkas-off':
for _ in range(2):
step(main=1, lkas=1, engaged=False)
+8 -1
View File
@@ -571,7 +571,14 @@ def run(
drain(control_socket, control, messaging.recv_one_or_none, sink, now)
drain(applied_socket, output, messaging.recv_one_or_none, sink, now)
source_valid, now = source_current()
if collector is not None:
# Decoding queued frames may outlast the sampled shared inputs. Consume
# real pending deliveries before pose/native checks; keep their original
# headers and receipts for the next iteration instead of polling twice.
source_delivery.refresh(sm)
source_valid, now = source_current(read=collector is not None)
if tracking_pose_header < source_delivery.pose_header <= now:
tracking_pose_header = source_delivery.pose_header
current_native = False
if source_valid and collector is not None and collector.ready:
current_native = current_native_health(sm, CP, collector.ready[-1][0], now)
@@ -0,0 +1,57 @@
"""Actual daemon scheduling only; synthetic collector is not fit/native proof."""
from types import SimpleNamespace as S
import pytest
from openpilot.starpilot.flm import steerlearnerd
from openpilot.starpilot.flm.tests.test_live_tracking_daemon import BASE, source
@pytest.mark.parametrize('fresh_allowed', [True, False])
def test_pose_observer_consumes_delivery_that_arrived_during_decoding(monkeypatch, fresh_allowed):
now = [BASE]
class Stop(Exception):
pass
class SM:
updated = {'deviceMotion': False}
logMonoTime = {'deviceMotion': BASE}
marker = 'old'
pending = False
def update(self, timeout=None):
if timeout == 0 and self.pending:
self.marker = 'new'
self.updated['deviceMotion'] = True
self.logMonoTime['deviceMotion'] = now[0]
self.pending = False
sm = SM()
evidence = S(source_epoch='b'*64, source_receipt_ns=BASE, control_ns=BASE,
identity='a'*64, generation=1, domain='normalized_torque', stage_revision='stage',
response_revision='response', controller_mode='torque', policy='policy',
baseline_revision='d'*64, controller_revision='controller', turn_assist=False)
adapter = S(event_collection=True, source_plant_protocol='fixture',
bind_source=lambda value: None, select_objective=lambda key: None, prepare_control=lambda value: value)
collector = S(adapter=adapter, ready=[(evidence, object())], control=lambda *args: None)
monkeypatch.setattr('openpilot.starpilot.flm.event_collector.EventFullrateCollector', lambda value: collector)
monkeypatch.setattr('openpilot.starpilot.flm.source_plant_runtime.start_original_capture', lambda value: True)
monkeypatch.setattr('openpilot.starpilot.flm.native_health.current_native_health',
lambda *args: sm.marker == 'new' and fresh_allowed)
monkeypatch.setattr(steerlearnerd, 'read_control', lambda event: evidence)
seen = []
def observe(_sm, cp, current, stamp, native):
seen.append((_sm.marker, stamp, native, _sm.logMonoTime['deviceMotion']))
raise Stop
monkeypatch.setattr('openpilot.starpilot.flm.source_plant_runtime.observe', observe)
control_socket, applied_socket = object(), object()
def drain(sock, callback, *args):
if sock is control_socket:
callback(S(which=lambda:'starpilotLateralState', starpilotLateralState=S(learningEvidence=S(version=1))), None, BASE)
else:
now[0] += 80_000_000
sm.pending = True
monkeypatch.setattr(steerlearnerd, 'drain', drain)
actor=S(ingress=None, interrupt=lambda *a,**k: None, close=lambda *a: True)
fitter=S(cancel=lambda *a: None, close=lambda *a: True)
with pytest.raises(Stop):
steerlearnerd.run(S(),sm,control_socket,applied_socket,S(),lambda *a:adapter,None,
lambda stamp:source(stamp),lambda value:('objective',),lambda value:'objective',
None,None,fitter,None,clock=lambda:now[0],live_actor=actor)
assert seen == [('new', BASE+80_000_000, fresh_allowed, BASE+80_000_000)]
assert sm.logMonoTime['deviceMotion'] == BASE+80_000_000
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "fd982ffeecd96a97883067e2a73d2d794c594ea548cc5c7bd82ad98e076f88d7", "schema_version": 1}
{"protected_inventory_sha256": "fd1aca7f7dace9d37ff77f6dbd3da45e95cf674ac48b3bb1a0a26ddad8f3435f", "schema_version": 1}