Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions opendbc/car/mazda/carstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from opendbc.car import Bus, DT_CTRL, create_button_events, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.interfaces import CarStateBase
from opendbc.car.mazda.values import DBC, LKAS_LIMITS, CarControllerParams
from opendbc.car.mazda.values import DBC, LKAS_LIMITS, CarControllerParams, MazdaFlags
from opendbc.sunnypilot.car.mazda.carstate_ext import CarStateExt

ButtonType = structs.CarState.ButtonEvent.Type
Expand Down Expand Up @@ -181,7 +181,12 @@ def update(self, can_parsers) -> tuple[structs.CarState, structs.CarStateSP]:
ret.cruiseState.enabled = cp.vl["CRZ_CTRL"]["CRZ_ACTIVE"] == 1
self.brake_pressed_prev = ret.brakePressed
ret.cruiseState.standstill = cp.vl["PEDALS"]["STANDSTILL"] == 1
ret.cruiseState.speed = cp.vl["CRZ_EVENTS"]["CRZ_SPEED"] * CV.KPH_TO_MS
cruise_speed_kph = cp.vl["CRZ_EVENTS"]["CRZ_SPEED"]
if self.CP.flags & MazdaFlags.PXM7_CRUISE_SPEED and cruise_speed_kph > 0:
# The shared DBC decodes CRZ_SPEED as raw / 200 - 0.5, which matches other
# Mazdas. Export CX-9s with PXM7 PCMs use (raw + 96) / 196 instead.
cruise_speed_kph = cruise_speed_kph * 50 / 49 + 1
ret.cruiseState.speed = cruise_speed_kph * CV.KPH_TO_MS

# stock lkas should be on
# TODO: is this needed?
Expand Down
7 changes: 6 additions & 1 deletion opendbc/car/mazda/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from opendbc.car.mazda.carcontroller import CarController
from opendbc.car.mazda.carstate import CarState
from opendbc.car.mazda.radar_interface import RadarInterface
from opendbc.car.mazda.values import CAR, DBC, LKAS_LIMITS, STEER_TO_ZERO_EPS_FW, MazdaSafetyFlags
from opendbc.car.mazda.values import CAR, DBC, LKAS_LIMITS, STEER_TO_ZERO_EPS_FW, MazdaFlags, MazdaSafetyFlags


class CarInterface(CarInterfaceBase):
Expand All @@ -20,6 +20,11 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_lo

ret.radarUnavailable = Bus.radar not in DBC[candidate]

if candidate == CAR.MAZDA_CX9_2021 and any(
fw.ecu == 'engine' and fw.fwVersion.startswith(b'PXM7-188K2-') for fw in car_fw
):
ret.flags |= MazdaFlags.PXM7_CRUISE_SPEED.value

# 2022+ CX-5 EPS can steer to zero and has no hands-off lockout. Detected by EPS firmware
# rather than by model, so an EPS swapped into an older Mazda is recognized as what it is.
steer_to_zero = candidate == CAR.MAZDA_CX5_2022 or \
Expand Down
57 changes: 53 additions & 4 deletions opendbc/car/mazda/tests/test_mazda_carstate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from opendbc.car import DT_CTRL, gen_empty_fingerprint
from opendbc.car import DT_CTRL, gen_empty_fingerprint, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.mazda.interface import CarInterface
from opendbc.car.mazda.values import CAR, CarControllerParams
Expand All @@ -15,11 +15,24 @@
FAULTED = bytes([0x42, 0b00000001, 0, 0, 0, 0x01, 0, 0]) # ERR_BIT (bit 40) set


def _interface(alpha_long=True):
Ecu = structs.CarParams.Ecu


def _engine_fw(version):
fw = structs.CarParams.CarFw()
fw.ecu = Ecu.engine
fw.address = 0x7e0
fw.subAddress = 0
fw.fwVersion = version
return [fw]


def _interface(alpha_long=True, candidate=CAR.MAZDA_CX5_2022, car_fw=None):
fingerprint = gen_empty_fingerprint()
CP = CarInterface.get_params(CAR.MAZDA_CX5_2022, fingerprint, [], alpha_long=alpha_long,
car_fw = car_fw or []
CP = CarInterface.get_params(candidate, fingerprint, car_fw, alpha_long=alpha_long,
is_release=False, docs=False)
CP_SP = CarInterface.get_params_sp(CP, CAR.MAZDA_CX5_2022, fingerprint, [],
CP_SP = CarInterface.get_params_sp(CP, candidate, fingerprint, car_fw,
alpha_long=alpha_long, is_release_sp=False, docs=False)
return CarInterface(CP, CP_SP)

Expand Down Expand Up @@ -193,6 +206,42 @@ def test_implausible_frames_read_as_no_limit(self, sign_on, speed_sign):
assert ret_sp.speedLimit == 0.0


class TestCruiseSetSpeed:
@staticmethod
def _decode(candidate, raw, engine_fw=None):
car_fw = _engine_fw(engine_fw) if engine_fw is not None else []
CI = _interface(alpha_long=False, candidate=candidate, car_fw=car_fw)
payload = raw.to_bytes(2, "big") + bytes(6)
ret = None
for i in range(2):
ret, _ = CI.update([(int(i * DT_CTRL * 1e9), [(0x21F, payload, 0)])])
return ret.cruiseState.speed / CV.KPH_TO_MS

@pytest.mark.parametrize(("raw", "cluster_kph"), [
(6176, 32),
(7352, 38),
(10098, 52),
(19504, 100),
])
@pytest.mark.parametrize("engine_fw", [b'PXM7-188K2-D', b'PXM7-188K2-E', b'PXM7-188K2-F'])
def test_pxm7_cx9_uses_cluster_scale(self, raw, cluster_kph, engine_fw):
# Real CRZ_EVENTS samples from the reporter's CX-9 route.
decoded_kph = self._decode(CAR.MAZDA_CX9_2021, raw, engine_fw=engine_fw)
assert decoded_kph == pytest.approx((raw + 96) / 196)
assert round(decoded_kph) == cluster_kph

def test_us_pxm4_cx9_uses_shared_dbc_scale(self):
raw = 19504
dbc_kph = raw * 0.005 - 0.5
assert self._decode(CAR.MAZDA_CX9_2021, raw, engine_fw=b'PXM4-188K2-D') == pytest.approx(dbc_kph)

@pytest.mark.parametrize("candidate", [CAR.MAZDA_CX5_2022, CAR.MAZDA_CX9])
def test_shared_dbc_decode_is_unchanged_for_other_platforms(self, candidate):
raw = 19504
dbc_kph = raw * 0.005 - 0.5
assert self._decode(candidate, raw) == pytest.approx(dbc_kph)


class TestCancelUnderBraking:
"""The availability brake-hold exists for brake-only PEDALS samples that arrive with both
bits low mid-press. A wheel CANCEL turns the MRCC main state off for real and must land
Expand Down
2 changes: 2 additions & 0 deletions opendbc/car/mazda/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class MazdaFlags(IntFlag):
# Static flags
# Gen 1 hardware: same CAN messages and same camera
GEN1 = 1
# Export CX-9 PCM family whose CRZ_SPEED scale differs from the shared Mazda DBC.
PXM7_CRUISE_SPEED = 2


class MazdaSafetyFlags(IntFlag):
Expand Down
Loading