Skip to content

Commit 3cfc935

Browse files
authored
Sync: commaai/opendbc:master into sunnypilot/opendbc:master-new
Sync: `commaai/opendbc:master` into `sunnypilot/opendbc:master-new`
2 parents a98ee4e + 4b2472a commit 3cfc935

File tree

99 files changed

+853
-466
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+853
-466
lines changed

.github/workflows/test_models_trigger.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
submodules: 'true'
3838

3939
- name: bump opendbc
40+
if: steps.check_comment.outputs.result == 'true'
4041
run: |
4142
cd opendbc_repo
4243
git fetch origin pull/${{ github.event.issue.number }}/head

.github/workflows/tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,15 @@ jobs:
9393
mutation:
9494
name: Safety mutation tests
9595
runs-on: ${{ github.repository == 'commaai/opendbc' && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
96-
timeout-minutes: 20
96+
timeout-minutes: 60
9797
env:
9898
GIT_REF: ${{ github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.event.before || format('origin/{0}', github.event.repository.default_branch) }}
9999
steps:
100100
- uses: actions/checkout@v4
101101
with:
102102
fetch-depth: 0 # need master to get diff
103103
- name: Run mutation tests
104-
timeout-minutes: 10
104+
timeout-minutes: 60
105105
run: |
106106
source setup.sh
107107
scons -j8

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,7 @@ opendbc/can/packer_pyx.cpp
2424
opendbc/can/parser_pyx.cpp
2525
opendbc/can/packer_pyx.html
2626
opendbc/can/parser_pyx.html
27-
opendbc/dbc/*_generated.dbc
27+
opendbc/dbc/*_generated.dbc
28+
29+
cppcheck-addon-ctu-file-list
30+
opendbc/safety/tests/coverage-out

.pre-commit-config.yaml

-7
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,3 @@ repos:
3737
- --counting=detailed
3838
- --linelength=240
3939
- --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces
40-
- repo: local
41-
hooks:
42-
- id: generator
43-
name: dbc generator
44-
entry: opendbc/dbc/generator/test_generator.py
45-
language: script
46-
pass_filenames: false

docs/CARS.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
3737
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
3838
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
39-
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Under review](#upstream)|
40-
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Under review](#upstream)|
39+
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
40+
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
4141
|Ford|Focus 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
4242
|Ford|Focus Hybrid 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
4343
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
@@ -47,8 +47,8 @@
4747
|Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
4848
|Ford|Maverick Hybrid 2022|LARIAT Luxury|[Upstream](#upstream)|
4949
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
50-
|Ford|Mustang Mach-E 2021-23|All|[Under review](#upstream)|
51-
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Under review](#upstream)|
50+
|Ford|Mustang Mach-E 2021-23|All|[Upstream](#upstream)|
51+
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
5252
|Genesis|G70 2018|All|[Upstream](#upstream)|
5353
|Genesis|G70 2019-21|All|[Upstream](#upstream)|
5454
|Genesis|G70 2022-23|All|[Upstream](#upstream)|

opendbc/car/CARS_template.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
22

3-
# Support Information for {{car_docs_with_extras | length}} Known Cars
3+
# Support Information for {{all_car_docs | length}} Known Cars
44

55
|{{ExtraCarsColumn | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}|
66
|---|---|---|{% for _ in range((ExtraCarsColumn | length) - 3) %}{{':---:|'}}{% endfor +%}
7-
{% for car_docs in car_docs_with_extras %}
7+
{% for car_docs in all_car_docs %}
88
|{% for column in ExtraCarsColumn %}{{car_docs.get_extra_cars_column(column)}}|{% endfor %}
99

1010
{% endfor %}

opendbc/car/__init__.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# functions common among cars
22
import numpy as np
3-
from collections import namedtuple
43
from dataclasses import dataclass, field
54
from enum import IntFlag, ReprEnum, StrEnum, EnumType, auto
65
from dataclasses import replace
@@ -17,7 +16,13 @@
1716
ACCELERATION_DUE_TO_GRAVITY = 9.81 # m/s^2
1817

1918
ButtonType = structs.CarState.ButtonEvent.Type
20-
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v'])
19+
20+
21+
@dataclass
22+
class AngleSteeringLimits:
23+
STEER_ANGLE_MAX: float
24+
ANGLE_RATE_LIMIT_UP: tuple[list[float], list[float]]
25+
ANGLE_RATE_LIMIT_DOWN: tuple[list[float], list[float]]
2126

2227

2328
def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float:
@@ -141,19 +146,20 @@ def apply_meas_steer_torque_limits(apply_torque, apply_torque_last, motor_torque
141146
LIMITS.STEER_ERROR_MAX, LIMITS.STEER_MAX)))
142147

143148

144-
def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, steering_angle, lat_active, LIMITS):
149+
def apply_std_steer_angle_limits(apply_angle: float, apply_angle_last: float, v_ego: float, steering_angle: float,
150+
lat_active: bool, limits: AngleSteeringLimits) -> float:
145151
# pick angle rate limits based on wind up/down
146152
steer_up = apply_angle_last * apply_angle >= 0. and abs(apply_angle) > abs(apply_angle_last)
147-
rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN
153+
rate_limits = limits.ANGLE_RATE_LIMIT_UP if steer_up else limits.ANGLE_RATE_LIMIT_DOWN
148154

149-
angle_rate_lim = np.interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v)
155+
angle_rate_lim = np.interp(v_ego, rate_limits[0], rate_limits[1])
150156
new_apply_angle = np.clip(apply_angle, apply_angle_last - angle_rate_lim, apply_angle_last + angle_rate_lim)
151157

152158
# angle is current steering wheel angle when inactive on all angle cars
153159
if not lat_active:
154160
new_apply_angle = steering_angle
155161

156-
return float(np.clip(new_apply_angle, -LIMITS.STEER_ANGLE_MAX, LIMITS.STEER_ANGLE_MAX))
162+
return float(np.clip(new_apply_angle, -limits.STEER_ANGLE_MAX, limits.STEER_ANGLE_MAX))
157163

158164

159165
def common_fault_avoidance(fault_condition: bool, request: bool, above_limit_frames: int,

opendbc/car/body/carcontroller.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def __init__(self, dbc_names, CP, CP_SP):
2020
self.packer = CANPacker(dbc_names[Bus.main])
2121

2222
# PIDs
23-
self.turn_pid = PIDController(110, k_i=11.5, rate=1/DT_CTRL)
24-
self.wheeled_speed_pid = PIDController(110, k_i=11.5, rate=1/DT_CTRL)
23+
self.turn_pid = PIDController(110, k_i=11.5, rate=1 / DT_CTRL)
24+
self.wheeled_speed_pid = PIDController(110, k_i=11.5, rate=1 / DT_CTRL)
2525

2626
self.torque_r_filtered = 0.
2727
self.torque_l_filtered = 0.

opendbc/car/car.capnp

+1
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ struct CarParams {
627627
psa @31;
628628
fcaGiorgio @32;
629629
rivian @33;
630+
volkswagenMeb @34;
630631
}
631632

632633
enum SteerControlType {

opendbc/car/car_helpers.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from opendbc.car.structs import CarParams, CarParamsT, CarParamsSP
88
from opendbc.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
99
from opendbc.car.fw_versions import ObdCallback, get_fw_versions_ordered, get_present_ecus, match_fw_to_car
10-
from opendbc.car.interfaces import get_interface_attr
1110
from opendbc.car.mock.values import CAR as MOCK
11+
from opendbc.car.values import BRANDS
1212
from opendbc.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN
1313

1414
FRAME_FINGERPRINT = 100 # 1s
@@ -30,8 +30,9 @@ def load_interfaces(brand_names):
3030
def _get_interface_names() -> dict[str, list[str]]:
3131
# returns a dict of brand name and its respective models
3232
brand_names = {}
33-
for brand_name, brand_models in get_interface_attr("CAR").items():
34-
brand_names[brand_name] = [model.value for model in brand_models]
33+
for brand in BRANDS:
34+
brand_name = brand.__module__.split('.')[-2]
35+
brand_names[brand_name] = [model.value for model in brand]
3536

3637
return brand_names
3738

opendbc/car/chrysler/carcontroller.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def update(self, CC, CC_SP, CS, now_nanos):
2828
lkas_active = CC.latActive and self.lkas_control_bit_prev
2929

3030
# cruise buttons
31-
if (self.frame - self.last_button_frame)*DT_CTRL > 0.05:
31+
if (self.frame - self.last_button_frame) * DT_CTRL > 0.05:
3232
das_bus = 2 if self.CP.carFingerprint in RAM_CARS else 0
3333

3434
# ACC cancellation

opendbc/car/docs.py

+18-29
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,28 @@
1111
from opendbc.car.common.basedir import BASEDIR
1212
from opendbc.car import gen_empty_fingerprint
1313
from opendbc.car.structs import CarParams
14-
from opendbc.car.docs_definitions import CarDocs, Device, ExtraCarDocs, Column, ExtraCarsColumn, CommonFootnote, PartType
15-
from opendbc.car.car_helpers import interfaces, get_interface_attr
16-
from opendbc.car.values import Platform, PLATFORMS
14+
from opendbc.car.docs_definitions import BaseCarHarness, CarDocs, Device, ExtraCarDocs, Column, ExtraCarsColumn, CommonFootnote, PartType, SupportType
15+
from opendbc.car.car_helpers import interfaces
16+
from opendbc.car.interfaces import get_interface_attr
17+
from opendbc.car.values import Platform
1718
from opendbc.car.mock.values import CAR as MOCK
1819
from opendbc.car.extra_cars import CAR as EXTRA
1920

2021

2122
EXTRA_CARS_MD_OUT = os.path.join(BASEDIR, "../", "../", "docs", "CARS.md")
2223
EXTRA_CARS_MD_TEMPLATE = os.path.join(BASEDIR, "CARS_template.md")
2324

25+
# TODO: merge these platforms into normal car ports with SupportType flag
2426
ExtraPlatform = Platform | EXTRA
2527
EXTRA_BRANDS = get_args(ExtraPlatform)
2628
EXTRA_PLATFORMS: dict[str, ExtraPlatform] = {str(platform): platform for brand in EXTRA_BRANDS for platform in brand}
2729

2830

29-
def get_params_for_docs(model, platform) -> CarParams:
30-
cp_model, cp_platform = (model, platform) if model in interfaces else ("MOCK", MOCK.MOCK)
31-
CP: CarParams = interfaces[cp_model][0].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
32-
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
33-
experimental_long=True, docs=True)
31+
def get_params_for_docs(platform) -> CarParams:
32+
cp_platform = platform if platform in interfaces else MOCK.MOCK
33+
CP: CarParams = interfaces[cp_platform][0].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
34+
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
35+
experimental_long=True, docs=True)
3436
return CP
3537

3638

@@ -41,13 +43,13 @@ def get_all_footnotes() -> dict[Enum, int]:
4143
return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)}
4244

4345

44-
def build_sorted_car_docs_list(platforms, footnotes=None, include_dashcam=False):
46+
def build_sorted_car_docs_list(platforms, footnotes=None):
4547
collected_car_docs: list[CarDocs | ExtraCarDocs] = []
46-
for model, platform in platforms.items():
48+
for platform in platforms.values():
4749
car_docs = platform.config.car_docs
48-
CP = get_params_for_docs(model, platform)
50+
CP = get_params_for_docs(platform)
4951

50-
if (CP.dashcamOnly and not include_dashcam) or not len(car_docs):
52+
if not len(car_docs):
5153
continue
5254

5355
# A platform can include multiple car models
@@ -65,12 +67,7 @@ def build_sorted_car_docs_list(platforms, footnotes=None, include_dashcam=False)
6567
# CAUTION: This function is imported by shop.comma.ai and comma.ai/vehicles, test changes carefully
6668
def get_all_car_docs() -> list[CarDocs]:
6769
collected_footnotes = get_all_footnotes()
68-
sorted_list: list[CarDocs] = build_sorted_car_docs_list(PLATFORMS, footnotes=collected_footnotes)
69-
return sorted_list
70-
71-
72-
def get_car_docs_with_extras() -> list[CarDocs | ExtraCarDocs]:
73-
sorted_list: list[CarDocs] = build_sorted_car_docs_list(EXTRA_PLATFORMS, include_dashcam=True)
70+
sorted_list: list[CarDocs] = build_sorted_car_docs_list(EXTRA_PLATFORMS, footnotes=collected_footnotes)
7471
return sorted_list
7572

7673

@@ -89,16 +86,8 @@ def generate_cars_md(all_car_docs: list[CarDocs], template_fn: str) -> str:
8986
footnotes = [fn.value.text for fn in get_all_footnotes()]
9087
cars_md: str = template.render(all_car_docs=all_car_docs, PartType=PartType,
9188
group_by_make=group_by_make, footnotes=footnotes,
92-
Device=Device, Column=Column)
93-
return cars_md
94-
95-
96-
def generate_cars_md_with_extras(car_docs_with_extras: list[CarDocs | ExtraCarDocs], template_fn: str) -> str:
97-
with open(template_fn) as f:
98-
template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True)
99-
100-
cars_md: str = template.render(car_docs_with_extras=car_docs_with_extras, PartType=PartType,
101-
group_by_make=group_by_make, ExtraCarsColumn=ExtraCarsColumn)
89+
Device=Device, Column=Column, ExtraCarsColumn=ExtraCarsColumn,
90+
BaseCarHarness=BaseCarHarness, SupportType=SupportType)
10291
return cars_md
10392

10493

@@ -111,5 +100,5 @@ def generate_cars_md_with_extras(car_docs_with_extras: list[CarDocs | ExtraCarDo
111100
args = parser.parse_args()
112101

113102
with open(args.out, 'w') as f:
114-
f.write(generate_cars_md_with_extras(get_car_docs_with_extras(), args.template))
103+
f.write(generate_cars_md(get_all_car_docs(), args.template))
115104
print(f"Generated and written to {args.out}")

opendbc/car/docs_definitions.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class CarHarness(EnumBase):
9898
nidec = BaseCarHarness("Honda Nidec connector")
9999
bosch_a = BaseCarHarness("Honda Bosch A connector")
100100
bosch_b = BaseCarHarness("Honda Bosch B connector")
101+
bosch_c = BaseCarHarness("Honda Bosch C connector")
101102
toyota_a = BaseCarHarness("Toyota A connector")
102103
toyota_b = BaseCarHarness("Toyota B connector")
103104
subaru_a = BaseCarHarness("Subaru A connector")
@@ -195,7 +196,7 @@ def all_parts(self):
195196
class CommonFootnote(Enum):
196197
EXP_LONG_AVAIL = CarFootnote(
197198
"openpilot Longitudinal Control (Alpha) is available behind a toggle; " +
198-
"the toggle is only available in non-release branches such as `devel` or `master-ci`.",
199+
"the toggle is only available in non-release branches such as `devel` or `nightly-dev`.",
199200
Column.LONGITUDINAL, docs_only=True)
200201
EXP_LONG_DSU = CarFootnote(
201202
"By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. " +
@@ -380,15 +381,15 @@ def get_detail_sentence(self, CP):
380381
sentence_builder += " This car may not be able to take tight turns on its own."
381382

382383
# experimental mode
383-
exp_link = "<a href='https://blog.comma.ai/090release/#experimental-mode' target='_blank' class='link-light-new-regular-text'>Experimental mode</a>"
384+
exp_link = "<a href='https://blog.comma.ai/090release/#experimental-mode' target='_blank' class='highlight'>Experimental mode</a>"
384385
if CP.openpilotLongitudinalControl and not CP.experimentalLongitudinalAvailable:
385386
sentence_builder += f" Traffic light and stop sign handling is also available in {exp_link}."
386387

387388
return sentence_builder.format(car_model=f"{self.make} {self.model}", alc=alc, acc=acc)
388389

389390
else:
390391
if CP.carFingerprint == "COMMA_BODY":
391-
return "The body is a robotics dev kit that can run openpilot. <a href='https://www.commabody.com'>Learn more.</a>"
392+
return "The body is a robotics dev kit that can run openpilot. <a href='https://www.commabody.com' target='_blank' class='highlight'>Learn more.</a>"
392393
else:
393394
raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}")
394395

opendbc/car/ford/carcontroller.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,32 @@
99
LongCtrlState = structs.CarControl.Actuators.LongControlState
1010
VisualAlert = structs.CarControl.HUDControl.VisualAlert
1111

12+
# ISO 11270
13+
ISO_LATERAL_ACCEL = 3.0 # m/s^2 # TODO: import from test lateral limits file?
1214

13-
def apply_ford_curvature_limits(apply_curvature, apply_curvature_last, current_curvature, v_ego_raw, steering_angle, lat_active):
15+
# Limit to average banked road since safety doesn't have the roll
16+
EARTH_G = 9.81
17+
AVERAGE_ROAD_ROLL = 0.06 # ~3.4 degrees, 6% superelevation
18+
MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL - (EARTH_G * AVERAGE_ROAD_ROLL) # ~2.4 m/s^2
19+
20+
21+
def apply_ford_curvature_limits(apply_curvature, apply_curvature_last, current_curvature, v_ego_raw, steering_angle, lat_active, CP):
1422
# No blending at low speed due to lack of torque wind-up and inaccurate current curvature
1523
if v_ego_raw > 9:
1624
apply_curvature = np.clip(apply_curvature, current_curvature - CarControllerParams.CURVATURE_ERROR,
1725
current_curvature + CarControllerParams.CURVATURE_ERROR)
1826

1927
# Curvature rate limit after driver torque limit
20-
return apply_std_steer_angle_limits(apply_curvature, apply_curvature_last, v_ego_raw, steering_angle, lat_active, CarControllerParams)
28+
apply_curvature = apply_std_steer_angle_limits(apply_curvature, apply_curvature_last, v_ego_raw, steering_angle, lat_active, CarControllerParams.ANGLE_LIMITS)
29+
30+
# Ford Q4/CAN FD has more torque available compared to Q3/CAN so we limit it based on lateral acceleration.
31+
# Safety is not aware of the road roll so we subtract a conservative amount at all times
32+
if CP.flags & FordFlags.CANFD:
33+
# Limit curvature to conservative max lateral acceleration
34+
curvature_accel_limit = MAX_LATERAL_ACCEL / (max(v_ego_raw, 1) ** 2)
35+
apply_curvature = float(np.clip(apply_curvature, -curvature_accel_limit, curvature_accel_limit))
36+
37+
return apply_curvature
2138

2239

2340
def apply_creep_compensation(accel: float, v_ego: float) -> float:
@@ -71,7 +88,7 @@ def update(self, CC, CC_SP, CS, now_nanos):
7188
# apply rate limits, curvature error limit, and clip to signal range
7289
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
7390
self.apply_curvature_last = apply_ford_curvature_limits(actuators.curvature, self.apply_curvature_last, current_curvature,
74-
CS.out.vEgoRaw, 0., CC.latActive)
91+
CS.out.vEgoRaw, 0., CC.latActive, self.CP)
7592

7693
if self.CP.flags & FordFlags.CANFD:
7794
# TODO: extended mode

opendbc/car/ford/fingerprints.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
106106
],
107107
(Ecu.eps, 0x730, None): [
108-
b'RL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
108+
b'RL38-14D003-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
109109
],
110110
},
111111
CAR.FORD_MUSTANG_MACH_E_MK1: {

opendbc/car/ford/interface.py

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
from opendbc.car import Bus, get_safety_config, structs
3+
from opendbc.car.carlog import carlog
34
from opendbc.car.common.conversions import Conversions as CV
45
from opendbc.car.ford.fordcan import CanBus
56
from opendbc.car.ford.values import CarControllerParams, DBC, Ecu, FordFlags, RADAR, FordSafetyFlags
@@ -47,17 +48,26 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
4748

4849
if ret.flags & FordFlags.CANFD:
4950
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.CANFD.value
51+
52+
# TRON (SecOC) platforms are not supported
53+
# LateralMotionControl2, ACCDATA are 16 bytes on these platforms
54+
if len(fingerprint[CAN.camera]):
55+
if fingerprint[CAN.camera].get(0x3d6) != 8 or fingerprint[CAN.camera].get(0x186) != 8:
56+
carlog.error('dashcamOnly: SecOC is unsupported')
57+
ret.dashcamOnly = True
5058
else:
5159
# Lock out if the car does not have needed lateral and longitudinal control APIs.
5260
# Note that we also check CAN for adaptive cruise, but no known signal for LCA exists
5361
pscm_config = next((fw for fw in car_fw if fw.ecu == Ecu.eps and b'\x22\xDE\x01' in fw.request), None)
5462
if pscm_config:
5563
if len(pscm_config.fwVersion) != 24:
64+
carlog.error('dashcamOnly: Invalid EPS FW version')
5665
ret.dashcamOnly = True
5766
else:
5867
config_tja = pscm_config.fwVersion[7] # Traffic Jam Assist
5968
config_lca = pscm_config.fwVersion[8] # Lane Centering Assist
6069
if config_tja != 0xFF or config_lca != 0xFF:
70+
carlog.error('dashcamOnly: Car lacks required lateral control APIs')
6171
ret.dashcamOnly = True
6272

6373
# Auto Transmission: 0x732 ECU or Gear_Shift_by_Wire_FD1

0 commit comments

Comments
 (0)