Merge branch 'upstream/opendbc/master' into sync-20250529-new

# Conflicts:
#	.github/workflows/tests.yml
#	opendbc/car/car_helpers.py
#	opendbc/car/docs.py
#	opendbc/car/tests/test_car_interfaces.py
#	opendbc/safety/modes/chrysler.h
#	opendbc/safety/modes/ford.h
#	opendbc/safety/modes/hyundai.h
#	opendbc/safety/modes/nissan.h
#	opendbc/safety/modes/subaru.h
#	opendbc/safety/modes/tesla.h
#	opendbc/safety/modes/toyota.h
This commit is contained in:
Jason Wen
2025-05-31 10:21:31 -04:00
56 changed files with 408 additions and 447 deletions

9
.github/workflows/cache/action.yaml vendored Normal file
View File

@@ -0,0 +1,9 @@
name: 'Restore cache'
runs:
using: "composite"
steps:
- name: Restore cached cppcheck
uses: actions/cache@v4
with:
path: opendbc/safety/tests/misra/cppcheck/
key: cppcheck-cache-${{ runner.os }}-${{ hashFiles('opendbc/safety/tests/misra/install.sh') }}

View File

@@ -16,63 +16,18 @@ jobs:
matrix:
include:
- os: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
flags: ''
- os: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-24.04' }}
flags: '--ubsan'
- os: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-macos-8x14' || 'macos-latest' }}
flags: ''
steps:
- uses: commaai/timeout@v1
with:
timeout: '240'
- uses: actions/checkout@v4
- name: Restore cached cppcheck
uses: actions/cache@v4
with:
path: opendbc/safety/tests/misra/cppcheck/
key: cppcheck-cache-${{ runner.os }}-${{ hashFiles('opendbc/safety/tests/misra/install.sh') }}
- run: ./test.sh
- name: Save cppcheck cache
uses: actions/cache@v4
with:
path: opendbc/safety/tests/misra/cppcheck/
key: cppcheck-cache-${{ runner.os }}-${{ hashFiles('opendbc/safety/tests/misra/install.sh') }}
safety_tests:
name: safety
runs-on: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
strategy:
fail-fast: false
matrix:
flags: ['--ubsan']
steps:
- uses: commaai/timeout@v1
with:
timeout: '240'
timeout: ${{ github.repository == 'commaai/opendbc' && '60' || '999' }}
- uses: actions/checkout@v4
- name: Run safety tests
run: ./opendbc/safety/tests/test.sh ${{ matrix.flags }}
misra_mutation:
name: MISRA C:2012 Mutation
runs-on: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Restore cached cppcheck
uses: actions/cache@v4
with:
path: opendbc/safety/tests/misra/cppcheck/
key: cppcheck-cache-${{ runner.os }}-${{ hashFiles('opendbc/safety/tests/misra/install.sh') }}
- name: MISRA mutation tests
timeout-minutes: 5
run: |
source setup.sh
scons -j8
cd opendbc/safety/tests/misra
./install.sh # cppcheck
pytest -s -n8 --randomly-seed $RANDOM test_mutation.py
- name: Save cppcheck cache
uses: actions/cache@v4
with:
path: opendbc/safety/tests/misra/cppcheck/
key: cppcheck-cache-${{ runner.os }}-${{ hashFiles('opendbc/safety/tests/misra/install.sh') }}
- uses: ./.github/workflows/cache
- run: ./test.sh ${{ matrix.flags }}
mutation:
name: Safety mutation tests
@@ -84,6 +39,7 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # need master to get diff
- uses: ./.github/workflows/cache
- name: Run mutation tests
timeout-minutes: 60
run: |

View File

@@ -1,4 +1,5 @@
# pytest attempts to execute shell scripts while collecting
collect_ignore_glob = [
"opendbc/safety/tests/misra/*",
"opendbc/safety/tests/misra/*.sh",
"opendbc/safety/tests/misra/cppcheck/",
]

View File

@@ -4,7 +4,7 @@ output:
- empty_summary # Print summary heading when there are no steps to run
- success # Print successful steps
- failure # Print failed steps printing
#- execution # Print any execution logs
- execution # Print any execution logs
#- execution_out # Print execution output
#- execution_info # Print `EXECUTE > ...` logging
- skips # Print "skip" (i.e. no files matched)

View File

@@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.notCar = True
ret.brand = "body"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.body)]

View File

@@ -152,7 +152,7 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool,
num_pandas: int = 1, cached_params: CarParamsT | None = None, fixed_fingerprint: str | None = None):
is_release: bool, num_pandas: int = 1, cached_params: CarParamsT | None = None, fixed_fingerprint: str | None = None):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params,
fixed_fingerprint)
@@ -161,7 +161,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
candidate = "MOCK"
CarInterface = interfaces[candidate]
CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, alpha_long_allowed, docs=False)
CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, alpha_long_allowed, is_release, docs=False)
CP.carVin = vin
CP.carFw = car_fw
CP.fingerprintSource = source

View File

@@ -13,7 +13,7 @@ class CarInterface(CarInterfaceBase):
RadarInterface = RadarInterface
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "chrysler"
ret.dashcamOnly = candidate in RAM_HD

View File

@@ -32,7 +32,7 @@ def get_params_for_docs(platform) -> tuple[CarParams, CarParamsSP]:
cp_platform = platform if platform in interfaces else MOCK.MOCK
CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
alpha_long=True, docs=True)
alpha_long=True, is_release=False, docs=True)
CP_SP: CarParamsSP = interfaces[cp_platform].get_params_sp(CP, cp_platform, fingerprint=gen_empty_fingerprint(),
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],

View File

@@ -26,7 +26,7 @@ class CarInterface(CarInterfaceBase):
return CarControllerParams.ACCEL_MIN, np.interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS)
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "ford"
ret.radarUnavailable = Bus.radar not in DBC[candidate]

View File

@@ -85,7 +85,7 @@ class CarInterface(CarInterfaceBase):
return self.torque_from_lateral_accel_linear
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "gm"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False

View File

@@ -31,7 +31,7 @@ class CarInterface(CarInterfaceBase):
return CarControllerParams.NIDEC_ACCEL_MIN, np.interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS)
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "honda"
CAN = CanBus(ret, fingerprint)

View File

@@ -27,7 +27,7 @@ class CarInterface(CarInterfaceBase):
RadarInterface = RadarInterface
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "hyundai"
cam_can = CanBus(None, fingerprint).CAM

View File

@@ -51,7 +51,7 @@ class TestHyundaiFingerprint:
if lka_steering:
cam_can = CanBus(None, fingerprint).CAM
fingerprint[cam_can] = [0x50, 0x110] # LKA steering messages
CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False)
CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False)
assert bool(CP.flags & HyundaiFlags.CANFD_LKA_STEERING) == lka_steering
# radar available
@@ -59,14 +59,14 @@ class TestHyundaiFingerprint:
fingerprint = gen_empty_fingerprint()
if radar:
fingerprint[1][RADAR_START_ADDR] = 8
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False)
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
assert CP.radarUnavailable != radar
def test_alternate_limits(self):
# Alternate lateral control limits, for high torque cars, verify Panda safety mode flag is set
fingerprint = gen_empty_fingerprint()
for car_model in CAR:
CP = CarInterface.get_params(car_model, fingerprint, [], False, False)
CP = CarInterface.get_params(car_model, fingerprint, [], False, False, False)
assert bool(CP.flags & HyundaiFlags.ALT_LIMITS) == bool(CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.ALT_LIMITS)
def test_can_features(self):

View File

@@ -138,7 +138,7 @@ class CarInterfaceBase(ABC):
"""
Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints.
"""
return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False)
return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False, False)
@classmethod
def get_non_essential_params_sp(cls, car_params, candidate: str) -> structs.CarParamsSP:
@@ -146,7 +146,7 @@ class CarInterfaceBase(ABC):
@classmethod
def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[structs.CarParams.CarFw],
alpha_long: bool, docs: bool) -> structs.CarParams:
alpha_long: bool, is_release: bool, docs: bool) -> structs.CarParams:
ret = CarInterfaceBase.get_std_params(candidate)
platform = PLATFORMS[candidate]
@@ -159,7 +159,7 @@ class CarInterfaceBase(ABC):
ret.tireStiffnessFactor = platform.config.specs.tireStiffnessFactor
ret.flags |= int(platform.config.flags)
ret = cls._get_params(ret, candidate, fingerprint, car_fw, alpha_long, docs)
ret = cls._get_params(ret, candidate, fingerprint, car_fw, alpha_long, is_release, docs)
# Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload
if not ret.notCar:
@@ -181,7 +181,7 @@ class CarInterfaceBase(ABC):
@staticmethod
@abstractmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint: dict[int, dict[int, int]],
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, docs: bool) -> structs.CarParams:
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release: bool, docs: bool) -> structs.CarParams:
raise NotImplementedError
@staticmethod

View File

@@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "mazda"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.mazda)]
ret.radarUnavailable = True

View File

@@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "mock"
ret.mass = 1700.
ret.wheelbase = 2.70

View File

@@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "nissan"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)]
ret.autoResumeSng = False

View File

@@ -13,7 +13,7 @@ class PandaRunner(AbstractContextManager):
# setup + fingerprinting
self.p.set_safety_mode(CarParams.SafetyModel.elm327, 1)
self.CI = get_car(self._can_recv, self.p.can_send_many, self.p.set_obd, True)
self.CI = get_car(self._can_recv, self.p.can_send_many, self.p.set_obd, True, False)
assert self.CI.CP.carFingerprint.lower() != "mock", "Unable to identify car. Check connections and ensure car is supported."
safety_model = self.CI.CP.safetyConfigs[0].safetyModel

View File

@@ -54,7 +54,7 @@ class CarState(CarStateBase):
if not self.CP.openpilotLongitudinalControl:
ret.cruiseState.speed = -1
ret.cruiseState.available = True # cp.vl["VDM_AdasSts"]["VDM_AdasInterfaceStatus"] == 1
ret.cruiseState.standstill = cp.vl["VDM_AdasSts"]["VDM_AdasAccelRequestAcknowledged"] == 1
ret.cruiseState.standstill = cp.vl["VDM_AdasSts"]["VDM_AdasVehicleHoldStatus"] == 1
# TODO: log ACM_Unkown2=3 as a fault. need to filter it at the start and end of routes though
# ACM_FaultStatus hasn't been seen yet

