Files
StarPilot/openpilot/starpilot/tests/test_gm_controls_startup.py
T
firestar5683 80fbb4f6db Feature registration
Register vehicle controls, planner modes, UI actions and Galaxy services after their providers exist. Wire the shared runtime entrypoints and cover their combined behavior.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com>
Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com>
Co-authored-by: Kacper Rączy <gfw.kra@gmail.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
Co-authored-by: stef <19478336+stefpi@users.noreply.github.com>
Co-authored-by: whoisdomi <dcantu83@gmail.com>

Co-authored-by: Intelli <contact@intelli.software>
Co-authored-by: haraschax <6804392+haraschax@users.noreply.github.com>
Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

145 lines
7.6 KiB
Python

"""Native GM Card publication and disabled Controls startup boundary."""
import itertools
import os
from pathlib import Path
import time
import unittest
from unittest.mock import patch
from openpilot.cereal import messaging
from opendbc.car import gen_empty_fingerprint, structs
from opendbc.car.gm.tests import test_bolt_pedal as pedal_fixture
from opendbc.car.gm.values import CAR
from openpilot.common.params import Params
from openpilot.common.prefix import OpenpilotPrefix
from openpilot.selfdrive.car.card import Car
from openpilot.selfdrive.controls.controlsd import Controls
from openpilot.starpilot.lateral.torque_settings import DOCUMENT_KEY, FieldChoice, PlatformProfile, serialize_document
class TestGMControlsStartup(unittest.TestCase):
def startup(self, identity, *, alpha=False, disable=False, camera=True, aol=False, torque='absent'):
params = Params()
for key, value in [('OpenpilotEnabledToggle', True), ('SafeMode', False), ('IsReleaseBranch', False),
('AlphaLongitudinalEnabled', alpha), ('GMPedalLongitudinal', True),
('DisableOpenpilotLongitudinal', disable), ('AlwaysOnLateral', aol)]:
params.put_bool(key, value, block=True)
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x201] = 6
if camera:
fingerprint[2][0x180] = 4
result = (identity, fingerprint, '0' * 17, [], structs.CarParams.FingerprintSource.can, True)
with patch('opendbc.car.car_helpers.fingerprint', return_value=result), \
patch('openpilot.selfdrive.car.card.messaging.recv_one_retry',
return_value=messaging.new_message('can', 1)):
card = Car()
if torque != 'absent':
params.put_bool('AdvancedLateralTune', True, block=True)
tune = card.CP.lateralTuning.torque
basis = (float(tune.latAccelFactor), float(tune.latAccelOffset), float(tune.friction))
raw = serialize_document({str(identity): PlatformProfile(basis, FieldChoice(), FieldChoice('custom', .14))})
Path(params.get_param_path(DOCUMENT_KEY)).write_bytes(raw if torque == 'valid' else b'{invalid')
controls = Controls()
self.assertEqual(controls.CP.to_dict(), card.CP.to_dict())
self.assertEqual(controls.torque_host is not None, torque == 'valid' and not card.CP.passive)
self.assertFalse(params.get_bool('ControlsReady'))
command, lateral_log = controls.state_control()
self.assertFalse(command.enabled)
self.assertFalse(command.latActive)
self.assertFalse(command.longActive)
deadline = time.monotonic() + 1
while not card.sm.seen['carControl'] and time.monotonic() < deadline:
controls.publish(command, lateral_log)
card.sm.update(10)
self.assertTrue(card.sm.seen['carControl'])
self.assertFalse(card.sm['carControl'].enabled)
invalid = structs.CarState.new_message()
card.controls_update(invalid, card.sm['carControl'])
self.assertFalse(params.get_bool('ControlsReady'))
return card, controls
def test_final_card_configuration_and_controls_constructor(self):
identities = (CAR.CHEVROLET_BOLT_CC_2018_2021, CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
for identity, alpha, disable, camera in itertools.product(identities, (False, True), (False, True), (False, True)):
with self.subTest(identity=identity, alpha=alpha, disable=disable, camera=camera), \
OpenpilotPrefix(), patch.dict(os.environ, {'SIMULATION': '1'}):
self.startup(identity, alpha=alpha, disable=disable, camera=camera)
def test_saved_torque_and_aol_disabled_initial_output(self):
for identity, aol, torque in itertools.product(
(CAR.CHEVROLET_BOLT_CC_2018_2021, CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL),
(False, True), ('absent', 'valid', 'malformed')):
with self.subTest(identity=identity, aol=aol, torque=torque), \
OpenpilotPrefix(), patch.dict(os.environ, {'SIMULATION': '1'}):
self.startup(identity, alpha=True, aol=aol, torque=torque)
def test_restored_gateway_discovery_card_publication_and_controls(self):
from opendbc.car.gm.fingerprints import FINGERPRINTS
from opendbc.car.gm.values import ORDINARY_CC_WORD, is_ordinary_cc_profile
identities = (CAR.CADILLAC_CT6_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_EQUINOX_CC,
CAR.CHEVROLET_SUBURBAN_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CHEVROLET_MALIBU_CC)
for identity, disable in itertools.product(identities, (False, True)):
with self.subTest(identity=identity, disable=disable), OpenpilotPrefix(), \
patch.dict(os.environ, {'SIMULATION': '1'}):
params = Params()
for key, value in [('OpenpilotEnabledToggle', True), ('SafeMode', False), ('IsReleaseBranch', False),
('AlphaLongitudinalEnabled', False), ('GMPedalLongitudinal', False),
('DisableOpenpilotLongitudinal', disable), ('AlwaysOnLateral', False)]:
params.put_bool(key, value, block=True)
fingerprint = gen_empty_fingerprint()
fingerprint[0].update(FINGERPRINTS[identity][0])
result = (identity, fingerprint, '0' * 17, [], structs.CarParams.FingerprintSource.can, True)
with patch('opendbc.car.car_helpers.fingerprint', return_value=result), \
patch('openpilot.selfdrive.car.card.messaging.recv_one_retry',
return_value=messaging.new_message('can', 1)):
card = Car()
self.assertTrue(is_ordinary_cc_profile(card.CP))
self.assertEqual(card.CP.openpilotLongitudinalControl, not disable)
self.assertEqual(card.CP.safetyConfigs[0].safetyParam, ORDINARY_CC_WORD)
self.assertFalse(card.CP.pcmCruise)
controls = Controls()
self.assertEqual(controls.CP.to_dict(), card.CP.to_dict())
self.assertIsNone(controls.torque_host)
command, lateral_log = controls.state_control()
self.assertFalse(command.enabled)
self.assertFalse(command.latActive)
self.assertFalse(command.longActive)
controls.publish(command, lateral_log)
self.assertFalse(params.get_bool('ControlsReady'))
def test_live_disabled_controls_and_real_parser_unlock_initialization(self):
with OpenpilotPrefix(), patch.dict(os.environ, {'SIMULATION': '1'}):
card, controls = self.startup(CAR.CHEVROLET_BOLT_CC_2018_2021, camera=True)
fixture = pedal_fixture.TestBoltPedalStartupParser()
with patch('opendbc.car.gm.tests.test_bolt_pedal.CarInterface', return_value=card.CI):
_, state = fixture.stream(card.CP)
self.assertTrue(state.canValid)
card.controls_update(state, card.sm['carControl'])
self.assertFalse(Params().get_bool('ControlsReady'))
deadline = time.monotonic() + 1
while not controls.sm.seen['carState'] and time.monotonic() < deadline:
event = messaging.new_message('carState')
event.valid = True
event.carState = state
card.pm.send('carState', event)
controls.sm.update(10)
self.assertTrue(controls.sm.seen['carState'])
# The fixture feeds the production parser, not Panda safety/permission.
command, lateral_log = controls.state_control()
controls.publish(command, lateral_log)
card.sm.update(100)
self.assertTrue(card.sm.valid['carControl'])
self.assertTrue(card.sm.alive['carControl'])
card.controls_update(state, card.sm['carControl'])
self.assertTrue(card.ci_initialized)
deadline = time.monotonic() + 1
while not Params().get_bool('ControlsReady') and time.monotonic() < deadline:
time.sleep(.001)
self.assertTrue(Params().get_bool('ControlsReady'))
self.assertFalse(card.sm['carControl'].enabled)
if __name__ == '__main__':
unittest.main()