mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-06-27 17:42:04 +08:00
The Plum
This commit is contained in:
@@ -165,6 +165,10 @@ jobs:
|
||||
"panda/board/obj/panda_h7.bin.signed"
|
||||
"panda/board/obj/panda_remote.bin.signed"
|
||||
"panda/board/obj/panda_h7_remote.bin.signed"
|
||||
"panda/board/obj/panda_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_h7_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_remote_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_h7_remote_can_ignition_only.bin.signed"
|
||||
"panda/board/obj/panda_jungle_h7.bin.signed"
|
||||
"panda/board/obj/body_h7.bin.signed"
|
||||
)
|
||||
|
||||
@@ -286,6 +286,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"FlashPanda", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
|
||||
{"GMDashSpoofOffsets", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2}},
|
||||
{"IgnoreIgnitionLine", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
|
||||
{"RemapCancelToDistance", {PERSISTENT, BOOL, "0", "0"}},
|
||||
|
||||
@@ -4,7 +4,7 @@ import numpy as np
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.car import Bus, DT_CTRL, make_tester_present_msg, rate_limit, structs
|
||||
from opendbc.car.common.filter_simple import FirstOrderFilter
|
||||
from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_steer_angle_limits_vm, common_fault_avoidance
|
||||
from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_steer_angle_limits_vm, common_fault_avoidance, get_max_angle_delta_vm
|
||||
from opendbc.car.common.conversions import Conversions as CV
|
||||
from opendbc.car.hyundai import hyundaicanfd, hyundaican
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
@@ -64,6 +64,10 @@ REDNECK_BUTTON_COPIES_TIME = 7
|
||||
REDNECK_BUTTON_COPIES_TIME_IMPERIAL = [REDNECK_BUTTON_COPIES_TIME + 3, 70]
|
||||
REDNECK_BUTTON_COPIES_TIME_METRIC = [REDNECK_BUTTON_COPIES_TIME, 40]
|
||||
ANGLE_SAFETY_BASELINE_MODEL = str(CAR.KIA_SPORTAGE_HEV_2026)
|
||||
DEFAULT_ANGLE_SMOOTHING_VEGO_BP = [5.0, 10.0, 20.0]
|
||||
DEFAULT_ANGLE_SMOOTHING_ALPHA_V = [0.2, 0.1, 0.0]
|
||||
KIA_EV9_ANGLE_SMOOTHING_VEGO_BP = [0.0, 8.5, 11.0, 13.8, 18.0]
|
||||
KIA_EV9_ANGLE_SMOOTHING_ALPHA_V = [0.05, 0.1, 0.3, 0.6, 1.0]
|
||||
|
||||
|
||||
def egmp_dynamic_longitudinal_tuning(CP) -> bool:
|
||||
@@ -220,6 +224,22 @@ def get_baseline_safety_cp():
|
||||
return CarInterface.get_non_essential_params(ANGLE_SAFETY_BASELINE_MODEL)
|
||||
|
||||
|
||||
def get_angle_smoothing_alpha(CP, v_ego: float) -> float:
|
||||
if CP.carFingerprint == CAR.KIA_EV9:
|
||||
return float(np.interp(v_ego, KIA_EV9_ANGLE_SMOOTHING_VEGO_BP, KIA_EV9_ANGLE_SMOOTHING_ALPHA_V))
|
||||
return float(np.interp(v_ego, DEFAULT_ANGLE_SMOOTHING_VEGO_BP, DEFAULT_ANGLE_SMOOTHING_ALPHA_V))
|
||||
|
||||
|
||||
def apply_steer_angle_limits_vm_checked(apply_angle: float, apply_angle_last: float, v_ego_raw: float,
|
||||
steering_angle: float, lat_active: bool, limits, VM: VehicleModel) -> float | None:
|
||||
new_apply_angle = apply_steer_angle_limits_vm(apply_angle, apply_angle_last, v_ego_raw, steering_angle, lat_active, limits, VM)
|
||||
v_ego_raw = max(v_ego_raw, 1.0)
|
||||
max_angle_delta = min(get_max_angle_delta_vm(v_ego_raw, VM, limits), limits.ANGLE_LIMITS.MAX_ANGLE_RATE)
|
||||
safety_violation = lat_active and not np.isclose(new_apply_angle,
|
||||
rate_limit(new_apply_angle, apply_angle_last, -max_angle_delta, max_angle_delta))
|
||||
return None if safety_violation else new_apply_angle
|
||||
|
||||
|
||||
def compute_torque_reduction_gain(steering_torque, v_ego, lat_active, last_gain):
|
||||
if lat_active:
|
||||
ceiling = np.interp(v_ego, [0.5, 1.5], [1.0, 0.85])
|
||||
@@ -382,15 +402,16 @@ class CarController(CarControllerBase):
|
||||
-self.params.ANGLE_LIMITS.STEER_ANGLE_MAX,
|
||||
self.params.ANGLE_LIMITS.STEER_ANGLE_MAX))
|
||||
|
||||
self.angle_filter.update_alpha(float(np.interp(CS.out.vEgo, [5.0, 10.0, 20.0], [0.2, 0.1, 0.0])))
|
||||
self.angle_filter.update_alpha(get_angle_smoothing_alpha(self.CP, CS.out.vEgo))
|
||||
desired_angle = self.angle_filter.update(desired_angle)
|
||||
|
||||
apply_angle = apply_steer_angle_limits_vm(desired_angle, self.apply_angle_last, v_ego_raw,
|
||||
CS.out.steeringAngleDeg, CC.latActive, self.params, self.VM)
|
||||
angle_limit_fn = apply_steer_angle_limits_vm_checked if self.CP.carFingerprint == CAR.KIA_EV9 else apply_steer_angle_limits_vm
|
||||
apply_angle = angle_limit_fn(desired_angle, self.apply_angle_last, v_ego_raw,
|
||||
CS.out.steeringAngleDeg, CC.latActive, self.params, self.VM)
|
||||
|
||||
if str(self.CP.carFingerprint) != ANGLE_SAFETY_BASELINE_MODEL:
|
||||
apply_angle = apply_steer_angle_limits_vm(apply_angle or desired_angle, self.apply_angle_last, v_ego_raw,
|
||||
CS.out.steeringAngleDeg, CC.latActive, self.params, self.BASELINE_VM)
|
||||
apply_angle = angle_limit_fn(apply_angle or desired_angle, self.apply_angle_last, v_ego_raw,
|
||||
CS.out.steeringAngleDeg, CC.latActive, self.params, self.BASELINE_VM)
|
||||
|
||||
apply_torque = compute_torque_reduction_gain(CS.out.steeringTorque, v_ego_raw, CC.latActive, self.apply_torque_last)
|
||||
apply_steer_req = CC.latActive and apply_torque != 0.0
|
||||
@@ -650,7 +671,8 @@ class CarController(CarControllerBase):
|
||||
# and stops publishing object tracks when it disappears. Spoof it periodically on
|
||||
# PT bus so the radar keeps tracking.
|
||||
if self.CP.carFingerprint in CANFD_RADAR_LIVE_LONGITUDINAL_CAR and self.frame % 4 == 0:
|
||||
can_sends.append(hyundaicanfd.create_accelerator_brake_alt_spoof(0, self.frame // 4, CS.out.brakePressed, CS.out.gasPressed))
|
||||
can_sends.append(hyundaicanfd.create_accelerator_brake_alt_spoof(0, self.frame // 4, CS.out.brakePressed,
|
||||
CS.out.gasPressed, self.CP.carFingerprint))
|
||||
elif not ccnc_non_hda2:
|
||||
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
|
||||
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.frame % 5 == 0:
|
||||
|
||||
@@ -96,6 +96,8 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
||||
lfa_base_values=None, lkas_base_values=None, lka_icon=None):
|
||||
if lka_icon is None:
|
||||
lka_icon = 2 if enabled else 1
|
||||
ev9_angle_lkas_alt = str(CP.carFingerprint) == "KIA_EV9" and CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and \
|
||||
CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
||||
|
||||
control_values = {
|
||||
"LKA_MODE": 2,
|
||||
@@ -128,6 +130,24 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
||||
lkas_values["ADAS_StrAnglReqVal"] = apply_angle
|
||||
lkas_values["LKAS_ANGLE_ACTIVE"] = 2 if lat_active else 1
|
||||
lkas_values["ADAS_ACIAnglTqRedcGainVal"] = apply_torque if lat_active else 0.0
|
||||
if ev9_angle_lkas_alt:
|
||||
lkas_values.update({
|
||||
"LKA_MODE": 0,
|
||||
"LKA_AVAILABLE": 3 if lat_active else 0,
|
||||
"LKA_WARNING": 0,
|
||||
"LKA_ICON": lka_icon,
|
||||
"FCA_SYSWARN": 0,
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 0,
|
||||
"LKA_ASSIST": 0,
|
||||
"DAMP_FACTOR": 100,
|
||||
"HAS_LANE_SAFETY": 0,
|
||||
})
|
||||
# These signals overlap DAMP_FACTOR in the local DBC naming; omitting them
|
||||
# preserves the stock angle-steering damping byte expected by the ADAS ECU.
|
||||
lkas_values.pop("STEER_MODE", None)
|
||||
lkas_values.pop("NEW_SIGNAL_2", None)
|
||||
|
||||
ret = []
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
@@ -709,11 +729,15 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
|
||||
# radar stops publishing real object tracks. Spoof this message ourselves with valid CRC
|
||||
# and current pedal state so the radar keeps tracking.
|
||||
# Length is 24 bytes on Ioniq 6 (DBC declares 32 for ICE Hyundais, but EV firmware uses 24).
|
||||
# Byte template captured from a real ADAS broadcast; bytes 6-23 appear static / config.
|
||||
# Byte templates captured from real ADAS broadcasts; only checksum, counter,
|
||||
# brake, and accelerator bits are updated for the radar heartbeat.
|
||||
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
|
||||
_KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000")
|
||||
|
||||
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool) -> CanData:
|
||||
d = bytearray(_ACCEL_BRAKE_ALT_TEMPLATE)
|
||||
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool,
|
||||
car_fingerprint=None) -> CanData:
|
||||
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE if str(car_fingerprint) == "KIA_EV9" else _ACCEL_BRAKE_ALT_TEMPLATE
|
||||
d = bytearray(template)
|
||||
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
|
||||
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
|
||||
d[22] = (d[22] & ~0x01) | (0x01 if accelerator_pressed else 0x00) # ACCELERATOR_PEDAL_PRESSED (bit 176)
|
||||
|
||||
@@ -4,6 +4,7 @@ from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
|
||||
CANFD_SECURITYACCESS_CAR, \
|
||||
CANFD_ANGLE_LONGITUDINAL_CAR, \
|
||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||
RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
|
||||
@@ -99,8 +100,8 @@ class CarInterface(CarInterfaceBase):
|
||||
# this needs to be figured out for cars without an ADAS ECU
|
||||
# Cars in CANFD_SECURITYACCESS_CAR are known to have ADAS ECUs that work with SecurityAccess
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
if lka_steering and ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
# Angle-steering LKA platforms still need stock longitudinal validation.
|
||||
if lka_steering and ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING and candidate not in CANFD_ANGLE_LONGITUDINAL_CAR:
|
||||
# Most angle-steering LKA platforms still need stock longitudinal validation.
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
|
||||
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN]
|
||||
|
||||
@@ -10,7 +10,8 @@ from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car
|
||||
from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \
|
||||
update_ioniq_6_longitudinal_tuning, \
|
||||
update_genesis_g90_longitudinal_tuning, egmp_dynamic_longitudinal_tuning, \
|
||||
should_reset_ev6_gt_line_longitudinal_tuning, reset_ev6_gt_line_longitudinal_tuning
|
||||
should_reset_ev6_gt_line_longitudinal_tuning, reset_ev6_gt_line_longitudinal_tuning, \
|
||||
get_angle_smoothing_alpha, apply_steer_angle_limits_vm_checked
|
||||
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai import hyundaican, hyundaicanfd
|
||||
@@ -22,6 +23,7 @@ from opendbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
|
||||
LEGACY_LONGITUDINAL_CAR, CarControllerParams, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
|
||||
HyundaiStarPilotSafetyFlags, Buttons, kia_ev6_gt_line_longitudinal_tuning
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
|
||||
LongCtrlState = CarControl.Actuators.LongControlState
|
||||
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
|
||||
@@ -168,6 +170,7 @@ class TestHyundaiFingerprint:
|
||||
(CAR.GENESIS_GV60_EV_1ST_GEN, MRR30_RADAR_START_ADDR),
|
||||
(CAR.HYUNDAI_KONA_EV_2ND_GEN, MRR35_RADAR_START_ADDR),
|
||||
(CAR.HYUNDAI_IONIQ_9, MRR35_RADAR_START_ADDR),
|
||||
(CAR.KIA_EV9, MRR35_RADAR_START_ADDR),
|
||||
):
|
||||
radar_config = get_radar_track_config(candidate)
|
||||
assert radar_config.start_addr == radar_addr
|
||||
@@ -226,6 +229,21 @@ class TestHyundaiFingerprint:
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert not CP.radarUnavailable
|
||||
|
||||
ev9_radar_config = get_radar_track_config(CAR.KIA_EV9)
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[CanBus(None, fingerprint).CAM][0x110] = 32
|
||||
fingerprint[ev9_radar_config.bus][ev9_radar_config.start_addr] = ev9_radar_config.expected_length
|
||||
ev9_car_fw = [CarParams.CarFw(ecu=Ecu.adas, fwVersion=b"", address=0x730, brand="hyundai")]
|
||||
CP = CarInterface.get_params(CAR.KIA_EV9, fingerprint, ev9_car_fw, True, False, False, None)
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert not CP.radarUnavailable
|
||||
assert CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_ANGLE_STEERING
|
||||
|
||||
CP = CarInterface.get_params(CAR.KIA_EV9, fingerprint, [], True, False, False, None)
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
|
||||
for candidate in HYUNDAI_NON_SCC_CARS:
|
||||
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], True, False, False, None)
|
||||
assert bool(CP.flags & HyundaiFlags.NON_SCC)
|
||||
@@ -260,6 +278,22 @@ class TestHyundaiFingerprint:
|
||||
assert CP.steerControlType == CarParams.SteerControlType.angle
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_ANGLE_STEERING
|
||||
|
||||
def test_ev9_angle_smoothing_is_ev9_specific(self):
|
||||
ev9_cp = SimpleNamespace(carFingerprint=CAR.KIA_EV9)
|
||||
other_cp = SimpleNamespace(carFingerprint=CAR.KIA_SPORTAGE_HEV_2026)
|
||||
|
||||
assert get_angle_smoothing_alpha(ev9_cp, 0.0) == pytest.approx(0.05)
|
||||
assert get_angle_smoothing_alpha(ev9_cp, 13.8) == pytest.approx(0.6)
|
||||
assert get_angle_smoothing_alpha(ev9_cp, 20.0) == pytest.approx(1.0)
|
||||
assert get_angle_smoothing_alpha(other_cp, 20.0) == pytest.approx(0.0)
|
||||
|
||||
def test_checked_angle_limiter_blocks_rate_accel_conflict(self):
|
||||
CP = CarInterface.get_non_essential_params(CAR.KIA_EV9)
|
||||
params = CarControllerParams(CP)
|
||||
|
||||
assert apply_steer_angle_limits_vm_checked(0.0, 100.0, 20.0, 100.0, True,
|
||||
params, VehicleModel(CP)) is None
|
||||
|
||||
def test_ccnc_hda2_lka_layout_does_not_set_ccnc_safety_param(self):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
cam_can = CanBus(None, fingerprint).CAM
|
||||
@@ -1554,6 +1588,67 @@ class TestHyundaiFingerprint:
|
||||
assert parser.vl["LKAS_ALT"]["STEER_REQ"] == 1
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ICON"] == 2
|
||||
|
||||
def test_ev9_angle_lkas_alt_uses_angle_status_fields(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.KIA_EV9
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 2,
|
||||
"LKA_AVAILABLE": 0,
|
||||
"LKA_WARNING": 1,
|
||||
"LKA_ICON": 1,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 17,
|
||||
"STEER_REQ": 1,
|
||||
"LFA_BUTTON": 1,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 5,
|
||||
"NEW_SIGNAL_2": 0,
|
||||
"LKAS_ANGLE_ACTIVE": 1,
|
||||
"HAS_LANE_SAFETY": 1,
|
||||
"ADAS_StrAnglReqVal": 12.3,
|
||||
"ADAS_ACIAnglTqRedcGainVal": 0.42,
|
||||
"DAMP_FACTOR": 0,
|
||||
}
|
||||
|
||||
msgs = hyundaicanfd.create_steering_messages(packer, CP, can_bus, True, True, 0.44, -31.5,
|
||||
lkas_base_values=stock_lkas, lka_icon=2)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["LKA_MODE"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_AVAILABLE"] == 3
|
||||
assert parser.vl["LKAS_ALT"]["LKA_WARNING"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ICON"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["FCA_SYSWARN"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["TORQUE_REQUEST"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["STEER_REQ"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LFA_BUTTON"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ASSIST"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["DAMP_FACTOR"] == 100
|
||||
assert parser.vl["LKAS_ALT"]["LKAS_ANGLE_ACTIVE"] == 2
|
||||
assert parser.vl["LKAS_ALT"]["HAS_LANE_SAFETY"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_StrAnglReqVal"] == pytest.approx(-31.5)
|
||||
assert parser.vl["LKAS_ALT"]["ADAS_ACIAnglTqRedcGainVal"] == pytest.approx(0.44)
|
||||
|
||||
def test_ev9_accelerator_brake_alt_spoof_matches_route_template(self):
|
||||
msg = hyundaicanfd.create_accelerator_brake_alt_spoof(0, 0x66, True, False, CAR.KIA_EV9)
|
||||
|
||||
assert msg.address == 0x100
|
||||
assert msg.src == 0
|
||||
assert msg.dat.hex() == "470c6600ff006f00e80400001201030055ffff0000000000"
|
||||
|
||||
def test_ioniq_6_lfahda_cluster_allows_lfa_icon_override(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.HYUNDAI_IONIQ_6
|
||||
|
||||
@@ -1129,7 +1129,9 @@ CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with
|
||||
# CAN-FD cars with ADAS ECUs that work with the communication-control path.
|
||||
CANFD_SECURITYACCESS_CAR = {CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN}
|
||||
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
|
||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.GENESIS_GV60_EV_1ST_GEN}
|
||||
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9}
|
||||
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.GENESIS_GV60_EV_1ST_GEN,
|
||||
CAR.KIA_EV9}
|
||||
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
|
||||
CAR.HYUNDAI_IONIQ,
|
||||
CAR.HYUNDAI_KONA_EV_2022,
|
||||
|
||||
@@ -68,10 +68,11 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
if candidate == CAR.TOYOTA_PRIUS:
|
||||
stop_and_go = True
|
||||
ret.flags |= ToyotaFlags.HYBRID.value
|
||||
# Only give steer angle deadzone to for bad angle sensor prius
|
||||
for fw in car_fw:
|
||||
if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00':
|
||||
ret.steerActuatorDelay = 0.25
|
||||
ret.steerActuatorDelay = 0.14
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.3)
|
||||
|
||||
elif candidate in (CAR.LEXUS_RX, CAR.LEXUS_RX_TSS2):
|
||||
@@ -154,7 +155,9 @@ class CarInterface(CarInterfaceBase):
|
||||
# to a negative value, so it won't matter.
|
||||
ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptorDEPRECATED) else MIN_ACC_SPEED
|
||||
|
||||
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED:
|
||||
prius_long_defaults = candidate == CAR.TOYOTA_PRIUS and ret.openpilotLongitudinalControl
|
||||
|
||||
if candidate in TSS2_CAR or ret.enableGasInterceptorDEPRECATED or prius_long_defaults:
|
||||
ret.flags |= ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
|
||||
ret.vEgoStopping = 0.25
|
||||
|
||||
@@ -61,6 +61,24 @@ class TestToyotaInterfaces:
|
||||
assert car_params.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value
|
||||
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||
|
||||
def test_prius_openpilot_long_uses_hybrid_long_defaults(self):
|
||||
car_params = CarInterface.get_params(
|
||||
CAR.TOYOTA_PRIUS,
|
||||
{0: {0x2FF: 8}},
|
||||
[],
|
||||
alpha_long=False,
|
||||
is_release=False,
|
||||
docs=False,
|
||||
starpilot_toggles=SimpleNamespace(),
|
||||
)
|
||||
|
||||
assert car_params.openpilotLongitudinalControl
|
||||
assert car_params.flags & ToyotaFlags.HYBRID.value
|
||||
assert car_params.flags & ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
assert abs(car_params.longitudinalActuatorDelay - 0.05) < 1e-6
|
||||
assert abs(car_params.vEgoStopping - 0.25) < 1e-6
|
||||
assert abs(car_params.vEgoStarting - 0.25) < 1e-6
|
||||
|
||||
def test_essential_ecus(self, subtests):
|
||||
# Asserts standard ECUs exist for each platform
|
||||
common_ecus = {Ecu.fwdRadar, Ecu.fwdCamera}
|
||||
|
||||
@@ -221,7 +221,8 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
|
||||
// steering
|
||||
const unsigned int steer_addr = (hyundai_canfd_lka_steering && !hyundai_longitudinal) ? hyundai_canfd_get_lka_addr() : 0x12aU;
|
||||
const unsigned int steer_addr = (hyundai_canfd_lka_steering && (hyundai_canfd_angle_steering || !hyundai_longitudinal)) ?
|
||||
hyundai_canfd_get_lka_addr() : 0x12aU;
|
||||
if (msg->addr == steer_addr) {
|
||||
if (hyundai_canfd_angle_steering) {
|
||||
const int lkas_angle_active = (msg->data[9] >> 4U) & 0x3U;
|
||||
@@ -334,6 +335,21 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_ALT_LONG_TX_MSGS[] = {
|
||||
HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(0, 1)
|
||||
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
|
||||
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(1, true)
|
||||
HYUNDAI_CANFD_BLINDSPOT_DASH_TX_MSGS(1)
|
||||
{0x51, 0, 32, .check_relay = false}, // ADRV_0x51
|
||||
{0x100, 0, 24, .check_relay = false}, // ACCELERATOR_BRAKE_ALT radar heartbeat spoof
|
||||
{0x730, 1, 8, .check_relay = false}, // tester present for ADAS ECU disable
|
||||
{0x160, 1, 16, .check_relay = false}, // ADRV_0x160
|
||||
{0x1EA, 1, 32, .check_relay = false}, // ADRV_0x1ea
|
||||
{0x200, 1, 8, .check_relay = false}, // ADRV_0x200
|
||||
{0x345, 1, 8, .check_relay = false}, // ADRV_0x345
|
||||
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CANFD_LFA_STEERING_TX_MSGS[] = {
|
||||
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
|
||||
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
|
||||
@@ -382,7 +398,11 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
};
|
||||
|
||||
SET_RX_CHECKS(hyundai_canfd_lka_steering_long_rx_checks, ret);
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
|
||||
if (hyundai_canfd_lka_steering_alt) {
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_LONG_TX_MSGS, ret);
|
||||
} else {
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Longitudinal checks for LFA steering
|
||||
|
||||
@@ -559,6 +559,61 @@ class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanf
|
||||
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
|
||||
|
||||
|
||||
class TestHyundaiCanfdLKASteeringAltAngleLongEV(HyundaiLongitudinalBase, TestHyundaiCanfdAngleSteering):
|
||||
|
||||
TX_MSGS = [[0x110, 0], [0x1CF, 1], [0x362, 0], [0x51, 0], [0x100, 0], [0x730, 1], [0x12a, 1], [0x160, 1],
|
||||
[0x1ba, 1], [0x1e0, 1], [0x1e5, 1], [0x31a, 1], [0x3b5, 1], [0x3c1, 1],
|
||||
[0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]]
|
||||
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (0x110, 0x362), 1: (0x1a0,)} # LKAS_ALT, CAM_0x362, SCC_CONTROL
|
||||
FWD_BLACKLISTED_ADDRS = {0: MRR35_RADAR_TRACK_ADDRS, 2: [0x110, 0x362]}
|
||||
|
||||
DISABLED_ECU_UDS_MSG = (0x730, 1)
|
||||
DISABLED_ECU_ACTUATION_MSG = (0x1a0, 1)
|
||||
|
||||
PT_BUS = 1
|
||||
SCC_BUS = 1
|
||||
BUTTONS_TX_BUS = 1
|
||||
STEER_MSG = "LKAS_ALT"
|
||||
GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
|
||||
SAFETY_PARAM = HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT | \
|
||||
HyundaiSafetyFlags.CANFD_ANGLE_STEERING | HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS
|
||||
|
||||
def _angle_cmd_msg(self, angle, enabled, increment_timer=True, gain_raw=250):
|
||||
if increment_timer:
|
||||
self.safety.set_timer(self.angle_cmd_cnt * int(1e6 / self.LATERAL_FREQUENCY))
|
||||
self.angle_cmd_cnt += 1
|
||||
|
||||
values = {
|
||||
"LKA_MODE": 0,
|
||||
"LKA_AVAILABLE": 3 if enabled else 0,
|
||||
"LKA_WARNING": 0,
|
||||
"LKA_ICON": 2 if enabled else 1,
|
||||
"FCA_SYSWARN": 0,
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 0,
|
||||
"LKA_ASSIST": 0,
|
||||
"DAMP_FACTOR": 100,
|
||||
"LKAS_ANGLE_ACTIVE": 2 if enabled else 1,
|
||||
"HAS_LANE_SAFETY": 0,
|
||||
"ADAS_StrAnglReqVal": angle,
|
||||
"ADAS_ACIAnglTqRedcGainVal": gain_raw * 0.004 if enabled or gain_raw != 250 else 0.0,
|
||||
}
|
||||
return self.packer.make_can_msg_safety("LKAS_ALT", 0, values)
|
||||
|
||||
def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
|
||||
values = {
|
||||
"aReqRaw": accel,
|
||||
"aReqValue": accel,
|
||||
}
|
||||
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
|
||||
|
||||
def _tx_acc_state_msg(self, main_on):
|
||||
values = {"MainMode_ACC": int(main_on), "ACCMode": 0}
|
||||
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
|
||||
|
||||
|
||||
# Tests longitudinal for ICE, hybrid, EV cars with LFA steering
|
||||
class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCanfdLFASteeringBase):
|
||||
|
||||
|
||||
@@ -169,6 +169,10 @@ build_project("panda", base_project_f4, "./board/main.c", [])
|
||||
build_project("panda_h7", base_project_h7, "./board/main.c", [])
|
||||
build_project("panda_remote", base_project_f4, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9"])
|
||||
build_project("panda_h7_remote", base_project_h7, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9"])
|
||||
build_project("panda_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_remote_can_ignition_only", base_project_f4, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
build_project("panda_h7_remote_can_ignition_only", base_project_h7, "./board/main.c", ["-DPANDA_GM_REMOTE_START_C9", "-DPANDA_IGNORE_IGNITION_LINE"])
|
||||
|
||||
# panda jungle fw
|
||||
flags = [
|
||||
|
||||
+13
-1
@@ -27,9 +27,21 @@
|
||||
#include "board/obj/gitversion.h"
|
||||
|
||||
#include "board/can_comms.h"
|
||||
|
||||
static bool panda_ignition_line(void);
|
||||
|
||||
#include "board/main_comms.h"
|
||||
|
||||
|
||||
static bool panda_ignition_line(void) {
|
||||
#ifdef PANDA_IGNORE_IGNITION_LINE
|
||||
return false;
|
||||
#else
|
||||
return harness_check_ignition();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ********************* Serial debugging *********************
|
||||
|
||||
void debug_ring_callback(uart_ring *ring) {
|
||||
@@ -176,7 +188,7 @@ static void tick_handler(void) {
|
||||
const bool recent_heartbeat = heartbeat_counter == 0U;
|
||||
|
||||
// tick drivers at 1Hz
|
||||
bool started = harness_check_ignition() || ignition_can;
|
||||
bool started = panda_ignition_line() || ignition_can;
|
||||
bootkick_tick(started, recent_heartbeat);
|
||||
|
||||
// increase heartbeat counter and cap it at the uint32 limit
|
||||
|
||||
@@ -12,7 +12,7 @@ static int get_health_pkt(void *dat) {
|
||||
health->voltage_pkt = current_board->read_voltage_mV();
|
||||
health->current_pkt = current_board->read_current_mA();
|
||||
|
||||
health->ignition_line_pkt = (uint8_t)(harness_check_ignition());
|
||||
health->ignition_line_pkt = (uint8_t)(panda_ignition_line());
|
||||
health->ignition_can_pkt = ignition_can;
|
||||
|
||||
health->controls_allowed_pkt = controls_allowed;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -649,28 +649,28 @@ VOLT_PLEXY_FRICTION_SCALE_MULT_RIGHT = 1.05
|
||||
VOLT_PLEXY_FRICTION_THRESHOLD_MULT_LEFT = 1.00
|
||||
VOLT_PLEXY_FRICTION_THRESHOLD_MULT_RIGHT = 0.96
|
||||
VOLT_PLEXY_CENTER_TAPER_REDUCTION_MULT = 0.94
|
||||
PRIUS_TRANSITION_SPEED = 10.0
|
||||
PRIUS_TRANSITION_SPEED = 8.5
|
||||
PRIUS_PHASE_SCALE = 0.09
|
||||
PRIUS_FF_GAIN_LEFT = 0.12
|
||||
PRIUS_FF_GAIN_RIGHT = 0.13
|
||||
PRIUS_FF_ONSET = 0.12
|
||||
PRIUS_FF_ONSET_WIDTH = 0.07
|
||||
PRIUS_FF_CUTOFF = 1.45
|
||||
PRIUS_FF_CUTOFF_WIDTH = 0.36
|
||||
PRIUS_FF_GAIN_LEFT = 0.08
|
||||
PRIUS_FF_GAIN_RIGHT = 0.09
|
||||
PRIUS_FF_ONSET = 0.15
|
||||
PRIUS_FF_ONSET_WIDTH = 0.08
|
||||
PRIUS_FF_CUTOFF = 1.30
|
||||
PRIUS_FF_CUTOFF_WIDTH = 0.32
|
||||
PRIUS_FRICTION_LAT_RISE = 0.18
|
||||
PRIUS_FRICTION_JERK_RISE = 0.22
|
||||
PRIUS_TURN_IN_BOOST_LEFT = 0.60
|
||||
PRIUS_TURN_IN_BOOST_RIGHT = 0.56
|
||||
PRIUS_UNWIND_TAPER_LEFT = 0.58
|
||||
PRIUS_UNWIND_TAPER_RIGHT = 0.84
|
||||
PRIUS_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.22
|
||||
PRIUS_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.22
|
||||
PRIUS_UNWIND_THRESHOLD_INCREASE_LEFT = 0.36
|
||||
PRIUS_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.52
|
||||
PRIUS_TURN_IN_FRICTION_BOOST_LEFT = 0.10
|
||||
PRIUS_TURN_IN_FRICTION_BOOST_RIGHT = 0.10
|
||||
PRIUS_UNWIND_FRICTION_REDUCTION_LEFT = 0.22
|
||||
PRIUS_UNWIND_FRICTION_REDUCTION_RIGHT = 0.32
|
||||
PRIUS_TURN_IN_BOOST_LEFT = 0.28
|
||||
PRIUS_TURN_IN_BOOST_RIGHT = 0.25
|
||||
PRIUS_UNWIND_TAPER_LEFT = 0.22
|
||||
PRIUS_UNWIND_TAPER_RIGHT = 0.34
|
||||
PRIUS_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.16
|
||||
PRIUS_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.16
|
||||
PRIUS_UNWIND_THRESHOLD_INCREASE_LEFT = 0.22
|
||||
PRIUS_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.32
|
||||
PRIUS_TURN_IN_FRICTION_BOOST_LEFT = 0.07
|
||||
PRIUS_TURN_IN_FRICTION_BOOST_RIGHT = 0.07
|
||||
PRIUS_UNWIND_FRICTION_REDUCTION_LEFT = 0.12
|
||||
PRIUS_UNWIND_FRICTION_REDUCTION_RIGHT = 0.18
|
||||
|
||||
TRAILER_LOAD_FULL_ASSIST_KG = 15000.0 * CV.LB_TO_KG
|
||||
TRAILER_LATERAL_MIN_SPEED = 15.0 * CV.MPH_TO_MS
|
||||
|
||||
@@ -137,7 +137,16 @@ std::optional<std::string> Panda::get_serial() {
|
||||
|
||||
bool Panda::up_to_date() {
|
||||
if (auto fw_sig = get_firmware_version()) {
|
||||
for (auto fn : { "panda.bin.signed", "panda_h7.bin.signed", "panda_remote.bin.signed", "panda_h7_remote.bin.signed" }) {
|
||||
for (auto fn : {
|
||||
"panda.bin.signed",
|
||||
"panda_h7.bin.signed",
|
||||
"panda_remote.bin.signed",
|
||||
"panda_h7_remote.bin.signed",
|
||||
"panda_can_ignition_only.bin.signed",
|
||||
"panda_h7_can_ignition_only.bin.signed",
|
||||
"panda_remote_can_ignition_only.bin.signed",
|
||||
"panda_h7_remote_can_ignition_only.bin.signed",
|
||||
}) {
|
||||
auto content = util::read_file(std::string("../../panda/board/obj/") + fn);
|
||||
if (content.size() >= fw_sig->size() &&
|
||||
memcmp(content.data() + content.size() - fw_sig->size(), fw_sig->data(), fw_sig->size()) == 0) {
|
||||
|
||||
@@ -217,7 +217,8 @@ void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const
|
||||
cs.setCanCoreResetCnt(can_health.can_core_reset_cnt);
|
||||
}
|
||||
|
||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool is_onroad, bool spoofing_started) {
|
||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool is_onroad,
|
||||
bool spoofing_started, bool ignore_ignition_line) {
|
||||
bool ignition_local = false;
|
||||
const uint32_t pandas_cnt = pandas.size();
|
||||
|
||||
@@ -265,6 +266,12 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
|
||||
health.ignition_line_pkt = 0;
|
||||
}
|
||||
|
||||
// Work around harness-box false ignition by relying only on CAN ignition.
|
||||
// This is only appropriate for vehicles with reliable panda CAN ignition support.
|
||||
if (ignore_ignition_line) {
|
||||
health.ignition_line_pkt = 0;
|
||||
}
|
||||
|
||||
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0));
|
||||
|
||||
pandaStates.push_back(health);
|
||||
@@ -353,14 +360,15 @@ void send_peripheral_state(Panda *panda, PubMaster *pm) {
|
||||
pm->send("peripheralState", msg);
|
||||
}
|
||||
|
||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool is_onroad, bool spoofing_started) {
|
||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool is_onroad,
|
||||
bool spoofing_started, bool ignore_ignition_line) {
|
||||
std::vector<std::string> connected_serials;
|
||||
for (Panda *p : pandas) {
|
||||
connected_serials.push_back(p->hw_serial());
|
||||
}
|
||||
|
||||
{
|
||||
auto ignition_opt = send_panda_states(pm, pandas, is_onroad, spoofing_started);
|
||||
auto ignition_opt = send_panda_states(pm, pandas, is_onroad, spoofing_started, ignore_ignition_line);
|
||||
if (!ignition_opt) {
|
||||
LOGE("Failed to get ignition_opt");
|
||||
return;
|
||||
@@ -494,7 +502,8 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
sm["selfdriveState"].getSelfdriveState().getEnabled() || preap_aol_engaged
|
||||
);
|
||||
is_onroad = params.getBool("IsOnroad");
|
||||
process_panda_state(pandas, &pm, engaged, is_onroad, spoofing_started);
|
||||
const bool ignore_ignition_line = params.getBool("IgnoreIgnitionLine");
|
||||
process_panda_state(pandas, &pm, engaged, is_onroad, spoofing_started, ignore_ignition_line);
|
||||
panda_safety.configureSafetyMode(is_onroad);
|
||||
}
|
||||
|
||||
|
||||
+35
-14
@@ -13,20 +13,33 @@ from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
def get_expected_firmware_path(panda: Panda, remote_start: bool) -> str:
|
||||
app_fn = panda.get_mcu_type().config.app_fn
|
||||
def get_selected_firmware_name(app_fn: str, remote_start: bool, ignore_ignition_line: bool) -> str:
|
||||
if not remote_start and not ignore_ignition_line:
|
||||
return app_fn
|
||||
|
||||
h7 = app_fn == "panda_h7.bin.signed"
|
||||
name_parts = ["panda_h7" if h7 else "panda"]
|
||||
if remote_start:
|
||||
remote_fn = "panda_h7_remote.bin.signed" if app_fn == "panda_h7.bin.signed" else "panda_remote.bin.signed"
|
||||
remote_path = os.path.join(FW_PATH, remote_fn)
|
||||
if os.path.isfile(remote_path):
|
||||
return remote_path
|
||||
cloudlog.warning(f"Remote-start panda firmware not found: {remote_path}, falling back to default")
|
||||
name_parts.append("remote")
|
||||
if ignore_ignition_line:
|
||||
name_parts.append("can_ignition_only")
|
||||
return "_".join(name_parts) + ".bin.signed"
|
||||
|
||||
|
||||
def get_expected_firmware_path(panda: Panda, remote_start: bool, ignore_ignition_line: bool) -> str:
|
||||
app_fn = panda.get_mcu_type().config.app_fn
|
||||
selected_fn = get_selected_firmware_name(app_fn, remote_start, ignore_ignition_line)
|
||||
if selected_fn != app_fn:
|
||||
selected_path = os.path.join(FW_PATH, selected_fn)
|
||||
if os.path.isfile(selected_path):
|
||||
return selected_path
|
||||
cloudlog.warning(f"Selected panda firmware not found: {selected_path}, falling back to default")
|
||||
return os.path.join(FW_PATH, app_fn)
|
||||
|
||||
|
||||
def get_expected_signature(panda: Panda, remote_start: bool) -> bytes:
|
||||
def get_expected_signature(panda: Panda, remote_start: bool, ignore_ignition_line: bool) -> bytes:
|
||||
try:
|
||||
fn = get_expected_firmware_path(panda, remote_start)
|
||||
fn = get_expected_firmware_path(panda, remote_start, ignore_ignition_line)
|
||||
return Panda.get_signature_from_firmware(fn)
|
||||
except Exception:
|
||||
cloudlog.exception("Error computing expected signature")
|
||||
@@ -40,7 +53,14 @@ def get_remote_start_boots_comma(params: Params) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def flash_panda(panda_serial: str, remote_start: bool) -> Panda:
|
||||
def get_ignore_ignition_line(params: Params) -> bool:
|
||||
try:
|
||||
return params.get_bool("IgnoreIgnitionLine")
|
||||
except UnknownKeyName:
|
||||
return False
|
||||
|
||||
|
||||
def flash_panda(panda_serial: str, remote_start: bool, ignore_ignition_line: bool) -> Panda:
|
||||
try:
|
||||
panda = Panda(panda_serial)
|
||||
except PandaProtocolMismatch:
|
||||
@@ -48,8 +68,8 @@ def flash_panda(panda_serial: str, remote_start: bool) -> Panda:
|
||||
HARDWARE.recover_internal_panda()
|
||||
raise
|
||||
|
||||
fw_path = get_expected_firmware_path(panda, remote_start)
|
||||
fw_signature = get_expected_signature(panda, remote_start)
|
||||
fw_path = get_expected_firmware_path(panda, remote_start, ignore_ignition_line)
|
||||
fw_signature = get_expected_signature(panda, remote_start, ignore_ignition_line)
|
||||
internal_panda = panda.is_internal()
|
||||
|
||||
panda_version = "bootstub" if panda.bootstub else panda.get_version()
|
||||
@@ -133,8 +153,9 @@ def main() -> None:
|
||||
# Flash pandas
|
||||
pandas: list[Panda] = []
|
||||
remote_start = get_remote_start_boots_comma(params)
|
||||
ignore_ignition_line = get_ignore_ignition_line(params)
|
||||
for serial in panda_serials:
|
||||
pandas.append(flash_panda(serial, remote_start))
|
||||
pandas.append(flash_panda(serial, remote_start, ignore_ignition_line))
|
||||
|
||||
# Ensure internal panda is present if expected
|
||||
internal_pandas = [panda for panda in pandas if panda.is_internal()]
|
||||
@@ -186,7 +207,7 @@ def main() -> None:
|
||||
first_run = False
|
||||
|
||||
# run pandad with all connected serials as arguments
|
||||
if get_remote_start_boots_comma(params):
|
||||
if get_remote_start_boots_comma(params) or get_ignore_ignition_line(params):
|
||||
os.environ["BOARDD_SKIP_FW_CHECK"] = "1"
|
||||
else:
|
||||
os.environ.pop("BOARDD_SKIP_FW_CHECK", None)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
import time
|
||||
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.ui.lib.application import FontWeight, gui_app
|
||||
from openpilot.system.ui.lib.multilang import tr, tr_noop
|
||||
from openpilot.system.ui.widgets import DialogResult, Widget
|
||||
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
|
||||
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog, alert_dialog
|
||||
from openpilot.system.ui.widgets.label import gui_label
|
||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||
from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog
|
||||
@@ -143,10 +146,16 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
"set_state": lambda s: self._controller._on_toggle("GMDashSpoofOffsets"),
|
||||
})
|
||||
if cs.isGM and cs.hasOpenpilotLongitudinal:
|
||||
toggles.append({
|
||||
"title": tr("CAN Ignition Only"),
|
||||
"subtitle": tr("Use Panda firmware that ignores the physical ignition line and starts only from CAN ignition."),
|
||||
"get_state": lambda: self._controller._params.get_bool("IgnoreIgnitionLine"),
|
||||
"set_state": lambda s: self._controller._on_panda_firmware_toggle("IgnoreIgnitionLine", tr("CAN Ignition Only requires a Panda firmware update.")),
|
||||
})
|
||||
toggles.append({
|
||||
"title": tr("Remote Start Panda"),
|
||||
"get_state": lambda: self._controller._params.get_bool("RemoteStartBootsComma"),
|
||||
"set_state": lambda s: self._controller._on_toggle("RemoteStartBootsComma"),
|
||||
"set_state": lambda s: self._controller._on_panda_firmware_toggle("RemoteStartBootsComma", tr("Remote Start requires a Panda firmware update.")),
|
||||
})
|
||||
if cs.isGM and cs.isVolt and not cs.hasSNG:
|
||||
toggles.append({
|
||||
@@ -559,6 +568,29 @@ class StarPilotVehicleSettingsLayout(_SettingsPage):
|
||||
if param_key == "ForceFingerprint":
|
||||
self._manager_view._rebuild_toggle_grid()
|
||||
|
||||
def _on_panda_firmware_toggle(self, param_key: str, prompt: str):
|
||||
current = self._params.get_bool(param_key) if self._params.get(param_key) is not None else False
|
||||
new_state = not current
|
||||
|
||||
def flash_and_reboot():
|
||||
self._params_memory.put_bool("FlashPanda", True)
|
||||
while self._params_memory.get_bool("FlashPanda"):
|
||||
time.sleep(0.1)
|
||||
HARDWARE.reboot()
|
||||
|
||||
def on_confirm(res):
|
||||
if res != DialogResult.CONFIRM:
|
||||
starpilot_state.update(force=True)
|
||||
self._manager_view._rebuild_toggle_grid()
|
||||
return
|
||||
self._params.put_bool(param_key, new_state)
|
||||
threading.Thread(target=flash_and_reboot, daemon=True).start()
|
||||
starpilot_state.update(force=True)
|
||||
self._manager_view._rebuild_toggle_grid()
|
||||
gui_app.push_widget(alert_dialog(tr("Panda flashing started. Device will reboot when finished.")))
|
||||
|
||||
gui_app.push_widget(ConfirmDialog(prompt, tr("Flash"), callback=on_confirm))
|
||||
|
||||
def _on_select(self, key: str):
|
||||
if key in ("CarMake", "CarModel") and not self._params.get_bool("ForceFingerprint"):
|
||||
return
|
||||
|
||||
@@ -173,26 +173,43 @@ def extract_zip(zip_file, extract_path):
|
||||
print(f"Extraction completed!")
|
||||
|
||||
|
||||
def get_selected_panda_firmware_name(app_fn, remote_start, ignore_ignition_line):
|
||||
if not remote_start and not ignore_ignition_line:
|
||||
return app_fn
|
||||
|
||||
h7 = app_fn == "panda_h7.bin.signed"
|
||||
name_parts = ["panda_h7" if h7 else "panda"]
|
||||
if remote_start:
|
||||
name_parts.append("remote")
|
||||
if ignore_ignition_line:
|
||||
name_parts.append("can_ignition_only")
|
||||
return "_".join(name_parts) + ".bin.signed"
|
||||
|
||||
|
||||
def flash_panda(params_memory):
|
||||
params = Params()
|
||||
try:
|
||||
remote_start = params.get_bool("RemoteStartBootsComma")
|
||||
except Exception:
|
||||
remote_start = False
|
||||
try:
|
||||
ignore_ignition_line = params.get_bool("IgnoreIgnitionLine")
|
||||
except Exception:
|
||||
ignore_ignition_line = False
|
||||
|
||||
for serial in Panda.list():
|
||||
try:
|
||||
with Panda(serial=serial) as panda:
|
||||
print(f"Flashing Panda {serial}")
|
||||
flash_fn = None
|
||||
if remote_start:
|
||||
app_fn = panda.get_mcu_type().config.app_fn
|
||||
remote_fn = "panda_h7_remote.bin.signed" if app_fn == "panda_h7.bin.signed" else "panda_remote.bin.signed"
|
||||
candidate = os.path.join(FW_PATH, remote_fn)
|
||||
app_fn = panda.get_mcu_type().config.app_fn
|
||||
selected_fn = get_selected_panda_firmware_name(app_fn, remote_start, ignore_ignition_line)
|
||||
if selected_fn != app_fn:
|
||||
candidate = os.path.join(FW_PATH, selected_fn)
|
||||
if os.path.isfile(candidate):
|
||||
flash_fn = candidate
|
||||
else:
|
||||
print(f"Remote-start panda firmware missing: {candidate}. Falling back to default firmware.")
|
||||
print(f"Selected panda firmware missing: {candidate}. Falling back to default firmware.")
|
||||
panda.flash(fn=flash_fn)
|
||||
except Exception as exception:
|
||||
print(f"Failed to flash Panda {serial}: {exception}")
|
||||
|
||||
@@ -1361,6 +1361,7 @@ class StarPilotVariables:
|
||||
"GMDashSpoofOffsets",
|
||||
condition=toggle.car_make == "gm" and toggle.has_pedal,
|
||||
)
|
||||
toggle.ignore_ignition_line = self.get_value("IgnoreIgnitionLine", condition=toggle.car_make == "gm")
|
||||
toggle.long_pitch = self.get_value(
|
||||
"LongPitch",
|
||||
condition=toggle.openpilot_longitudinal and toggle.car_make == "gm",
|
||||
|
||||
@@ -2480,6 +2480,13 @@
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle"
|
||||
},
|
||||
{
|
||||
"key": "IgnoreIgnitionLine",
|
||||
"label": "Use CAN Ignition Only",
|
||||
"description": "Use Panda firmware that ignores the physical ignition line and starts from CAN ignition only.\n\nRequires a Panda flash. Use this only on vehicles with reliable CAN ignition when the harness box reports false ignition.",
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle"
|
||||
},
|
||||
{
|
||||
"key": "LongPitch",
|
||||
"label": "Smooth Pedal Response on Hills",
|
||||
|
||||
@@ -173,6 +173,7 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
{"GMToggles", tr("General Motors Settings"), tr("<b>StarPilot features for General Motors vehicles.</b>"), ""},
|
||||
{"GMPedalLongitudinal", tr("Use Pedal For Longitudinal"), tr("<b>Use the pedal interceptor for full longitudinal control</b> on supported GM vehicles."), ""},
|
||||
{"GMDashSpoofOffsets", tr("Apply Offsets To Dash Spoof"), tr("<b>On GM pedal-long cars, add the configured set-speed offset</b> to the spoofed dash set speed so it matches the on-screen set speed."), ""},
|
||||
{"IgnoreIgnitionLine", tr("Use CAN Ignition Only"), tr("<b>Use CAN ignition only and ignore the physical ignition line in Panda firmware.</b><br><br>Requires a Panda flash. Use this only on vehicles with reliable CAN ignition when the harness box reports false ignition."), ""},
|
||||
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("<b>Smoothen acceleration and braking</b> when driving downhill/uphill."), ""},
|
||||
{"RemoteStartBootsComma", tr("Remote Start Boots comma"), tr("<b>Use the remote-start GM panda firmware at boot.</b><br><br>Required for GM remote-start startup signal behavior."), ""},
|
||||
{"RemapCancelToDistance", tr("Remap Cancel Button"), tr("<b>On pedal-interceptor Bolts, treat the steering-wheel CANCEL button as an extra mappable button.</b>"), ""},
|
||||
@@ -300,24 +301,28 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
|
||||
});
|
||||
}
|
||||
|
||||
ParamControl *remoteStartToggle = static_cast<ParamControl*>(toggles["RemoteStartBootsComma"]);
|
||||
QObject::connect(remoteStartToggle, &ToggleControl::toggleFlipped, [parent, remoteStartToggle, this](bool state) {
|
||||
const QString prompt = tr("Remote Start requires a Panda firmware update. Flash the Panda now?");
|
||||
if (!StarPilotConfirmationDialog::yesorno(prompt, this)) {
|
||||
params.putBool("RemoteStartBootsComma", !state);
|
||||
remoteStartToggle->refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread([parent, this]() {
|
||||
parent->keepScreenOn = true;
|
||||
params_memory.putBool("FlashPanda", true);
|
||||
while (params_memory.getBool("FlashPanda")) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto connectPandaFlashToggle = [parent, this](const QString &key, const QString &prompt) {
|
||||
ParamControl *toggle = static_cast<ParamControl*>(toggles[key]);
|
||||
QObject::connect(toggle, &ToggleControl::toggleFlipped, [parent, key, prompt, toggle, this](bool state) {
|
||||
if (!StarPilotConfirmationDialog::yesorno(prompt, this)) {
|
||||
params.putBool(key.toStdString(), !state);
|
||||
toggle->refresh();
|
||||
return;
|
||||
}
|
||||
Hardware::reboot();
|
||||
}).detach();
|
||||
});
|
||||
|
||||
std::thread([parent, this]() {
|
||||
parent->keepScreenOn = true;
|
||||
params_memory.putBool("FlashPanda", true);
|
||||
while (params_memory.getBool("FlashPanda")) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
Hardware::reboot();
|
||||
}).detach();
|
||||
});
|
||||
};
|
||||
|
||||
connectPandaFlashToggle("IgnoreIgnitionLine", tr("CAN Ignition Only requires a Panda firmware update. Flash the Panda now?"));
|
||||
connectPandaFlashToggle("RemoteStartBootsComma", tr("Remote Start requires a Panda firmware update. Flash the Panda now?"));
|
||||
|
||||
openDescriptions(forceOpenDescriptions, toggles);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
QSet<QString> gmKeys = {"GMPedalLongitudinal", "GMDashSpoofOffsets", "LongPitch", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
|
||||
QSet<QString> gmKeys = {"GMPedalLongitudinal", "GMDashSpoofOffsets", "IgnoreIgnitionLine", "LongPitch", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
|
||||
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "GMDashSpoofOffsets", "LongPitch", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
|
||||
QSet<QString> subaruKeys = {"SubaruSNG", "SubaruSNGManualParkingBrake"};
|
||||
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
||||
|
||||
@@ -114,6 +114,7 @@ ForceTorqueController
|
||||
FrogsGoMoosTweak
|
||||
GMDashSpoofOffsets
|
||||
GMPedalLongitudinal
|
||||
IgnoreIgnitionLine
|
||||
GoatScream
|
||||
GoatScreamCriticalAlerts
|
||||
GreenLightAlert
|
||||
|
||||
Reference in New Issue
Block a user