View File

@@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase):
RadarInterface = RadarInterface
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "rivian"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.rivian)]

View File

@@ -85,10 +85,10 @@ def create_adas_status(packer, vdm_adas_status, interface_status):
"VDM_AdasFaultStatus",
"VDM_AdasAccelLimit",
"VDM_AdasDriverModeStatus",
"VDM_AdasAccelRequest",
"VDM_AdasUnkown1",
"VDM_AdasInterfaceStatus",
"VDM_AdasAccelRequestAcknowledged",
"VDM_AdasVehicleHoldStatus",
"VDM_UserAdasRequest",
)}
if interface_status is not None:

View File

@@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "subaru"
ret.radarUnavailable = True
# for HYBRID CARS to be upstreamed, we need:

View File

@@ -31,6 +31,7 @@ FW_VERSIONS = {
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4003.02.0',
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4003.03.2',
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4P003.02.0',
b'TeMYG4_SingleECU_0.0.0 (28),Y4S002.23.0',
b'TeMYG4_SingleECU_0.0.0 (33),Y4S002.26',
],
},

View File

@@ -10,7 +10,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "tesla"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.tesla)]

View File

@@ -59,7 +59,7 @@ class TestCarInterfaces:
args = get_fuzzy_car_interface_args(data.draw)
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
alpha_long=args['alpha_long'], docs=False)
alpha_long=args['alpha_long'], is_release=False, docs=False)
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
alpha_long=args['alpha_long'], docs=False)
car_interface = CarInterface(car_params, car_params_sp)

View File

@@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase):
return CarControllerParams(CP).ACCEL_MIN, CarControllerParams(CP).ACCEL_MAX
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "toyota"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.toyota)]
ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate]
@@ -34,6 +34,7 @@ class CarInterface(CarInterfaceBase):
if ret.flags & ToyotaFlags.SECOC.value:
ret.secOcRequired = True
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.SECOC.value
ret.dashcamOnly = is_release
if candidate in ANGLE_CONTROL_CAR:
ret.steerControlType = SteerControlType.angle

View File

@@ -10,7 +10,7 @@ class CarInterface(CarInterfaceBase):
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, docs) -> structs.CarParams:
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "volkswagen"
ret.radarUnavailable = True

View File

@@ -182,15 +182,15 @@ BO_ 352 ACM_longitudinalRequest: 5 ACM
BO_ 354 VDM_AdasSts: 8 VDM
SG_ VDM_AdasStatus_Checksum : 7|8@0+ (1,0) [0|0] "" ACM
SG_ VDM_AdasStatus_Counter : 11|4@0+ (1,0) [0|0] "" ACM
SG_ VDM_AdasDecelLimit : 17|10@0+ (0.01,0) [0|10.23] "m/s^2" ACM
SG_ VDM_AdasDecelLimit : 17|10@0+ (0.01,0) [0|-10.23] "m/s^2" ACM
SG_ VDM_AdasDriverAccelPriorityStatus : 19|2@0+ (1,0) [0|3] "" ACM
SG_ VDM_AdasFaultStatus : 23|4@0+ (1,0) [0|15] "" ACM
SG_ VDM_AdasAccelLimit : 33|10@0+ (0.01,0) [0|10.23] "m/s^2" ACM
SG_ VDM_AdasDriverModeStatus : 36|3@0+ (1,0) [0|7] "" ACM
SG_ VDM_AdasAccelRequest : 50|11@0+ (0.01,-10.24) [-10.24|10.23] "m/s^2" ACM
SG_ VDM_AdasUnkown1 : 50|8@0+ (1,0) [0|255] "" XXX
SG_ VDM_AdasInterfaceStatus : 52|2@0+ (1,0) [0|3] "" ACM
SG_ VDM_AdasAccelRequestAcknowledged : 54|2@0+ (1,0) [0|3] "" ACM
SG_ VDM_AdasVehicleHoldStatus : 55|1@0+ (1,0) [0|1] "" ACM
SG_ VDM_AdasVehicleHoldStatus : 55|3@0+ (1,0) [0|7] "" ACM
SG_ VDM_UserAdasRequest : 58|3@0+ (1,0) [0|7] "" ACM
BO_ 357 VDM_AdasStalk: 4 VDM
SG_ VDM_AdasStalk_Checksum : 7|8@0+ (1,0) [0|255] "Unitless" ACM
@@ -615,7 +615,6 @@ CM_ SG_ 354 VDM_AdasStatus_Checksum "VDM_AdasSts message j1850 checksum.";
CM_ SG_ 354 VDM_AdasStatus_Counter "VDM_AdasSts message counter.";
CM_ SG_ 354 VDM_AdasFaultStatus "Fault status of ADAS requests from VDM.";
CM_ SG_ 354 VDM_AdasDriverModeStatus "Signal which describes who is commanding the torque - Human or ADAS";
CM_ SG_ 354 VDM_AdasAccelRequestAcknowledged "An acknowleddge signal to the ADAS system to show that TQM is honoring their request";
CM_ SG_ 432 ESP_Torque_Front_MinQ "Indication of whether signal with corresponding name is valid";
CM_ SG_ 432 ESP_Torque_Front_MaxQ "Indication of whether signal with corresponding name is valid";
CM_ SG_ 432 ESP_Torque_Front_Max "ESP intervention, ESP tractive torque limit per axle.";
@@ -878,7 +877,6 @@ VAL_ 354 VDM_AdasDriverAccelPriorityStatus 0 "VDM_AdasDriverAccelPriorityStatus_
VAL_ 354 VDM_AdasFaultStatus 0 "VDM_AdasFlaultStatus_No_Fault" 1 "VDM_AdasFaultStatus_Brk_Intv" 2 "VDM_AdasFlaultStatus_Cntr_Fault" 3 "VDM_AdasFlaultStatus_Imps_Cmd" 15 "VDM_AdasFlaultStatus_Sna";
VAL_ 354 VDM_AdasDriverModeStatus 0 "VDM_AdasDriverModeStatus_Human" 1 "VDM_AdasDriverModeStatus_Adas" 2 "VDM_AdasDriverModeStatus_Reserved" 3 "VDM_AdasDriverModeStatus_Sna";
VAL_ 354 VDM_AdasInterfaceStatus 0 "VDM_AdasInterfaceStatus_Unavailable" 1 "VDM_AdasInterfaceStatus_Available" 2 "VDM_AdasInterfaceStatus_Enabled" 3 "VDM_AdasInterfaceStatus_Faulted";
VAL_ 354 VDM_AdasAccelRequestAcknowledged 0 "VDM_AdasAccelRequestAcknowledged_Not_Acknowledged" 1 "VDM_AdasAccelRequestAcknowledged_Acknowledged" 2 "VDM_AdasAccelRequestAcknowledged_Fault_Ignored" 3 "VDM_AdasAccelRequestAcknowledged_Sna";
VAL_ 354 VDM_AdasVehicleHoldStatus 0 "VDM_AdasVehicleHoldStatus_NotHold" 1 "VDM_AdasVehicleHoldStatus_Hold";
VAL_ 357 VDM_AdasStalkGapAdjust 0 "VDM_AdasStalkGapAdjust_No_Required" 1 "VDM_AdasStalkGapAdjust_GapDecrement" 2 "VDM_AdasStalkGapAdjust_GapIncrement";
VAL_ 357 VDM_AdasStalkAccCancelRes 0 "VDM_AdasStalkAccCancelRes_NoRequired" 1 "VDM_AdasStalkAccCancelRes_Cancel" 2 "VDM_AdasStalkAccCancelRes_Resume";

View File

