mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-06 16:13:48 +08:00
Compare commits
17 Commits
TickleMeELMo
..
Dom
| Author | SHA1 | Date | |
|---|---|---|---|
| 422488562f | |||
| 7f1f926c47 | |||
| 9cb1b6b11d | |||
| 7d46313213 | |||
| edf76af796 | |||
| f51059956c | |||
| 604a433ee4 | |||
| 87d007eb10 | |||
| ab77a59497 | |||
| 54a03a91b0 | |||
| cecc9bc8b6 | |||
| cec1a0fb62 | |||
| 097d63caef | |||
| de9cb64165 | |||
| 53e5c5246d | |||
| b5ab54ab6d | |||
| f55ad9162d |
Binary file not shown.
@@ -310,6 +310,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"DeveloperSidebarMetric7", {PERSISTENT, INT, "7", "0", 3}},
|
{"DeveloperSidebarMetric7", {PERSISTENT, INT, "7", "0", 3}},
|
||||||
{"DeveloperUI", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"DeveloperUI", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
|
{"GalaxyMobileDefault", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_ADVANCED}},
|
||||||
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
|
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||||
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}},
|
{"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}},
|
||||||
@@ -510,6 +511,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"ModeButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"ModeButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"ModelDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
{"ModelDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||||
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
|
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
|
||||||
|
{"ModelLabConfig", {PERSISTENT, JSON, "{}", "{}"}},
|
||||||
|
{"ModelLabModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||||
|
{"ModelLabRuntime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
|
||||||
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
|
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
|
||||||
{"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}},
|
{"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
{"LatSmoothSeconds", {PERSISTENT, FLOAT, "0.1", "0.1", 3}},
|
{"LatSmoothSeconds", {PERSISTENT, FLOAT, "0.1", "0.1", 3}},
|
||||||
@@ -544,6 +548,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"FavoriteTrafficModeCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"FavoriteTrafficModeCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"WheelControlAOLCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"WheelControlAOLCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
|
{"WheelControlDisengageCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
|
{"WheelControlEngageCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"WheelControlForceCoastCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"WheelControlForceCoastCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"WheelControlPulseGlideCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
{"WheelControlPulseGlideCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
|
||||||
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
|
||||||
@@ -705,7 +711,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"SubaruStopStartOff", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"SubaruStopStartOff", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"SubaruAvhOnAtStartup", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"SubaruRedneckCruise", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
|
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||||
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
|
||||||
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
|
||||||
|
|||||||
Binary file not shown.
@@ -28,6 +28,9 @@ BOLT_CC_BUTTON_CARS = {
|
|||||||
BOLT_CC_TARGET_DEADBAND_MPH = 0.75
|
BOLT_CC_TARGET_DEADBAND_MPH = 0.75
|
||||||
BOLT_CC_REVERSE_CONFIRM_S = 0.6
|
BOLT_CC_REVERSE_CONFIRM_S = 0.6
|
||||||
BOLT_CC_DIRECTION_MEMORY_S = 1.5
|
BOLT_CC_DIRECTION_MEMORY_S = 1.5
|
||||||
|
VOLT_CC_CARS = {
|
||||||
|
CAR.CHEVROLET_VOLT_CC,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def malibu_phase_map_for_button(button):
|
def malibu_phase_map_for_button(button):
|
||||||
@@ -336,6 +339,28 @@ def stabilize_bolt_cc_button(controller, CP, requested_button):
|
|||||||
return requested_button
|
return requested_button
|
||||||
|
|
||||||
|
|
||||||
|
def _create_volt_cc_spam_command(CS, actuators, ms_convert):
|
||||||
|
accel = float(actuators.accel)
|
||||||
|
speed_setpoint = int(round(CS.out.cruiseState.speed * ms_convert))
|
||||||
|
ego_speed = CS.out.vEgo * ms_convert
|
||||||
|
|
||||||
|
if accel == 0.0:
|
||||||
|
return CruiseButtons.INIT, float("inf")
|
||||||
|
|
||||||
|
if accel < 0.0:
|
||||||
|
if speed_setpoint > ego_speed + 3.0:
|
||||||
|
rate = 0.2
|
||||||
|
else:
|
||||||
|
rate = max(1.0 / (-accel * ms_convert), 0.2)
|
||||||
|
return CruiseButtons.DECEL_SET, rate
|
||||||
|
|
||||||
|
if speed_setpoint < ego_speed - 3.0:
|
||||||
|
rate = 0.2
|
||||||
|
else:
|
||||||
|
rate = max(1.0 / (accel * ms_convert), 0.2)
|
||||||
|
return CruiseButtons.RES_ACCEL, rate
|
||||||
|
|
||||||
|
|
||||||
def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggles):
|
def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggles):
|
||||||
accel = actuators.accel
|
accel = actuators.accel
|
||||||
v_ego = CS.out.vEgo
|
v_ego = CS.out.vEgo
|
||||||
@@ -350,12 +375,15 @@ def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggl
|
|||||||
target_deadband = BOLT_CC_TARGET_DEADBAND_MPH * (CV.MPH_TO_KPH if is_metric else 1.0) if bolt_cc else 0.0
|
target_deadband = BOLT_CC_TARGET_DEADBAND_MPH * (CV.MPH_TO_KPH if is_metric else 1.0) if bolt_cc else 0.0
|
||||||
comparison_setpoint = projected_setpoint if bolt_cc else desired_setpoint
|
comparison_setpoint = projected_setpoint if bolt_cc else desired_setpoint
|
||||||
|
|
||||||
if CS.CP.minEnableSpeed - (desired_setpoint / ms_convert) > 3.25:
|
if CS.CP.carFingerprint in VOLT_CC_CARS:
|
||||||
cruise_btn = CruiseButtons.CANCEL
|
cruise_btn, rate = _create_volt_cc_spam_command(CS, actuators, ms_convert)
|
||||||
elif comparison_setpoint < speed_setpoint - target_deadband and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
|
else:
|
||||||
cruise_btn = CruiseButtons.DECEL_SET
|
if CS.CP.minEnableSpeed - (desired_setpoint / ms_convert) > 3.25:
|
||||||
elif comparison_setpoint > speed_setpoint + target_deadband:
|
cruise_btn = CruiseButtons.CANCEL
|
||||||
cruise_btn = CruiseButtons.RES_ACCEL
|
elif comparison_setpoint < speed_setpoint - target_deadband and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
|
||||||
|
cruise_btn = CruiseButtons.DECEL_SET
|
||||||
|
elif comparison_setpoint > speed_setpoint + target_deadband:
|
||||||
|
cruise_btn = CruiseButtons.RES_ACCEL
|
||||||
|
|
||||||
cruise_btn = stabilize_bolt_cc_button(controller, CS.CP, cruise_btn)
|
cruise_btn = stabilize_bolt_cc_button(controller, CS.CP, cruise_btn)
|
||||||
if cruise_btn == CruiseButtons.CANCEL:
|
if cruise_btn == CruiseButtons.CANCEL:
|
||||||
|
|||||||
@@ -657,6 +657,60 @@ class TestGMCarController:
|
|||||||
|
|
||||||
assert [msg[2] for msg in msgs] == [0, 2]
|
assert [msg[2] for msg in msgs] == [0, 2]
|
||||||
|
|
||||||
|
def test_volt_cc_redneck_holds_setpoint_without_planner_acceleration(self):
|
||||||
|
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_CC][Bus.pt])
|
||||||
|
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0, malibu_button_phase=0)
|
||||||
|
cs = SimpleNamespace(
|
||||||
|
CP=SimpleNamespace(
|
||||||
|
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
||||||
|
flags=GMFlags.NO_CAMERA.value,
|
||||||
|
networkLocation=structs.CarParams.NetworkLocation.gateway,
|
||||||
|
minEnableSpeed=0.0,
|
||||||
|
),
|
||||||
|
buttons_counter=2,
|
||||||
|
out=SimpleNamespace(
|
||||||
|
vEgo=60.0 * CV.KPH_TO_MS,
|
||||||
|
cruiseState=SimpleNamespace(speed=60.0 * CV.KPH_TO_MS),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
msgs = gmcan.create_gm_cc_spam_command(
|
||||||
|
packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert msgs == []
|
||||||
|
assert controller.apply_speed == 60
|
||||||
|
|
||||||
|
def test_volt_cc_redneck_rate_limits_setpoint_changes_by_planner_acceleration(self):
|
||||||
|
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_CC][Bus.pt])
|
||||||
|
controller = SimpleNamespace(frame=int(0.5 / DT_CTRL), last_button_frame=0, apply_speed=0, malibu_button_phase=0)
|
||||||
|
cs = SimpleNamespace(
|
||||||
|
CP=SimpleNamespace(
|
||||||
|
carFingerprint=CAR.CHEVROLET_VOLT_CC,
|
||||||
|
flags=GMFlags.NO_CAMERA.value,
|
||||||
|
networkLocation=structs.CarParams.NetworkLocation.gateway,
|
||||||
|
minEnableSpeed=0.0,
|
||||||
|
),
|
||||||
|
buttons_counter=2,
|
||||||
|
out=SimpleNamespace(
|
||||||
|
vEgo=60.0 * CV.KPH_TO_MS,
|
||||||
|
cruiseState=SimpleNamespace(speed=60.0 * CV.KPH_TO_MS),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
msgs = gmcan.create_gm_cc_spam_command(
|
||||||
|
packer, controller, cs, SimpleNamespace(accel=0.5), SimpleNamespace(is_metric=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert msgs == []
|
||||||
|
|
||||||
|
controller.frame = int(0.7 / DT_CTRL)
|
||||||
|
msgs = gmcan.create_gm_cc_spam_command(
|
||||||
|
packer, controller, cs, SimpleNamespace(accel=0.5), SimpleNamespace(is_metric=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(msgs) == 1
|
||||||
|
|
||||||
def test_volt_cc_no_camera_redneck_spam_stays_on_powertrain_bus(self):
|
def test_volt_cc_no_camera_redneck_spam_stays_on_powertrain_bus(self):
|
||||||
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_CC][Bus.pt])
|
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_CC][Bus.pt])
|
||||||
controller = SimpleNamespace(frame=int(0.3 / DT_CTRL), last_button_frame=0, apply_speed=0, malibu_button_phase=0)
|
controller = SimpleNamespace(frame=int(0.3 / DT_CTRL), last_button_frame=0, apply_speed=0, malibu_button_phase=0)
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ LongCtrlState = structs.CarControl.Actuators.LongControlState
|
|||||||
MAX_ANGLE = 85
|
MAX_ANGLE = 85
|
||||||
MAX_ANGLE_FRAMES = 89
|
MAX_ANGLE_FRAMES = 89
|
||||||
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||||
|
|
||||||
|
CANCEL_BUTTON_DELAY_FRAMES = 10
|
||||||
|
|
||||||
CANFD_BLINDSPOT_STATUS_STALE_NS = 200_000_000
|
CANFD_BLINDSPOT_STATUS_STALE_NS = 200_000_000
|
||||||
CANFD_CAMERA_LEAD_STALE_NS = 300_000_000
|
CANFD_CAMERA_LEAD_STALE_NS = 300_000_000
|
||||||
CANFD_LEAD_MIN_DISTANCE = 0.1
|
CANFD_LEAD_MIN_DISTANCE = 0.1
|
||||||
@@ -454,6 +457,7 @@ class CarController(CarControllerBase):
|
|||||||
self.apply_angle_last = 0.0
|
self.apply_angle_last = 0.0
|
||||||
self.car_fingerprint = CP.carFingerprint
|
self.car_fingerprint = CP.carFingerprint
|
||||||
self.last_button_frame = 0
|
self.last_button_frame = 0
|
||||||
|
self.cancel_counter = 0
|
||||||
self.redneck_button_frame = 0
|
self.redneck_button_frame = 0
|
||||||
self.ecu_disable_failed = False
|
self.ecu_disable_failed = False
|
||||||
self._ecu_disable_checked = False
|
self._ecu_disable_checked = False
|
||||||
@@ -717,6 +721,8 @@ class CarController(CarControllerBase):
|
|||||||
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True))
|
can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True))
|
||||||
|
|
||||||
|
self.cancel_counter = self.cancel_counter + 1 if CC.cruiseControl.cancel else 0
|
||||||
|
|
||||||
# *** CAN/CAN FD specific ***
|
# *** CAN/CAN FD specific ***
|
||||||
if self.CP.flags & HyundaiFlags.CANFD:
|
if self.CP.flags & HyundaiFlags.CANFD:
|
||||||
can_sends.extend(self.create_canfd_msgs(now_nanos, apply_steer_req, apply_torque, apply_angle, set_speed_in_units, accel,
|
can_sends.extend(self.create_canfd_msgs(now_nanos, apply_steer_req, apply_torque, apply_angle, set_speed_in_units, accel,
|
||||||
@@ -782,7 +788,7 @@ class CarController(CarControllerBase):
|
|||||||
|
|
||||||
# Button messages
|
# Button messages
|
||||||
if not self.long_active_ecu:
|
if not self.long_active_ecu:
|
||||||
if CC.cruiseControl.cancel:
|
if self.cancel_counter > CANCEL_BUTTON_DELAY_FRAMES:
|
||||||
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP))
|
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP))
|
||||||
elif CC.cruiseControl.resume:
|
elif CC.cruiseControl.resume:
|
||||||
# send resume at a max freq of 10Hz
|
# send resume at a max freq of 10Hz
|
||||||
@@ -1046,7 +1052,7 @@ class CarController(CarControllerBase):
|
|||||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
||||||
self.last_button_frame = self.frame
|
self.last_button_frame = self.frame
|
||||||
else:
|
elif self.cancel_counter > CANCEL_BUTTON_DELAY_FRAMES:
|
||||||
for _ in range(20):
|
for _ in range(20):
|
||||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.CANCEL))
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.CANCEL))
|
||||||
self.last_button_frame = self.frame
|
self.last_button_frame = self.frame
|
||||||
|
|||||||
@@ -245,7 +245,10 @@ class CarState(CarStateBase):
|
|||||||
return button_events
|
return button_events
|
||||||
|
|
||||||
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
|
def create_lkas_button_events(self, cp: CANParser, prev_lda_button: int) -> list[structs.CarState.ButtonEvent]:
|
||||||
if self.CP.carFingerprint == CAR.HYUNDAI_SONATA:
|
if self.CP.carFingerprint == CAR.KIA_RAY_EV:
|
||||||
|
self.lda_button = int(cp.vl["BCM_PO_11"]["RAY_LKAS_BTN"] != 0) \
|
||||||
|
if cp.ts_nanos["BCM_PO_11"]["RAY_LKAS_BTN"] > 0 else 0
|
||||||
|
elif self.CP.carFingerprint == CAR.HYUNDAI_SONATA:
|
||||||
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0
|
self.lda_button = int(cp.vl["BCM_PO_11"]["LDA_BTN"]) if cp.ts_nanos["BCM_PO_11"]["LDA_BTN"] > 0 else 0
|
||||||
elif self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
|
elif self.CP.carFingerprint == CAR.HYUNDAI_SONATA_HYBRID:
|
||||||
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
|
self.lda_button = self.get_sonata_hybrid_lkas_button_state(cp)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
|
|||||||
|
|
||||||
def apply_kia_ev6_gt_line_longitudinal_params(ret: structs.CarParams) -> None:
|
def apply_kia_ev6_gt_line_longitudinal_params(ret: structs.CarParams) -> None:
|
||||||
ret.startAccel = 1.4
|
ret.startAccel = 1.4
|
||||||
ret.longitudinalActuatorDelay = 0.35
|
ret.longitudinalActuatorDelay = 0.5
|
||||||
ret.vEgoStarting = 0.5
|
ret.vEgoStarting = 0.5
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from opendbc.can import CANPacker, CANParser
|
|||||||
from opendbc.car import Bus, ButtonType, gen_empty_fingerprint, structs
|
from opendbc.car import Bus, ButtonType, gen_empty_fingerprint, structs
|
||||||
from opendbc.car.structs import CarControl, CarParams
|
from opendbc.car.structs import CarControl, CarParams
|
||||||
from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car
|
from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car
|
||||||
from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \
|
from opendbc.car.hyundai.carcontroller import CarController, CANCEL_BUTTON_DELAY_FRAMES, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \
|
||||||
EV9LongitudinalTuningState, update_ev9_longitudinal_tuning, \
|
EV9LongitudinalTuningState, update_ev9_longitudinal_tuning, \
|
||||||
BlindspotWarningState, update_blindspot_warning, \
|
BlindspotWarningState, update_blindspot_warning, \
|
||||||
reset_egmp_longitudinal_tuning, \
|
reset_egmp_longitudinal_tuning, \
|
||||||
@@ -783,6 +783,36 @@ class TestHyundaiFingerprint:
|
|||||||
assert not any(addr == 0x340 for addr, _, _ in first)
|
assert not any(addr == 0x340 for addr, _, _ in first)
|
||||||
assert any(addr == 0x340 for addr, _, _ in second)
|
assert any(addr == 0x340 for addr, _, _ in second)
|
||||||
|
|
||||||
|
def test_stock_scc_cancel_waits_for_factory_disengagement(self):
|
||||||
|
CP = CarInterface.get_params(CAR.HYUNDAI_SANTA_FE_2022, gen_empty_fingerprint(), [], False, False, False, None)
|
||||||
|
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||||
|
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS11", 0), ("CLU11", 0)], 0)
|
||||||
|
|
||||||
|
hud_control = SimpleNamespace(
|
||||||
|
visualAlert=CarControl.HUDControl.VisualAlert.none,
|
||||||
|
leftLaneVisible=True,
|
||||||
|
rightLaneVisible=True,
|
||||||
|
leftLaneDepart=False,
|
||||||
|
rightLaneDepart=False,
|
||||||
|
)
|
||||||
|
CS = SimpleNamespace(
|
||||||
|
lkas11=parser.vl["LKAS11"],
|
||||||
|
clu11=parser.vl["CLU11"],
|
||||||
|
redneck_send_button=Buttons.NONE,
|
||||||
|
is_metric=False,
|
||||||
|
)
|
||||||
|
CC = SimpleNamespace(enabled=False, cruiseControl=SimpleNamespace(cancel=True, resume=False))
|
||||||
|
actuators = SimpleNamespace(longControlState=LongCtrlState.off)
|
||||||
|
|
||||||
|
for counter in range(1, CANCEL_BUTTON_DELAY_FRAMES + 1):
|
||||||
|
controller.cancel_counter = counter
|
||||||
|
msgs = controller.create_can_msgs(True, 0, False, 0.0, 0.0, False, hud_control, actuators, CS, CC, 2, 2)
|
||||||
|
assert not any(addr == 0x4F1 for addr, _, _ in msgs)
|
||||||
|
|
||||||
|
controller.cancel_counter = CANCEL_BUTTON_DELAY_FRAMES + 1
|
||||||
|
msgs = controller.create_can_msgs(True, 0, False, 0.0, 0.0, False, hud_control, actuators, CS, CC, 2, 2)
|
||||||
|
assert any(addr == 0x4F1 for addr, _, _ in msgs)
|
||||||
|
|
||||||
@pytest.mark.parametrize("candidate", (CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024))
|
@pytest.mark.parametrize("candidate", (CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024))
|
||||||
def test_hyundai_can_refresh_platforms_use_refresh_dbc_and_safety_param(self, candidate):
|
def test_hyundai_can_refresh_platforms_use_refresh_dbc_and_safety_param(self, candidate):
|
||||||
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, False, False, None)
|
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, False, False, None)
|
||||||
@@ -988,6 +1018,46 @@ class TestHyundaiFingerprint:
|
|||||||
assert ret.cruiseState.enabled
|
assert ret.cruiseState.enabled
|
||||||
assert ret.cruiseState.speed == pytest.approx(10 * 0.2777778)
|
assert ret.cruiseState.speed == pytest.approx(10 * 0.2777778)
|
||||||
|
|
||||||
|
def test_kia_ray_ev_decodes_bcm_lkas_button_pulse(self):
|
||||||
|
toggles = get_test_toggles()
|
||||||
|
CP = CarInterface.get_params(CAR.KIA_RAY_EV, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||||
|
FPCP = CarInterface.get_starpilot_params(CAR.KIA_RAY_EV, gen_empty_fingerprint(), [], CP, toggles)
|
||||||
|
car_state = CarState(CP, FPCP)
|
||||||
|
can_parsers = car_state.get_can_parsers(CP)
|
||||||
|
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||||
|
|
||||||
|
def update(ray_lkas_button: int, frame: int):
|
||||||
|
msg = packer.make_can_msg("BCM_PO_11", 0, {"RAY_LKAS_BTN": ray_lkas_button})
|
||||||
|
can_parsers[Bus.pt].update([(frame, [msg])])
|
||||||
|
return car_state.update(can_parsers, toggles)[0]
|
||||||
|
|
||||||
|
update(0, 1)
|
||||||
|
ret = update(1, 2)
|
||||||
|
assert any(be.type == ButtonType.lkas and be.pressed for be in ret.buttonEvents)
|
||||||
|
|
||||||
|
ret = update(0, 3)
|
||||||
|
assert any(be.type == ButtonType.lkas and not be.pressed for be in ret.buttonEvents)
|
||||||
|
|
||||||
|
ret = update(2, 4)
|
||||||
|
assert any(be.type == ButtonType.lkas and be.pressed for be in ret.buttonEvents)
|
||||||
|
|
||||||
|
def test_non_ray_does_not_use_ray_lkas_signal(self):
|
||||||
|
CP = CarInterface.get_params(CAR.KIA_FORTE_2021_NON_SCC, gen_empty_fingerprint(), [], False, False, False, None)
|
||||||
|
car_state = CarState(CP, CarInterface.get_starpilot_params(CAR.KIA_FORTE_2021_NON_SCC,
|
||||||
|
gen_empty_fingerprint(), [], CP, get_test_toggles()))
|
||||||
|
parser_cycle = SimpleNamespace(
|
||||||
|
vl={
|
||||||
|
"CLU13": {"CF_Clu_LdwsLkasSW": 0},
|
||||||
|
"BCM_PO_11": {"LDA_BTN": 0, "RAY_LKAS_BTN": 1},
|
||||||
|
},
|
||||||
|
ts_nanos={
|
||||||
|
"CLU13": {"CF_Clu_LdwsLkasSW": 1},
|
||||||
|
"BCM_PO_11": {"LDA_BTN": 1, "RAY_LKAS_BTN": 1},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not car_state.create_lkas_button_events(parser_cycle, 0)
|
||||||
|
|
||||||
def test_hyundai_redneck_cruise_availability(self, monkeypatch):
|
def test_hyundai_redneck_cruise_availability(self, monkeypatch):
|
||||||
class FakeParams:
|
class FakeParams:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -1281,7 +1351,7 @@ class TestHyundaiFingerprint:
|
|||||||
|
|
||||||
assert CP.startAccel == pytest.approx(1.4)
|
assert CP.startAccel == pytest.approx(1.4)
|
||||||
assert CP.vEgoStarting == pytest.approx(0.5)
|
assert CP.vEgoStarting == pytest.approx(0.5)
|
||||||
assert CP.longitudinalActuatorDelay == pytest.approx(0.35)
|
assert CP.longitudinalActuatorDelay == pytest.approx(0.5)
|
||||||
assert CP.vEgoStopping == pytest.approx(0.3)
|
assert CP.vEgoStopping == pytest.approx(0.3)
|
||||||
assert CP.stoppingDecelRate == pytest.approx(0.4)
|
assert CP.stoppingDecelRate == pytest.approx(0.4)
|
||||||
assert kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin)
|
assert kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin)
|
||||||
@@ -1310,7 +1380,7 @@ class TestHyundaiFingerprint:
|
|||||||
|
|
||||||
assert CP.startAccel == pytest.approx(1.4)
|
assert CP.startAccel == pytest.approx(1.4)
|
||||||
assert CP.vEgoStarting == pytest.approx(0.5)
|
assert CP.vEgoStarting == pytest.approx(0.5)
|
||||||
assert CP.longitudinalActuatorDelay == pytest.approx(0.35)
|
assert CP.longitudinalActuatorDelay == pytest.approx(0.5)
|
||||||
|
|
||||||
assert kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin, testing_ground_active=True)
|
assert kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, CP.carVin, testing_ground_active=True)
|
||||||
assert not kia_ev6_gt_line_longitudinal_tuning(CAR.KIA_EV6_2025, CP.carVin, testing_ground_active=True)
|
assert not kia_ev6_gt_line_longitudinal_tuning(CAR.KIA_EV6_2025, CP.carVin, testing_ground_active=True)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from opendbc.car.honda.values import CAR as HONDA, HONDA_BOSCH, HondaFlags, Hond
|
|||||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||||
from opendbc.car.hyundai.values import CAR as HYUNDAI, CANFD_CAR, HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, ALT_BUS_LDA_BUTTON_CARS
|
from opendbc.car.hyundai.values import CAR as HYUNDAI, CANFD_CAR, HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, ALT_BUS_LDA_BUTTON_CARS
|
||||||
from opendbc.car.mock.values import CAR as MOCK
|
from opendbc.car.mock.values import CAR as MOCK
|
||||||
from opendbc.car.subaru.values import CAR as SUBARU, SubaruSafetyFlags
|
from opendbc.car.subaru.values import CAR as SUBARU, SUBARU_REDNECK_CRUISE_CARS, SubaruSafetyFlags
|
||||||
from opendbc.car.toyota.values import CAR as TOYOTA, NO_DSU_CAR, TSS2_CAR, UNSUPPORTED_DSU_CAR, ToyotaStarPilotFlags, ToyotaSafetyFlags
|
from opendbc.car.toyota.values import CAR as TOYOTA, NO_DSU_CAR, TSS2_CAR, UNSUPPORTED_DSU_CAR, ToyotaStarPilotFlags, ToyotaSafetyFlags
|
||||||
from opendbc.car.values import PLATFORMS
|
from opendbc.car.values import PLATFORMS
|
||||||
from opendbc.can import CANParser
|
from opendbc.can import CANParser
|
||||||
@@ -300,6 +300,14 @@ class CarInterfaceBase(ABC):
|
|||||||
if getattr(starpilot_toggles, "subaru_sng", False):
|
if getattr(starpilot_toggles, "subaru_sng", False):
|
||||||
fp_ret.safetyConfigs[-1].safetyParam |= SubaruSafetyFlags.STOP_AND_GO.value
|
fp_ret.safetyConfigs[-1].safetyParam |= SubaruSafetyFlags.STOP_AND_GO.value
|
||||||
|
|
||||||
|
fp_ret.redneckCruiseAvailable = candidate in SUBARU_REDNECK_CRUISE_CARS
|
||||||
|
if fp_ret.redneckCruiseAvailable and params.get_bool("SubaruRedneckCruise") and \
|
||||||
|
not CP.openpilotLongitudinalControl:
|
||||||
|
fp_ret.pcmCruiseSpeed = False
|
||||||
|
CP.openpilotLongitudinalControl = True
|
||||||
|
CP.safetyConfigs[-1].safetyParam |= SubaruSafetyFlags.REDNECK_CRUISE.value
|
||||||
|
fp_ret.safetyConfigs[-1].safetyParam |= SubaruSafetyFlags.REDNECK_CRUISE.value
|
||||||
|
|
||||||
return fp_ret
|
return fp_ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from opendbc.car import Bus, DT_CTRL, make_tester_present_msg, structs
|
|||||||
from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_std_steer_angle_limits, apply_steer_angle_limits_vm, common_fault_avoidance
|
from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_std_steer_angle_limits, apply_steer_angle_limits_vm, common_fault_avoidance
|
||||||
from opendbc.car.interfaces import CarControllerBase
|
from opendbc.car.interfaces import CarControllerBase
|
||||||
from opendbc.car.subaru import subarucan
|
from opendbc.car.subaru import subarucan
|
||||||
from opendbc.car.subaru.values import CAR, DBC, GLOBAL_ES_ADDR, SUBARU_AVH_CARS, SUBARU_STOP_START_CARS, CanBus, CarControllerParams, SubaruFlags
|
from opendbc.car.subaru.values import CAR, DBC, GLOBAL_ES_ADDR, SUBARU_STOP_START_CARS, CanBus, CarControllerParams, SubaruFlags
|
||||||
from opendbc.car.vehicle_model import VehicleModel
|
from opendbc.car.vehicle_model import VehicleModel
|
||||||
|
|
||||||
# FIXME: These limits aren't exact. The real limit is more than likely over a larger time period and
|
# FIXME: These limits aren't exact. The real limit is more than likely over a larger time period and
|
||||||
@@ -37,9 +37,8 @@ _STOP_START_STARTUP_DELAY_FRAMES = 100
|
|||||||
_STOP_START_STARTUP_DEADLINE_FRAMES = 1000
|
_STOP_START_STARTUP_DEADLINE_FRAMES = 1000
|
||||||
_STOP_START_PULSE_FRAMES = 30
|
_STOP_START_PULSE_FRAMES = 30
|
||||||
_STOP_START_PULSE_PERIOD_FRAMES = 5
|
_STOP_START_PULSE_PERIOD_FRAMES = 5
|
||||||
_AVH_STARTUP_DELAY_FRAMES = _STOP_START_STARTUP_DELAY_FRAMES
|
_REDNECK_BUTTON_INTERVAL_FRAMES = 10
|
||||||
_AVH_STARTUP_DEADLINE_FRAMES = _STOP_START_STARTUP_DEADLINE_FRAMES
|
_REDNECK_BUTTON_COPIES = 2
|
||||||
_AVH_PULSE_MESSAGES = 15 # Match the native 10 Hz AVH frame for roughly 1.5 seconds
|
|
||||||
|
|
||||||
|
|
||||||
def get_safety_CP():
|
def get_safety_CP():
|
||||||
@@ -90,10 +89,7 @@ class CarController(CarControllerBase):
|
|||||||
self.stop_start_initial_state = None
|
self.stop_start_initial_state = None
|
||||||
self.stop_start_counter = 0
|
self.stop_start_counter = 0
|
||||||
self.stop_start_acknowledged = False
|
self.stop_start_acknowledged = False
|
||||||
self.avh_attempted = False
|
self.last_redneck_button_frame = 0
|
||||||
self.avh_request_started = False
|
|
||||||
self.avh_last_counter = None
|
|
||||||
self.avh_messages_sent = 0
|
|
||||||
|
|
||||||
def _stop_start_off_request(self, CC, CS, starpilot_toggles):
|
def _stop_start_off_request(self, CC, CS, starpilot_toggles):
|
||||||
"""Send one bounded Subaru Stop/Start OFF request after ignition.
|
"""Send one bounded Subaru Stop/Start OFF request after ignition.
|
||||||
@@ -150,55 +146,6 @@ class CarController(CarControllerBase):
|
|||||||
self.stop_start_counter = (self.stop_start_counter + 1) % 0x10
|
self.stop_start_counter = (self.stop_start_counter + 1) % 0x10
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def _avh_on_request(self, CC, CS, starpilot_toggles):
|
|
||||||
"""Send a bounded Subaru AVH ON pulse after ignition.
|
|
||||||
|
|
||||||
The AVH button frame was identified on the 2025 Legacy only. Keep this
|
|
||||||
independent from Stop/Start so the existing Outback request is unchanged.
|
|
||||||
"""
|
|
||||||
if self.CP.carFingerprint not in SUBARU_AVH_CARS or \
|
|
||||||
not getattr(starpilot_toggles, "subaru_avh_on", False) or self.avh_attempted:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self.frame > _AVH_STARTUP_DEADLINE_FRAMES or getattr(CC, "enabled", False):
|
|
||||||
self.avh_attempted = True
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self.frame < _AVH_STARTUP_DELAY_FRAMES or not getattr(getattr(CS, "out", None), "canValid", True):
|
|
||||||
return None
|
|
||||||
|
|
||||||
out = CS.out
|
|
||||||
if not getattr(out, "standstill", False) or out.gearShifter not in (
|
|
||||||
structs.CarState.GearShifter.park,
|
|
||||||
structs.CarState.GearShifter.neutral,
|
|
||||||
):
|
|
||||||
return None
|
|
||||||
|
|
||||||
avh_msg = getattr(CS, "avh_msg", None)
|
|
||||||
avh_dat = getattr(CS, "avh_dat", None)
|
|
||||||
if not avh_msg or not avh_dat:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not self.avh_request_started:
|
|
||||||
self.avh_request_started = True
|
|
||||||
self.avh_last_counter = int(avh_msg.get("COUNTER", 0)) % 0x10
|
|
||||||
|
|
||||||
if self.avh_messages_sent >= _AVH_PULSE_MESSAGES:
|
|
||||||
self.avh_attempted = True
|
|
||||||
return None
|
|
||||||
|
|
||||||
counter = int(avh_msg.get("COUNTER", 0)) % 0x10
|
|
||||||
if counter == self.avh_last_counter:
|
|
||||||
return None
|
|
||||||
|
|
||||||
msg = subarucan.create_avh_control(
|
|
||||||
self.packer, avh_msg, raw_dat=avh_dat,
|
|
||||||
counter=counter, bus=CanBus.alt_for_cp(self.CP),
|
|
||||||
)
|
|
||||||
self.avh_last_counter = counter
|
|
||||||
self.avh_messages_sent += 1
|
|
||||||
return msg
|
|
||||||
|
|
||||||
def _reset_legacy_2025_handoff(self):
|
def _reset_legacy_2025_handoff(self):
|
||||||
self.driver_override = False
|
self.driver_override = False
|
||||||
self.angle_override_confirm_frames = 0
|
self.angle_override_confirm_frames = 0
|
||||||
@@ -465,6 +412,10 @@ class CarController(CarControllerBase):
|
|||||||
actuators = CC.actuators
|
actuators = CC.actuators
|
||||||
hud_control = CC.hudControl
|
hud_control = CC.hudControl
|
||||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||||
|
subaru_redneck_cruise = bool(
|
||||||
|
self.CP.carFingerprint == CAR.SUBARU_IMPREZA_2020 and
|
||||||
|
getattr(starpilot_toggles, "subaru_redneck_cruise", False)
|
||||||
|
)
|
||||||
|
|
||||||
can_sends = []
|
can_sends = []
|
||||||
|
|
||||||
@@ -472,10 +423,6 @@ class CarController(CarControllerBase):
|
|||||||
if stop_start_msg is not None:
|
if stop_start_msg is not None:
|
||||||
can_sends.append(stop_start_msg)
|
can_sends.append(stop_start_msg)
|
||||||
|
|
||||||
avh_msg = self._avh_on_request(CC, CS, starpilot_toggles)
|
|
||||||
if avh_msg is not None:
|
|
||||||
can_sends.append(avh_msg)
|
|
||||||
|
|
||||||
# *** steering ***
|
# *** steering ***
|
||||||
if (self.frame % self.p.STEER_STEP) == 0:
|
if (self.frame % self.p.STEER_STEP) == 0:
|
||||||
if self.CP.flags & SubaruFlags.LKAS_ANGLE:
|
if self.CP.flags & SubaruFlags.LKAS_ANGLE:
|
||||||
@@ -533,7 +480,8 @@ class CarController(CarControllerBase):
|
|||||||
else:
|
else:
|
||||||
if self.frame % 10 == 0:
|
if self.frame % 10 == 0:
|
||||||
can_sends.append(subarucan.create_es_dashstatus(self.packer, self.frame // 10, CS.es_dashstatus_msg, CC.enabled,
|
can_sends.append(subarucan.create_es_dashstatus(self.packer, self.frame // 10, CS.es_dashstatus_msg, CC.enabled,
|
||||||
self.CP.openpilotLongitudinalControl, CC.longActive, hud_control.leadVisible,
|
self.CP.openpilotLongitudinalControl and not subaru_redneck_cruise,
|
||||||
|
CC.longActive, hud_control.leadVisible,
|
||||||
self.status_bus))
|
self.status_bus))
|
||||||
|
|
||||||
can_sends.append(subarucan.create_es_lkas_state(self.packer, self.frame // 10, CS.es_lkas_state_msg, CC.latActive, hud_control.visualAlert,
|
can_sends.append(subarucan.create_es_lkas_state(self.packer, self.frame // 10, CS.es_lkas_state_msg, CC.latActive, hud_control.visualAlert,
|
||||||
@@ -551,7 +499,7 @@ class CarController(CarControllerBase):
|
|||||||
can_sends.append(subarucan.create_brake_pedal(self.packer, self.frame // 2, CS.brake_pedal_msg,
|
can_sends.append(subarucan.create_brake_pedal(self.packer, self.frame // 2, CS.brake_pedal_msg,
|
||||||
speed_cmd, pcm_cancel_cmd))
|
speed_cmd, pcm_cancel_cmd))
|
||||||
|
|
||||||
if self.CP.openpilotLongitudinalControl:
|
if self.CP.openpilotLongitudinalControl and not subaru_redneck_cruise:
|
||||||
if self.frame % 5 == 0:
|
if self.frame % 5 == 0:
|
||||||
can_sends.append(subarucan.create_es_status(self.packer, self.frame // 5, CS.es_status_msg,
|
can_sends.append(subarucan.create_es_status(self.packer, self.frame // 5, CS.es_status_msg,
|
||||||
self.CP.openpilotLongitudinalControl, CC.longActive, cruise_rpm))
|
self.CP.openpilotLongitudinalControl, CC.longActive, cruise_rpm))
|
||||||
@@ -567,6 +515,20 @@ class CarController(CarControllerBase):
|
|||||||
bus = CanBus.alt_for_cp(self.CP) if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else self.main_bus
|
bus = CanBus.alt_for_cp(self.CP) if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else self.main_bus
|
||||||
can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg["COUNTER"] + 1, CS.es_distance_msg, bus, pcm_cancel_cmd))
|
can_sends.append(subarucan.create_es_distance(self.packer, CS.es_distance_msg["COUNTER"] + 1, CS.es_distance_msg, bus, pcm_cancel_cmd))
|
||||||
|
|
||||||
|
if subaru_redneck_cruise:
|
||||||
|
redneck_button = {
|
||||||
|
1: subarucan.CRUISE_BUTTON_RESUME,
|
||||||
|
2: subarucan.CRUISE_BUTTON_SET,
|
||||||
|
}.get(getattr(CS, "redneck_send_button", 0))
|
||||||
|
cruise_buttons_msg = getattr(CS, "cruise_buttons_msg", None)
|
||||||
|
if redneck_button and cruise_buttons_msg and self.frame - self.last_redneck_button_frame >= _REDNECK_BUTTON_INTERVAL_FRAMES:
|
||||||
|
counter = (int(cruise_buttons_msg["COUNTER"]) + 1) % 0x10
|
||||||
|
for copy_idx in range(_REDNECK_BUTTON_COPIES):
|
||||||
|
can_sends.append(subarucan.create_cruise_buttons(
|
||||||
|
self.packer, counter + copy_idx, cruise_buttons_msg, redneck_button, self.main_bus,
|
||||||
|
))
|
||||||
|
self.last_redneck_button_frame = self.frame
|
||||||
|
|
||||||
if self.CP.flags & SubaruFlags.DISABLE_EYESIGHT:
|
if self.CP.flags & SubaruFlags.DISABLE_EYESIGHT:
|
||||||
# Tester present (keeps eyesight disabled)
|
# Tester present (keeps eyesight disabled)
|
||||||
if self.frame % 100 == 0:
|
if self.frame % 100 == 0:
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
import copy
|
import copy
|
||||||
from cereal import custom
|
from cereal import custom
|
||||||
from opendbc.can import CANDefine, CANParser
|
from opendbc.can import CANDefine, CANParser
|
||||||
from opendbc.car import Bus, structs
|
from opendbc.car import Bus, create_button_events, structs
|
||||||
from opendbc.car.common.conversions import Conversions as CV
|
from opendbc.car.common.conversions import Conversions as CV
|
||||||
from opendbc.car.interfaces import CarStateBase
|
from opendbc.car.interfaces import CarStateBase
|
||||||
from opendbc.car.subaru.values import DBC, CanBus, SUBARU_AVH_CARS, SUBARU_STOP_START_CARS, SubaruFlags
|
from opendbc.car.subaru.values import DBC, CanBus, SUBARU_REDNECK_CRUISE_CARS, SUBARU_STOP_START_CARS, SubaruFlags
|
||||||
from opendbc.car import CanSignalRateCalculator
|
from opendbc.car import CanSignalRateCalculator
|
||||||
|
|
||||||
|
ButtonType = structs.CarState.ButtonEvent.Type
|
||||||
|
|
||||||
|
SUBARU_CRUISE_BUTTONS = {
|
||||||
|
"Main": ButtonType.mainCruise,
|
||||||
|
"Set": ButtonType.decelCruise,
|
||||||
|
"Resume": ButtonType.accelCruise,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class CarState(CarStateBase):
|
class CarState(CarStateBase):
|
||||||
def __init__(self, CP, FPCP):
|
def __init__(self, CP, FPCP):
|
||||||
@@ -18,8 +26,8 @@ class CarState(CarStateBase):
|
|||||||
self.dashlights_msg = {}
|
self.dashlights_msg = {}
|
||||||
self.dashlights_dat = b""
|
self.dashlights_dat = b""
|
||||||
self.stop_start_state = 0
|
self.stop_start_state = 0
|
||||||
self.avh_msg = {}
|
self.cruise_buttons_msg = {}
|
||||||
self.avh_dat = b""
|
self.cruise_buttons = {button: 0 for button in SUBARU_CRUISE_BUTTONS}
|
||||||
|
|
||||||
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
|
||||||
cp = can_parsers[Bus.pt]
|
cp = can_parsers[Bus.pt]
|
||||||
@@ -35,11 +43,6 @@ class CarState(CarStateBase):
|
|||||||
self.dashlights_dat = stop_start_cp.vl_raw["Dashlights"]
|
self.dashlights_dat = stop_start_cp.vl_raw["Dashlights"]
|
||||||
self.stop_start_state = stop_start_cp.vl["Engine_Stop_Start"]["STOP_START_STATE"]
|
self.stop_start_state = stop_start_cp.vl["Engine_Stop_Start"]["STOP_START_STATE"]
|
||||||
|
|
||||||
if self.CP.carFingerprint in SUBARU_AVH_CARS:
|
|
||||||
avh_cp = cp_alt if self.CP.flags & SubaruFlags.GLOBAL_GEN2 else cp
|
|
||||||
self.avh_msg = copy.copy(avh_cp.vl["AVH"])
|
|
||||||
self.avh_dat = avh_cp.vl_raw["AVH"]
|
|
||||||
|
|
||||||
throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_alt.vl["Throttle_Hybrid"]
|
throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_alt.vl["Throttle_Hybrid"]
|
||||||
ret.gasPressed = throttle_msg["Throttle_Pedal"] > 1e-5
|
ret.gasPressed = throttle_msg["Throttle_Pedal"] > 1e-5
|
||||||
if self.CP.flags & SubaruFlags.PREGLOBAL:
|
if self.CP.flags & SubaruFlags.PREGLOBAL:
|
||||||
@@ -143,6 +146,17 @@ class CarState(CarStateBase):
|
|||||||
self.es_status_msg = copy.copy(cp_es_brake.vl["ES_Status"])
|
self.es_status_msg = copy.copy(cp_es_brake.vl["ES_Status"])
|
||||||
self.cruise_control_msg = copy.copy(cp_cruise.vl["CruiseControl"])
|
self.cruise_control_msg = copy.copy(cp_cruise.vl["CruiseControl"])
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in SUBARU_REDNECK_CRUISE_CARS:
|
||||||
|
cruise_buttons = cp.vl["Cruise_Buttons"]
|
||||||
|
if getattr(starpilot_toggles, "subaru_redneck_cruise", False):
|
||||||
|
ret.buttonEvents = []
|
||||||
|
for button, button_type in SUBARU_CRUISE_BUTTONS.items():
|
||||||
|
ret.buttonEvents.extend(create_button_events(
|
||||||
|
int(bool(cruise_buttons[button])), self.cruise_buttons[button], {1: button_type},
|
||||||
|
))
|
||||||
|
self.cruise_buttons = {button: int(bool(cruise_buttons[button])) for button in SUBARU_CRUISE_BUTTONS}
|
||||||
|
self.cruise_buttons_msg = copy.copy(cruise_buttons)
|
||||||
|
|
||||||
if not (self.CP.flags & SubaruFlags.HYBRID):
|
if not (self.CP.flags & SubaruFlags.HYBRID):
|
||||||
self.es_distance_msg = copy.copy(cp_es_distance.vl["ES_Distance"])
|
self.es_distance_msg = copy.copy(cp_es_distance.vl["ES_Distance"])
|
||||||
|
|
||||||
@@ -163,11 +177,10 @@ class CarState(CarStateBase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_can_parsers(CP):
|
def get_can_parsers(CP):
|
||||||
avh_messages = [("AVH", 0)] if CP.carFingerprint in SUBARU_AVH_CARS else []
|
|
||||||
parsers = {
|
parsers = {
|
||||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.main_for_cp(CP)),
|
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.main_for_cp(CP)),
|
||||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.camera),
|
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.camera),
|
||||||
Bus.alt: CANParser(DBC[CP.carFingerprint][Bus.pt], avh_messages, CanBus.alt_for_cp(CP))
|
Bus.alt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.alt_for_cp(CP))
|
||||||
}
|
}
|
||||||
if CP.flags & SubaruFlags.D_PLATFORM:
|
if CP.flags & SubaruFlags.D_PLATFORM:
|
||||||
parsers[Bus.main] = CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.main)
|
parsers[Bus.main] = CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus.main)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from opendbc.car.disable_ecu import disable_ecu
|
|||||||
from opendbc.car.interfaces import CarInterfaceBase
|
from opendbc.car.interfaces import CarInterfaceBase
|
||||||
from opendbc.car.subaru.carcontroller import CarController
|
from opendbc.car.subaru.carcontroller import CarController
|
||||||
from opendbc.car.subaru.carstate import CarState
|
from opendbc.car.subaru.carstate import CarState
|
||||||
from opendbc.car.subaru.values import CAR, CanBus, GLOBAL_ES_ADDR, SUBARU_AVH_CARS, SUBARU_STOP_START_CARS, SubaruFlags, SubaruSafetyFlags
|
from opendbc.car.subaru.values import CAR, CanBus, GLOBAL_ES_ADDR, SUBARU_STOP_START_CARS, SubaruFlags, SubaruSafetyFlags
|
||||||
|
|
||||||
|
|
||||||
class CarInterface(CarInterfaceBase):
|
class CarInterface(CarInterfaceBase):
|
||||||
@@ -42,8 +42,6 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.D_PLATFORM_CAMERA.value
|
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.D_PLATFORM_CAMERA.value
|
||||||
if candidate in SUBARU_STOP_START_CARS:
|
if candidate in SUBARU_STOP_START_CARS:
|
||||||
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.STOP_START_BUTTON.value
|
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.STOP_START_BUTTON.value
|
||||||
if candidate in SUBARU_AVH_CARS:
|
|
||||||
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.AVH_BUTTON.value
|
|
||||||
if candidate in (CAR.SUBARU_LEGACY_2025, CAR.SUBARU_ASCENT_2023):
|
if candidate in (CAR.SUBARU_LEGACY_2025, CAR.SUBARU_ASCENT_2023):
|
||||||
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.FIXED_ANGLE_LIMITS.value
|
ret.safetyConfigs[0].safetyParam |= SubaruSafetyFlags.FIXED_ANGLE_LIMITS.value
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ from opendbc.car.subaru.values import CanBus
|
|||||||
|
|
||||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||||
|
|
||||||
|
CRUISE_BUTTON_MAIN = 1
|
||||||
|
CRUISE_BUTTON_SET = 2
|
||||||
|
CRUISE_BUTTON_RESUME = 3
|
||||||
|
|
||||||
|
|
||||||
def create_steering_control(packer, apply_torque, steer_req):
|
def create_steering_control(packer, apply_torque, steer_req):
|
||||||
values = {
|
values = {
|
||||||
@@ -67,6 +71,19 @@ def create_es_distance(packer, frame, es_distance_msg, bus, pcm_cancel_cmd, long
|
|||||||
return packer.make_can_msg("ES_Distance", bus, values)
|
return packer.make_can_msg("ES_Distance", bus, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_cruise_buttons(packer, frame, cruise_buttons_msg, button, bus=CanBus.main):
|
||||||
|
values = {s: cruise_buttons_msg[s] for s in [
|
||||||
|
"CHECKSUM",
|
||||||
|
"Signal1",
|
||||||
|
"Signal2",
|
||||||
|
]}
|
||||||
|
values["COUNTER"] = frame % 0x10
|
||||||
|
values["Main"] = button == CRUISE_BUTTON_MAIN
|
||||||
|
values["Set"] = button == CRUISE_BUTTON_SET
|
||||||
|
values["Resume"] = button == CRUISE_BUTTON_RESUME
|
||||||
|
return packer.make_can_msg("Cruise_Buttons", bus, values)
|
||||||
|
|
||||||
|
|
||||||
def create_es_lkas_state(packer, frame, es_lkas_state_msg, enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart,
|
def create_es_lkas_state(packer, frame, es_lkas_state_msg, enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart,
|
||||||
bus=CanBus.main):
|
bus=CanBus.main):
|
||||||
values = {s: es_lkas_state_msg[s] for s in [
|
values = {s: es_lkas_state_msg[s] for s in [
|
||||||
@@ -208,31 +225,6 @@ def create_stop_start_control(packer, dashlights_msg, raw_dat=None, counter=None
|
|||||||
return packer.make_can_msg("Dashlights", bus, values)
|
return packer.make_can_msg("Dashlights", bus, values)
|
||||||
|
|
||||||
|
|
||||||
def create_avh_control(packer, avh_msg, raw_dat=None, counter=None, bus=CanBus.alt):
|
|
||||||
"""Create the supported Subaru Legacy AVH ON request.
|
|
||||||
|
|
||||||
AVH is carried in the live 0x32b frame. Preserve the other bytes and update
|
|
||||||
only the rolling counter, AVH bit, and Subaru additive checksum.
|
|
||||||
"""
|
|
||||||
if raw_dat:
|
|
||||||
dat = bytearray(raw_dat)
|
|
||||||
if len(dat) != 8:
|
|
||||||
raise ValueError(f"AVH frame must be 8 bytes, got {len(dat)}")
|
|
||||||
if counter is None:
|
|
||||||
counter = (int(avh_msg.get("COUNTER", 0)) + 1) % 0x10
|
|
||||||
dat[1] = (dat[1] & 0xF0) | (counter % 0x10)
|
|
||||||
dat[5] |= 0x20 # AVH, big-endian bit 45
|
|
||||||
dat[0] = ((0x32B & 0xFF) + ((0x32B >> 8) & 0xFF) + sum(dat[1:])) & 0xFF
|
|
||||||
return 0x32B, bytes(dat), bus
|
|
||||||
|
|
||||||
values = dict(avh_msg)
|
|
||||||
if counter is None:
|
|
||||||
counter = (int(values.get("COUNTER", 0)) + 1) % 0x10
|
|
||||||
values["COUNTER"] = counter % 0x10
|
|
||||||
values["AVH"] = 1
|
|
||||||
return packer.make_can_msg("AVH", bus, values)
|
|
||||||
|
|
||||||
|
|
||||||
def create_es_brake(packer, frame, es_brake_msg, long_enabled, long_active, brake_value, bus=CanBus.main):
|
def create_es_brake(packer, frame, es_brake_msg, long_enabled, long_active, brake_value, bus=CanBus.main):
|
||||||
values = {s: es_brake_msg[s] for s in [
|
values = {s: es_brake_msg[s] for s in [
|
||||||
"CHECKSUM",
|
"CHECKSUM",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from types import SimpleNamespace
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from opendbc.can import CANPacker, CANParser
|
from opendbc.can import CANPacker, CANParser
|
||||||
from opendbc.car import Bus, fw_versions, structs
|
from opendbc.car import Bus, fw_versions, gen_empty_fingerprint, structs
|
||||||
from opendbc.car.fw_query_definitions import StdQueries
|
from opendbc.car.fw_query_definitions import StdQueries
|
||||||
from opendbc.car.subaru import subarucan
|
from opendbc.car.subaru import subarucan
|
||||||
from opendbc.car.subaru.carcontroller import CarController
|
from opendbc.car.subaru.carcontroller import CarController
|
||||||
@@ -67,6 +67,56 @@ def test_preglobal_sng_does_not_send_standstill_keepalive_without_manual_toggle(
|
|||||||
assert speed_cmd is False
|
assert speed_cmd is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_redneck_cruise_buttons_use_resume_for_increase_and_set_for_decrease():
|
||||||
|
dbc = DBC[CAR.SUBARU_IMPREZA_2020][Bus.pt]
|
||||||
|
packer = CANPacker(dbc)
|
||||||
|
parser = CANParser(dbc, [("Cruise_Buttons", 0)], CanBus.main)
|
||||||
|
stock_buttons = defaultdict(int)
|
||||||
|
|
||||||
|
resume_msg = subarucan.create_cruise_buttons(
|
||||||
|
packer, 1, stock_buttons, subarucan.CRUISE_BUTTON_RESUME, CanBus.main,
|
||||||
|
)
|
||||||
|
parser.update([(1, [resume_msg])])
|
||||||
|
assert parser.vl["Cruise_Buttons"]["Resume"] == 1
|
||||||
|
assert parser.vl["Cruise_Buttons"]["Set"] == 0
|
||||||
|
|
||||||
|
set_msg = subarucan.create_cruise_buttons(
|
||||||
|
packer, 2, stock_buttons, subarucan.CRUISE_BUTTON_SET, CanBus.main,
|
||||||
|
)
|
||||||
|
parser.update([(2, [set_msg])])
|
||||||
|
assert parser.vl["Cruise_Buttons"]["Resume"] == 0
|
||||||
|
assert parser.vl["Cruise_Buttons"]["Set"] == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_redneck_cruise_is_only_available_on_the_experimental_impreza(monkeypatch):
|
||||||
|
class FakeParams:
|
||||||
|
def __init__(self, **_kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_bool(self, key):
|
||||||
|
return key == "SubaruRedneckCruise"
|
||||||
|
|
||||||
|
monkeypatch.setattr("opendbc.car.interfaces.Params", FakeParams)
|
||||||
|
toggles = SimpleNamespace(subaru_sng=False)
|
||||||
|
|
||||||
|
impreza_cp = CarInterface.get_non_essential_params(CAR.SUBARU_IMPREZA_2020)
|
||||||
|
impreza_fpcp = CarInterface.get_starpilot_params(
|
||||||
|
CAR.SUBARU_IMPREZA_2020, gen_empty_fingerprint(), [], impreza_cp, toggles,
|
||||||
|
)
|
||||||
|
assert impreza_fpcp.redneckCruiseAvailable
|
||||||
|
assert not impreza_fpcp.pcmCruiseSpeed
|
||||||
|
assert impreza_cp.openpilotLongitudinalControl
|
||||||
|
assert impreza_cp.safetyConfigs[0].safetyParam & SubaruSafetyFlags.REDNECK_CRUISE
|
||||||
|
|
||||||
|
old_impreza_cp = CarInterface.get_non_essential_params(CAR.SUBARU_IMPREZA)
|
||||||
|
old_impreza_fpcp = CarInterface.get_starpilot_params(
|
||||||
|
CAR.SUBARU_IMPREZA, gen_empty_fingerprint(), [], old_impreza_cp, toggles,
|
||||||
|
)
|
||||||
|
assert not old_impreza_fpcp.redneckCruiseAvailable
|
||||||
|
assert old_impreza_fpcp.pcmCruiseSpeed
|
||||||
|
assert not old_impreza_cp.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
|
||||||
class TestSubaruFingerprint:
|
class TestSubaruFingerprint:
|
||||||
def test_eyesight_queries_do_not_change_diagnostic_state(self, monkeypatch):
|
def test_eyesight_queries_do_not_change_diagnostic_state(self, monkeypatch):
|
||||||
camera_requests = [request for request in FW_QUERY_CONFIG.requests if CarParams.Ecu.fwdCamera in request.whitelist_ecus]
|
camera_requests = [request for request in FW_QUERY_CONFIG.requests if CarParams.Ecu.fwdCamera in request.whitelist_ecus]
|
||||||
@@ -194,7 +244,6 @@ def test_outback_2023_uses_d_platform_bus_layout():
|
|||||||
assert CP.flags & SubaruFlags.D_PLATFORM
|
assert CP.flags & SubaruFlags.D_PLATFORM
|
||||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM
|
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM
|
||||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.STOP_START_BUTTON
|
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.STOP_START_BUTTON
|
||||||
assert not (CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.AVH_BUTTON)
|
|
||||||
assert not (CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.LEGACY_2025_ANGLE_LIMITS)
|
assert not (CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.LEGACY_2025_ANGLE_LIMITS)
|
||||||
assert CanBus.main_for_cp(CP) == CanBus.alt
|
assert CanBus.main_for_cp(CP) == CanBus.alt
|
||||||
assert CanBus.angle_for_cp(CP) == CanBus.main
|
assert CanBus.angle_for_cp(CP) == CanBus.main
|
||||||
@@ -225,21 +274,6 @@ def test_stop_start_inputs_are_captured_for_supported_models(platform):
|
|||||||
assert car_state.stop_start_state == 3
|
assert car_state.stop_start_state == 3
|
||||||
|
|
||||||
|
|
||||||
def test_avh_inputs_are_captured_for_legacy_2025():
|
|
||||||
CP = CarInterface.get_non_essential_params(CAR.SUBARU_LEGACY_2025)
|
|
||||||
car_state = CarState(CP, None)
|
|
||||||
parsers = car_state.get_can_parsers(CP)
|
|
||||||
raw_avh = bytes.fromhex("230f1c4208800000")
|
|
||||||
parsers[Bus.alt].vl["AVH"]["COUNTER"] = 15
|
|
||||||
parsers[Bus.alt].vl["AVH"]["AVH"] = 0
|
|
||||||
parsers[Bus.alt].vl_raw["AVH"] = raw_avh
|
|
||||||
|
|
||||||
car_state.update(parsers, SimpleNamespace(subaru_sng=False))
|
|
||||||
|
|
||||||
assert car_state.avh_msg["COUNTER"] == 15
|
|
||||||
assert car_state.avh_dat == raw_avh
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("platform, expected_bus, start_frame", [
|
@pytest.mark.parametrize("platform, expected_bus, start_frame", [
|
||||||
(CAR.SUBARU_OUTBACK_2023, CanBus.alt, 101),
|
(CAR.SUBARU_OUTBACK_2023, CanBus.alt, 101),
|
||||||
(CAR.SUBARU_LEGACY_2025, CanBus.alt, 401),
|
(CAR.SUBARU_LEGACY_2025, CanBus.alt, 401),
|
||||||
@@ -292,94 +326,6 @@ def test_stop_start_request_is_bounded_and_uses_live_dashlights(platform, expect
|
|||||||
assert controller.stop_start_acknowledged
|
assert controller.stop_start_acknowledged
|
||||||
|
|
||||||
|
|
||||||
def test_avh_request_sets_observed_bit_and_pulses_at_native_rate():
|
|
||||||
CP = CarInterface.get_non_essential_params(CAR.SUBARU_LEGACY_2025)
|
|
||||||
controller = CarController({}, CP)
|
|
||||||
controller.frame = 101
|
|
||||||
|
|
||||||
class TestActuators:
|
|
||||||
steeringAngleDeg = 0.0
|
|
||||||
|
|
||||||
def as_builder(self):
|
|
||||||
return SimpleNamespace(steeringAngleDeg=self.steeringAngleDeg)
|
|
||||||
|
|
||||||
CC = SimpleNamespace(
|
|
||||||
enabled=False,
|
|
||||||
latActive=False,
|
|
||||||
longActive=False,
|
|
||||||
actuators=TestActuators(),
|
|
||||||
hudControl=SimpleNamespace(leadVisible=False),
|
|
||||||
cruiseControl=SimpleNamespace(cancel=False),
|
|
||||||
)
|
|
||||||
CS = SimpleNamespace(
|
|
||||||
canValid=True,
|
|
||||||
avh_msg={"COUNTER": 15, "AVH": 0},
|
|
||||||
avh_dat=bytes.fromhex("230f1c4208800000"),
|
|
||||||
out=SimpleNamespace(
|
|
||||||
standstill=True,
|
|
||||||
gearShifter=structs.CarState.GearShifter.park,
|
|
||||||
vEgoRaw=0.0,
|
|
||||||
steeringAngleDeg=0.0,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
toggles = SimpleNamespace(subaru_stop_start_off=False, subaru_avh_on=True, subaru_sng=False)
|
|
||||||
|
|
||||||
# Start the request from the current live counter. AVH is a native 10 Hz
|
|
||||||
# frame, so the controller waits for each next live counter before sending
|
|
||||||
# its matching button frame.
|
|
||||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
|
||||||
avh_msgs = [msg for msg in can_sends if msg[0] == 0x32b]
|
|
||||||
assert not avh_msgs
|
|
||||||
|
|
||||||
CS.avh_msg["COUNTER"] = 0
|
|
||||||
CS.avh_dat = bytes.fromhex("14001c4208800000")
|
|
||||||
controller.frame = 103
|
|
||||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
|
||||||
avh_msgs = [msg for msg in can_sends if msg[0] == 0x32b]
|
|
||||||
assert avh_msgs == [(0x32b, bytes.fromhex("34001c4208a00000"), CanBus.alt)]
|
|
||||||
|
|
||||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("AVH", 0)], CanBus.alt)
|
|
||||||
parser.update([(CanBus.alt, avh_msgs)])
|
|
||||||
assert parser.vl["AVH"]["AVH"] == 1
|
|
||||||
assert parser.vl["AVH"]["COUNTER"] == 0
|
|
||||||
|
|
||||||
controller.frame = 104
|
|
||||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
|
||||||
assert not any(msg[0] == 0x32b for msg in can_sends)
|
|
||||||
|
|
||||||
avh_msgs = []
|
|
||||||
for counter in range(1, 15):
|
|
||||||
CS.avh_msg["COUNTER"] = counter
|
|
||||||
raw_dat = bytearray.fromhex("14001c4208800000")
|
|
||||||
raw_dat[1] = counter
|
|
||||||
raw_dat[0] = ((0x32B & 0xFF) + ((0x32B >> 8) & 0xFF) + sum(raw_dat[1:])) & 0xFF
|
|
||||||
CS.avh_dat = bytes(raw_dat)
|
|
||||||
controller.frame = 103 + (counter * 10)
|
|
||||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
|
||||||
sent = [msg for msg in can_sends if msg[0] == 0x32b]
|
|
||||||
assert len(sent) == 1
|
|
||||||
avh_msgs.extend(sent)
|
|
||||||
|
|
||||||
assert len(avh_msgs) == 14
|
|
||||||
assert [msg[1][1] & 0x0F for msg in avh_msgs] == list(range(1, 15))
|
|
||||||
assert all(msg[1][5] & 0x20 for msg in avh_msgs)
|
|
||||||
assert not controller.avh_attempted
|
|
||||||
|
|
||||||
CS.avh_msg["COUNTER"] = 15
|
|
||||||
CS.avh_dat = bytes.fromhex("230f1c4208800000")
|
|
||||||
controller.frame = 253
|
|
||||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
|
||||||
assert not any(msg[0] == 0x32b for msg in can_sends)
|
|
||||||
assert controller.avh_attempted
|
|
||||||
|
|
||||||
CS.avh_msg["COUNTER"] = 0
|
|
||||||
CS.avh_dat = bytes.fromhex("14001c4208800000")
|
|
||||||
controller.frame = 131
|
|
||||||
_, can_sends = controller.update(CC, CS, 0, toggles)
|
|
||||||
assert not any(msg[0] == 0x32b for msg in can_sends)
|
|
||||||
assert controller.avh_attempted
|
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_2025_uses_gen2_angle_bus_layout():
|
def test_legacy_2025_uses_gen2_angle_bus_layout():
|
||||||
CP = CarInterface.get_non_essential_params(CAR.SUBARU_LEGACY_2025)
|
CP = CarInterface.get_non_essential_params(CAR.SUBARU_LEGACY_2025)
|
||||||
parsers = CarState.get_can_parsers(CP)
|
parsers = CarState.get_can_parsers(CP)
|
||||||
@@ -391,7 +337,6 @@ def test_legacy_2025_uses_gen2_angle_bus_layout():
|
|||||||
assert not (CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM_CAMERA)
|
assert not (CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM_CAMERA)
|
||||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.FIXED_ANGLE_LIMITS
|
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.FIXED_ANGLE_LIMITS
|
||||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.STOP_START_BUTTON
|
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.STOP_START_BUTTON
|
||||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.AVH_BUTTON
|
|
||||||
assert CanBus.main_for_cp(CP) == CanBus.main
|
assert CanBus.main_for_cp(CP) == CanBus.main
|
||||||
assert CanBus.angle_for_cp(CP) == CanBus.main
|
assert CanBus.angle_for_cp(CP) == CanBus.main
|
||||||
assert parsers[Bus.pt].bus == CanBus.main
|
assert parsers[Bus.pt].bus == CanBus.main
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class SubaruSafetyFlags(IntFlag):
|
|||||||
D_PLATFORM_CAMERA = 64
|
D_PLATFORM_CAMERA = 64
|
||||||
FIXED_ANGLE_LIMITS = 128
|
FIXED_ANGLE_LIMITS = 128
|
||||||
STOP_START_BUTTON = 256
|
STOP_START_BUTTON = 256
|
||||||
AVH_BUTTON = 512
|
REDNECK_CRUISE = 512
|
||||||
LEGACY_2025_ANGLE_LIMITS = FIXED_ANGLE_LIMITS
|
LEGACY_2025_ANGLE_LIMITS = FIXED_ANGLE_LIMITS
|
||||||
|
|
||||||
|
|
||||||
@@ -276,11 +276,10 @@ SUBARU_STOP_START_CARS = (
|
|||||||
CAR.SUBARU_LEGACY_2025,
|
CAR.SUBARU_LEGACY_2025,
|
||||||
)
|
)
|
||||||
|
|
||||||
SUBARU_AVH_CARS = (
|
SUBARU_REDNECK_CRUISE_CARS = (
|
||||||
CAR.SUBARU_LEGACY_2025,
|
CAR.SUBARU_IMPREZA_2020,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
SUBARU_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
|
SUBARU_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
|
||||||
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION)
|
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_DATA_IDENTIFICATION)
|
||||||
SUBARU_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
|
SUBARU_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from opendbc.car.interfaces import CarControllerBase
|
|||||||
from opendbc.car.toyota import toyotacan
|
from opendbc.car.toyota import toyotacan
|
||||||
from opendbc.car.toyota.values import CAR, MIN_ACC_SPEED, NO_STOP_TIMER_CAR, PEDAL_TRANSITION, TSS2_CAR, \
|
from opendbc.car.toyota.values import CAR, MIN_ACC_SPEED, NO_STOP_TIMER_CAR, PEDAL_TRANSITION, TSS2_CAR, \
|
||||||
CarControllerParams, ToyotaFlags, \
|
CarControllerParams, ToyotaFlags, \
|
||||||
UNSUPPORTED_DSU_CAR, LEGACY_PRIUS_CAR
|
UNSUPPORTED_DSU_CAR, LEGACY_PRIUS_CAR, RADAR_ACC_CAR, SECOC_CAR
|
||||||
from opendbc.can import CANPacker
|
from opendbc.can import CANPacker
|
||||||
|
|
||||||
Ecu = structs.CarParams.Ecu
|
Ecu = structs.CarParams.Ecu
|
||||||
@@ -49,6 +49,8 @@ MAX_USER_TORQUE = 500
|
|||||||
PARK = structs.CarState.GearShifter.park
|
PARK = structs.CarState.GearShifter.park
|
||||||
REVERSE = structs.CarState.GearShifter.reverse
|
REVERSE = structs.CarState.GearShifter.reverse
|
||||||
|
|
||||||
|
TOYOTA_AUTO_HOLD_CARS = TSS2_CAR - RADAR_ACC_CAR - SECOC_CAR
|
||||||
|
|
||||||
# Lock / unlock door commands - Credit goes to AlexandreSato!
|
# Lock / unlock door commands - Credit goes to AlexandreSato!
|
||||||
LOCK_CMD = b"\x40\x05\x30\x11\x00\x80\x00\x00"
|
LOCK_CMD = b"\x40\x05\x30\x11\x00\x80\x00\x00"
|
||||||
UNLOCK_CMD = b"\x40\x05\x30\x11\x00\x40\x00\x00"
|
UNLOCK_CMD = b"\x40\x05\x30\x11\x00\x40\x00\x00"
|
||||||
@@ -72,6 +74,14 @@ def should_bypass_toyota_long_pid(CP, starpilot_toggles=None) -> bool:
|
|||||||
) or highlander_sdsu)
|
) or highlander_sdsu)
|
||||||
|
|
||||||
|
|
||||||
|
def supports_toyota_auto_hold(CP, auto_hold_enabled: bool) -> bool:
|
||||||
|
return (
|
||||||
|
auto_hold_enabled and
|
||||||
|
CP.carFingerprint in TOYOTA_AUTO_HOLD_CARS and
|
||||||
|
bool(CP.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_long_tune(CP, params):
|
def get_long_tune(CP, params):
|
||||||
kiBP = [2., 5.]
|
kiBP = [2., 5.]
|
||||||
kiV = [0.5, 0.25]
|
kiV = [0.5, 0.25]
|
||||||
@@ -243,11 +253,8 @@ class CarController(CarControllerBase):
|
|||||||
self.secoc_prev_reset_counter = 0
|
self.secoc_prev_reset_counter = 0
|
||||||
|
|
||||||
self.doors_locked = False
|
self.doors_locked = False
|
||||||
self.auto_brake_hold = bool(self.CP.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value)
|
|
||||||
self.brake_hold_active = False
|
self.brake_hold_active = False
|
||||||
self._brake_hold_counter = 0
|
self._brake_hold_counter = 0
|
||||||
self._brake_hold_reset = False
|
|
||||||
self._prev_brake_pressed = False
|
|
||||||
|
|
||||||
def _compute_interceptor_gas_cmd(self, CC, CS):
|
def _compute_interceptor_gas_cmd(self, CC, CS):
|
||||||
if not (self.CP.enableGasInterceptorDEPRECATED and self.CP.openpilotLongitudinalControl and CC.longActive):
|
if not (self.CP.enableGasInterceptorDEPRECATED and self.CP.openpilotLongitudinalControl and CC.longActive):
|
||||||
@@ -299,15 +306,12 @@ class CarController(CarControllerBase):
|
|||||||
not CS.out.gasPressed and not CS.out.cruiseState.enabled and
|
not CS.out.gasPressed and not CS.out.cruiseState.enabled and
|
||||||
CS.out.gearShifter not in (PARK, REVERSE))
|
CS.out.gearShifter not in (PARK, REVERSE))
|
||||||
|
|
||||||
if brake_hold_allowed:
|
if brake_hold_allowed and not self.brake_hold_active and CS.out.brakePressed:
|
||||||
self._brake_hold_counter += 1
|
self._brake_hold_counter += 1
|
||||||
self.brake_hold_active = self._brake_hold_counter > brake_hold_allowed_timer and not self._brake_hold_reset
|
self.brake_hold_active = self._brake_hold_counter > brake_hold_allowed_timer
|
||||||
self._brake_hold_reset = not self._prev_brake_pressed and CS.out.brakePressed and not self._brake_hold_reset
|
elif not brake_hold_allowed:
|
||||||
else:
|
|
||||||
self._brake_hold_counter = 0
|
self._brake_hold_counter = 0
|
||||||
self.brake_hold_active = False
|
self.brake_hold_active = False
|
||||||
self._brake_hold_reset = False
|
|
||||||
self._prev_brake_pressed = CS.out.brakePressed
|
|
||||||
|
|
||||||
if self.frame % 2 == 0:
|
if self.frame % 2 == 0:
|
||||||
can_sends.append(toyotacan.create_brake_hold_command(self.packer, self.frame, CS.pre_collision_2, self.brake_hold_active))
|
can_sends.append(toyotacan.create_brake_hold_command(self.packer, self.frame, CS.pre_collision_2, self.brake_hold_active))
|
||||||
@@ -409,8 +413,11 @@ class CarController(CarControllerBase):
|
|||||||
# *** gas and brake ***
|
# *** gas and brake ***
|
||||||
|
|
||||||
self._update_standstill_request(CC, CS, actuators, starpilot_toggles)
|
self._update_standstill_request(CC, CS, actuators, starpilot_toggles)
|
||||||
if self.auto_brake_hold:
|
if supports_toyota_auto_hold(self.CP, getattr(starpilot_toggles, "toyota_auto_hold", False)):
|
||||||
can_sends.extend(self.create_auto_brake_hold_messages(CS))
|
can_sends.extend(self.create_auto_brake_hold_messages(CS))
|
||||||
|
elif self.brake_hold_active:
|
||||||
|
self._brake_hold_counter = 0
|
||||||
|
self.brake_hold_active = False
|
||||||
|
|
||||||
interceptor_gas_cmd = self._compute_interceptor_gas_cmd(CC, CS)
|
interceptor_gas_cmd = self._compute_interceptor_gas_cmd(CC, CS)
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class CarState(CarStateBase):
|
|||||||
self.distance_button = 0
|
self.distance_button = 0
|
||||||
|
|
||||||
self.pcm_follow_distance = 0
|
self.pcm_follow_distance = 0
|
||||||
|
self.pcm_acc_status = 0
|
||||||
|
|
||||||
self.acc_type = 1
|
self.acc_type = 1
|
||||||
self.lkas_hud = {}
|
self.lkas_hud = {}
|
||||||
@@ -208,6 +209,7 @@ class CarState(CarStateBase):
|
|||||||
if self.CP.openpilotLongitudinalControl:
|
if self.CP.openpilotLongitudinalControl:
|
||||||
ret.accFaulted = ret.accFaulted or cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2
|
ret.accFaulted = ret.accFaulted or cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2
|
||||||
|
|
||||||
|
prev_pcm_acc_status = self.pcm_acc_status
|
||||||
self.pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"]
|
self.pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"]
|
||||||
if self.CP.carFingerprint not in (NO_STOP_TIMER_CAR - TSS2_CAR):
|
if self.CP.carFingerprint not in (NO_STOP_TIMER_CAR - TSS2_CAR):
|
||||||
# ignore standstill state in certain vehicles, since pcm allows to restart with just an acceleration request
|
# ignore standstill state in certain vehicles, since pcm allows to restart with just an acceleration request
|
||||||
@@ -264,8 +266,8 @@ class CarState(CarStateBase):
|
|||||||
buttonEvents += create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
buttonEvents += create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||||
|
|
||||||
buttonEvents += [
|
buttonEvents += [
|
||||||
*create_button_events(self.pcm_acc_status == 9, False, {1: ButtonType.accelCruise}),
|
*create_button_events(self.pcm_acc_status == 9, prev_pcm_acc_status == 9, {1: ButtonType.accelCruise}),
|
||||||
*create_button_events(self.pcm_acc_status == 10, False, {1: ButtonType.decelCruise}),
|
*create_button_events(self.pcm_acc_status == 10, prev_pcm_acc_status == 10, {1: ButtonType.decelCruise}),
|
||||||
]
|
]
|
||||||
|
|
||||||
fp_ret.dashboardSpeedLimit = calculate_speed_limit(cp_cam)
|
fp_ret.dashboardSpeedLimit = calculate_speed_limit(cp_cam)
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ from opendbc.car.toyota.carcontroller import CarController, get_camry_hybrid_fee
|
|||||||
get_prius_positive_feedforward_scale, \
|
get_prius_positive_feedforward_scale, \
|
||||||
limit_interceptor_pcm_accel, \
|
limit_interceptor_pcm_accel, \
|
||||||
limit_interceptor_stopping_accel, limit_no_lead_cruise_sign_flip, \
|
limit_interceptor_stopping_accel, limit_no_lead_cruise_sign_flip, \
|
||||||
limit_prius_stopping_accel, should_bypass_toyota_long_pid, update_permit_braking
|
limit_prius_stopping_accel, should_bypass_toyota_long_pid, supports_toyota_auto_hold, \
|
||||||
|
update_permit_braking
|
||||||
from opendbc.car.toyota.carstate import CarState, LKAS_BUTTON_CAR, calculate_interceptor_gas_pressed, create_lkas_button_events
|
from opendbc.car.toyota.carstate import CarState, LKAS_BUTTON_CAR, calculate_interceptor_gas_pressed, create_lkas_button_events
|
||||||
from opendbc.car.toyota.fingerprints import FW_VERSIONS
|
from opendbc.car.toyota.fingerprints import FW_VERSIONS
|
||||||
from opendbc.car.toyota.interface import CarInterface
|
from opendbc.car.toyota.interface import CarInterface
|
||||||
@@ -205,6 +206,22 @@ class TestToyotaInterfaces:
|
|||||||
assert car_params.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value
|
assert car_params.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value
|
||||||
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||||
|
|
||||||
|
def test_auto_hold_is_disabled_by_default(self):
|
||||||
|
params = Params()
|
||||||
|
params.remove("ToyotaAutoHold")
|
||||||
|
car_params = CarInterface.get_params(
|
||||||
|
CAR.TOYOTA_CAMRY_TSS2,
|
||||||
|
{bus: {} for bus in range(8)},
|
||||||
|
[],
|
||||||
|
alpha_long=False,
|
||||||
|
is_release=False,
|
||||||
|
docs=False,
|
||||||
|
starpilot_toggles=SimpleNamespace(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not car_params.flags & ToyotaFlags.AUTO_BRAKE_HOLD.value
|
||||||
|
assert not car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||||
|
|
||||||
def test_prius_openpilot_long_uses_hybrid_long_defaults(self):
|
def test_prius_openpilot_long_uses_hybrid_long_defaults(self):
|
||||||
car_params = CarInterface.get_params(
|
car_params = CarInterface.get_params(
|
||||||
CAR.TOYOTA_PRIUS,
|
CAR.TOYOTA_PRIUS,
|
||||||
@@ -750,6 +767,74 @@ class TestToyotaCarController:
|
|||||||
|
|
||||||
assert controller.standstill_req is True
|
assert controller.standstill_req is True
|
||||||
|
|
||||||
|
def test_toyota_auto_hold_requires_toggle_supported_car_and_capability(self):
|
||||||
|
CP = SimpleNamespace(
|
||||||
|
carFingerprint=CAR.TOYOTA_CAMRY_TSS2,
|
||||||
|
flags=ToyotaFlags.AUTO_BRAKE_HOLD.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert supports_toyota_auto_hold(CP, True)
|
||||||
|
assert not supports_toyota_auto_hold(CP, False)
|
||||||
|
assert not supports_toyota_auto_hold(SimpleNamespace(
|
||||||
|
carFingerprint=CAR.TOYOTA_CAMRY_TSS2,
|
||||||
|
flags=0,
|
||||||
|
), True)
|
||||||
|
assert not supports_toyota_auto_hold(SimpleNamespace(
|
||||||
|
carFingerprint=CAR.TOYOTA_CAMRY,
|
||||||
|
flags=ToyotaFlags.AUTO_BRAKE_HOLD.value,
|
||||||
|
), True)
|
||||||
|
|
||||||
|
def test_toyota_auto_hold_latches_after_brake_press_until_gas(self):
|
||||||
|
controller = self._make_controller()
|
||||||
|
controller.packer = CANPacker(DBC[CAR.TOYOTA_CAMRY_TSS2][Bus.pt])
|
||||||
|
controller.frame = 0
|
||||||
|
controller.brake_hold_active = False
|
||||||
|
controller._brake_hold_counter = 0
|
||||||
|
|
||||||
|
cs = SimpleNamespace(
|
||||||
|
out=SimpleNamespace(
|
||||||
|
standstill=True,
|
||||||
|
cruiseState=SimpleNamespace(available=True, enabled=False),
|
||||||
|
gasPressed=False,
|
||||||
|
brakePressed=True,
|
||||||
|
gearShifter=structs.CarState.GearShifter.drive,
|
||||||
|
),
|
||||||
|
pre_collision_2={},
|
||||||
|
)
|
||||||
|
|
||||||
|
controller.create_auto_brake_hold_messages(cs, brake_hold_allowed_timer=0)
|
||||||
|
assert controller.brake_hold_active
|
||||||
|
|
||||||
|
cs.out.brakePressed = False
|
||||||
|
controller.frame = 2
|
||||||
|
controller.create_auto_brake_hold_messages(cs, brake_hold_allowed_timer=0)
|
||||||
|
assert controller.brake_hold_active
|
||||||
|
|
||||||
|
cs.out.gasPressed = True
|
||||||
|
controller.frame = 4
|
||||||
|
controller.create_auto_brake_hold_messages(cs, brake_hold_allowed_timer=0)
|
||||||
|
assert not controller.brake_hold_active
|
||||||
|
|
||||||
|
def test_toyota_auto_hold_does_not_trigger_without_brake_press(self):
|
||||||
|
controller = self._make_controller()
|
||||||
|
controller.packer = CANPacker(DBC[CAR.TOYOTA_CAMRY_TSS2][Bus.pt])
|
||||||
|
controller.frame = 0
|
||||||
|
controller.brake_hold_active = False
|
||||||
|
controller._brake_hold_counter = 0
|
||||||
|
cs = SimpleNamespace(
|
||||||
|
out=SimpleNamespace(
|
||||||
|
standstill=True,
|
||||||
|
cruiseState=SimpleNamespace(available=True, enabled=False),
|
||||||
|
gasPressed=False,
|
||||||
|
brakePressed=False,
|
||||||
|
gearShifter=structs.CarState.GearShifter.drive,
|
||||||
|
),
|
||||||
|
pre_collision_2={},
|
||||||
|
)
|
||||||
|
|
||||||
|
controller.create_auto_brake_hold_messages(cs, brake_hold_allowed_timer=0)
|
||||||
|
assert not controller.brake_hold_active
|
||||||
|
|
||||||
def test_prius_resume_request_releases_standstill_latch(self):
|
def test_prius_resume_request_releases_standstill_latch(self):
|
||||||
controller = self._make_controller(standstill_req=True, last_standstill=True)
|
controller = self._make_controller(standstill_req=True, last_standstill=True)
|
||||||
|
|
||||||
@@ -893,14 +978,12 @@ class TestToyotaCarController:
|
|||||||
controller.frame = 0
|
controller.frame = 0
|
||||||
controller.brake_hold_active = False
|
controller.brake_hold_active = False
|
||||||
controller._brake_hold_counter = 0
|
controller._brake_hold_counter = 0
|
||||||
controller._brake_hold_reset = False
|
|
||||||
controller._prev_brake_pressed = False
|
|
||||||
cs = SimpleNamespace(
|
cs = SimpleNamespace(
|
||||||
out=SimpleNamespace(
|
out=SimpleNamespace(
|
||||||
standstill=True,
|
standstill=True,
|
||||||
cruiseState=SimpleNamespace(available=True, enabled=False),
|
cruiseState=SimpleNamespace(available=True, enabled=False),
|
||||||
gasPressed=False,
|
gasPressed=False,
|
||||||
brakePressed=False,
|
brakePressed=True,
|
||||||
gearShifter=structs.CarState.GearShifter.drive,
|
gearShifter=structs.CarState.GearShifter.drive,
|
||||||
),
|
),
|
||||||
pre_collision_2={},
|
pre_collision_2={},
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ TransmissionType = structs.CarParams.TransmissionType
|
|||||||
# Must match VOLVO_SPEED_TO_MS in opendbc/safety/modes/volvo.h.
|
# Must match VOLVO_SPEED_TO_MS in opendbc/safety/modes/volvo.h.
|
||||||
SPEED_TO_MS = 0.003977
|
SPEED_TO_MS = 0.003977
|
||||||
STEERING_PRESSED_THRESHOLD = 2
|
STEERING_PRESSED_THRESHOLD = 2
|
||||||
STEERING_DISENGAGE_THRESHOLD = 5
|
|
||||||
|
|
||||||
|
|
||||||
class CarState(CarStateBase):
|
class CarState(CarStateBase):
|
||||||
@@ -75,11 +74,9 @@ class CarState(CarStateBase):
|
|||||||
ret.steeringAngleDeg = cp_party.vl['PSCM']['PSCM_ANGLE_SENSOR'] # openpilot expects a negative value for a right turn
|
ret.steeringAngleDeg = cp_party.vl['PSCM']['PSCM_ANGLE_SENSOR'] # openpilot expects a negative value for a right turn
|
||||||
#ret.steeringAngleDeg = cp_party.vl['SAS']['SAS_ANGLE_SENSOR']
|
#ret.steeringAngleDeg = cp_party.vl['SAS']['SAS_ANGLE_SENSOR']
|
||||||
|
|
||||||
# Driver steering torque feedback (used for driver override detection)
|
|
||||||
ret.steeringTorque = -cp_party.vl['DRIVER_INPUT']['STEERING_DRIVER_INPUT'] # Car right turn is negative, openpilot right turn is positive
|
ret.steeringTorque = -cp_party.vl['DRIVER_INPUT']['STEERING_DRIVER_INPUT'] # Car right turn is negative, openpilot right turn is positive
|
||||||
driver_input = abs(cp_party.vl['DRIVER_INPUT']['STEERING_DRIVER_INPUT'])
|
driver_input = abs(cp_party.vl['DRIVER_INPUT']['STEERING_DRIVER_INPUT'])
|
||||||
ret.steeringPressed = driver_input > STEERING_PRESSED_THRESHOLD
|
ret.steeringPressed = driver_input > STEERING_PRESSED_THRESHOLD
|
||||||
ret.steeringDisengage = driver_input > STEERING_DISENGAGE_THRESHOLD
|
|
||||||
|
|
||||||
# EPS status - placeholder until actual signal is found
|
# EPS status - placeholder until actual signal is found
|
||||||
self.eps_active = True # Assume EPS is active for now
|
self.eps_active = True # Assume EPS is active for now
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
CM_ "IMPORT _subaru_global.dbc";
|
CM_ "IMPORT _subaru_global.dbc";
|
||||||
|
|
||||||
BO_ 811 AVH: 8 XXX
|
|
||||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
|
||||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
|
||||||
SG_ AVH : 45|1@0+ (1,0) [0|1] "" XXX
|
|
||||||
|
|
||||||
BO_ 72 Transmission: 8 XXX
|
BO_ 72 Transmission: 8 XXX
|
||||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||||
|
|||||||
@@ -1497,6 +1497,7 @@ BO_ 913 BCM_PO_11: 8 Vector__XXX
|
|||||||
SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
|
SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
|
||||||
SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
|
SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
|
||||||
SG_ LDA_BTN : 4|1@0+ (1,0) [0|1] "" XXX
|
SG_ LDA_BTN : 4|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RAY_LKAS_BTN : 0|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
BO_ 1426 LABEL11: 8 XXX
|
BO_ 1426 LABEL11: 8 XXX
|
||||||
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
|
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
|||||||
@@ -1497,6 +1497,7 @@ BO_ 913 BCM_PO_11: 8 Vector__XXX
|
|||||||
SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
|
SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
|
||||||
SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
|
SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
|
||||||
SG_ LDA_BTN : 4|1@0+ (1,0) [0|1] "" XXX
|
SG_ LDA_BTN : 4|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RAY_LKAS_BTN : 0|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
BO_ 1426 LABEL11: 8 XXX
|
BO_ 1426 LABEL11: 8 XXX
|
||||||
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
|
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
|||||||
@@ -307,11 +307,6 @@ VAL_ 544 AEB_Status 12 "AEB related" 8 "AEB actuation" 4 "AEB related" 0 "No AEB
|
|||||||
|
|
||||||
CM_ "subaru_global_2017.dbc starts here";
|
CM_ "subaru_global_2017.dbc starts here";
|
||||||
|
|
||||||
BO_ 811 AVH: 8 XXX
|
|
||||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
|
||||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
|
||||||
SG_ AVH : 45|1@0+ (1,0) [0|1] "" XXX
|
|
||||||
|
|
||||||
BO_ 72 Transmission: 8 XXX
|
BO_ 72 Transmission: 8 XXX
|
||||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#define MSG_SUBARU_ES_DashStatus 0x321U
|
#define MSG_SUBARU_ES_DashStatus 0x321U
|
||||||
#define MSG_SUBARU_ES_LKAS_State 0x322U
|
#define MSG_SUBARU_ES_LKAS_State 0x322U
|
||||||
#define MSG_SUBARU_ES_Infotainment 0x323U
|
#define MSG_SUBARU_ES_Infotainment 0x323U
|
||||||
|
#define MSG_SUBARU_Cruise_Buttons 0x146U
|
||||||
|
|
||||||
#define MSG_SUBARU_ES_UDS_Request 0x787U
|
#define MSG_SUBARU_ES_UDS_Request 0x787U
|
||||||
|
|
||||||
@@ -42,7 +43,6 @@
|
|||||||
#define MSG_SUBARU_ES_STATIC_1 0x22aU
|
#define MSG_SUBARU_ES_STATIC_1 0x22aU
|
||||||
#define MSG_SUBARU_ES_STATIC_2 0x325U
|
#define MSG_SUBARU_ES_STATIC_2 0x325U
|
||||||
#define MSG_SUBARU_Dashlights 0x390U
|
#define MSG_SUBARU_Dashlights 0x390U
|
||||||
#define MSG_SUBARU_AVH 0x32bU
|
|
||||||
|
|
||||||
#define SUBARU_MAIN_BUS 0U
|
#define SUBARU_MAIN_BUS 0U
|
||||||
#define SUBARU_ALT_BUS 1U
|
#define SUBARU_ALT_BUS 1U
|
||||||
@@ -57,6 +57,9 @@
|
|||||||
#define SUBARU_COMMON_TX_MSGS(alt_bus) \
|
#define SUBARU_COMMON_TX_MSGS(alt_bus) \
|
||||||
{MSG_SUBARU_ES_Distance, alt_bus, 8, .check_relay = false}, \
|
{MSG_SUBARU_ES_Distance, alt_bus, 8, .check_relay = false}, \
|
||||||
|
|
||||||
|
#define SUBARU_REDNECK_TX_MSGS() \
|
||||||
|
{MSG_SUBARU_Cruise_Buttons, SUBARU_MAIN_BUS, 8, .check_relay = false}, \
|
||||||
|
|
||||||
#define SUBARU_D_PLATFORM_ANGLE_TX_MSGS(bus) \
|
#define SUBARU_D_PLATFORM_ANGLE_TX_MSGS(bus) \
|
||||||
{MSG_SUBARU_ES_LKAS_ANGLE, bus, 8, .check_relay = true}, \
|
{MSG_SUBARU_ES_LKAS_ANGLE, bus, 8, .check_relay = true}, \
|
||||||
{MSG_SUBARU_ES_DashStatus, bus, 8, .check_relay = true}, \
|
{MSG_SUBARU_ES_DashStatus, bus, 8, .check_relay = true}, \
|
||||||
@@ -66,13 +69,6 @@
|
|||||||
#define SUBARU_STOP_START_TX_MSGS(bus) \
|
#define SUBARU_STOP_START_TX_MSGS(bus) \
|
||||||
{MSG_SUBARU_Dashlights, bus, 8, .check_relay = false}, \
|
{MSG_SUBARU_Dashlights, bus, 8, .check_relay = false}, \
|
||||||
|
|
||||||
#define SUBARU_AVH_TX_MSGS(bus) \
|
|
||||||
{MSG_SUBARU_AVH, bus, 8, .check_relay = false}, \
|
|
||||||
|
|
||||||
#define SUBARU_STOP_START_AVH_TX_MSGS(bus) \
|
|
||||||
SUBARU_STOP_START_TX_MSGS(bus) \
|
|
||||||
SUBARU_AVH_TX_MSGS(bus)
|
|
||||||
|
|
||||||
#define SUBARU_COMMON_LONG_TX_MSGS(alt_bus) \
|
#define SUBARU_COMMON_LONG_TX_MSGS(alt_bus) \
|
||||||
{MSG_SUBARU_ES_Distance, alt_bus, 8, .check_relay = true}, \
|
{MSG_SUBARU_ES_Distance, alt_bus, 8, .check_relay = true}, \
|
||||||
{MSG_SUBARU_ES_Brake, alt_bus, 8, .check_relay = true}, \
|
{MSG_SUBARU_ES_Brake, alt_bus, 8, .check_relay = true}, \
|
||||||
@@ -121,7 +117,7 @@ static bool subaru_lkas_angle = false;
|
|||||||
static bool subaru_d_platform = false;
|
static bool subaru_d_platform = false;
|
||||||
static bool subaru_fixed_angle_limits = false;
|
static bool subaru_fixed_angle_limits = false;
|
||||||
static bool subaru_stop_start_button = false;
|
static bool subaru_stop_start_button = false;
|
||||||
static bool subaru_avh_button = false;
|
static bool subaru_redneck_cruise = false;
|
||||||
|
|
||||||
static uint32_t subaru_get_checksum(const CANPacket_t *msg) {
|
static uint32_t subaru_get_checksum(const CANPacket_t *msg) {
|
||||||
return (uint8_t)msg->data[0];
|
return (uint8_t)msg->data[0];
|
||||||
@@ -306,10 +302,9 @@ static bool subaru_tx_hook(const CANPacket_t *msg) {
|
|||||||
violation |= subaru_get_checksum(msg) != subaru_compute_checksum(msg);
|
violation |= subaru_get_checksum(msg) != subaru_compute_checksum(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->addr == MSG_SUBARU_AVH) {
|
if (msg->addr == MSG_SUBARU_Cruise_Buttons) {
|
||||||
violation |= !subaru_avh_button;
|
violation |= !subaru_redneck_cruise;
|
||||||
violation |= msg->bus != (subaru_gen2 ? SUBARU_ALT_BUS : SUBARU_MAIN_BUS);
|
violation |= msg->bus != SUBARU_MAIN_BUS;
|
||||||
violation |= !GET_BIT(msg, 45U);
|
|
||||||
violation |= subaru_get_checksum(msg) != subaru_compute_checksum(msg);
|
violation |= subaru_get_checksum(msg) != subaru_compute_checksum(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,6 +320,19 @@ static safety_config subaru_init(uint16_t param) {
|
|||||||
SUBARU_COMMON_TX_MSGS(SUBARU_MAIN_BUS)
|
SUBARU_COMMON_TX_MSGS(SUBARU_MAIN_BUS)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const CanMsg SUBARU_REDNECK_TX_MSGS_CONFIG[] = {
|
||||||
|
SUBARU_BASE_TX_MSGS(SUBARU_MAIN_BUS, MSG_SUBARU_ES_LKAS)
|
||||||
|
SUBARU_COMMON_TX_MSGS(SUBARU_MAIN_BUS)
|
||||||
|
SUBARU_REDNECK_TX_MSGS()
|
||||||
|
};
|
||||||
|
|
||||||
|
static const CanMsg SUBARU_REDNECK_STOP_AND_GO_TX_MSGS_CONFIG[] = {
|
||||||
|
SUBARU_BASE_TX_MSGS(SUBARU_MAIN_BUS, MSG_SUBARU_ES_LKAS)
|
||||||
|
SUBARU_COMMON_TX_MSGS(SUBARU_MAIN_BUS)
|
||||||
|
SUBARU_REDNECK_TX_MSGS()
|
||||||
|
SUBARU_STOP_AND_GO_ADDITIONAL_TX_MSGS()
|
||||||
|
};
|
||||||
|
|
||||||
static const CanMsg SUBARU_LONG_TX_MSGS[] = {
|
static const CanMsg SUBARU_LONG_TX_MSGS[] = {
|
||||||
SUBARU_BASE_TX_MSGS(SUBARU_MAIN_BUS, MSG_SUBARU_ES_LKAS)
|
SUBARU_BASE_TX_MSGS(SUBARU_MAIN_BUS, MSG_SUBARU_ES_LKAS)
|
||||||
SUBARU_COMMON_LONG_TX_MSGS(SUBARU_MAIN_BUS)
|
SUBARU_COMMON_LONG_TX_MSGS(SUBARU_MAIN_BUS)
|
||||||
@@ -363,12 +371,6 @@ static safety_config subaru_init(uint16_t param) {
|
|||||||
SUBARU_STOP_START_TX_MSGS(SUBARU_ALT_BUS)
|
SUBARU_STOP_START_TX_MSGS(SUBARU_ALT_BUS)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const CanMsg SUBARU_GEN2_LKAS_ANGLE_STOP_START_AVH_TX_MSGS[] = {
|
|
||||||
SUBARU_BASE_TX_MSGS(SUBARU_ALT_BUS, MSG_SUBARU_ES_LKAS_ANGLE)
|
|
||||||
SUBARU_COMMON_TX_MSGS(SUBARU_ALT_BUS)
|
|
||||||
SUBARU_STOP_START_AVH_TX_MSGS(SUBARU_ALT_BUS)
|
|
||||||
};
|
|
||||||
|
|
||||||
static const CanMsg SUBARU_D_PLATFORM_ANGLE_MAIN_TX_MSGS[] = {
|
static const CanMsg SUBARU_D_PLATFORM_ANGLE_MAIN_TX_MSGS[] = {
|
||||||
SUBARU_D_PLATFORM_ANGLE_TX_MSGS(SUBARU_MAIN_BUS)
|
SUBARU_D_PLATFORM_ANGLE_TX_MSGS(SUBARU_MAIN_BUS)
|
||||||
SUBARU_COMMON_TX_MSGS(SUBARU_ALT_BUS)
|
SUBARU_COMMON_TX_MSGS(SUBARU_ALT_BUS)
|
||||||
@@ -380,12 +382,6 @@ static safety_config subaru_init(uint16_t param) {
|
|||||||
SUBARU_STOP_START_TX_MSGS(SUBARU_ALT_BUS)
|
SUBARU_STOP_START_TX_MSGS(SUBARU_ALT_BUS)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const CanMsg SUBARU_D_PLATFORM_ANGLE_STOP_START_AVH_MAIN_TX_MSGS[] = {
|
|
||||||
SUBARU_D_PLATFORM_ANGLE_TX_MSGS(SUBARU_MAIN_BUS)
|
|
||||||
SUBARU_COMMON_TX_MSGS(SUBARU_ALT_BUS)
|
|
||||||
SUBARU_STOP_START_AVH_TX_MSGS(SUBARU_ALT_BUS)
|
|
||||||
};
|
|
||||||
|
|
||||||
static const CanMsg SUBARU_D_PLATFORM_ANGLE_CAMERA_TX_MSGS[] = {
|
static const CanMsg SUBARU_D_PLATFORM_ANGLE_CAMERA_TX_MSGS[] = {
|
||||||
SUBARU_D_PLATFORM_ANGLE_TX_MSGS(SUBARU_CAM_BUS)
|
SUBARU_D_PLATFORM_ANGLE_TX_MSGS(SUBARU_CAM_BUS)
|
||||||
SUBARU_COMMON_TX_MSGS(SUBARU_ALT_BUS)
|
SUBARU_COMMON_TX_MSGS(SUBARU_ALT_BUS)
|
||||||
@@ -433,8 +429,8 @@ static safety_config subaru_init(uint16_t param) {
|
|||||||
const uint16_t SUBARU_PARAM_STOP_START_BUTTON = 256;
|
const uint16_t SUBARU_PARAM_STOP_START_BUTTON = 256;
|
||||||
subaru_stop_start_button = GET_FLAG(param, SUBARU_PARAM_STOP_START_BUTTON);
|
subaru_stop_start_button = GET_FLAG(param, SUBARU_PARAM_STOP_START_BUTTON);
|
||||||
|
|
||||||
const uint16_t SUBARU_PARAM_AVH_BUTTON = 512;
|
const uint16_t SUBARU_PARAM_REDNECK_CRUISE = 512;
|
||||||
subaru_avh_button = GET_FLAG(param, SUBARU_PARAM_AVH_BUTTON);
|
subaru_redneck_cruise = GET_FLAG(param, SUBARU_PARAM_REDNECK_CRUISE);
|
||||||
|
|
||||||
#ifdef ALLOW_DEBUG
|
#ifdef ALLOW_DEBUG
|
||||||
const uint16_t SUBARU_PARAM_LONGITUDINAL = 2;
|
const uint16_t SUBARU_PARAM_LONGITUDINAL = 2;
|
||||||
@@ -443,19 +439,19 @@ static safety_config subaru_init(uint16_t param) {
|
|||||||
|
|
||||||
safety_config ret;
|
safety_config ret;
|
||||||
if (subaru_lkas_angle) {
|
if (subaru_lkas_angle) {
|
||||||
ret = subaru_d_platform ? (subaru_stop_start_button ? (subaru_avh_button ? BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_STOP_START_AVH_MAIN_TX_MSGS) : \
|
ret = subaru_d_platform ? (subaru_stop_start_button ? BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_STOP_START_MAIN_TX_MSGS) : \
|
||||||
BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_STOP_START_MAIN_TX_MSGS)) : \
|
|
||||||
(subaru_d_platform_camera ? BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_CAMERA_TX_MSGS) : \
|
(subaru_d_platform_camera ? BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_CAMERA_TX_MSGS) : \
|
||||||
BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_MAIN_TX_MSGS))) : \
|
BUILD_SAFETY_CFG(subaru_d_platform_angle_rx_checks, SUBARU_D_PLATFORM_ANGLE_MAIN_TX_MSGS))) : \
|
||||||
subaru_gen2 ? (subaru_stop_start_button ? (subaru_avh_button ? BUILD_SAFETY_CFG(subaru_gen2_lkas_angle_rx_checks, SUBARU_GEN2_LKAS_ANGLE_STOP_START_AVH_TX_MSGS) : \
|
subaru_gen2 ? (subaru_stop_start_button ? BUILD_SAFETY_CFG(subaru_gen2_lkas_angle_rx_checks, SUBARU_GEN2_LKAS_ANGLE_STOP_START_TX_MSGS) : \
|
||||||
BUILD_SAFETY_CFG(subaru_gen2_lkas_angle_rx_checks, SUBARU_GEN2_LKAS_ANGLE_STOP_START_TX_MSGS)) : \
|
|
||||||
BUILD_SAFETY_CFG(subaru_gen2_lkas_angle_rx_checks, SUBARU_GEN2_LKAS_ANGLE_TX_MSGS)) : \
|
BUILD_SAFETY_CFG(subaru_gen2_lkas_angle_rx_checks, SUBARU_GEN2_LKAS_ANGLE_TX_MSGS)) : \
|
||||||
BUILD_SAFETY_CFG(subaru_lkas_angle_rx_checks, SUBARU_LKAS_ANGLE_TX_MSGS);
|
BUILD_SAFETY_CFG(subaru_lkas_angle_rx_checks, SUBARU_LKAS_ANGLE_TX_MSGS);
|
||||||
} else if (subaru_gen2) {
|
} else if (subaru_gen2) {
|
||||||
ret = subaru_longitudinal ? BUILD_SAFETY_CFG(subaru_gen2_rx_checks, SUBARU_GEN2_LONG_TX_MSGS) : \
|
ret = subaru_longitudinal ? BUILD_SAFETY_CFG(subaru_gen2_rx_checks, SUBARU_GEN2_LONG_TX_MSGS) : \
|
||||||
BUILD_SAFETY_CFG(subaru_gen2_rx_checks, SUBARU_GEN2_TX_MSGS);
|
BUILD_SAFETY_CFG(subaru_gen2_rx_checks, SUBARU_GEN2_TX_MSGS);
|
||||||
} else {
|
} else {
|
||||||
ret = subaru_longitudinal ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_LONG_TX_MSGS) : \
|
ret = subaru_redneck_cruise ? (subaru_stop_and_go ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_REDNECK_STOP_AND_GO_TX_MSGS_CONFIG) : \
|
||||||
|
BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_REDNECK_TX_MSGS_CONFIG)) : \
|
||||||
|
subaru_longitudinal ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_LONG_TX_MSGS) : \
|
||||||
subaru_stop_and_go ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_STOP_AND_GO_TX_MSGS) : \
|
subaru_stop_and_go ? BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_STOP_AND_GO_TX_MSGS) : \
|
||||||
BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_TX_MSGS);
|
BUILD_SAFETY_CFG(subaru_rx_checks, SUBARU_TX_MSGS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
#define VOLVO_ANGLE_DEG_TO_CAN 17.869907f
|
#define VOLVO_ANGLE_DEG_TO_CAN 17.869907f
|
||||||
#define VOLVO_MAX_ANGLE_CAN 9650
|
#define VOLVO_MAX_ANGLE_CAN 9650
|
||||||
#define VOLVO_RELAY_ANGLE_TOLERANCE 54 // approximately 3 degrees
|
#define VOLVO_RELAY_ANGLE_TOLERANCE 54 // approximately 3 degrees
|
||||||
#define VOLVO_DRIVER_OVERRIDE 5
|
|
||||||
|
|
||||||
|
|
||||||
// CAN bus definitions for Volvo
|
// CAN bus definitions for Volvo
|
||||||
@@ -83,8 +82,6 @@ static const AngleSteeringLimits VOLVO_ANGLE_STEERING_LIMITS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void volvo_rx_hook(const CANPacket_t *msg) {
|
static void volvo_rx_hook(const CANPacket_t *msg) {
|
||||||
// Monitor the vehicle state required for cruise, disengagement, and angle
|
|
||||||
// safety. All steering TX frames are separately constrained in volvo_tx_hook.
|
|
||||||
|
|
||||||
// Main bus (bus 0) messages
|
// Main bus (bus 0) messages
|
||||||
if (msg->bus == VOLVO_MAIN_BUS) {
|
if (msg->bus == VOLVO_MAIN_BUS) {
|
||||||
@@ -148,13 +145,11 @@ static void volvo_rx_hook(const CANPacket_t *msg) {
|
|||||||
|
|
||||||
// DRIVER_INPUT is the signal consumed by carstate.py for driver torque.
|
// DRIVER_INPUT is the signal consumed by carstate.py for driver torque.
|
||||||
// The PSCM frame's DRIVER_INPUT_DEVIATION is a different signal and must
|
// The PSCM frame's DRIVER_INPUT_DEVIATION is a different signal and must
|
||||||
// not be substituted here: doing so leaves the hardware disengage path blind.
|
|
||||||
if (msg->addr == VOLVO_DRIVER_INPUT) {
|
if (msg->addr == VOLVO_DRIVER_INPUT) {
|
||||||
// STEERING_DRIVER_INPUT is a Motorola signal starting at bit 55. The
|
// STEERING_DRIVER_INPUT is a Motorola signal starting at bit 55. The
|
||||||
// DBC also carries a +1 offset, so its raw byte is data[6].
|
// DBC also carries a +1 offset, so its raw byte is data[6].
|
||||||
const int driver_input = to_signed(msg->data[6], 8) + 1;
|
const int driver_input = to_signed(msg->data[6], 8) + 1;
|
||||||
update_sample(&torque_driver, driver_input);
|
update_sample(&torque_driver, driver_input);
|
||||||
steering_disengage = SAFETY_ABS(driver_input) > VOLVO_DRIVER_OVERRIDE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class SubaruMsg(enum.IntEnum):
|
|||||||
ES_STATIC_1 = 0x22a
|
ES_STATIC_1 = 0x22a
|
||||||
ES_STATIC_2 = 0x325
|
ES_STATIC_2 = 0x325
|
||||||
Dashlights = 0x390
|
Dashlights = 0x390
|
||||||
AVH = 0x32b
|
|
||||||
|
|
||||||
|
|
||||||
SUBARU_MAIN_BUS = 0
|
SUBARU_MAIN_BUS = 0
|
||||||
@@ -386,20 +385,6 @@ class TestSubaruGen2FixedAngleStopStartSafety(TestSubaruGen2FixedAngleSafety):
|
|||||||
self.assertFalse(self._tx(self._stop_start_msg(False)))
|
self.assertFalse(self._tx(self._stop_start_msg(False)))
|
||||||
|
|
||||||
|
|
||||||
class TestSubaruGen2FixedAngleStopStartAvhSafety(TestSubaruGen2FixedAngleStopStartSafety):
|
|
||||||
FLAGS = TestSubaruGen2FixedAngleStopStartSafety.FLAGS | SubaruSafetyFlags.AVH_BUTTON
|
|
||||||
TX_MSGS = TestSubaruGen2FixedAngleStopStartSafety.TX_MSGS + [[SubaruMsg.AVH, SUBARU_ALT_BUS]]
|
|
||||||
|
|
||||||
def _avh_msg(self, pressed):
|
|
||||||
return self.packer.make_can_msg_safety(
|
|
||||||
"AVH", SUBARU_ALT_BUS, {"COUNTER": 0, "AVH": pressed},
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_avh_tx_requires_pressed_bit(self):
|
|
||||||
self.assertTrue(self._tx(self._avh_msg(True)))
|
|
||||||
self.assertFalse(self._tx(self._avh_msg(False)))
|
|
||||||
|
|
||||||
|
|
||||||
class TestSubaruDPlatformAngleSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruAngleSafetyBase):
|
class TestSubaruDPlatformAngleSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruAngleSafetyBase):
|
||||||
FLAGS = SubaruSafetyFlags.GEN2 | SubaruSafetyFlags.LKAS_ANGLE | SubaruSafetyFlags.D_PLATFORM
|
FLAGS = SubaruSafetyFlags.GEN2 | SubaruSafetyFlags.LKAS_ANGLE | SubaruSafetyFlags.D_PLATFORM
|
||||||
ALT_MAIN_BUS = SUBARU_ALT_BUS
|
ALT_MAIN_BUS = SUBARU_ALT_BUS
|
||||||
|
|||||||
@@ -211,21 +211,17 @@ class TestVolvoSafetyBase(common.CarSafetyTest):
|
|||||||
self.assertTrue(self._tx(valid))
|
self.assertTrue(self._tx(valid))
|
||||||
self.assertFalse(self._tx(invalid))
|
self.assertFalse(self._tx(invalid))
|
||||||
|
|
||||||
def test_driver_override_disengages_controls(self):
|
def test_driver_input_is_a_normal_override(self):
|
||||||
def driver_input_msg(value):
|
def driver_input_msg(value):
|
||||||
return self.mid_packer.make_can_msg_safety(
|
return self.mid_packer.make_can_msg_safety(
|
||||||
"DRIVER_INPUT", VOLVO_PARTY_BUS, {"STEERING_DRIVER_INPUT": value})
|
"DRIVER_INPUT", VOLVO_PARTY_BUS, {"STEERING_DRIVER_INPUT": value})
|
||||||
|
|
||||||
for value in (2, 3, 5):
|
for value in (2, 3, 5, 6, 20, -20):
|
||||||
self._rx(driver_input_msg(0))
|
self._rx(driver_input_msg(0))
|
||||||
self.safety.set_controls_allowed(True)
|
self.safety.set_controls_allowed(True)
|
||||||
self._rx(driver_input_msg(value))
|
self._rx(driver_input_msg(value))
|
||||||
self.assertTrue(self.safety.get_controls_allowed(), f"unexpected disengage at {value=}")
|
self.assertTrue(self.safety.get_controls_allowed(), f"unexpected safety disengage at {value=}")
|
||||||
|
self.assertFalse(self.safety.get_steering_disengage_prev())
|
||||||
self._rx(driver_input_msg(0))
|
|
||||||
self.safety.set_controls_allowed(True)
|
|
||||||
self._rx(driver_input_msg(6))
|
|
||||||
self.assertFalse(self.safety.get_controls_allowed())
|
|
||||||
|
|
||||||
# ---- Volvo-specific consistency tests ----
|
# ---- Volvo-specific consistency tests ----
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +1,2 @@
|
|||||||
extern const uint8_t gitversion[19];
|
extern const uint8_t gitversion[19];
|
||||||
const uint8_t gitversion[19] = "DEV-26ce46ba-DEBUG";
|
const uint8_t gitversion[19] = "DEV-9cb1b6b1-DEBUG";
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
DEV-26ce46ba-DEBUG
|
DEV-9cb1b6b1-DEBUG
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user