@@ -31,7 +31,7 @@ static bool body_tx_hook(const CANPacket_t *to_send) {
static safety_config body_init(uint16_t param) {
static RxCheck body_rx_checks[] = {
{.msg = {{0x201, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{0x201, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
};
static const CanMsg BODY_TX_MSGS[] = {{0x250, 0, 8, .check_relay = false}, {0x250, 0, 6, .check_relay = false}, {0x251, 0, 5, .check_relay = false}, // body

View File

@@ -207,22 +207,22 @@ static safety_config chrysler_init(uint16_t param) {
};
static RxCheck chrysler_ram_dt_rx_checks[] = {
{.msg = {{CHRYSLER_RAM_DT_ADDRS.EPS_2, 0, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.ESP_1, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.ESP_8, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.ECM_5, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.DAS_3, 2, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.Center_Stack_2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 1U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.EPS_2, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.ESP_1, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.ESP_8, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.ECM_5, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.DAS_3, 2, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_DT_ADDRS.Center_Stack_2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}},
};
static RxCheck chrysler_rx_checks[] = {
{.msg = {{CHRYSLER_ADDRS.EPS_2, 0, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.ESP_1, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
//{.msg = {{ESP_8, 0, 8, .max_counter = 15U, .frequency = 50U}}},
{.msg = {{514, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.ECM_5, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.DAS_3, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.TRACTION_BUTTON, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 1U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.EPS_2, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.ESP_1, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
//{.msg = {{ESP_8, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}}},
{.msg = {{514, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.ECM_5, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.DAS_3, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_ADDRS.TRACTION_BUTTON, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}},
};
static const CanMsg CHRYSLER_TX_MSGS[] = {
@@ -253,12 +253,12 @@ static safety_config chrysler_init(uint16_t param) {
};
static RxCheck chrysler_ram_hd_rx_checks[] = {
{.msg = {{CHRYSLER_RAM_HD_ADDRS.EPS_2, 0, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.ESP_1, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.ESP_8, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.ECM_5, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.DAS_3, 2, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.Center_Stack_2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 1U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.EPS_2, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.ESP_1, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.ESP_8, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.ECM_5, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.DAS_3, 2, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{CHRYSLER_RAM_HD_ADDRS.Center_Stack_2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}},
};
static const CanMsg CHRYSLER_RAM_HD_TX_MSGS[] = {

View File

@@ -94,8 +94,6 @@ static bool ford_get_quality_flag_valid(const CANPacket_t *to_push) {
#define FORD_CANFD_INACTIVE_CURVATURE_RATE 1024U
#define FORD_MAX_SPEED_DELTA 2.0 // m/s
// Curvature rate limits
#define FORD_LIMITS(limit_lateral_acceleration) { \
.max_angle = 1000, /* 0.02 curvature */ \
@@ -133,19 +131,15 @@ static void ford_rx_hook(const CANPacket_t *to_push) {
// Update vehicle speed
if (addr == FORD_BrakeSysFeatures) {
// Signal: Veh_V_ActlBrk
UPDATE_VEHICLE_SPEED(((GET_BYTE(to_push, 0) << 8) | GET_BYTE(to_push, 1)) * 0.01 / 3.6);
UPDATE_VEHICLE_SPEED(((GET_BYTE(to_push, 0) << 8) | GET_BYTE(to_push, 1)) * 0.01 * KPH_TO_MS);
}
// Check vehicle speed against a second source
if (addr == FORD_EngVehicleSpThrottle2) {
// Disable controls if speeds from ABS and PCM ECUs are too far apart.
// Signal: Veh_V_ActlEng
float filtered_pcm_speed = ((GET_BYTE(to_push, 6) << 8) | GET_BYTE(to_push, 7)) * 0.01 / 3.6;
bool is_invalid_speed = ABS(filtered_pcm_speed - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > FORD_MAX_SPEED_DELTA;
// TODO: this should generically cause rx valid to fall until re-enable
if (is_invalid_speed) {
controls_allowed = false;
}
float filtered_pcm_speed = ((GET_BYTE(to_push, 6) << 8) | GET_BYTE(to_push, 7)) * 0.01 * KPH_TO_MS;
speed_mismatch_check(filtered_pcm_speed);
}
// Update vehicle yaw rate
@@ -176,7 +170,7 @@ static void ford_rx_hook(const CANPacket_t *to_push) {
pcm_cruise_check(cruise_engaged);
acc_main_on = (cruise_state == 3U) || cruise_engaged;
}
if (addr == FORD_Steering_Data_FD1) {
mads_button_press = GET_BIT(to_push, 40U) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
@@ -309,17 +303,17 @@ static safety_config ford_init(uint16_t param) {
// warning: quality flags are not yet checked in openpilot's CAN parser,
// this may be the cause of blocked messages
static RxCheck ford_rx_checks[] = {
{.msg = {{FORD_BrakeSysFeatures, 0, 8, .max_counter = 15U, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_BrakeSysFeatures, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
// FORD_EngVehicleSpThrottle2 has a counter that either randomly skips or by 2, likely ECU bug
// Some hybrid models also experience a bug where this checksum mismatches for one or two frames under heavy acceleration with ACC
// It has been confirmed that the Bronco Sport's camera only disallows ACC for bad quality flags, not counters or checksums, so we match that
{.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_Yaw_Data_FD1, 0, 8, .max_counter = 255U, .quality_flag=true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_Yaw_Data_FD1, 0, 8, .max_counter = 255U, .frequency = 100U}, { 0 }, { 0 }}},
// These messages have no counter or checksum
{.msg = {{FORD_EngBrakeData, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{FORD_EngVehicleSpThrottle, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{FORD_DesiredTorqBrk, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_Steering_Data_FD1, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{FORD_EngBrakeData, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{FORD_EngVehicleSpThrottle, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{FORD_DesiredTorqBrk, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_Steering_Data_FD1, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}},
};
#define FORD_COMMON_TX_MSGS \

View File

@@ -4,14 +4,14 @@
// TODO: do checksum and counter checks. Add correct timestep, 0.1s for now.
#define GM_COMMON_RX_CHECKS \
{.msg = {{0x184, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0x34A, 0, 5, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0x1E1, 0, 7, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0xBE, 0, 6, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, /* Volt, Silverado, Acadia Denali */ \
{0xBE, 0, 7, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, /* Bolt EUV */ \
{0xBE, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}}}, /* Escalade */ \
{.msg = {{0x1C4, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0xC9, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0x184, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0x34A, 0, 5, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0x1E1, 0, 7, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0xBE, 0, 6, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, /* Volt, Silverado, Acadia Denali */ \
{0xBE, 0, 7, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, /* Bolt EUV */ \
{0xBE, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}}}, /* Escalade */ \
{.msg = {{0x1C4, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
{.msg = {{0xC9, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
static const LongitudinalLimits *gm_long_limits;
@@ -200,7 +200,7 @@ static safety_config gm_init(uint16_t param) {
static RxCheck gm_ev_rx_checks[] = {
GM_COMMON_RX_CHECKS
{.msg = {{0xBD, 0, 7, .ignore_checksum = true, .ignore_counter = true, .frequency = 40U}, { 0 }, { 0 }}},
{.msg = {{0xBD, 0, 7, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 40U}, { 0 }, { 0 }}},
};
static const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, // pt bus

View File

@@ -3,19 +3,19 @@
#include "opendbc/safety/safety_declarations.h"
// All common address checks except SCM_BUTTONS which isn't on one Nidec safety configuration
#define HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(pt_bus) \
{.msg = {{0x1A6, (pt_bus), 8, .max_counter = 3U, .frequency = 25U}, /* SCM_BUTTONS */ \
{0x296, (pt_bus), 4, .max_counter = 3U, .frequency = 25U}, { 0 }}}, \
{.msg = {{0x158, (pt_bus), 8, .max_counter = 3U, .frequency = 100U}, { 0 }, { 0 }}}, /* ENGINE_DATA */ \
{.msg = {{0x17C, (pt_bus), 8, .max_counter = 3U, .frequency = 100U}, { 0 }, { 0 }}}, /* POWERTRAIN_DATA */ \
#define HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(pt_bus) \
{.msg = {{0x1A6, (pt_bus), 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 25U}, /* SCM_BUTTONS */ \
{0x296, (pt_bus), 4, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 25U}, { 0 }}}, \
{.msg = {{0x158, (pt_bus), 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, /* ENGINE_DATA */ \
{.msg = {{0x17C, (pt_bus), 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, /* POWERTRAIN_DATA */ \
#define HONDA_COMMON_RX_CHECKS(pt_bus) \
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(pt_bus) \
{.msg = {{0x326, (pt_bus), 8, .max_counter = 3U, .frequency = 10U}, { 0 }, { 0 }}}, /* SCM_FEEDBACK */ \
#define HONDA_COMMON_RX_CHECKS(pt_bus) \
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(pt_bus) \
{.msg = {{0x326, (pt_bus), 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, /* SCM_FEEDBACK */ \
// Alternate brake message is used on some Honda Bosch, and Honda Bosch radarless (where PT bus is 0)
#define HONDA_ALT_BRAKE_ADDR_CHECK(pt_bus) \
{.msg = {{0x1BE, (pt_bus), 3, .max_counter = 3U, .frequency = 50U}, { 0 }, { 0 }}}, /* BRAKE_MODULE */ \
#define HONDA_ALT_BRAKE_ADDR_CHECK(pt_bus) \
{.msg = {{0x1BE, (pt_bus), 3, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, /* BRAKE_MODULE */ \
enum {
HONDA_BTN_NONE = 0,
@@ -310,7 +310,7 @@ static safety_config honda_nidec_init(uint16_t param) {
// For Nidecs with main on signal on an alternate msg (missing 0x326)
static RxCheck honda_nidec_alt_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
{.msg = {{0x1FA, 2, 8, .max_counter = 3U, .frequency = 50U}, { 0 }, { 0 }}}, // BRAKE_COMMAND
{.msg = {{0x1FA, 2, 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, // BRAKE_COMMAND
};
SET_RX_CHECKS(honda_nidec_alt_rx_checks, ret);
@@ -318,7 +318,7 @@ static safety_config honda_nidec_init(uint16_t param) {
// Nidec includes BRAKE_COMMAND
static RxCheck honda_nidec_common_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
{.msg = {{0x1FA, 2, 8, .max_counter = 3U, .frequency = 50U}, { 0 }, { 0 }}}, // BRAKE_COMMAND
{.msg = {{0x1FA, 2, 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, // BRAKE_COMMAND
};
SET_RX_CHECKS(honda_nidec_common_rx_checks, ret);

View File

@@ -38,25 +38,25 @@ const LongitudinalLimits HYUNDAI_LONG_LIMITS = {
{0x389, 0, 8, .check_relay = true}, /* SCC14 Bus 0 */ \
{0x4A2, 0, 2, .check_relay = false}, /* FRT_RADAR11 Bus 0 */ \
#define HYUNDAI_COMMON_RX_CHECKS(legacy) \
{.msg = {{0x260, 0, 8, .max_counter = 3U, .frequency = 100U}, \
{0x371, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }}}, \
{.msg = {{0x386, 0, 8, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 15U, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x394, 0, 8, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 7U, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x251, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{0x4F1, 0, 4, .ignore_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_COMMON_RX_CHECKS(legacy) \
{.msg = {{0x260, 0, 8, .max_counter = 3U, .ignore_quality_flag = true, .frequency = 100U}, \
{0x371, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }}}, \
{.msg = {{0x386, 0, 8, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x394, 0, 8, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 7U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x251, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{0x4F1, 0, 4, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_SCC11_ADDR_CHECK(scc_bus) \
{.msg = {{0x420, (scc_bus), 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_SCC11_ADDR_CHECK(scc_bus) \
{.msg = {{0x420, (scc_bus), 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \
{.msg = {{0x421, (scc_bus), 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \
{.msg = {{0x421, (scc_bus), 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_FCEV_GAS_ADDR_CHECK \
{.msg = {{0x91, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0x91, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
#define HYUNDAI_LDA_BUTTON_ADDR_CHECK \
{.msg = {{0x391, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{0x391, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
static const CanMsg HYUNDAI_TX_MSGS[] = {
HYUNDAI_COMMON_TX_MSGS(0)

View File

@@ -25,25 +25,25 @@
// *** Addresses checked in rx hook ***
// EV, ICE, HYBRID: ACCELERATOR (0x35), ACCELERATOR_BRAKE_ALT (0x100), ACCELERATOR_ALT (0x105)
#define HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x35, (pt_bus), 32, .max_counter = 0xffU, .frequency = 100U}, \
{0x100, (pt_bus), 32, .max_counter = 0xffU, .frequency = 100U}, \
{0x105, (pt_bus), 32, .max_counter = 0xffU, .frequency = 100U}}}, \
{.msg = {{0x175, (pt_bus), 24, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{0xa0, (pt_bus), 24, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0xea, (pt_bus), 24, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x35, (pt_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, \
{0x100, (pt_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, \
{0x105, (pt_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}}}, \
{.msg = {{0x175, (pt_bus), 24, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{0xa0, (pt_bus), 24, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{0xea, (pt_bus), 24, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(pt_bus) \
HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x1cf, (pt_bus), 8, .ignore_checksum = true, .max_counter = 0xfU, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(pt_bus) \
HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x1cf, (pt_bus), 8, .ignore_checksum = true, .max_counter = 0xfU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(pt_bus) \
HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x1aa, (pt_bus), 16, .ignore_checksum = true, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(pt_bus) \
HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
{.msg = {{0x1aa, (pt_bus), 16, .ignore_checksum = true, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
// SCC_CONTROL (from ADAS unit or camera)
#define HYUNDAI_CANFD_SCC_ADDR_CHECK(scc_bus) \
{.msg = {{0x1a0, (scc_bus), 32, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_CANFD_SCC_ADDR_CHECK(scc_bus) \
{.msg = {{0x1a0, (scc_bus), 32, .max_counter = 0xffU, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
static bool hyundai_canfd_alt_buttons = false;
static bool hyundai_canfd_lka_steering_alt = false;
@@ -124,7 +124,7 @@ static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
(rl > HYUNDAI_STANDSTILL_THRSLD) || (rr > HYUNDAI_STANDSTILL_THRSLD);
// average of all 4 wheel speeds. Conversion: raw * 0.03125 / 3.6 = m/s
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 / 3.6);
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 * KPH_TO_MS);
}
}

View File

@@ -93,11 +93,11 @@ static safety_config mazda_init(uint16_t param) {
static const CanMsg MAZDA_TX_MSGS[] = {{MAZDA_LKAS, 0, 8, .check_relay = true}, {MAZDA_CRZ_BTNS, 0, 8, .check_relay = false}, {MAZDA_LKAS_HUD, 0, 8, .check_relay = true}};
static RxCheck mazda_rx_checks[] = {
{.msg = {{MAZDA_CRZ_CTRL, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_CRZ_BTNS, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_STEER_TORQUE, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 83U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_ENGINE_DATA, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_PEDALS, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_CRZ_CTRL, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_CRZ_BTNS, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_STEER_TORQUE, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 83U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_ENGINE_DATA, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MAZDA_PEDALS, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
};
UNUSED(param);

View File

@@ -2,22 +2,22 @@
#include "opendbc/safety/safety_declarations.h"
#define NISSAN_COMMON_RX_CHECKS \
{.msg = {{0x2, 0, 5, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, \
{0x2, 1, 5, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }}}, /* STEER_ANGLE_SENSOR */ \
{.msg = {{0x285, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, \
{0x285, 1, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }}}, /* WHEEL_SPEEDS_REAR */ \
{.msg = {{0x30f, 2, 3, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, \
{0x30f, 1, 3, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }}}, /* CRUISE_STATE */ \
{.msg = {{0x15c, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, \
{0x15c, 1, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, \
{0x239, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}}}, /* GAS_PEDAL */ \
{.msg = {{0x454, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, \
{0x454, 1, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, \
{0x1cc, 0, 4, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}}}, /* DOORS_LIGHTS / BRAKE */ \
#define NISSAN_COMMON_RX_CHECKS \
{.msg = {{0x2, 0, 5, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, \
{0x2, 1, 5, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }}}, /* STEER_ANGLE_SENSOR */ \
{.msg = {{0x285, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, \
{0x285, 1, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }}}, /* WHEEL_SPEEDS_REAR */ \
{.msg = {{0x30f, 2, 3, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, \
{0x30f, 1, 3, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }}}, /* CRUISE_STATE */ \
{.msg = {{0x15c, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, \
{0x15c, 1, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, \
{0x239, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}}}, /* GAS_PEDAL */ \
{.msg = {{0x454, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, \
{0x454, 1, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, \
{0x1cc, 0, 4, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}}}, /* DOORS_LIGHTS / BRAKE */ \
#define NISSAN_PRO_PILOT_RX_CHECKS(alt_eps_bus) \
{.msg = {{0x1B6, alt_eps_bus, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}}, \
#define NISSAN_PRO_PILOT_RX_CHECKS(alt_eps_bus) \
{.msg = {{0x1B6, alt_eps_bus, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
static bool nissan_alt_eps = false;
@@ -42,7 +42,7 @@ static void nissan_rx_hook(const CANPacket_t *to_push) {
uint16_t right_rear = (GET_BYTE(to_push, 0) << 8) | (GET_BYTE(to_push, 1));
uint16_t left_rear = (GET_BYTE(to_push, 2) << 8) | (GET_BYTE(to_push, 3));
vehicle_moving = (right_rear | left_rear) != 0U;
UPDATE_VEHICLE_SPEED((right_rear + left_rear) / 2.0 * 0.005 / 3.6);
UPDATE_VEHICLE_SPEED((right_rear + left_rear) / 2.0 * 0.005 * KPH_TO_MS);
}
// X-Trail 0x15c, Leaf 0x239

View File

@@ -2,8 +2,6 @@
#include "opendbc/safety/safety_declarations.h"
#define RIVIAN_MAX_SPEED_DELTA 2.0 // m/s
static uint8_t rivian_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
@@ -81,7 +79,7 @@ static void rivian_rx_hook(const CANPacket_t *to_push) {
if (addr == 0x208) {
float speed = ((GET_BYTE(to_push, 6) << 8) | GET_BYTE(to_push, 7)) * 0.01;
vehicle_moving = speed > 0.0;
UPDATE_VEHICLE_SPEED(speed / 3.6);
UPDATE_VEHICLE_SPEED(speed * KPH_TO_MS);
}
// Gas pressed and second speed source for variable torque limit
@@ -89,12 +87,8 @@ static void rivian_rx_hook(const CANPacket_t *to_push) {
gas_pressed = GET_BYTE(to_push, 3) | (GET_BYTE(to_push, 4) & 0xC0U);
// Disable controls if speeds from VDM and ESP ECUs are too far apart.
float vdm_speed = ((GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6)) * 0.01 / 3.6;
bool is_invalid_speed = ABS(vdm_speed - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > RIVIAN_MAX_SPEED_DELTA;
// TODO: this should generically cause rx valid to fall until re-enable
if (is_invalid_speed) {
controls_allowed = false;
}
float vdm_speed = ((GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6)) * 0.01 * KPH_TO_MS;
speed_mismatch_check(vdm_speed);
}
// Driver torque
@@ -178,11 +172,11 @@ static safety_config rivian_init(uint16_t param) {
static const CanMsg RIVIAN_LONG_TX_MSGS[] = {{0x120, 0, 8, .check_relay = true}, {0x321, 2, 7, .check_relay = true}, {0x160, 0, 5, .check_relay = true}};
static RxCheck rivian_rx_checks[] = {
{.msg = {{0x208, 0, 8, .frequency = 50U, .max_counter = 14U, .quality_flag = true}, { 0 }, { 0 }}}, // ESP_Status (speed)
{.msg = {{0x150, 0, 7, .frequency = 50U, .max_counter = 14U, .quality_flag = true}, { 0 }, { 0 }}}, // VDM_PropStatus (gas pedal & 2nd speed)
{.msg = {{0x380, 0, 5, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // EPAS_SystemStatus (driver torque)
{.msg = {{0x38f, 0, 6, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // iBESP2 (brakes)
{.msg = {{0x100, 2, 8, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // ACM_Status (cruise state)
{.msg = {{0x208, 0, 8, .frequency = 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // ESP_Status (speed)
{.msg = {{0x150, 0, 7, .frequency = 50U, .max_counter = 14U}, { 0 }, { 0 }}}, // VDM_PropStatus (gas pedal & 2nd speed)
{.msg = {{0x380, 0, 5, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EPAS_SystemStatus (driver torque)
{.msg = {{0x38f, 0, 6, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // iBESP2 (brakes)
{.msg = {{0x100, 2, 8, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // ACM_Status (cruise state)
};
bool rivian_longitudinal = false;

View File

@@ -63,13 +63,13 @@
{MSG_SUBARU_ES_STATIC_1, SUBARU_MAIN_BUS, 8, .check_relay = false}, \
{MSG_SUBARU_ES_STATIC_2, SUBARU_MAIN_BUS, 8, .check_relay = false}, \
#define SUBARU_COMMON_RX_CHECKS(alt_bus) \
{.msg = {{MSG_SUBARU_Throttle, SUBARU_MAIN_BUS, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_Steering_Torque, SUBARU_MAIN_BUS, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_Wheel_Speeds, alt_bus, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_Brake_Status, alt_bus, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_CruiseControl, alt_bus, 8, .max_counter = 15U, .frequency = 20U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_ES_LKAS_State, SUBARU_CAM_BUS, 8, .max_counter = 15U, .frequency = 10U}, { 0 }, { 0 }}}, \
#define SUBARU_COMMON_RX_CHECKS(alt_bus) \
{.msg = {{MSG_SUBARU_Throttle, SUBARU_MAIN_BUS, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_Steering_Torque, SUBARU_MAIN_BUS, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_Wheel_Speeds, alt_bus, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_Brake_Status, alt_bus, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_CruiseControl, alt_bus, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 20U}, { 0 }, { 0 }}}, \
{.msg = {{MSG_SUBARU_ES_LKAS_State, SUBARU_CAM_BUS, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, \
static bool subaru_gen2 = false;
static bool subaru_longitudinal = false;
@@ -132,7 +132,7 @@ static void subaru_rx_hook(const CANPacket_t *to_push) {
vehicle_moving = (fr > 0U) || (rr > 0U) || (rl > 0U) || (fl > 0U);
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.057 / 3.6);
UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.057 * KPH_TO_MS);
}
if ((addr == MSG_SUBARU_Brake_Status) && (bus == alt_main_bus)) {

View File

@@ -91,11 +91,11 @@ static safety_config subaru_preglobal_init(uint16_t param) {
// TODO: do checksum and counter checks after adding the signals to the outback dbc file
static RxCheck subaru_preglobal_rx_checks[] = {
{.msg = {{MSG_SUBARU_PG_Throttle, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Steering_Torque, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_CruiseControl, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Wheel_Speeds, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Brake_Pedal, SUBARU_PG_MAIN_BUS, 4, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Throttle, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Steering_Torque, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_CruiseControl, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Wheel_Speeds, SUBARU_PG_MAIN_BUS, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_SUBARU_PG_Brake_Pedal, SUBARU_PG_MAIN_BUS, 4, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
};
const int SUBARU_PG_PARAM_REVERSED_DRIVER_TORQUE = 4;

View File

@@ -2,15 +2,6 @@
#include "opendbc/safety/safety_declarations.h"
// parameters for lateral accel/jerk angle limiting using a simple vehicle model
typedef struct {
const float slip_factor;
const float steer_ratio;
const float wheelbase;
} AngleSteeringParams;
#define TESLA_MAX_SPEED_DELTA 2.0 // m/s
static bool tesla_longitudinal = false;
static bool tesla_stock_aeb = false;
@@ -23,68 +14,6 @@ static bool tesla_stock_lkas_prev = false;
static bool tesla_autopark = false;
static bool tesla_autopark_prev = false;
static float tesla_curvature_factor(const float speed, const AngleSteeringParams params) {
return 1. / (1. - (params.slip_factor * (speed * speed))) / params.wheelbase;
}
static bool tesla_steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const AngleSteeringLimits limits,
const AngleSteeringParams params) {
static const float RAD_TO_DEG = 57.29577951308232;
static const float ISO_LATERAL_ACCEL = 3.0; // m/s^2
// Highway curves are rolled in the direction of the turn, add tolerance to compensate
static const float EARTH_G = 9.81;
static const float AVERAGE_ROAD_ROLL = 0.06; // ~3.4 degrees, 6% superelevation
static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^2
static const float MAX_LATERAL_JERK = 3.0 + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^3
const float fudged_speed = (vehicle_speed.min / VEHICLE_SPEED_FACTOR) - 1.;
const float curvature_factor = tesla_curvature_factor(fudged_speed, params);
bool violation = false;
if (is_lat_active() && steer_control_enabled) {
// *** ISO lateral jerk limit ***
// calculate maximum angle rate per second
const float speed = MAX(fudged_speed, 1.0);
const float max_curvature_rate_sec = MAX_LATERAL_JERK / (speed * speed);
const float max_angle_rate_sec = max_curvature_rate_sec * params.steer_ratio / curvature_factor * RAD_TO_DEG;
// finally get max angle delta per frame
const float max_angle_delta = max_angle_rate_sec * (0.01f * 2.0f); // 50 Hz
const int max_angle_delta_can = (max_angle_delta * limits.angle_deg_to_can) + 1.;
// NOTE: symmetric up and down limits
const int highest_desired_angle = desired_angle_last + max_angle_delta_can;
const int lowest_desired_angle = desired_angle_last - max_angle_delta_can;
violation |= max_limit_check(desired_angle, highest_desired_angle, lowest_desired_angle);
// *** ISO lateral accel limit ***
const float max_curvature = MAX_LATERAL_ACCEL / (speed * speed);
const float max_angle = max_curvature * params.steer_ratio / curvature_factor * RAD_TO_DEG;
const int max_angle_can = (max_angle * limits.angle_deg_to_can) + 1.;
violation |= max_limit_check(desired_angle, max_angle_can, -max_angle_can);
}
desired_angle_last = desired_angle;
// Angle should either be 0 or same as current angle while not steering
if (!steer_control_enabled) {
const int max_inactive_angle = CLAMP(angle_meas.max, -limits.max_angle, limits.max_angle) + 1;
const int min_inactive_angle = CLAMP(angle_meas.min, -limits.max_angle, limits.max_angle) - 1;
violation |= (limits.inactive_angle_is_zero ? (desired_angle != 0) :
max_limit_check(desired_angle, max_inactive_angle, min_inactive_angle));
}
// No angle control allowed when controls are not allowed
violation |= !is_lat_active() && steer_control_enabled;
return violation;
}
static uint8_t tesla_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
@@ -158,6 +87,8 @@ static bool tesla_get_quality_flag_valid(const CANPacket_t *to_push) {
bool valid = false;
if (addr == 0x155) {
valid = (GET_BYTE(to_push, 5) & 0x1U) == 0x1U; // ESP_wheelSpeedsQF
} else if (addr == 0x39d) {
valid = (GET_BYTE(to_push, 2) & 0x03U) != 3U; // IBST_driverBrakeApply=FAULT
} else {
}
return valid;
@@ -185,19 +116,15 @@ static void tesla_rx_hook(const CANPacket_t *to_push) {
// Vehicle speed (DI_speed)
if (addr == 0x257) {
// Vehicle speed: ((val * 0.08) - 40) / MS_TO_KPH
float speed = ((((GET_BYTE(to_push, 2) << 4) | (GET_BYTE(to_push, 1) >> 4)) * 0.08) - 40.) / 3.6;
float speed = ((((GET_BYTE(to_push, 2) << 4) | (GET_BYTE(to_push, 1) >> 4)) * 0.08) - 40.) * KPH_TO_MS;
UPDATE_VEHICLE_SPEED(speed);
}
// 2nd vehicle speed (ESP_B)
if (addr == 0x155) {
// Disable controls if speeds from DI (Drive Inverter) and ESP ECUs are too far apart.
float esp_speed = (((GET_BYTE(to_push, 6) & 0x0FU) << 6) | GET_BYTE(to_push, 5) >> 2) * 0.5 / 3.6;
bool is_invalid_speed = ABS(esp_speed - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > TESLA_MAX_SPEED_DELTA;
// TODO: this should generically cause rx valid to fall until re-enable
if (is_invalid_speed) {
controls_allowed = false;
}
float esp_speed = (((GET_BYTE(to_push, 6) & 0x0FU) << 6) | GET_BYTE(to_push, 5) >> 2) * 0.5 * KPH_TO_MS;
speed_mismatch_check(esp_speed);
}
// Gas pressed
@@ -303,7 +230,7 @@ static bool tesla_tx_hook(const CANPacket_t *to_send) {
bool steer_control_enabled = (steer_control_type == 1) || // ANGLE_CONTROL
(steer_control_type == 2); // LANE_KEEP_ASSIST
if (tesla_steer_angle_cmd_checks(desired_angle, steer_control_enabled, TESLA_STEERING_LIMITS, TESLA_STEERING_PARAMS)) {
if (steer_angle_cmd_checks_vm(desired_angle, steer_control_enabled, TESLA_STEERING_LIMITS, TESLA_STEERING_PARAMS)) {
violation = true;
}
@@ -420,15 +347,15 @@ static safety_config tesla_init(uint16_t param) {
tesla_autopark_prev = false;
static RxCheck tesla_model3_y_rx_checks[] = {
{.msg = {{0x2b9, 2, 8, .max_counter = 7U, .frequency = 25U}, { 0 }, { 0 }}}, // DAS_control
{.msg = {{0x488, 2, 4, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, // DAS_steeringControl
{.msg = {{0x257, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, // DI_speed (speed in kph)
{.msg = {{0x155, 0, 8, .max_counter = 15U, .quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, // ESP_B (2nd speed in kph)
{.msg = {{0x370, 0, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, // EPAS3S_sysStatus (steering angle)
{.msg = {{0x118, 0, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}}, // DI_systemStatus (gas pedal)
{.msg = {{0x39d, 0, 5, .max_counter = 15U, .frequency = 25U}, { 0 }, { 0 }}}, // IBST_status (brakes)
{.msg = {{0x286, 0, 8, .max_counter = 15U, .frequency = 10U}, { 0 }, { 0 }}}, // DI_state (acc state)
{.msg = {{0x311, 0, 7, .max_counter = 15U, .frequency = 10U}, { 0 }, { 0 }}}, // UI_warning (blinkers, buckle switch & doors)
{.msg = {{0x2b9, 2, 8, .max_counter = 7U, .ignore_quality_flag = true, .frequency = 25U}, { 0 }, { 0 }}}, // DAS_control
{.msg = {{0x488, 2, 4, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, // DAS_steeringControl
{.msg = {{0x257, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, // DI_speed (speed in kph)
{.msg = {{0x155, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, // ESP_B (2nd speed in kph)
{.msg = {{0x370, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, // EPAS3S_sysStatus (steering angle)
{.msg = {{0x118, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}}, // DI_systemStatus (gas pedal)
{.msg = {{0x39d, 0, 5, .max_counter = 15U, .frequency = 25U}, { 0 }, { 0 }}}, // IBST_status (brakes)
{.msg = {{0x286, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, // DI_state (acc state)
{.msg = {{0x311, 0, 7, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}}, // UI_warning (blinkers, buckle switch & doors)
};
safety_config ret;

View File

@@ -36,31 +36,31 @@
{0x343, 0, 8, .check_relay = true}, /* ACC */ \
{0x183, 0, 8, .check_relay = true}, /* ACC_CONTROL_2 */ \
#define TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{ 0xaa, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 83U}, { 0 }, { 0 }}}, \
{.msg = {{0x260, 0, 8, .ignore_counter = true, .quality_flag = (lta), .frequency = 50U}, { 0 }, { 0 }}}, \
#define TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{ 0xaa, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 83U}, { 0 }, { 0 }}}, \
{.msg = {{0x260, 0, 8, .ignore_counter = true, .ignore_quality_flag=!(lta), .frequency = 50U}, { 0 }, { 0 }}}, \
#define TOYOTA_RX_CHECKS(lta) \
TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{0x1D2, 0, 8, .ignore_counter = true, .frequency = 33U}, { 0 }, { 0 }}}, \
{.msg = {{0x226, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 40U}, { 0 }, { 0 }}}, \
#define TOYOTA_RX_CHECKS(lta) \
TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{0x1D2, 0, 8, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 33U}, { 0 }, { 0 }}}, \
{.msg = {{0x226, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 40U}, { 0 }, { 0 }}}, \
#define TOYOTA_ALT_BRAKE_RX_CHECKS(lta) \
TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{0x1D2, 0, 8, .ignore_counter = true, .frequency = 33U}, { 0 }, { 0 }}}, \
{.msg = {{0x224, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 40U}, { 0 }, { 0 }}}, \
#define TOYOTA_ALT_BRAKE_RX_CHECKS(lta) \
TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{0x1D2, 0, 8, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 33U}, { 0 }, { 0 }}}, \
{.msg = {{0x224, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 40U}, { 0 }, { 0 }}}, \
#define TOYOTA_SECOC_RX_CHECKS \
TOYOTA_COMMON_RX_CHECKS(false) \
{.msg = {{0x176, 0, 8, .ignore_counter = true, .frequency = 32U}, { 0 }, { 0 }}}, \
{.msg = {{0x116, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 42U}, { 0 }, { 0 }}}, \
{.msg = {{0x101, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define TOYOTA_SECOC_RX_CHECKS \
TOYOTA_COMMON_RX_CHECKS(false) \
{.msg = {{0x176, 0, 8, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 32U}, { 0 }, { 0 }}}, \
{.msg = {{0x116, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 42U}, { 0 }, { 0 }}}, \
{.msg = {{0x101, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define TOYOTA_PCM_CRUISE_2_ADDR_CHECK \
{.msg = {{0x1D3, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 33U}, { 0 }, { 0 }}}, \
#define TOYOTA_PCM_CRUISE_2_ADDR_CHECK \
{.msg = {{0x1D3, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 33U}, { 0 }, { 0 }}}, \
#define TOYOTA_DSU_CRUISE_ADDR_CHECK \
{.msg = {{0x365, 0, 7, .ignore_checksum = true, .ignore_counter = true, .frequency = 5U}, { 0 }, { 0 }}}, \
#define TOYOTA_DSU_CRUISE_ADDR_CHECK \
{.msg = {{0x365, 0, 7, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 5U}, { 0 }, { 0 }}}, \
static bool toyota_secoc = false;
static bool toyota_alt_brake = false;
@@ -173,7 +173,7 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
// check that all wheel speeds are at zero value
vehicle_moving = speed != 0;
UPDATE_VEHICLE_SPEED(speed / 4.0 * 0.01 / 3.6);
UPDATE_VEHICLE_SPEED(speed / 4.0 * 0.01 * KPH_TO_MS);
}
if (addr == 0x1D3) {

View File

@@ -17,13 +17,13 @@ static safety_config volkswagen_mqb_init(uint16_t param) {
{MSG_ACC_02, 0, 8, .check_relay = true}, {MSG_ACC_06, 0, 8, .check_relay = true}, {MSG_ACC_07, 0, 8, .check_relay = true}};
static RxCheck volkswagen_mqb_rx_checks[] = {
{.msg = {{MSG_ESP_19, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_LH_EPS_03, 0, 8, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_ESP_05, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_TSK_06, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_20, 0, 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_14, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{MSG_GRA_ACC_01, 0, 8, .max_counter = 15U, .frequency = 33U}, { 0 }, { 0 }}},
{.msg = {{MSG_ESP_19, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_LH_EPS_03, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_ESP_05, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_TSK_06, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_20, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_14, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 10U}, { 0 }, { 0 }}},
{.msg = {{MSG_GRA_ACC_01, 0, 8, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 33U}, { 0 }, { 0 }}},
};
UNUSED(param);

View File

@@ -59,12 +59,12 @@ static safety_config volkswagen_pq_init(uint16_t param) {
{MSG_ACC_SYSTEM, 0, 8, .check_relay = true}, {MSG_ACC_GRA_ANZEIGE, 0, 8, .check_relay = true}};
static RxCheck volkswagen_pq_rx_checks[] = {
{.msg = {{MSG_LENKHILFE_3, 0, 6, .max_counter = 15U, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_BREMSE_1, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_3, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_5, 0, 8, .ignore_counter = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_GRA_NEU, 0, 4, .max_counter = 15U, .frequency = 30U}, { 0 }, { 0 }}},
{.msg = {{MSG_LENKHILFE_3, 0, 6, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_BREMSE_1, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_2, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_3, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 100U}, { 0 }, { 0 }}},
{.msg = {{MSG_MOTOR_5, 0, 8, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{MSG_GRA_NEU, 0, 4, .max_counter = 15U, .ignore_quality_flag = true, .frequency = 30U}, { 0 }, { 0 }}},
};
UNUSED(param);

View File

@@ -180,10 +180,10 @@ static bool rx_msg_safety_check(const CANPacket_t *to_push,
}
// quality flag check
if ((safety_hooks->get_quality_flag_valid != NULL) && cfg->rx_checks[index].msg[cfg->rx_checks[index].status.index].quality_flag) {
if ((safety_hooks->get_quality_flag_valid != NULL) && !cfg->rx_checks[index].msg[cfg->rx_checks[index].status.index].ignore_quality_flag) {
cfg->rx_checks[index].status.valid_quality_flag = safety_hooks->get_quality_flag_valid(to_push);
} else {
cfg->rx_checks[index].status.valid_quality_flag = true;
cfg->rx_checks[index].status.valid_quality_flag = cfg->rx_checks[index].msg[cfg->rx_checks[index].status.index].ignore_quality_flag;
}
}
return is_msg_valid(cfg->rx_checks, index);
@@ -525,7 +525,7 @@ void update_sample(struct sample_t *sample, int sample_new) {
}
}
bool max_limit_check(int val, const int MAX_VAL, const int MIN_VAL) {
static bool max_limit_check(int val, const int MAX_VAL, const int MIN_VAL) {
return (val > MAX_VAL) || (val < MIN_VAL);
}
@@ -790,12 +790,8 @@ bool steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const
// check not above ISO 11270 lateral accel assuming worst case road roll
if (limits.angle_is_curvature) {
// ISO 11270
static const float ISO_LATERAL_ACCEL = 3.0; // m/s^2
// Limit to average banked road since safety doesn't have the roll
static const float EARTH_G = 9.81;
static const float AVERAGE_ROAD_ROLL = 0.06; // ~3.4 degrees, 6% superelevation
static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL - (EARTH_G * AVERAGE_ROAD_ROLL); // ~2.4 m/s^2
// Allow small tolerance by using minimum speed and rounding curvature up
@@ -833,6 +829,67 @@ bool steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const
return violation;
}
static float get_curvature_factor(const float speed, const AngleSteeringParams params) {
return 1. / (1. - (params.slip_factor * (speed * speed))) / params.wheelbase;
}
bool steer_angle_cmd_checks_vm(int desired_angle, bool steer_control_enabled, const AngleSteeringLimits limits,
const AngleSteeringParams params) {
// This check uses a simple vehicle model to allow for true lateral acceleration and jerk limits.
// TODO: remove the inaccurate breakpoint angle limiting function above and always use this one
static const float RAD_TO_DEG = 57.29577951308232;
// Highway curves are rolled in the direction of the turn, add tolerance to compensate
static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^2
// Lower than ISO 11270 lateral jerk limit, which is 5.0 m/s^3
static const float MAX_LATERAL_JERK = 3.0 + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^3
const float fudged_speed = (vehicle_speed.min / VEHICLE_SPEED_FACTOR) - 1.;
const float curvature_factor = get_curvature_factor(fudged_speed, params);
bool violation = false;
if (is_lat_active() && steer_control_enabled) {
// *** ISO lateral jerk limit ***
// calculate maximum angle rate per second
const float speed = MAX(fudged_speed, 1.0);
const float max_curvature_rate_sec = MAX_LATERAL_JERK / (speed * speed);
const float max_angle_rate_sec = max_curvature_rate_sec * params.steer_ratio / curvature_factor * RAD_TO_DEG;
// finally get max angle delta per frame
const float max_angle_delta = max_angle_rate_sec * (0.01f * 2.0f); // 50 Hz
const int max_angle_delta_can = (max_angle_delta * limits.angle_deg_to_can) + 1.;
// NOTE: symmetric up and down limits
const int highest_desired_angle = desired_angle_last + max_angle_delta_can;
const int lowest_desired_angle = desired_angle_last - max_angle_delta_can;
violation |= max_limit_check(desired_angle, highest_desired_angle, lowest_desired_angle);
// *** ISO lateral accel limit ***
const float max_curvature = MAX_LATERAL_ACCEL / (speed * speed);
const float max_angle = max_curvature * params.steer_ratio / curvature_factor * RAD_TO_DEG;
const int max_angle_can = (max_angle * limits.angle_deg_to_can) + 1.;
violation |= max_limit_check(desired_angle, max_angle_can, -max_angle_can);
}
desired_angle_last = desired_angle;
// Angle should either be 0 or same as current angle while not steering
if (!steer_control_enabled) {
const int max_inactive_angle = CLAMP(angle_meas.max, -limits.max_angle, limits.max_angle) + 1;
const int min_inactive_angle = CLAMP(angle_meas.min, -limits.max_angle, limits.max_angle) - 1;
violation |= (limits.inactive_angle_is_zero ? (desired_angle != 0) :
max_limit_check(desired_angle, max_inactive_angle, min_inactive_angle));
}
// No angle control allowed when controls are not allowed
violation |= !is_lat_active() && steer_control_enabled;
return violation;
}
void pcm_cruise_check(bool cruise_engaged) {
// Enter controls on rising edge of stock ACC, exit controls if stock ACC disengages
if (!cruise_engaged) {
@@ -843,3 +900,13 @@ void pcm_cruise_check(bool cruise_engaged) {
}
cruise_engaged_prev = cruise_engaged;
}
void speed_mismatch_check(const float speed_2) {
// Disable controls if speeds from two sources are too far apart.
// For safety modes that use speed to adjust torque or angle limits
const float MAX_SPEED_DELTA = 2.0; // m/s
bool is_invalid_speed = ABS(speed_2 - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > MAX_SPEED_DELTA;
if (is_invalid_speed) {
controls_allowed = false;
}
}

View File

@@ -65,6 +65,15 @@ extern const int MAX_WRONG_COUNTERS;
#define VEHICLE_SPEED_FACTOR 1000.0
#define MAX_TORQUE_RT_INTERVAL 250000U
// Conversions
#define KPH_TO_MS (1.0 / 3.6)
// Lateral constants
// ISO 11270
static const float ISO_LATERAL_ACCEL = 3.0; // m/s^2
static const float EARTH_G = 9.81;
static const float AVERAGE_ROAD_ROLL = 0.06; // ~3.4 degrees, 6% superelevation
// sample struct that keeps 6 samples in memory
struct sample_t {
@@ -133,6 +142,13 @@ typedef struct {
const bool inactive_angle_is_zero; // if false, enforces angle near meas when disabled (default)
} AngleSteeringLimits;
// parameters for lateral accel/jerk angle limiting using a simple vehicle model
typedef struct {
const float slip_factor;
const float steer_ratio;
const float wheelbase;
} AngleSteeringParams;
typedef struct {
// acceleration cmd limits
const int max_accel;
@@ -162,7 +178,7 @@ typedef struct {
const bool ignore_checksum; // checksum check is not performed when set to true
const bool ignore_counter; // counter check is not performed when set to true
const uint8_t max_counter; // maximum value of the counter. 0 means that the counter check is skipped
const bool quality_flag; // true is quality flag check is performed
const bool ignore_quality_flag; // true if quality flag check is skipped
const uint32_t frequency; // expected frequency of the message [Hz]
} CanMsgCheck;
@@ -217,7 +233,6 @@ bool safety_rx_hook(const CANPacket_t *to_push);
bool safety_tx_hook(CANPacket_t *to_send);
int to_signed(int d, int bits);
void update_sample(struct sample_t *sample, int sample_new);
bool max_limit_check(int val, const int MAX_VAL, const int MIN_VAL);
bool get_longitudinal_allowed(void);
int ROUND(float val);
void gen_crc_lookup_table_8(uint8_t poly, uint8_t crc_lut[]);
@@ -226,12 +241,15 @@ void gen_crc_lookup_table_16(uint16_t poly, uint16_t crc_lut[]);
#endif
bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueSteeringLimits limits);
bool steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const AngleSteeringLimits limits);
bool steer_angle_cmd_checks_vm(int desired_angle, bool steer_control_enabled, const AngleSteeringLimits limits,
const AngleSteeringParams params);
bool longitudinal_accel_checks(int desired_accel, const LongitudinalLimits limits);
bool longitudinal_speed_checks(int desired_speed, const LongitudinalLimits limits);
bool longitudinal_gas_checks(int desired_gas, const LongitudinalLimits limits);
bool longitudinal_transmission_rpm_checks(int desired_transmission_rpm, const LongitudinalLimits limits);
bool longitudinal_brake_checks(int desired_brake, const LongitudinalLimits limits);
void pcm_cruise_check(bool cruise_engaged);
void speed_mismatch_check(const float speed_2);
void safety_tick(const safety_config *safety_config);

View File

@@ -115,4 +115,4 @@ extern void m_update_button_state(ButtonStateTracking *button_state);
extern void m_update_binary_state(BinaryStateTracking *state);
extern void m_update_control_state(void);
bool is_lat_active(void);
extern bool is_lat_active(void);

View File

@@ -16,6 +16,9 @@ MAX_WRONG_COUNTERS = 5
MAX_SAMPLE_VALS = 6
VEHICLE_SPEED_FACTOR = 1000
# Max allowed delta between car speeds
MAX_SPEED_DELTA = 2.0 # m/s
MessageFunction = Callable[[float], libsafety_py.CANPacket]
@@ -920,6 +923,10 @@ class PandaCarSafetyTest(PandaSafetyTest, MadsSafetyTestBase):
def _speed_msg(self, speed):
pass
@abc.abstractmethod
def _speed_msg_2(self, speed: float):
pass
# Safety modes can override if vehicle_moving is driven by a different message
def _vehicle_moving_msg(self, speed: float):
return self._speed_msg(speed)
@@ -1060,6 +1067,21 @@ class PandaCarSafetyTest(PandaSafetyTest, MadsSafetyTestBase):
self._rx(self._vehicle_moving_msg(self.STANDSTILL_THRESHOLD + 1))
self.assertTrue(self.safety.get_vehicle_moving())
def test_rx_hook_speed_mismatch(self):
if self._speed_msg_2(0) is None:
raise unittest.SkipTest("No second speed message for this safety mode")
for speed in np.arange(0, 40, 0.5):
for speed_delta in np.arange(-5, 5, 0.1):
speed_2 = round(max(speed + speed_delta, 0), 1)
# Set controls allowed in between rx since first message can reset it
self._rx(self._speed_msg(speed))
self.safety.set_controls_allowed(True)
self._rx(self._speed_msg_2(speed_2))
within_delta = abs(speed - speed_2) <= MAX_SPEED_DELTA
self.assertEqual(self.safety.get_controls_allowed(), within_delta)
def test_safety_tick(self):
self.safety.set_timer(int(2e6))
self.safety.set_controls_allowed(True)

View File

@@ -4,6 +4,11 @@ set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
: "${CPPCHECK_DIR:=$DIR/cppcheck/}"
# skip if we're running in parallel with test_mutation.py
if [ ! -z "$OPENDBC_ROOT" ]; then
exit 0
fi
if [ ! -d "$CPPCHECK_DIR" ]; then
git clone https://github.com/danmar/cppcheck.git $CPPCHECK_DIR
fi

View File

@@ -14,20 +14,15 @@ NC='\033[0m'
: "${CPPCHECK_DIR:=$DIR/cppcheck/}"
# ensure checked in coverage table is up to date
if [ -z "$SKIP_TABLES_DIFF" ]; then
python3 $CPPCHECK_DIR/addons/misra.py -generate-table > coverage_table
if ! git diff --quiet coverage_table; then
echo -e "${YELLOW}MISRA coverage table doesn't match. Update and commit:${NC}"
exit 3
fi
python3 $CPPCHECK_DIR/addons/misra.py -generate-table > coverage_table
if ! git diff --quiet coverage_table; then
echo -e "${YELLOW}MISRA coverage table doesn't match. Update and commit:${NC}"
exit 3
fi
cd $BASEDIR
if [ -z "${SKIP_BUILD}" ]; then
scons -j8
fi
CHECKLIST=$DIR/checkers.txt
CHECKLIST=$(mktemp)
echo "Cppcheck checkers list from test_misra.sh:" > $CHECKLIST
cppcheck() {
@@ -35,12 +30,13 @@ cppcheck() {
COMMON_DEFINES="-D__GNUC__=9"
# note that cppcheck build cache results in inconsistent results as of v2.13.0
OUTPUT=$DIR/.output.log
OUTPUT=$(mktemp)
echo -e "\n\n\n\n\nTEST variant options:" >> $CHECKLIST
echo -e ""${@//$BASEDIR/}"\n\n" >> $CHECKLIST # (absolute path removed)
$CPPCHECK_DIR/cppcheck --inline-suppr -I $BASEDIR \
OPENDBC_ROOT=${OPENDBC_ROOT:-$BASEDIR}
$CPPCHECK_DIR/cppcheck --inline-suppr -I $OPENDBC_ROOT \
-I "$(gcc -print-file-name=include)" --suppress=*:*gcc*include/* --suppress=*:*clang*include/* \
--suppressions-list=$DIR/suppressions.txt \
--error-exitcode=2 --check-level=exhaustive --safety \
@@ -65,8 +61,11 @@ cppcheck $PANDA_OPTS -DCANFD $BASEDIR/opendbc/safety/main.c
printf "\n${GREEN}Success!${NC} took $SECONDS seconds\n"
# ensure list of checkers is up to date
cd $DIR
if [ -z "$SKIP_TABLES_DIFF" ] && ! git diff --quiet $CHECKLIST; then
echo -e "\n${YELLOW}WARNING: Cppcheck checkers.txt report has changed. Review and commit...${NC}"
exit 4
if [ -z "$OPENDBC_ROOT" ]; then
cd $DIR
if ! git diff --quiet $CHECKLIST; then
echo -e "\n${YELLOW}WARNING: Cppcheck checkers.txt report has changed. Review and commit...${NC}"
mv $CHECKLIST $DIR/checkers.txt
exit 4
fi
fi

61
opendbc/safety/tests/misra/test_mutation.py Executable file → Normal file
View File

@@ -11,38 +11,27 @@ HERE = os.path.abspath(os.path.dirname(__file__))
ROOT = os.path.join(HERE, "../../../../")
IGNORED_PATHS = (
'opendbc/safety/main.c',
'opendbc/safety/tests/',
'opendbc/safety/board/',
)
mutations = [
# default
(None, None, False),
# general safety
("opendbc/safety/modes/toyota.h", "s/if (addr == 0x260) {/if (addr == 1 || addr == 2) {/g", True),
# no mutation, should pass
(None, None, lambda s: s, False),
]
patterns = [
# misra-c2012-13.3
"$a void test(int tmp) { int tmp2 = tmp++ + 2; if (tmp2) {;}}",
# misra-c2012-13.4
"$a int test(int x, int y) { return (x=2) && (y=2); }",
# misra-c2012-13.5
"$a void test(int tmp) { if (true && tmp++) {;} }",
# misra-c2012-13.6
"$a void test(int tmp) { if (sizeof(tmp++)) {;} }",
# misra-c2012-14.1
"$a void test(float len) { for (float j = 0; j < len; j++) {;} }",
# misra-c2012-14.4
"$a void test(int len) { if (len - 8) {;} }",
# misra-c2012-16.4
r"$a void test(int temp) {switch (temp) { case 1: ; }}\n",
# misra-c2012-17.8
"$a void test(int cnt) { for (cnt=0;;cnt++) {;} }",
# misra-c2012-20.4
r"$a #define auto 1\n",
# misra-c2012-20.5
r"$a #define TEST 1\n#undef TEST\n",
("misra-c2012-10.3", lambda s: s + "\nvoid test(float len) { for (float j = 0; j < len; j++) {;} }\n"),
("misra-c2012-13.3", lambda s: s + "\nvoid test(int tmp) { int tmp2 = tmp++ + 2; if (tmp2) {;}}\n"),
("misra-c2012-13.4", lambda s: s + "\nint test(int x, int y) { return (x=2) && (y=2); }\n"),
("misra-c2012-13.5", lambda s: s + "\nvoid test(int tmp) { if (true && tmp++) {;} }\n"),
("misra-c2012-13.6", lambda s: s + "\nvoid test(int tmp) { if (sizeof(tmp++)) {;} }\n"),
("misra-c2012-14.2", lambda s: s + "\nvoid test(int cnt) { for (cnt=0;;cnt++) {;} }\n"),
("misra-c2012-14.4", lambda s: s + "\nvoid test(int len) { if (len - 8) {;} }\n"),
("misra-c2012-16.4", lambda s: s + "\nvoid test(int temp) {switch (temp) { case 1: ; }}\n"),
("misra-c2012-20.4", lambda s: s + "\n#define auto 1\n"),
("misra-c2012-20.5", lambda s: s + "\n#define TEST 1\n#undef TEST\n"),
]
all_files = glob.glob('opendbc/safety/**', root_dir=ROOT, recursive=True)
@@ -50,20 +39,28 @@ files = [f for f in all_files if f.endswith(('.c', '.h')) and not f.startswith(I
assert len(files) > 20, files
for p in patterns:
mutations.append((random.choice(files), p, True))
mutations.append((random.choice(files), *p, True))
@pytest.mark.parametrize("fn, patch, should_fail", mutations)
def test_misra_mutation(fn, patch, should_fail):
mutations = random.sample(mutations, 2) # can remove this once cppcheck is faster
@pytest.mark.parametrize("fn, rule, transform, should_fail", mutations)
def test_misra_mutation(fn, rule, transform, should_fail):
with tempfile.TemporaryDirectory() as tmp:
shutil.copytree(ROOT, tmp, dirs_exist_ok=True)
shutil.rmtree(os.path.join(tmp, '.venv'), ignore_errors=True)
shutil.copytree(ROOT, tmp, dirs_exist_ok=True,
ignore=shutil.ignore_patterns('.venv', 'cppcheck', '.git', '*.ctu-info'))
# apply patch
if fn is not None:
r = os.system(f"cd {tmp} && sed -i '{patch}' {fn}")
assert r == 0
with open(os.path.join(tmp, fn), 'r+') as f:
content = f.read()
f.seek(0)
f.write(transform(content))
# run test
r = subprocess.run("SKIP_TABLES_DIFF=1 SKIP_BUILD=1 opendbc/safety/tests/misra/test_misra.sh", cwd=tmp, shell=True)
r = subprocess.run(f"OPENDBC_ROOT={tmp} opendbc/safety/tests/misra/test_misra.sh",
stdout=subprocess.PIPE, cwd=ROOT, shell=True, encoding='utf8')
print(r.stdout) # helpful for debugging failures
failed = r.returncode != 0
assert failed == should_fail
if should_fail:
assert rule in r.stdout, "MISRA test failed but not for the correct violation"

View File

@@ -13,4 +13,4 @@ echo -e "$MULL_OPS" > $GIT_ROOT/mull.yml
scons --mutation -j$(nproc) -D
echo -e "timeout: 60000\ngitDiffRef: $GIT_REF\ngitProjectRoot: $GIT_ROOT" >> $GIT_ROOT/mull.yml
mull-runner-17 --ld-search-path /lib/x86_64-linux-gnu/ ./libsafety/libsafety.so -test-program=pytest -- -n8
mull-runner-17 --ld-search-path /lib/x86_64-linux-gnu/ ./libsafety/libsafety.so -test-program=pytest -- -n8 --ignore-glob=misra/*

View File

@@ -73,9 +73,6 @@ class TestFordSafetyBase(common.PandaCarSafetyTest):
FWD_BLACKLISTED_ADDRS = {2: [MSG_ACCDATA_3, MSG_Lane_Assist_Data1, MSG_LateralMotionControl,
MSG_LateralMotionControl2, MSG_IPMA_Data]}
# Max allowed delta between car speeds
MAX_SPEED_DELTA = 2.0 # m/s
STEER_MESSAGE = 0
# Curvature control limits
@@ -130,6 +127,7 @@ class TestFordSafetyBase(common.PandaCarSafetyTest):
# PCM vehicle speed
def _speed_msg_2(self, speed: float, quality_flag=True):
# Ford relies on speed for driver curvature limiting, so it checks two sources
values = {"Veh_V_ActlEng": speed * 3.6, "VehVActlEng_D_Qf": 3 if quality_flag else 0, "VehVActlEng_No_Cnt": self.cnt_speed_2 % 16}
self.__class__.cnt_speed_2 += 1
return self.packer.make_can_msg_panda("EngVehicleSpThrottle2", 0, values, fix_checksum=checksum)
@@ -222,19 +220,6 @@ class TestFordSafetyBase(common.PandaCarSafetyTest):
self.assertEqual(should_rx, self._rx(to_push))
self.assertEqual(should_rx, self.safety.get_controls_allowed())
def test_rx_hook_speed_mismatch(self):
# Ford relies on speed for driver curvature limiting, so it checks two sources
for speed in np.arange(0, 40, 0.5):
for speed_delta in np.arange(-5, 5, 0.1):
speed_2 = round(max(speed + speed_delta, 0), 1)
# Set controls allowed in between rx since first message can reset it
self._rx(self._speed_msg(speed))
self.safety.set_controls_allowed(True)
self._rx(self._speed_msg_2(speed_2))
within_delta = abs(speed - speed_2) <= self.MAX_SPEED_DELTA
self.assertEqual(self.safety.get_controls_allowed(), within_delta)
def test_angle_measurements(self):
"""Tests rx hook correctly parses the curvature measurement from the vehicle speed and yaw rate"""
for speed in np.arange(0.5, 40, 0.5):

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python3
import unittest
import numpy as np
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
@@ -40,9 +39,6 @@ class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteerin
DRIVER_TORQUE_ALLOWANCE = 100
DRIVER_TORQUE_FACTOR = 2
# Max allowed delta between car speeds
MAX_SPEED_DELTA = 2.0 # m/s
cnt_speed = 0
cnt_speed_2 = 0
@@ -61,6 +57,7 @@ class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteerin
return self.packer.make_can_msg_panda("ESP_Status", 0, values, fix_checksum=checksum)
def _speed_msg_2(self, speed, quality_flag=True):
# Rivian has a dynamic max torque limit based on speed, so it checks two sources
return self._user_gas_msg(0, speed, quality_flag)
def _user_brake_msg(self, brake):
@@ -112,20 +109,6 @@ class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteerin
self.assertFalse(self._rx(to_push))
self.assertFalse(self.safety.get_controls_allowed())
def test_rx_hook_speed_mismatch(self):
# TODO: this can be a common test w/ Ford
# Rivian has a dynamic max torque limit based on speed, so it checks two sources
for speed in np.arange(0, 40, 0.5):
for speed_delta in np.arange(-5, 5, 0.1):
speed_2 = round(max(speed + speed_delta, 0), 1)
# Set controls allowed in between rx since first message can reset it
self._rx(self._speed_msg(speed))
self.safety.set_controls_allowed(True)
self._rx(self._speed_msg_2(speed_2))
within_delta = abs(speed - speed_2) <= self.MAX_SPEED_DELTA
self.assertEqual(self.safety.get_controls_allowed(), within_delta)
class TestRivianStockSafety(TestRivianSafetyBase):

View File

@@ -9,7 +9,7 @@ from opendbc.car.vehicle_model import VehicleModel
from opendbc.can.can_define import CANDefine
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerPanda, MAX_WRONG_COUNTERS, away_round, round_speed
from opendbc.safety.tests.common import CANPackerPanda, MAX_SPEED_DELTA, MAX_WRONG_COUNTERS, away_round, round_speed
MSG_DAS_steeringControl = 0x488
MSG_APS_eacMonitor = 0x27d
@@ -46,9 +46,6 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
MIN_ACCEL = -3.48
INACTIVE_ACCEL = 0.0
# Max allowed delta between car speeds
MAX_SPEED_DELTA = 2.0 # m/s
cnt_epas = 0
packer: CANPackerPanda
@@ -74,8 +71,10 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
self.__class__.cnt_epas += 1
return self.packer.make_can_msg_panda("EPAS3S_sysStatus", 0, values)
def _user_brake_msg(self, brake):
def _user_brake_msg(self, brake, quality_flag: bool = True):
values = {"IBST_driverBrakeApply": 2 if brake else 1}
if not quality_flag:
values["IBST_driverBrakeApply"] = 3 # FAULT
return self.packer.make_can_msg_panda("IBST_status", 0, values)
def _speed_msg(self, speed):
@@ -159,7 +158,7 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
self.safety.get_vehicle_speed_min, self.safety.get_vehicle_speed_max)
def test_rx_hook_speed_mismatch(self):
# TODO: this can be a common test w/ Ford
# TODO: overridden because of custom rounding
# Tesla relies on speed for lateral limits close to ISO 11270, so it checks two sources
for speed in np.arange(0, 40, 0.5):
# match signal rounding on CAN
@@ -173,7 +172,7 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
self.safety.set_controls_allowed(True)
self.assertTrue(self._rx(self._speed_msg_2(speed_2)))
within_delta = abs(speed - speed_2) <= self.MAX_SPEED_DELTA
within_delta = abs(speed - speed_2) <= MAX_SPEED_DELTA
self.assertEqual(self.safety.get_controls_allowed(), within_delta)
# Test ESP_B quality flag
@@ -183,6 +182,11 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
self.assertEqual(quality_flag, self._rx(self._speed_msg_2(0, quality_flag=quality_flag)))
self.assertEqual(quality_flag, self.safety.get_controls_allowed())
def test_user_brake_quality_flag(self):
for quality_flag in (True, False):
to_push = self._user_brake_msg(True, quality_flag=quality_flag)
self.assertEqual(quality_flag, self._rx(to_push))
def test_steering_wheel_disengage(self):
# Tesla disengages when the user forcibly overrides the locked-in angle steering control
# Either when the hands on level is high, or if there is a high angle rate fault

View File

@@ -7,7 +7,7 @@ cd $DIR
source ./setup.sh
# *** build ***
scons -j8
scons -j8 "$@"
# *** lint + test ***
lefthook run test