diff --git a/.github/workflows/auto_pr_review.yaml b/.github/workflows/auto_pr_review.yaml
index abcebd1d64..4585b98244 100644
--- a/.github/workflows/auto_pr_review.yaml
+++ b/.github/workflows/auto_pr_review.yaml
@@ -33,11 +33,12 @@ jobs:
already-exists-comment: "Your PR should be made against the `master` branch"
# Welcome comment
- - name: comment
- uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6
+ - name: "First timers PR"
+ uses: actions/first-interaction@v1
if: github.event.pull_request.head.repo.full_name != 'commaai/opendbc'
with:
- message: |
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ pr-message: |
Thanks for contributing to opendbc! In order for us to review your PR as quickly as possible, check the following:
* Convert your PR to a draft unless it's ready to review
@@ -46,5 +47,3 @@ jobs:
* the goal is clearly stated in the description
* all the tests are passing
* include a route or your device' dongle ID if relevant
- comment_tag: run_id
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c1f2b1e6a6..493a5de0ec 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -13,7 +13,7 @@ on:
jobs:
unit-tests:
name: unit tests
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
timeout-minutes: 1
#strategy:
# fail-fast: false
@@ -21,24 +21,32 @@ jobs:
# run: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-python@v5
- with:
- cache: 'pip'
- python-version: '3.11'
- - run: pip install -e .[testing,docs]
- - run: scons -j$(nproc)
- - run: pytest -n logical --durations=0
+ - name: setup python
+ run: |
+ curl -LsSf https://astral.sh/uv/install.sh | sh
+ uv venv
+ # TODO: remove setuptools once https://github.com/cython/cython/issues/5751 is fixed
+ uv pip install -e .[testing,docs] setuptools
+ - run: uv run scons -j$(nproc)
+ - run: uv run pytest .
static-analysis:
name: static analysis
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
timeout-minutes: 1
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-python@v5
- with:
- cache: 'pip'
- python-version: '3.11'
- run: sudo apt install --no-install-recommends -y cppcheck
- - run: pip install -e .
- - uses: pre-commit/action@v3.0.1
+ - name: setup python
+ run: |
+ curl -LsSf https://astral.sh/uv/install.sh | sh
+ uv venv
+ uv pip install -e . pre-commit
+ - name: cache pre-commit environments
+ uses: actions/cache@v4
+ with:
+ path: ~/.cache/pre-commit
+ key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-pre-commit-
+ - run: uv run pre-commit run --all
diff --git a/.gitignore b/.gitignore
index bfe2238555..d66bd7dcb5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,8 @@
.sconsign.dblite
.hypothesis
*.egg-info/
+*.html
+uv.lock
opendbc/can/*.so
opendbc/can/*.a
diff --git a/README.md b/README.md
index 1aa116fa09..d2139b54b5 100644
--- a/README.md
+++ b/README.md
@@ -26,3 +26,24 @@ pytest .
# Run the linter
pre-commit run --all-files
```
+
+[`examples/`](examples/) contains small example programs that can read state from the car and control the steering, gas, and brakes.
+[`examples/joystick.py`](examples/joystick.py) allows you to control a car with a joystick.
+
+## Roadmap
+
+This project was pulled out from [openpilot](https://github.com/commaai/openpilot).
+We're still figuring out the exact API between openpilot and opendbc, so some of these
+may end up going in openpilot.
+
+* Extend support to every car with LKAS + ACC interfaces
+* Automatic lateral and longitudinal control/tuning evaluation
+* Auto-tuning for [lateral](https://blog.comma.ai/090release/#torqued-an-auto-tuner-for-lateral-control) and longitudinal control
+* [Automatic Emergency Braking](https://en.wikipedia.org/wiki/Automated_emergency_braking_system)
+* `pip install opendbc`
+* 100% type coverage
+* 100% line coverage
+* Make car ports easier: refactors, tools, tests, and docs
+* Expose the state of all supported cars better: https://github.com/commaai/opendbc/issues/1144
+
+Contributions towards anything here is welcome. Join the [Discord](https://discord.comma.ai)!
diff --git a/examples/joystick.py b/examples/joystick.py
new file mode 100755
index 0000000000..0167c8d201
--- /dev/null
+++ b/examples/joystick.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+import time
+import threading
+import argparse
+import numpy as np
+from pprint import pprint
+from inputs import get_gamepad
+
+from kbhit import KBHit
+
+from opendbc.car.structs import CarControl
+from opendbc.car.panda_runner import PandaRunner
+
+class Keyboard:
+ def __init__(self):
+ self.kb = KBHit()
+ self.axis_increment = 0.05 # 5% of full actuation each key press
+ self.axes_map = {'w': 'gb', 's': 'gb',
+ 'a': 'steer', 'd': 'steer'}
+ self.axes_values = {'gb': 0., 'steer': 0.}
+ self.axes_order = ['gb', 'steer']
+ self.cancel = False
+
+ def update(self):
+ key = self.kb.getch().lower()
+ print(key)
+ self.cancel = False
+ if key == 'r':
+ self.axes_values = {ax: 0. for ax in self.axes_values}
+ elif key == 'c':
+ self.cancel = True
+ elif key in self.axes_map:
+ axis = self.axes_map[key]
+ incr = self.axis_increment if key in ['w', 'a'] else -self.axis_increment
+ self.axes_values[axis] = float(np.clip(self.axes_values[axis] + incr, -1, 1))
+ else:
+ return False
+ return True
+
+class Joystick:
+ def __init__(self, gamepad=False):
+ # TODO: find a way to get this from API, perhaps "inputs" doesn't support it
+ if gamepad:
+ self.cancel_button = 'BTN_NORTH' # (BTN_NORTH=X, ABS_RZ=Right Trigger)
+ accel_axis = 'ABS_Y'
+ steer_axis = 'ABS_RX'
+ else:
+ self.cancel_button = 'BTN_TRIGGER'
+ accel_axis = 'ABS_Y'
+ steer_axis = 'ABS_RX'
+ self.min_axis_value = {accel_axis: 0., steer_axis: 0.}
+ self.max_axis_value = {accel_axis: 255., steer_axis: 255.}
+ self.axes_values = {accel_axis: 0., steer_axis: 0.}
+ self.axes_order = [accel_axis, steer_axis]
+ self.cancel = False
+
+ def update(self):
+ joystick_event = get_gamepad()[0]
+ event = (joystick_event.code, joystick_event.state)
+ if event[0] == self.cancel_button:
+ if event[1] == 1:
+ self.cancel = True
+ elif event[1] == 0: # state 0 is falling edge
+ self.cancel = False
+ elif event[0] in self.axes_values:
+ self.max_axis_value[event[0]] = max(event[1], self.max_axis_value[event[0]])
+ self.min_axis_value[event[0]] = min(event[1], self.min_axis_value[event[0]])
+
+ norm = -float(np.interp(event[1], [self.min_axis_value[event[0]], self.max_axis_value[event[0]]], [-1., 1.]))
+ self.axes_values[event[0]] = norm if abs(norm) > 0.05 else 0. # center can be noisy, deadzone of 5%
+ else:
+ return False
+ return True
+
+def joystick_thread(joystick):
+ while True:
+ joystick.update()
+
+def main(joystick):
+ threading.Thread(target=joystick_thread, args=(joystick,), daemon=True).start()
+ with PandaRunner() as p:
+ CC = CarControl(enabled=False)
+ while True:
+ CC.actuators.accel = float(4.0*np.clip(joystick.axes_values['gb'], -1, 1))
+ CC.actuators.steer = float(np.clip(joystick.axes_values['steer'], -1, 1))
+ pprint(CC)
+
+ p.read()
+ p.write(CC)
+
+ # 100Hz
+ time.sleep(0.01)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Test the car interface with a joystick. Uses keyboard by default.',
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ parser.add_argument('--mode', choices=['keyboard', 'gamepad', 'joystick'], default='keyboard')
+ args = parser.parse_args()
+
+ print()
+ joystick: Keyboard | Joystick
+ if args.mode == 'keyboard':
+ print('Gas/brake control: `W` and `S` keys')
+ print('Steering control: `A` and `D` keys')
+ print('Buttons')
+ print('- `R`: Resets axes')
+ print('- `C`: Cancel cruise control')
+ joystick = Keyboard()
+ else:
+ joystick = Joystick(gamepad=(args.mode == 'gamepad'))
+ main(joystick)
\ No newline at end of file
diff --git a/examples/kbhit.py b/examples/kbhit.py
new file mode 100755
index 0000000000..35f67b4771
--- /dev/null
+++ b/examples/kbhit.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+import sys
+import termios
+import atexit
+from select import select
+
+STDIN_FD = sys.stdin.fileno()
+
+class KBHit:
+ def __init__(self) -> None:
+ self.set_kbhit_terminal()
+
+ def set_kbhit_terminal(self) -> None:
+ # Save the terminal settings
+ self.old_term = termios.tcgetattr(STDIN_FD)
+ self.new_term = self.old_term.copy()
+
+ # New terminal setting unbuffered
+ self.new_term[3] &= ~(termios.ICANON | termios.ECHO)
+ termios.tcsetattr(STDIN_FD, termios.TCSAFLUSH, self.new_term)
+
+ # Support normal-terminal reset at exit
+ atexit.register(self.set_normal_term)
+
+ def set_normal_term(self) -> None:
+ termios.tcsetattr(STDIN_FD, termios.TCSAFLUSH, self.old_term)
+
+ @staticmethod
+ def getch() -> str:
+ return sys.stdin.read(1)
+
+ @staticmethod
+ def getarrow() -> int:
+ c = sys.stdin.read(3)[2]
+ vals = [65, 67, 66, 68]
+ return vals.index(ord(c))
+
+ @staticmethod
+ def kbhit():
+ ''' Returns True if keyboard character was hit, False otherwise.
+ '''
+ return select([sys.stdin], [], [], 0)[0] != []
+
+
+if __name__ == "__main__":
+
+ kb = KBHit()
+
+ print('Hit any key, or ESC to exit')
+
+ while True:
+
+ if kb.kbhit():
+ c = kb.getch()
+ if c == '\x1b': # ESC
+ break
+ print(c)
+
+ kb.set_normal_term()
diff --git a/examples/longitudinal-profiles.py b/examples/longitudinal-profiles.py
new file mode 100755
index 0000000000..e7a366d1e2
--- /dev/null
+++ b/examples/longitudinal-profiles.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python3
+import io
+import os
+import time
+import base64
+import argparse
+import numpy as np
+import matplotlib.pyplot as plt
+from collections import defaultdict
+from dataclasses import dataclass, asdict
+from pathlib import Path
+
+from opendbc.car.structs import CarControl
+from opendbc.car.panda_runner import PandaRunner
+from opendbc.car.common.conversions import Conversions
+
+DT = 0.01 # step time (s)
+
+# TODOs
+# - support lateral maneuvers
+# - setup: show countdown?
+
+
+class Ratekeeper:
+ def __init__(self, rate: float) -> None:
+ self.interval = 1. / rate
+ self.next_frame_time = time.monotonic() + self.interval
+
+ def keep_time(self) -> bool:
+ lagged = False
+ remaining = self.next_frame_time - time.monotonic()
+ self.next_frame_time += self.interval
+ if remaining < -0.1:
+ print(f"lagging by {-remaining * 1000:.2f} ms")
+ lagged = True
+
+ if remaining > 0:
+ time.sleep(remaining)
+ return lagged
+
+@dataclass
+class Action:
+ accel: float # m/s^2
+ duration: float # seconds
+ longControlState: CarControl.Actuators.LongControlState = CarControl.Actuators.LongControlState.pid
+
+ def get_msgs(self):
+ return [
+ (t, CarControl(
+ enabled=True,
+ longActive=True,
+ actuators=CarControl.Actuators(
+ accel=self.accel,
+ longControlState=self.longControlState,
+ ),
+ ))
+ for t in np.linspace(0, self.duration, int(self.duration/DT))
+ ]
+
+@dataclass
+class Maneuver:
+ description: str
+ actions: list[Action]
+ repeat: int = 1
+ initial_speed: float = 0. # m/s
+
+ def get_msgs(self):
+ t0 = 0
+ for action in self.actions:
+ for lt, msg in action.get_msgs():
+ yield lt + t0, msg
+ t0 += lt
+
+MANEUVERS = [
+ Maneuver(
+ "creep: alternate between +1m/ss and -1m/ss",
+ [
+ Action(1, 2), Action(-1, 2),
+ Action(1, 2), Action(-1, 2),
+ Action(1, 2), Action(-1, 2),
+ ],
+ repeat=2,
+ initial_speed=0.,
+ ),
+ Maneuver(
+ "brake step response: -1m/ss from 20mph",
+ [Action(0, 2), Action(-1, 3)],
+ repeat=3,
+ initial_speed=20. * Conversions.MPH_TO_MS,
+ ),
+ Maneuver(
+ "brake step response: -4m/ss from 20mph",
+ [Action(0, 2), Action(-4, 3)],
+ repeat=3,
+ initial_speed=20. * Conversions.MPH_TO_MS,
+ ),
+ Maneuver(
+ "gas step response: +1m/ss from 20mph",
+ [Action(0, 2), Action(1, 3)],
+ repeat=3,
+ initial_speed=20. * Conversions.MPH_TO_MS,
+ ),
+ Maneuver(
+ "gas step response: +4m/ss from 20mph",
+ [Action(0, 2), Action(4, 3)],
+ repeat=3,
+ initial_speed=20. * Conversions.MPH_TO_MS,
+ ),
+]
+
+def report(args, logs, fp):
+ output_path = Path(__file__).resolve().parent / "longitudinal_reports"
+ output_fn = args.output or output_path / f"{fp}_{time.strftime('%Y%m%d-%H_%M_%S')}.html"
+ output_path.mkdir(exist_ok=True)
+ with open(output_fn, "w") as f:
+ f.write("
Longitudinal maneuver report
\n")
+ f.write(f"{fp}
\n")
+ if args.desc:
+ f.write(f"{args.desc}
")
+ for description, runs in logs.items():
+ f.write("\n")
+ f.write(f"{description}
\n")
+ for run, log in runs.items():
+ f.write(f"Run #{int(run)+1}
\n")
+ plt.rcParams['font.size'] = 40
+ fig = plt.figure(figsize=(30, 25))
+ ax = fig.subplots(4, 1, sharex=True, gridspec_kw={'hspace': 0, 'height_ratios': [5, 3, 1, 1]})
+
+ ax[0].grid(linewidth=4)
+ ax[0].plot(log["t"], log["carControl.actuators.accel"], label='accel command', linewidth=6)
+ ax[0].plot(log["t"], log["carState.aEgo"], label='aEgo', linewidth=6)
+ ax[0].set_ylabel('Acceleration (m/s^2)')
+ #ax[0].set_ylim(-6.5, 6.5)
+ ax[0].legend()
+
+ ax[1].grid(linewidth=4)
+ ax[1].plot(log["t"], log["carState.vEgo"], 'g', label='vEgo', linewidth=6)
+ ax[1].set_ylabel('Velocity (m/s)')
+ ax[1].legend()
+
+ ax[2].plot(log["t"], log["carControl.enabled"], label='enabled', linewidth=6)
+ ax[3].plot(log["t"], log["carState.gasPressed"], label='gasPressed', linewidth=6)
+ ax[3].plot(log["t"], log["carState.brakePressed"], label='brakePressed', linewidth=6)
+ for i in (2, 3):
+ ax[i].set_yticks([0, 1], minor=False)
+ ax[i].set_ylim(-1, 2)
+ ax[i].legend()
+
+ ax[-1].set_xlabel("Time (s)")
+ fig.tight_layout()
+
+ buffer = io.BytesIO()
+ fig.savefig(buffer, format='png')
+ buffer.seek(0)
+ f.write(f"\n")
+
+ import json
+ f.write(f"{json.dumps(logs)}
")
+ print(f"\nReport written to {output_fn}\n")
+
+def main(args):
+ with PandaRunner() as p:
+ print("\n\n")
+
+ maneuvers = MANEUVERS
+ if len(args.maneuvers):
+ maneuvers = [MANEUVERS[i-1] for i in set(args.maneuvers)]
+
+ logs = {}
+ rk = Ratekeeper(int(1./DT))
+ for i, m in enumerate(maneuvers):
+ logs[m.description] = {}
+ print(f"Running {i+1}/{len(MANEUVERS)} '{m.description}'")
+ for run in range(m.repeat):
+ print(f"- run #{run}")
+ print("- setting up, engage cruise")
+ ready_cnt = 0
+ for _ in range(int(2*60./DT)):
+ cs = p.read(strict=False)
+ cc = CarControl(
+ enabled=True,
+ longActive=True,
+ actuators=CarControl.Actuators(
+ accel=(m.initial_speed - cs.vEgo)*0.8,
+ longControlState=CarControl.Actuators.LongControlState.pid,
+ ),
+ )
+ if m.initial_speed < 0.1:
+ cc.actuators.accel = -2
+ cc.actuators.longControlState = CarControl.Actuators.LongControlState.stopping
+ p.write(cc)
+
+ ready = cs.cruiseState.enabled and not cs.cruiseState.standstill and ((m.initial_speed - 0.6) < cs.vEgo < (m.initial_speed + 0.6))
+ ready_cnt = (ready_cnt+1) if ready else 0
+ if ready_cnt > (2./DT):
+ break
+ rk.keep_time()
+ else:
+ print("ERROR: failed to setup")
+ continue
+
+ print("- executing maneuver")
+ logs[m.description][run] = defaultdict(list)
+ for t, cc in m.get_msgs():
+ cs = p.read()
+ p.write(cc)
+
+ logs[m.description][run]["t"].append(t)
+ to_log = {"carControl": cc, "carState": cs, "carControl.actuators": cc.actuators,
+ "carControl.cruiseControl": cc.cruiseControl, "carState.cruiseState": cs.cruiseState}
+ for k, v in to_log.items():
+ for k2, v2 in asdict(v).items():
+ logs[m.description][run][f"{k}.{k2}"].append(v2)
+
+ rk.keep_time()
+
+ print("writing out report")
+ with open('/tmp/logs.json', 'w') as f:
+ import json
+ json.dump(logs, f, indent=2)
+ report(args, logs, p.CI.CP.carFingerprint)
+
+
+if __name__ == "__main__":
+ maneuver_help = "\n".join([f"{i+1}. {m.description}" for i, m in enumerate(MANEUVERS)])
+ parser = argparse.ArgumentParser(description="A tool for longitudinal control testing.",
+ formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument('--desc', help="Extra description to include in report.")
+ parser.add_argument('--output', help="Write out report to this file.", default=None)
+ parser.add_argument('maneuvers', nargs='*', type=int, default=None, help=f'Deafult is all.\n{maneuver_help}')
+ args = parser.parse_args()
+ print(args)
+
+ if "REPORT_TEST" in os.environ:
+ with open(os.environ["REPORT_TEST"]) as f:
+ import json
+ logs = json.loads(f.read().split("none'>")[1].split('')[0])
+ report(args, logs, "testing")
+ exit()
+
+ assert args.output is None or args.output.endswith(".html"), "Output filename must end with '.html'"
+
+ main(args)
diff --git a/opendbc/car/car_helpers.py b/opendbc/car/car_helpers.py
index f94c88ba8e..9d518be4d2 100644
--- a/opendbc/car/car_helpers.py
+++ b/opendbc/car/car_helpers.py
@@ -20,8 +20,9 @@ def load_interfaces(brand_names):
CarInterface = __import__(path + '.interface', fromlist=['CarInterface']).CarInterface
CarState = __import__(path + '.carstate', fromlist=['CarState']).CarState
CarController = __import__(path + '.carcontroller', fromlist=['CarController']).CarController
+ RadarInterface = __import__(path + '.radar_interface', fromlist=['RadarInterface']).RadarInterface
for model_name in brand_names[brand_name]:
- ret[model_name] = (CarInterface, CarController, CarState)
+ ret[model_name] = (CarInterface, CarController, CarState, RadarInterface)
return ret
@@ -149,10 +150,15 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
def get_car_interface(CP: CarParams):
- CarInterface, CarController, CarState = interfaces[CP.carFingerprint]
+ CarInterface, CarController, CarState, _ = interfaces[CP.carFingerprint]
return CarInterface(CP, CarController, CarState)
+def get_radar_interface(CP: CarParams):
+ _, _, _, RadarInterface = interfaces[CP.carFingerprint]
+ return RadarInterface(CP)
+
+
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, experimental_long_allowed: bool,
num_pandas: int = 1, cached_params: CarParams | None = None):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params)
@@ -161,7 +167,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
carlog.error({"event": "car doesn't match any fingerprints", "fingerprints": repr(fingerprints)})
candidate = "MOCK"
- CarInterface, _, _ = interfaces[candidate]
+ CarInterface, _, _, _ = interfaces[candidate]
CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, docs=False)
CP.carVin = vin
CP.carFw = car_fw
@@ -173,6 +179,6 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
def get_demo_car_params():
platform = MOCK.MOCK
- CarInterface, _, _ = interfaces[platform]
+ CarInterface, _, _, _ = interfaces[platform]
CP = CarInterface.get_non_essential_params(platform)
return CP
diff --git a/opendbc/car/docs_definitions.py b/opendbc/car/docs_definitions.py
index db022f9143..5e0fa28a00 100644
--- a/opendbc/car/docs_definitions.py
+++ b/opendbc/car/docs_definitions.py
@@ -114,6 +114,8 @@ class CarHarness(EnumBase):
custom = BaseCarHarness("Developer connector")
obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable, Cable.long_obdc_cable], has_connector=False)
gm = BaseCarHarness("GM connector", parts=[Accessory.harness_box])
+ gmsdgm = BaseCarHarness("GM SDGM connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable,
+ Cable.usbc_coupler, Accessory.comma_power_v2])
nissan_a = BaseCarHarness("Nissan A connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable, Cable.usbc_coupler])
nissan_b = BaseCarHarness("Nissan B connector", parts=[Accessory.harness_box, Cable.rj45_cable_7ft, Cable.long_obdc_cable, Cable.usbc_coupler])
mazda = BaseCarHarness("Mazda connector")
diff --git a/opendbc/car/fingerprints.py b/opendbc/car/fingerprints.py
index 1670ac6342..4619eb5443 100644
--- a/opendbc/car/fingerprints.py
+++ b/opendbc/car/fingerprints.py
@@ -314,6 +314,7 @@ def all_legacy_fingerprint_cars():
"VOLKSWAGEN CADDY 3RD GEN": VW.VOLKSWAGEN_CADDY_MK3,
"VOLKSWAGEN CRAFTER 2ND GEN": VW.VOLKSWAGEN_CRAFTER_MK2,
"VOLKSWAGEN GOLF 7TH GEN": VW.VOLKSWAGEN_GOLF_MK7,
+ "VOLKSWAGEN JETTA 6TH GEN": VW.VOLKSWAGEN_JETTA_MK6,
"VOLKSWAGEN JETTA 7TH GEN": VW.VOLKSWAGEN_JETTA_MK7,
"VOLKSWAGEN PASSAT 8TH GEN": VW.VOLKSWAGEN_PASSAT_MK8,
"VOLKSWAGEN PASSAT NMS": VW.VOLKSWAGEN_PASSAT_NMS,
diff --git a/opendbc/car/gm/carstate.py b/opendbc/car/gm/carstate.py
index cd30639787..318646bbe2 100644
--- a/opendbc/car/gm/carstate.py
+++ b/opendbc/car/gm/carstate.py
@@ -5,7 +5,7 @@
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.common.numpy_fast import mean
from opendbc.car.interfaces import CarStateBase
-from opendbc.car.gm.values import DBC, AccState, CanBus, CruiseButtons, STEER_THRESHOLD
+from opendbc.car.gm.values import DBC, AccState, CanBus, CruiseButtons, STEER_THRESHOLD, SDGM_CAR
ButtonType = structs.CarState.ButtonEvent.Type
TransmissionType = structs.CarParams.TransmissionType
@@ -119,7 +119,8 @@ def update(self, pt_cp, cam_cp, _, __, loopback_cp) -> structs.CarState:
ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL
if self.CP.networkLocation == NetworkLocation.fwdCamera:
ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS
- ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
+ if self.CP.carFingerprint not in SDGM_CAR:
+ ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
# openpilot controls nonAdaptive when not pcmCruise
if self.CP.pcmCruise:
ret.cruiseState.nonAdaptive = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCruiseState"] not in (2, 3)
@@ -144,10 +145,13 @@ def get_cam_can_parser(CP):
messages = []
if CP.networkLocation == NetworkLocation.fwdCamera:
messages += [
- ("AEBCmd", 10),
("ASCMLKASteeringCmd", 10),
("ASCMActiveCruiseControlStatus", 25),
]
+ if CP.carFingerprint not in SDGM_CAR:
+ messages += [
+ ("AEBCmd", 10),
+ ]
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus.CAMERA)
diff --git a/opendbc/car/gm/fingerprints.py b/opendbc/car/gm/fingerprints.py
index 57dbff41b6..784ae01d40 100644
--- a/opendbc/car/gm/fingerprints.py
+++ b/opendbc/car/gm/fingerprints.py
@@ -57,6 +57,14 @@
{
190: 6, 201: 8, 211: 2, 717: 5, 241: 6, 451: 8, 298: 8, 452: 8, 453: 6, 479: 3, 485: 8, 249: 8, 500: 6, 587: 8, 1611: 8, 289: 8, 481: 7, 193: 8, 197: 8, 209: 7, 455: 7, 489: 8, 309: 8, 413: 8, 501: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 311: 8, 510: 8, 528: 5, 532: 6, 715: 8, 560: 8, 562: 8, 707: 8, 789: 5, 869: 4, 880: 6, 761: 7, 840: 5, 842: 5, 844: 8, 313: 8, 381: 8, 386: 8, 810: 8, 322: 7, 384: 4, 800: 6, 1033: 7, 1034: 7, 1296: 4, 753: 5, 388: 8, 288: 5, 497: 8, 463: 3, 304: 3, 977: 8, 1001: 8, 1280: 4, 320: 4, 352: 5, 563: 5, 565: 5, 1221: 5, 1011: 6, 1017: 8, 1020: 8, 1249: 8, 1300: 8, 328: 1, 1217: 8, 1233: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1930: 7, 1271: 8
}],
+ CAR.CADILLAC_XT4: [
+ {
+ 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 719: 5, 761: 7, 806: 1, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 880: 6, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 5, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1037: 5, 1105: 5, 1187: 5, 1195: 3, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1276: 2, 1277: 7, 1278: 4, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1517: 8, 1601: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 8, 1924: 8, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1984: 8, 1988: 8, 2000: 8, 2001: 8, 2002: 8, 2016: 8, 2017: 8, 2018: 8, 2020: 8, 2021: 8, 2024: 8, 2026: 8
+ }],
+ CAR.CHEVROLET_VOLT_2019: [
+ {
+ 170: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 331: 3, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 7, 567: 5, 573: 1, 577: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 715: 8, 717: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 5, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1268: 2, 1273: 3, 1275: 3, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1513: 8, 1516: 8, 1517: 8, 1601: 8, 1609: 8, 1611: 8, 1618: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1871: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1920: 8, 1922: 7, 1927: 7, 1930: 7, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1988: 8, 1990: 8, 2000: 8, 2001: 8, 2004: 8, 2017: 8, 2018: 8, 2020: 8, 2021: 8, 2023: 8, 2025: 8, 2028: 8, 2031: 8
+ }],
}
FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = {
diff --git a/opendbc/car/gm/interface.py b/opendbc/car/gm/interface.py
index 410ca590a1..65eb9134ef 100755
--- a/opendbc/car/gm/interface.py
+++ b/opendbc/car/gm/interface.py
@@ -7,7 +7,7 @@
from opendbc.car.common.basedir import BASEDIR
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.radar_interface import RADAR_HEADER_MSG
-from opendbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus
+from opendbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, CanBus
from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel
TransmissionType = structs.CarParams.TransmissionType
@@ -93,13 +93,13 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
ret.longitudinalTuning.kiBP = [5., 35.]
- if candidate in CAMERA_ACC_CAR:
- ret.experimentalLongitudinalAvailable = True
+ if candidate in (CAMERA_ACC_CAR | SDGM_CAR):
+ ret.experimentalLongitudinalAvailable = candidate not in SDGM_CAR
ret.networkLocation = NetworkLocation.fwdCamera
ret.radarUnavailable = True # no radar
ret.pcmCruise = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
- ret.minEnableSpeed = 5 * CV.KPH_TO_MS
+ ret.minEnableSpeed = -1 if candidate in SDGM_CAR else 5 * CV.KPH_TO_MS
ret.minSteerSpeed = 10 * CV.KPH_TO_MS
# Tuning for experimental long
@@ -127,7 +127,7 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
# These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is
- # added to openpilot/selfdrive/car/tests/routes.py, we can remove it from this list.
+ # added to opendbc/car/tests/routes.py, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.CHEVROLET_MALIBU, CAR.BUICK_REGAL} or \
(ret.networkLocation == NetworkLocation.gateway and ret.radarUnavailable)
@@ -191,4 +191,13 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
+ elif candidate == CAR.CADILLAC_XT4:
+ ret.steerActuatorDelay = 0.2
+ ret.minSteerSpeed = 30 * CV.MPH_TO_MS
+ CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
+
+ elif candidate == CAR.CHEVROLET_VOLT_2019:
+ ret.steerActuatorDelay = 0.2
+ CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
+
return ret
diff --git a/opendbc/car/gm/values.py b/opendbc/car/gm/values.py
index 1fbee8c256..b7196ce1d2 100644
--- a/opendbc/car/gm/values.py
+++ b/opendbc/car/gm/values.py
@@ -36,7 +36,7 @@ def __init__(self, CP):
self.ZERO_GAS = 2048 # Coasting
self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen
- if CP.carFingerprint in CAMERA_ACC_CAR:
+ if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR):
self.MAX_GAS = 3400
self.MAX_ACC_REGEN = 1514
self.INACTIVE_REGEN = 1554
@@ -65,7 +65,10 @@ class GMCarDocs(CarDocs):
def init_make(self, CP: CarParams):
if CP.networkLocation == CarParams.NetworkLocation.fwdCamera:
- self.car_parts = CarParts.common([CarHarness.gm])
+ if CP.carFingerprint in SDGM_CAR:
+ self.car_parts = CarParts.common([CarHarness.gmsdgm])
+ else:
+ self.car_parts = CarParts.common([CarHarness.gm])
else:
self.car_parts = CarParts.common([CarHarness.obd_ii])
@@ -86,6 +89,12 @@ def init(self):
# ASCM is supported, but due to a janky install and hardware configuration, we are not showing in the car docs
self.car_docs = []
+@dataclass
+class GMSDGMPlatformConfig(GMPlatformConfig):
+ def init(self):
+ # Don't show in docs until the harness is sold. See https://github.com/commaai/openpilot/issues/32471
+ self.car_docs = []
+
class CAR(Platforms):
HOLDEN_ASTRA = GMASCMPlatformConfig(
@@ -150,6 +159,14 @@ class CAR(Platforms):
[GMCarDocs("Chevrolet Trailblazer 2021-22")],
GMCarSpecs(mass=1345, wheelbase=2.64, steerRatio=16.8, centerToFrontRatio=0.4, tireStiffnessFactor=1.0),
)
+ CADILLAC_XT4 = GMSDGMPlatformConfig(
+ [GMCarDocs("Cadillac XT4 2023", "Driver Assist Package")],
+ CarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
+ )
+ CHEVROLET_VOLT_2019 = GMSDGMPlatformConfig(
+ [GMCarDocs("Chevrolet Volt 2019", "Adaptive Cruise Control (ACC) & LKAS")],
+ GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=15.7, centerToFrontRatio=0.45),
+ )
class CruiseButtons:
@@ -224,11 +241,15 @@ class CanBus:
extra_ecus=[(Ecu.fwdCamera, 0x24b, None)],
)
-EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_BOLT_EUV}
+# TODO: detect most of these sets live
+EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_BOLT_EUV}
# We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness)
CAMERA_ACC_CAR = {CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_TRAILBLAZER}
+# We're integrated at the Safety Data Gateway Module on these cars
+SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CHEVROLET_VOLT_2019}
+
STEER_THRESHOLD = 1.0
DBC = CAR.create_dbc_map()
diff --git a/opendbc/car/honda/hondacan.py b/opendbc/car/honda/hondacan.py
index f843d35708..2a9465b65b 100644
--- a/opendbc/car/honda/hondacan.py
+++ b/opendbc/car/honda/hondacan.py
@@ -144,7 +144,7 @@ def create_ui_commands(packer, CAN, CP, enabled, pcm_speed, hud, is_metric, acc_
'CRUISE_SPEED': hud.v_cruise,
'ENABLE_MINI_CAR': 1 if enabled else 0,
# only moves the lead car without ACC_ON
- 'HUD_DISTANCE': (hud.lead_distance_bars + 1) % 4, # wraps to 0 at 4 bars
+ 'HUD_DISTANCE': hud.lead_distance_bars, # wraps to 0 at 4 bars
'IMPERIAL_UNIT': int(not is_metric),
'HUD_LEAD': 2 if enabled and hud.lead_visible else 1 if enabled else 0,
'SET_ME_X01_2': 1,
diff --git a/opendbc/car/honda/interface.py b/opendbc/car/honda/interface.py
index 9f2036e1cb..4e8ce829e8 100755
--- a/opendbc/car/honda/interface.py
+++ b/opendbc/car/honda/interface.py
@@ -206,6 +206,7 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
ret.steerActuatorDelay = 0.1
ret.steerLimitTimer = 0.8
+ ret.radarDelay = 0.1
return ret
diff --git a/opendbc/car/honda/radar_interface.py b/opendbc/car/honda/radar_interface.py
index a47cc70e7f..316838aa5d 100755
--- a/opendbc/car/honda/radar_interface.py
+++ b/opendbc/car/honda/radar_interface.py
@@ -20,8 +20,6 @@ def __init__(self, CP):
self.radar_off_can = CP.radarUnavailable
self.radar_ts = CP.radarTimeStep
- self.delay = int(round(0.1 / CP.radarTimeStep)) # 0.1s delay of radar
-
# Nidec
if self.radar_off_can:
self.rcp = None
diff --git a/opendbc/car/hyundai/interface.py b/opendbc/car/hyundai/interface.py
index 1f383bcc41..27df5b556d 100644
--- a/opendbc/car/hyundai/interface.py
+++ b/opendbc/car/hyundai/interface.py
@@ -21,7 +21,7 @@ def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experime
# These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is
- # added to openpilot/selfdrive/car/tests/routes.py, we can remove it from this list.
+ # added to opendbc/car/tests/routes.py, we can remove it from this list.
# FIXME: the Optima Hybrid 2017 uses a different SCC12 checksum
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, }
diff --git a/opendbc/car/hyundai/values.py b/opendbc/car/hyundai/values.py
index 2394708de2..cbf3688f5e 100644
--- a/opendbc/car/hyundai/values.py
+++ b/opendbc/car/hyundai/values.py
@@ -478,7 +478,7 @@ class CAR(Platforms):
)
KIA_EV6 = HyundaiCanFDPlatformConfig(
[
- HyundaiCarDocs("Kia EV6 (Non-US only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
+ HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
HyundaiCarDocs("Kia EV6 (without HDA II) 2022-24", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])),
HyundaiCarDocs("Kia EV6 (with HDA II) 2022-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
],
diff --git a/opendbc/car/interfaces.py b/opendbc/car/interfaces.py
index c82d66320b..92147da514 100644
--- a/opendbc/car/interfaces.py
+++ b/opendbc/car/interfaces.py
@@ -1,6 +1,7 @@
import json
import os
import numpy as np
+import time
import tomllib
from abc import abstractmethod, ABC
from enum import StrEnum
@@ -101,7 +102,9 @@ def __init__(self, CP: structs.CarParams, CarController, CarState):
dbc_name = "" if self.cp is None else self.cp.dbc_name
self.CC: CarControllerBase = CarController(dbc_name, CP)
- def apply(self, c: structs.CarControl, now_nanos: int) -> tuple[structs.CarControl.Actuators, list[CanData]]:
+ def apply(self, c: structs.CarControl, now_nanos: int | None = None) -> tuple[structs.CarControl.Actuators, list[CanData]]:
+ if now_nanos is None:
+ now_nanos = int(time.monotonic() * 1e9)
return self.CC.update(c, self.CS, now_nanos)
@staticmethod
@@ -257,11 +260,10 @@ def __init__(self, CP: structs.CarParams):
self.CP = CP
self.rcp = None
self.pts: dict[int, structs.RadarData.RadarPoint] = {}
- self.delay = 0
self.radar_ts = CP.radarTimeStep
self.frame = 0
- def update(self, can_strings) -> structs.RadarData | None:
+ def update(self, can_packets: list[tuple[int, list[CanData]]]) -> structs.RadarData | None:
self.frame += 1
if (self.frame % int(100 * self.radar_ts)) == 0:
return structs.RadarData()
diff --git a/opendbc/car/panda_runner.py b/opendbc/car/panda_runner.py
new file mode 100644
index 0000000000..598ff51e4a
--- /dev/null
+++ b/opendbc/car/panda_runner.py
@@ -0,0 +1,57 @@
+import time
+from contextlib import AbstractContextManager
+
+from panda import Panda
+from opendbc.car.car_helpers import get_car
+from opendbc.car.can_definitions import CanData
+from opendbc.car.structs import CarParams, CarControl
+
+class PandaRunner(AbstractContextManager):
+ def __enter__(self):
+ self.p = Panda()
+ self.p.reset()
+
+ # setup + fingerprinting
+ self.p.set_safety_mode(Panda.SAFETY_ELM327, 1)
+ self.CI = get_car(self._can_recv, self.p.can_send_many, self.p.set_obd, True)
+ assert self.CI.CP.carFingerprint.lower() != "mock", "Unable to identify car. Check connections and ensure car is supported."
+
+ safety_model = list(CarParams.SafetyModel).index(self.CI.CP.safetyConfigs[0].safetyModel)
+ self.p.set_safety_mode(Panda.SAFETY_ELM327, 1)
+ self.CI.init(self.CI.CP, self._can_recv, self.p.can_send_many)
+ self.p.set_safety_mode(safety_model, self.CI.CP.safetyConfigs[0].safetyParam)
+
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.p.set_safety_mode(Panda.SAFETY_NOOUTPUT)
+ self.p.reset() # avoid siren
+ return super().__exit__(exc_type, exc_value, traceback)
+
+ @property
+ def panda(self) -> Panda:
+ return self.p
+
+ def _can_recv(self, wait_for_one: bool = False) -> list[list[CanData]]:
+ recv = self.p.can_recv()
+ while len(recv) == 0 and wait_for_one:
+ recv = self.p.can_recv()
+ return [[CanData(addr, dat, bus) for addr, dat, bus in recv], ]
+
+ def read(self, strict: bool = True):
+ cs = self.CI.update([int(time.monotonic()*1e9), self._can_recv()[0]])
+ if strict:
+ assert cs.canValid, "CAN went invalid, check connections"
+ return cs
+
+ def write(self, cc: CarControl) -> None:
+ if cc.enabled and not self.p.health()['controls_allowed']:
+ # prevent the car from faulting. print a warning?
+ cc = CarControl(enabled=False)
+ _, can_sends = self.CI.apply(cc)
+ self.p.can_send_many(can_sends, timeout=25)
+ self.p.send_heartbeat()
+
+if __name__ == "__main__":
+ with PandaRunner() as p:
+ print(p.read())
diff --git a/opendbc/car/structs.py b/opendbc/car/structs.py
index c375468353..a9777312ca 100644
--- a/opendbc/car/structs.py
+++ b/opendbc/car/structs.py
@@ -385,6 +385,7 @@ class LateralTorqueTuning:
carFw: list['CarParams.CarFw'] = auto_field()
radarTimeStep: float = 0.05 # time delta between radar updates, 20Hz is very standard
+ radarDelay: float = auto_field()
fingerprintSource: 'CarParams.FingerprintSource' = field(default_factory=lambda: CarParams.FingerprintSource.can)
# Where Panda/C2 is integrated into the car's CAN network
networkLocation: 'CarParams.NetworkLocation' = field(default_factory=lambda: CarParams.NetworkLocation.fwdCamera)
diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py
new file mode 100644
index 0000000000..8b6ea9dfaf
--- /dev/null
+++ b/opendbc/car/tests/routes.py
@@ -0,0 +1,298 @@
+from typing import NamedTuple
+
+from opendbc.car.chrysler.values import CAR as CHRYSLER
+from opendbc.car.gm.values import CAR as GM
+from opendbc.car.ford.values import CAR as FORD
+from opendbc.car.honda.values import CAR as HONDA
+from opendbc.car.hyundai.values import CAR as HYUNDAI
+from opendbc.car.nissan.values import CAR as NISSAN
+from opendbc.car.mazda.values import CAR as MAZDA
+from opendbc.car.mock.values import CAR as MOCK
+from opendbc.car.subaru.values import CAR as SUBARU
+from opendbc.car.toyota.values import CAR as TOYOTA
+from opendbc.car.values import Platform
+from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN
+from opendbc.car.body.values import CAR as COMMA
+
+# FIXME: add routes for these cars
+non_tested_cars = [
+ MOCK.MOCK,
+ FORD.FORD_F_150_MK14,
+ GM.CADILLAC_ATS,
+ GM.HOLDEN_ASTRA,
+ GM.CHEVROLET_MALIBU,
+ HYUNDAI.GENESIS_G90,
+ HONDA.HONDA_ODYSSEY_CHN,
+ VOLKSWAGEN.VOLKSWAGEN_CRAFTER_MK2, # need a route from an ACC-equipped Crafter
+ SUBARU.SUBARU_FORESTER_HYBRID,
+]
+
+
+class CarTestRoute(NamedTuple):
+ route: str
+ car_model: Platform | None
+ segment: int | None = None
+
+
+routes = [
+ CarTestRoute("efdf9af95e71cd84|2022-05-13--19-03-31", COMMA.COMMA_BODY),
+
+ CarTestRoute("0c94aa1e1296d7c6|2021-05-05--19-48-37", CHRYSLER.JEEP_GRAND_CHEROKEE),
+ CarTestRoute("91dfedae61d7bd75|2021-05-22--20-07-52", CHRYSLER.JEEP_GRAND_CHEROKEE_2019),
+ CarTestRoute("420a8e183f1aed48|2020-03-05--07-15-29", CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID), # 2017
+ CarTestRoute("43a685a66291579b|2021-05-27--19-47-29", CHRYSLER.CHRYSLER_PACIFICA_2018),
+ CarTestRoute("378472f830ee7395|2021-05-28--07-38-43", CHRYSLER.CHRYSLER_PACIFICA_2018_HYBRID),
+ CarTestRoute("8190c7275a24557b|2020-01-29--08-33-58", CHRYSLER.CHRYSLER_PACIFICA_2019_HYBRID),
+ CarTestRoute("3d84727705fecd04|2021-05-25--08-38-56", CHRYSLER.CHRYSLER_PACIFICA_2020),
+ CarTestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500_5TH_GEN),
+ CarTestRoute("8fb5eabf914632ae|2022-08-04--17-28-53", CHRYSLER.RAM_HD_5TH_GEN, segment=6),
+ CarTestRoute("3379c85aeedc8285|2023-12-07--17-49-39", CHRYSLER.DODGE_DURANGO),
+
+ CarTestRoute("54827bf84c38b14f|2023-01-25--14-14-11", FORD.FORD_BRONCO_SPORT_MK1),
+ CarTestRoute("f8eaaccd2a90aef8|2023-05-04--15-10-09", FORD.FORD_ESCAPE_MK4),
+ CarTestRoute("62241b0c7fea4589|2022-09-01--15-32-49", FORD.FORD_EXPLORER_MK6),
+ CarTestRoute("e886087f430e7fe7|2023-06-16--23-06-36", FORD.FORD_FOCUS_MK4),
+ CarTestRoute("bd37e43731e5964b|2023-04-30--10-42-26", FORD.FORD_MAVERICK_MK1),
+ CarTestRoute("112e4d6e0cad05e1|2023-11-14--08-21-43", FORD.FORD_F_150_LIGHTNING_MK1),
+ CarTestRoute("83a4e056c7072678|2023-11-13--16-51-33", FORD.FORD_MUSTANG_MACH_E_MK1),
+ CarTestRoute("37998aa0fade36ab/00000000--48f927c4f5", FORD.FORD_RANGER_MK2),
+ #TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION),
+
+ CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.GMC_ACADIA),
+ CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL),
+ CarTestRoute("75a6bcb9b8b40373|2023-03-11--22-47-33", GM.BUICK_LACROSSE),
+ CarTestRoute("e746f59bc96fd789|2024-01-31--22-25-58", GM.CHEVROLET_EQUINOX),
+ CarTestRoute("ef8f2185104d862e|2023-02-09--18-37-13", GM.CADILLAC_ESCALADE),
+ CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.CADILLAC_ESCALADE_ESV),
+ CarTestRoute("168f8b3be57f66ae|2023-09-12--21-44-42", GM.CADILLAC_ESCALADE_ESV_2019),
+ CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.CHEVROLET_VOLT),
+ CarTestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.CHEVROLET_BOLT_EUV, segment=1),
+ CarTestRoute("555d4087cf86aa91|2022-12-02--12-15-07", GM.CHEVROLET_BOLT_EUV, segment=14), # Bolt EV
+ CarTestRoute("38aa7da107d5d252|2022-08-15--16-01-12", GM.CHEVROLET_SILVERADO),
+ CarTestRoute("5085c761395d1fe6|2023-04-07--18-20-06", GM.CHEVROLET_TRAILBLAZER),
+ CarTestRoute("162796f1469f2f1b/00000005--6f334eda14", GM.CADILLAC_XT4),
+ CarTestRoute("477dd485611d1e6e/00000009--85fc06e10a", GM.CHEVROLET_VOLT_2019),
+
+ CarTestRoute("0e7a2ba168465df5|2020-10-18--14-14-22", HONDA.ACURA_RDX_3G),
+ CarTestRoute("a74b011b32b51b56|2020-07-26--17-09-36", HONDA.HONDA_CIVIC),
+ CarTestRoute("a859a044a447c2b0|2020-03-03--18-42-45", HONDA.HONDA_CRV_EU),
+ CarTestRoute("68aac44ad69f838e|2021-05-18--20-40-52", HONDA.HONDA_CRV),
+ CarTestRoute("14fed2e5fa0aa1a5|2021-05-25--14-59-42", HONDA.HONDA_CRV_HYBRID),
+ CarTestRoute("52f3e9ae60c0d886|2021-05-23--15-59-43", HONDA.HONDA_FIT),
+ CarTestRoute("2c4292a5cd10536c|2021-08-19--21-32-15", HONDA.HONDA_FREED),
+ CarTestRoute("03be5f2fd5c508d1|2020-04-19--18-44-15", HONDA.HONDA_HRV),
+ CarTestRoute("320098ff6c5e4730|2023-04-13--17-47-46", HONDA.HONDA_HRV_3G),
+ CarTestRoute("147613502316e718/00000001--dd141a3140", HONDA.HONDA_HRV_3G), # Brazilian model
+ CarTestRoute("917b074700869333|2021-05-24--20-40-20", HONDA.ACURA_ILX),
+ CarTestRoute("08a3deb07573f157|2020-03-06--16-11-19", HONDA.HONDA_ACCORD), # 1.5T
+ CarTestRoute("1da5847ac2488106|2021-05-24--19-31-50", HONDA.HONDA_ACCORD), # 2.0T
+ CarTestRoute("085ac1d942c35910|2021-03-25--20-11-15", HONDA.HONDA_ACCORD), # 2021 with new style HUD msgs
+ CarTestRoute("07585b0da3c88459|2021-05-26--18-52-04", HONDA.HONDA_ACCORD), # hybrid
+ CarTestRoute("f29e2b57a55e7ad5|2021-03-24--20-52-38", HONDA.HONDA_ACCORD), # hybrid, 2021 with new style HUD msgs
+ CarTestRoute("1ad763dd22ef1a0e|2020-02-29--18-37-03", HONDA.HONDA_CRV_5G),
+ CarTestRoute("0a96f86fcfe35964|2020-02-05--07-25-51", HONDA.HONDA_ODYSSEY),
+ CarTestRoute("d83f36766f8012a5|2020-02-05--18-42-21", HONDA.HONDA_CIVIC_BOSCH_DIESEL),
+ CarTestRoute("f0890d16a07a236b|2021-05-25--17-27-22", HONDA.HONDA_INSIGHT),
+ CarTestRoute("07d37d27996096b6|2020-03-04--21-57-27", HONDA.HONDA_PILOT),
+ CarTestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.HONDA_PILOT), # Passport
+ CarTestRoute("0a78dfbacc8504ef|2020-03-04--13-29-55", HONDA.HONDA_CIVIC_BOSCH),
+ CarTestRoute("f34a60d68d83b1e5|2020-10-06--14-35-55", HONDA.ACURA_RDX),
+ CarTestRoute("54fd8451b3974762|2021-04-01--14-50-10", HONDA.HONDA_RIDGELINE),
+ CarTestRoute("2d5808fae0b38ac6|2021-09-01--17-14-11", HONDA.HONDA_E),
+ CarTestRoute("f44aa96ace22f34a|2021-12-22--06-22-31", HONDA.HONDA_CIVIC_2022),
+
+ CarTestRoute("87d7f06ade479c2e|2023-09-11--23-30-11", HYUNDAI.HYUNDAI_AZERA_6TH_GEN),
+ CarTestRoute("66189dd8ec7b50e6|2023-09-20--07-02-12", HYUNDAI.HYUNDAI_AZERA_HEV_6TH_GEN),
+ CarTestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS),
+ CarTestRoute("b5d6dc830ad63071|2022-12-12--21-28-25", HYUNDAI.GENESIS_GV60_EV_1ST_GEN, segment=12),
+ CarTestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70),
+ CarTestRoute("ca4de5b12321bd98|2022-10-18--21-15-59", HYUNDAI.GENESIS_GV70_1ST_GEN),
+ CarTestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80),
+ CarTestRoute("0bbe367c98fa1538|2023-09-16--00-16-49", HYUNDAI.HYUNDAI_CUSTIN_1ST_GEN),
+ CarTestRoute("f0709d2bc6ca451f|2022-10-15--08-13-54", HYUNDAI.HYUNDAI_SANTA_CRUZ_1ST_GEN),
+ CarTestRoute("4dbd55df87507948|2022-03-01--09-45-38", HYUNDAI.HYUNDAI_SANTA_FE),
+ CarTestRoute("bf43d9df2b660eb0|2021-09-23--14-16-37", HYUNDAI.HYUNDAI_SANTA_FE_2022),
+ CarTestRoute("37398f32561a23ad|2021-11-18--00-11-35", HYUNDAI.HYUNDAI_SANTA_FE_HEV_2022),
+ CarTestRoute("656ac0d830792fcc|2021-12-28--14-45-56", HYUNDAI.HYUNDAI_SANTA_FE_PHEV_2022, segment=1),
+ CarTestRoute("de59124955b921d8|2023-06-24--00-12-50", HYUNDAI.KIA_CARNIVAL_4TH_GEN),
+ CarTestRoute("409c9409979a8abc|2023-07-11--09-06-44", HYUNDAI.KIA_CARNIVAL_4TH_GEN), # Chinese model
+ CarTestRoute("e0e98335f3ebc58f|2021-03-07--16-38-29", HYUNDAI.KIA_CEED),
+ CarTestRoute("7653b2bce7bcfdaa|2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA_G4),
+ CarTestRoute("018654717bc93d7d|2022-09-19--23-11-10", HYUNDAI.KIA_OPTIMA_G4_FL, segment=0),
+ CarTestRoute("f9716670b2481438|2023-08-23--14-49-50", HYUNDAI.KIA_OPTIMA_H),
+ CarTestRoute("6a42c1197b2a8179|2023-09-21--10-23-44", HYUNDAI.KIA_OPTIMA_H_G4_FL),
+ CarTestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS),
+ CarTestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.HYUNDAI_SONATA),
+ CarTestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.HYUNDAI_SONATA_LF),
+ CarTestRoute("c344fd2492c7a9d2|2023-12-11--09-03-23", HYUNDAI.HYUNDAI_STARIA_4TH_GEN),
+ CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.HYUNDAI_TUCSON),
+ CarTestRoute("db68bbe12250812c|2022-12-05--00-54-12", HYUNDAI.HYUNDAI_TUCSON_4TH_GEN), # 2023
+ CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.HYUNDAI_TUCSON_4TH_GEN), # hybrid
+ CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO),
+ CarTestRoute("1d0d000db3370fd0|2023-01-04--22-28-42", HYUNDAI.KIA_SORENTO_4TH_GEN, segment=5),
+ CarTestRoute("fc19648042eb6896|2023-08-16--11-43-27", HYUNDAI.KIA_SORENTO_HEV_4TH_GEN, segment=14),
+ CarTestRoute("628935d7d3e5f4f7|2022-11-30--01-12-46", HYUNDAI.KIA_SORENTO_HEV_4TH_GEN), # plug-in hybrid
+ CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.HYUNDAI_PALISADE),
+ CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.HYUNDAI_IONIQ_5), # HDA2
+ CarTestRoute("eb4eae1476647463|2023-08-26--18-07-04", HYUNDAI.HYUNDAI_IONIQ_6, segment=6), # HDA2
+ CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.HYUNDAI_IONIQ_PHEV_2019),
+ CarTestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.HYUNDAI_IONIQ_PHEV),
+ CarTestRoute("e1107f9d04dfb1e2|2023-09-05--22-32-12", HYUNDAI.HYUNDAI_IONIQ_PHEV), # openpilot longitudinal enabled
+ CarTestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.HYUNDAI_IONIQ_EV_2020),
+ CarTestRoute("610ebb9faaad6b43|2020-06-13--15-28-36", HYUNDAI.HYUNDAI_IONIQ_EV_LTD),
+ CarTestRoute("2c5cf2dd6102e5da|2020-06-26--16-00-08", HYUNDAI.HYUNDAI_IONIQ),
+ CarTestRoute("012c95f06918eca4|2023-01-15--11-19-36", HYUNDAI.HYUNDAI_IONIQ), # openpilot longitudinal enabled
+ CarTestRoute("ab59fe909f626921|2021-10-18--18-34-28", HYUNDAI.HYUNDAI_IONIQ_HEV_2022),
+ CarTestRoute("22d955b2cd499c22|2020-08-10--19-58-21", HYUNDAI.HYUNDAI_KONA),
+ CarTestRoute("efc48acf44b1e64d|2021-05-28--21-05-04", HYUNDAI.HYUNDAI_KONA_EV),
+ CarTestRoute("f90d3cd06caeb6fa|2023-09-06--17-15-47", HYUNDAI.HYUNDAI_KONA_EV), # openpilot longitudinal enabled
+ CarTestRoute("ff973b941a69366f|2022-07-28--22-01-19", HYUNDAI.HYUNDAI_KONA_EV_2022, segment=11),
+ CarTestRoute("1618132d68afc876|2023-08-27--09-32-14", HYUNDAI.HYUNDAI_KONA_EV_2ND_GEN, segment=13),
+ CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.HYUNDAI_KONA_HEV),
+ CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER),
+ CarTestRoute("5b50b883a4259afb|2022-11-09--15-00-42", HYUNDAI.KIA_STINGER_2022),
+ CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.HYUNDAI_VELOSTER),
+ CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2
+ CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1
+ CarTestRoute("9b25e8c1484a1b67|2023-04-13--10-41-45", HYUNDAI.KIA_EV6),
+ CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021),
+ CarTestRoute("c58dfc9fc16590e0|2023-01-14--13-51-48", HYUNDAI.KIA_K5_HEV_2020),
+ CarTestRoute("78ad5150de133637|2023-09-13--16-15-57", HYUNDAI.KIA_K8_HEV_1ST_GEN),
+ CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV),
+ CarTestRoute("b153671049a867b3|2023-04-05--10-00-30", HYUNDAI.KIA_NIRO_EV_2ND_GEN),
+ CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV),
+ CarTestRoute("23349923ba5c4e3b|2023-12-02--08-51-54", HYUNDAI.KIA_NIRO_PHEV_2022),
+ CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021),
+ CarTestRoute("db04d2c63990e3ba|2023-02-08--16-52-39", HYUNDAI.KIA_NIRO_HEV_2ND_GEN),
+ CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE),
+ CarTestRoute("192283cdbb7a58c2|2022-10-15--01-43-18", HYUNDAI.KIA_SPORTAGE_5TH_GEN),
+ CarTestRoute("09559f1fcaed4704|2023-11-16--02-24-57", HYUNDAI.KIA_SPORTAGE_5TH_GEN), # openpilot longitudinal
+ CarTestRoute("b3537035ffe6a7d6|2022-10-17--15-23-49", HYUNDAI.KIA_SPORTAGE_5TH_GEN), # hybrid
+ CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.HYUNDAI_ELANTRA),
+ CarTestRoute("734ef96182ddf940|2022-10-02--16-41-44", HYUNDAI.HYUNDAI_ELANTRA_GT_I30),
+ CarTestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.HYUNDAI_ELANTRA_2021),
+ CarTestRoute("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.HYUNDAI_ELANTRA_HEV_2021),
+ CarTestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.HYUNDAI_SONATA_HYBRID),
+ CarTestRoute("715ac05b594e9c59|2021-10-27--23-24-56", HYUNDAI.GENESIS_G70_2020),
+ CarTestRoute("6b0d44d22df18134|2023-05-06--10-36-55", HYUNDAI.GENESIS_GV80),
+
+ CarTestRoute("00c829b1b7613dea|2021-06-24--09-10-10", TOYOTA.TOYOTA_ALPHARD_TSS2),
+ CarTestRoute("912119ebd02c7a42|2022-03-19--07-24-50", TOYOTA.TOYOTA_ALPHARD_TSS2), # hybrid
+ CarTestRoute("000cf3730200c71c|2021-05-24--10-42-05", TOYOTA.TOYOTA_AVALON),
+ CarTestRoute("0bb588106852abb7|2021-05-26--12-22-01", TOYOTA.TOYOTA_AVALON_2019),
+ CarTestRoute("87bef2930af86592|2021-05-30--09-40-54", TOYOTA.TOYOTA_AVALON_2019), # hybrid
+ CarTestRoute("e9966711cfb04ce3|2022-01-11--07-59-43", TOYOTA.TOYOTA_AVALON_TSS2),
+ CarTestRoute("eca1080a91720a54|2022-03-17--13-32-29", TOYOTA.TOYOTA_AVALON_TSS2), # hybrid
+ CarTestRoute("6cdecc4728d4af37|2020-02-23--15-44-18", TOYOTA.TOYOTA_CAMRY),
+ CarTestRoute("2f37c007683e85ba|2023-09-02--14-39-44", TOYOTA.TOYOTA_CAMRY), # openpilot longitudinal, with radar CAN filter
+ CarTestRoute("54034823d30962f5|2021-05-24--06-37-34", TOYOTA.TOYOTA_CAMRY), # hybrid
+ CarTestRoute("3456ad0cd7281b24|2020-12-13--17-45-56", TOYOTA.TOYOTA_CAMRY_TSS2),
+ CarTestRoute("ffccc77938ddbc44|2021-01-04--16-55-41", TOYOTA.TOYOTA_CAMRY_TSS2), # hybrid
+ CarTestRoute("4e45c89c38e8ec4d|2021-05-02--02-49-28", TOYOTA.TOYOTA_COROLLA),
+ CarTestRoute("5f5afb36036506e4|2019-05-14--02-09-54", TOYOTA.TOYOTA_COROLLA_TSS2),
+ CarTestRoute("5ceff72287a5c86c|2019-10-19--10-59-02", TOYOTA.TOYOTA_COROLLA_TSS2), # hybrid
+ CarTestRoute("d2525c22173da58b|2021-04-25--16-47-04", TOYOTA.TOYOTA_PRIUS),
+ CarTestRoute("b14c5b4742e6fc85|2020-07-28--19-50-11", TOYOTA.TOYOTA_RAV4),
+ CarTestRoute("32a7df20486b0f70|2020-02-06--16-06-50", TOYOTA.TOYOTA_RAV4H),
+ CarTestRoute("cdf2f7de565d40ae|2019-04-25--03-53-41", TOYOTA.TOYOTA_RAV4_TSS2),
+ CarTestRoute("a5c341bb250ca2f0|2022-05-18--16-05-17", TOYOTA.TOYOTA_RAV4_TSS2_2022),
+ CarTestRoute("ad5a3fa719bc2f83|2023-10-17--19-48-42", TOYOTA.TOYOTA_RAV4_TSS2_2023),
+ CarTestRoute("7e34a988419b5307|2019-12-18--19-13-30", TOYOTA.TOYOTA_RAV4_TSS2), # hybrid
+ CarTestRoute("2475fb3eb2ffcc2e|2022-04-29--12-46-23", TOYOTA.TOYOTA_RAV4_TSS2_2022), # hybrid
+ CarTestRoute("7a31f030957b9c85|2023-04-01--14-12-51", TOYOTA.LEXUS_ES),
+ CarTestRoute("37041c500fd30100|2020-12-30--12-17-24", TOYOTA.LEXUS_ES), # hybrid
+ CarTestRoute("e6a24be49a6cd46e|2019-10-29--10-52-42", TOYOTA.LEXUS_ES_TSS2),
+ CarTestRoute("f49e8041283f2939|2019-05-30--11-51-51", TOYOTA.LEXUS_ES_TSS2), # hybrid
+ CarTestRoute("da23c367491f53e2|2021-05-21--09-09-11", TOYOTA.LEXUS_CTH, segment=3),
+ CarTestRoute("32696cea52831b02|2021-11-19--18-13-30", TOYOTA.LEXUS_RC),
+ CarTestRoute("ab9b64a5e5960cba|2023-10-24--17-32-08", TOYOTA.LEXUS_GS_F),
+ CarTestRoute("886fcd8408d570e9|2020-01-29--02-18-55", TOYOTA.LEXUS_RX),
+ CarTestRoute("d27ad752e9b08d4f|2021-05-26--19-39-51", TOYOTA.LEXUS_RX), # hybrid
+ CarTestRoute("01b22eb2ed121565|2020-02-02--11-25-51", TOYOTA.LEXUS_RX_TSS2),
+ CarTestRoute("b74758c690a49668|2020-05-20--15-58-57", TOYOTA.LEXUS_RX_TSS2), # hybrid
+ CarTestRoute("964c09eb11ca8089|2020-11-03--22-04-00", TOYOTA.LEXUS_NX),
+ CarTestRoute("ec429c0f37564e3c|2020-02-01--17-28-12", TOYOTA.LEXUS_NX), # hybrid
+ CarTestRoute("3fd5305f8b6ca765|2021-04-28--19-26-49", TOYOTA.LEXUS_NX_TSS2),
+ CarTestRoute("09ae96064ed85a14|2022-06-09--12-22-31", TOYOTA.LEXUS_NX_TSS2), # hybrid
+ CarTestRoute("4765fbbf59e3cd88|2024-02-06--17-45-32", TOYOTA.LEXUS_LC_TSS2),
+ CarTestRoute("0a302ffddbb3e3d3|2020-02-08--16-19-08", TOYOTA.TOYOTA_HIGHLANDER_TSS2),
+ CarTestRoute("437e4d2402abf524|2021-05-25--07-58-50", TOYOTA.TOYOTA_HIGHLANDER_TSS2), # hybrid
+ CarTestRoute("3183cd9b021e89ce|2021-05-25--10-34-44", TOYOTA.TOYOTA_HIGHLANDER),
+ CarTestRoute("80d16a262e33d57f|2021-05-23--20-01-43", TOYOTA.TOYOTA_HIGHLANDER), # hybrid
+ CarTestRoute("eb6acd681135480d|2019-06-20--20-00-00", TOYOTA.TOYOTA_SIENNA),
+ CarTestRoute("2e07163a1ba9a780|2019-08-25--13-15-13", TOYOTA.LEXUS_IS),
+ CarTestRoute("649bf2997ada6e3a|2023-08-08--18-04-22", TOYOTA.LEXUS_IS_TSS2),
+ CarTestRoute("0a0de17a1e6a2d15|2020-09-21--21-24-41", TOYOTA.TOYOTA_PRIUS_TSS2),
+ CarTestRoute("9b36accae406390e|2021-03-30--10-41-38", TOYOTA.TOYOTA_MIRAI),
+ CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.TOYOTA_CHR),
+ CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.TOYOTA_CHR), # hybrid
+ CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.TOYOTA_CHR_TSS2),
+ CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.TOYOTA_CHR_TSS2), # hybrid
+ CarTestRoute("6719965b0e1d1737|2023-08-29--06-40-05", TOYOTA.TOYOTA_CHR_TSS2), # hybrid, openpilot longitudinal, radar disabled
+ CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.TOYOTA_PRIUS_V),
+
+ CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.VOLKSWAGEN_ARTEON_MK1),
+ CarTestRoute("2c68dda277d887ac|2021-05-11--15-22-20", VOLKSWAGEN.VOLKSWAGEN_ATLAS_MK1),
+ CarTestRoute("ffcd23abbbd02219|2024-02-28--14-59-38", VOLKSWAGEN.VOLKSWAGEN_CADDY_MK3),
+ CarTestRoute("cae14e88932eb364|2021-03-26--14-43-28", VOLKSWAGEN.VOLKSWAGEN_GOLF_MK7), # Stock ACC
+ CarTestRoute("3cfdec54aa035f3f|2022-10-13--14-58-58", VOLKSWAGEN.VOLKSWAGEN_GOLF_MK7), # openpilot longitudinal
+ CarTestRoute("578742b26807f756|00000010--41ee3e5bec", VOLKSWAGEN.VOLKSWAGEN_JETTA_MK6),
+ CarTestRoute("58a7d3b707987d65|2021-03-25--17-26-37", VOLKSWAGEN.VOLKSWAGEN_JETTA_MK7),
+ CarTestRoute("4d134e099430fba2|2021-03-26--00-26-06", VOLKSWAGEN.VOLKSWAGEN_PASSAT_MK8),
+ CarTestRoute("3cfdec54aa035f3f|2022-07-19--23-45-10", VOLKSWAGEN.VOLKSWAGEN_PASSAT_NMS),
+ CarTestRoute("0cd0b7f7e31a3853|2021-11-03--19-30-22", VOLKSWAGEN.VOLKSWAGEN_POLO_MK6),
+ CarTestRoute("064d1816e448f8eb|2022-09-29--15-32-34", VOLKSWAGEN.VOLKSWAGEN_SHARAN_MK2),
+ CarTestRoute("7d82b2f3a9115f1f|2021-10-21--15-39-42", VOLKSWAGEN.VOLKSWAGEN_TAOS_MK1),
+ CarTestRoute("2744c89a8dda9a51|2021-07-24--21-28-06", VOLKSWAGEN.VOLKSWAGEN_TCROSS_MK1),
+ CarTestRoute("2cef8a0b898f331a|2021-03-25--20-13-57", VOLKSWAGEN.VOLKSWAGEN_TIGUAN_MK2),
+ CarTestRoute("a589dcc642fdb10a|2021-06-14--20-54-26", VOLKSWAGEN.VOLKSWAGEN_TOURAN_MK2),
+ CarTestRoute("a459f4556782eba1|2021-09-19--09-48-00", VOLKSWAGEN.VOLKSWAGEN_TRANSPORTER_T61),
+ CarTestRoute("0cd0b7f7e31a3853|2021-11-18--00-38-32", VOLKSWAGEN.VOLKSWAGEN_TROC_MK1),
+ CarTestRoute("07667b885add75fd|2021-01-23--19-48-42", VOLKSWAGEN.AUDI_A3_MK3),
+ CarTestRoute("6c6b466346192818|2021-06-06--14-17-47", VOLKSWAGEN.AUDI_Q2_MK1),
+ CarTestRoute("0cd0b7f7e31a3853|2021-12-03--03-12-05", VOLKSWAGEN.AUDI_Q3_MK2),
+ CarTestRoute("8f205bdd11bcbb65|2021-03-26--01-00-17", VOLKSWAGEN.SEAT_ATECA_MK1),
+ CarTestRoute("fc6b6c9a3471c846|2021-05-27--13-39-56", VOLKSWAGEN.SEAT_ATECA_MK1), # Leon
+ CarTestRoute("0bbe367c98fa1538|2023-03-04--17-46-11", VOLKSWAGEN.SKODA_FABIA_MK4),
+ CarTestRoute("12d6ae3057c04b0d|2021-09-15--00-04-07", VOLKSWAGEN.SKODA_KAMIQ_MK1),
+ CarTestRoute("12d6ae3057c04b0d|2021-09-04--21-21-21", VOLKSWAGEN.SKODA_KAROQ_MK1),
+ CarTestRoute("90434ff5d7c8d603|2021-03-15--12-07-31", VOLKSWAGEN.SKODA_KODIAQ_MK1),
+ CarTestRoute("66e5edc3a16459c5|2021-05-25--19-00-29", VOLKSWAGEN.SKODA_OCTAVIA_MK3),
+ CarTestRoute("026b6d18fba6417f|2021-03-26--09-17-04", VOLKSWAGEN.SKODA_KAMIQ_MK1), # Scala
+ CarTestRoute("b2e9858e29db492b|2021-03-26--16-58-42", VOLKSWAGEN.SKODA_SUPERB_MK3),
+
+ CarTestRoute("3c8f0c502e119c1c|2020-06-30--12-58-02", SUBARU.SUBARU_ASCENT),
+ CarTestRoute("c321c6b697c5a5ff|2020-06-23--11-04-33", SUBARU.SUBARU_FORESTER),
+ CarTestRoute("791340bc01ed993d|2019-03-10--16-28-08", SUBARU.SUBARU_IMPREZA),
+ CarTestRoute("8bf7e79a3ce64055|2021-05-24--09-36-27", SUBARU.SUBARU_IMPREZA_2020),
+ CarTestRoute("8de015561e1ea4a0|2023-08-29--17-08-31", SUBARU.SUBARU_IMPREZA), # openpilot longitudinal
+ # CarTestRoute("c3d1ccb52f5f9d65|2023-07-22--01-23-20", SUBARU.OUTBACK, segment=9), # gen2 longitudinal, eyesight disabled
+ CarTestRoute("1bbe6bf2d62f58a8|2022-07-14--17-11-43", SUBARU.SUBARU_OUTBACK, segment=10),
+ CarTestRoute("c56e69bbc74b8fad|2022-08-18--09-43-51", SUBARU.SUBARU_LEGACY, segment=3),
+ CarTestRoute("f4e3a0c511a076f4|2022-08-04--16-16-48", SUBARU.SUBARU_CROSSTREK_HYBRID, segment=2),
+ CarTestRoute("7fd1e4f3a33c1673|2022-12-04--15-09-53", SUBARU.SUBARU_FORESTER_2022, segment=4),
+ CarTestRoute("f3b34c0d2632aa83|2023-07-23--20-43-25", SUBARU.SUBARU_OUTBACK_2023, segment=7),
+ CarTestRoute("99437cef6d5ff2ee|2023-03-13--21-21-38", SUBARU.SUBARU_ASCENT_2023, segment=7),
+ # Pre-global, dashcam
+ CarTestRoute("95441c38ae8c130e|2020-06-08--12-10-17", SUBARU.SUBARU_FORESTER_PREGLOBAL),
+ CarTestRoute("df5ca7660000fba8|2020-06-16--17-37-19", SUBARU.SUBARU_LEGACY_PREGLOBAL),
+ CarTestRoute("5ab784f361e19b78|2020-06-08--16-30-41", SUBARU.SUBARU_OUTBACK_PREGLOBAL),
+ CarTestRoute("e19eb5d5353b1ac1|2020-08-09--14-37-56", SUBARU.SUBARU_OUTBACK_PREGLOBAL_2018),
+
+ CarTestRoute("fbbfa6af821552b9|2020-03-03--08-09-43", NISSAN.NISSAN_XTRAIL),
+ CarTestRoute("5b7c365c50084530|2020-03-25--22-10-13", NISSAN.NISSAN_LEAF),
+ CarTestRoute("22c3dcce2dd627eb|2020-12-30--16-38-48", NISSAN.NISSAN_LEAF_IC),
+ CarTestRoute("059ab9162e23198e|2020-05-30--09-41-01", NISSAN.NISSAN_ROGUE),
+ CarTestRoute("b72d3ec617c0a90f|2020-12-11--15-38-17", NISSAN.NISSAN_ALTIMA),
+
+ CarTestRoute("32a319f057902bb3|2020-04-27--15-18-58", MAZDA.MAZDA_CX5),
+ CarTestRoute("10b5a4b380434151|2020-08-26--17-11-45", MAZDA.MAZDA_CX9),
+ CarTestRoute("74f1038827005090|2020-08-26--20-05-50", MAZDA.MAZDA_3),
+ CarTestRoute("fb53c640f499b73d|2021-06-01--04-17-56", MAZDA.MAZDA_6),
+ CarTestRoute("f6d5b1a9d7a1c92e|2021-07-08--06-56-59", MAZDA.MAZDA_CX9_2021),
+ CarTestRoute("a4af1602d8e668ac|2022-02-03--12-17-07", MAZDA.MAZDA_CX5_2022),
+
+ # Segments that test specific issues
+ # Controls mismatch due to standstill threshold
+ CarTestRoute("bec2dcfde6a64235|2022-04-08--14-21-32", HONDA.HONDA_CRV_HYBRID, segment=22),
+]
diff --git a/opendbc/car/tests/test_car_interfaces.py b/opendbc/car/tests/test_car_interfaces.py
new file mode 100644
index 0000000000..0066c97b5d
--- /dev/null
+++ b/opendbc/car/tests/test_car_interfaces.py
@@ -0,0 +1,144 @@
+import os
+import math
+import hypothesis.strategies as st
+from hypothesis import Phase, given, settings
+from parameterized import parameterized
+from collections.abc import Callable
+from typing import Any
+
+from opendbc.car import DT_CTRL, CanData, gen_empty_fingerprint, structs
+from opendbc.car.car_helpers import interfaces
+from opendbc.car.fingerprints import all_known_cars
+from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
+from opendbc.car.interfaces import get_interface_attr
+from opendbc.car.mock.values import CAR as MOCK
+
+DrawType = Callable[[st.SearchStrategy], Any]
+
+ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}
+ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus}
+
+ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r in config.requests}
+
+MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '5'))
+
+
+def get_fuzzy_car_interface_args(draw: DrawType) -> dict:
+ # Fuzzy CAN fingerprints and FW versions to test more states of the CarInterface
+ fingerprint_strategy = st.fixed_dictionaries({key: st.dictionaries(st.integers(min_value=0, max_value=0x800),
+ st.integers(min_value=0, max_value=64)) for key in
+ gen_empty_fingerprint()})
+
+ # only pick from possible ecus to reduce search space
+ car_fw_strategy = st.lists(st.sampled_from(sorted(ALL_ECUS)))
+
+ params_strategy = st.fixed_dictionaries({
+ 'fingerprints': fingerprint_strategy,
+ 'car_fw': car_fw_strategy,
+ 'experimental_long': st.booleans(),
+ })
+
+ params: dict = draw(params_strategy)
+ params['car_fw'] = [structs.CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0,
+ request=draw(st.sampled_from(sorted(ALL_REQUESTS))))
+ for fw in params['car_fw']]
+ return params
+
+
+class TestCarInterfaces:
+ # FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause
+ # many generated examples to overrun when max_examples > ~20, don't use it
+ @parameterized.expand([(car,) for car in sorted(all_known_cars())] + [MOCK.MOCK])
+ @settings(max_examples=MAX_EXAMPLES, deadline=None,
+ phases=(Phase.reuse, Phase.generate, Phase.shrink))
+ @given(data=st.data())
+ def test_car_interfaces(self, car_name, data):
+ CarInterface, CarController, CarState, RadarInterface = interfaces[car_name]
+
+ args = get_fuzzy_car_interface_args(data.draw)
+
+ car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
+ experimental_long=args['experimental_long'], docs=False)
+ car_interface = CarInterface(car_params, CarController, CarState)
+ assert car_params
+ assert car_interface
+
+ assert car_params.mass > 1
+ assert car_params.wheelbase > 0
+ # centerToFront is center of gravity to front wheels, assert a reasonable range
+ assert car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7
+ assert car_params.maxLateralAccel > 0
+
+ # Longitudinal sanity checks
+ assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP)
+ assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
+
+ # Lateral sanity checks
+ if car_params.steerControlType != structs.CarParams.SteerControlType.angle:
+ tune = car_params.lateralTuning
+ if tune.which() == 'pid':
+ if car_name != MOCK.MOCK:
+ assert not math.isnan(tune.pid.kf) and tune.pid.kf > 0
+ assert len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)
+ assert len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)
+
+ elif tune.which() == 'torque':
+ assert not math.isnan(tune.torque.kf) and tune.torque.kf > 0
+ assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
+
+ # Run car interface
+ # TODO: use hypothesis to generate random messages
+ now_nanos = 0
+ CC = structs.CarControl()
+ for _ in range(10):
+ car_interface.update([])
+ car_interface.apply(CC, now_nanos)
+ now_nanos += DT_CTRL * 1e9 # 10 ms
+
+ CC = structs.CarControl()
+ CC.enabled = True
+ for _ in range(10):
+ car_interface.update([])
+ car_interface.apply(CC, now_nanos)
+ now_nanos += DT_CTRL * 1e9 # 10ms
+
+ # Test radar interface
+ radar_interface = RadarInterface(car_params)
+ assert radar_interface
+
+ # Run radar interface once
+ radar_interface.update([])
+ if not car_params.radarUnavailable and radar_interface.rcp is not None and \
+ hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'):
+ radar_interface._update([radar_interface.trigger_msg])
+
+ # Test radar fault
+ if not car_params.radarUnavailable and radar_interface.rcp is not None:
+ cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
+ rr = radar_interface.update(cans)
+ assert rr is None or len(rr.errors) > 0
+
+ def test_interface_attrs(self):
+ """Asserts basic behavior of interface attribute getter"""
+ num_brands = len(get_interface_attr('CAR'))
+ assert num_brands >= 12
+
+ # Should return value for all brands when not combining, even if attribute doesn't exist
+ ret = get_interface_attr('FAKE_ATTR')
+ assert len(ret) == num_brands
+
+ # Make sure we can combine dicts
+ ret = get_interface_attr('DBC', combine_brands=True)
+ assert len(ret) >= 160
+
+ # We don't support combining non-dicts
+ ret = get_interface_attr('CAR', combine_brands=True)
+ assert len(ret) == 0
+
+ # If brand has None value, it shouldn't return when ignore_none=True is specified
+ none_brands = {b for b, v in get_interface_attr('FINGERPRINTS').items() if v is None}
+ assert len(none_brands) >= 1
+
+ ret = get_interface_attr('FINGERPRINTS', ignore_none=True)
+ none_brands_in_ret = none_brands.intersection(ret)
+ assert len(none_brands_in_ret) == 0, f'Brands with None values in ignore_none=True result: {none_brands_in_ret}'
diff --git a/opendbc/car/tests/test_fw_fingerprint.py b/opendbc/car/tests/test_fw_fingerprint.py
index 8e966df5c4..aabdaa4ce6 100644
--- a/opendbc/car/tests/test_fw_fingerprint.py
+++ b/opendbc/car/tests/test_fw_fingerprint.py
@@ -9,7 +9,7 @@
from opendbc.car.structs import CarParams
from opendbc.car.fingerprints import FW_VERSIONS
from opendbc.car.fw_versions import ESSENTIAL_ECUS, FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, build_fw_dict, \
- match_fw_to_car, get_brand_ecu_matches, get_fw_versions, get_fw_versions_ordered, get_present_ecus
+ match_fw_to_car, get_brand_ecu_matches, get_fw_versions, get_present_ecus
from opendbc.car.vin import get_vin
CarFw = CarParams.CarFw
@@ -26,7 +26,7 @@ def assertFingerprints(self, candidates, expected):
def test_exact_match(self, brand, car_model, ecus, test_non_essential):
config = FW_QUERY_CONFIGS[brand]
CP = CarParams()
- for _ in range(100):
+ for _ in range(20):
fw = []
for ecu, fw_versions in ecus.items():
# Assume non-essential ECUs apply to all cars, so we catch cases where Car A with
@@ -316,8 +316,15 @@ def test_get_fw_versions(self, subtests, mocker):
def fake_carlog_exception(*args, **kwargs):
raise
+ t = 0
+
+ def fake_monotonic():
+ nonlocal t
+ t += 0.0001
+ return t
+
mocker.patch("opendbc.car.carlog.exception", fake_carlog_exception)
- get_fw_versions_ordered(self.fake_can_recv, self.fake_can_send, lambda obd: None, '0' * 17, set())
+ mocker.patch("time.monotonic", fake_monotonic)
for brand in FW_QUERY_CONFIGS.keys():
with subtests.test(brand=brand):
get_fw_versions(self.fake_can_recv, self.fake_can_send, lambda obd: None, brand)
diff --git a/opendbc/car/tests/test_lateral_limits.py b/opendbc/car/tests/test_lateral_limits.py
new file mode 100755
index 0000000000..585289968d
--- /dev/null
+++ b/opendbc/car/tests/test_lateral_limits.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+from collections import defaultdict
+import importlib
+from parameterized import parameterized_class
+import pytest
+import sys
+
+from opendbc.car import DT_CTRL
+from opendbc.car.car_helpers import interfaces
+from opendbc.car.fingerprints import all_known_cars
+from opendbc.car.interfaces import get_torque_params
+
+CAR_MODELS = all_known_cars()
+
+# ISO 11270 - allowed up jerk is strictly lower than recommended limits
+MAX_LAT_ACCEL = 3.0 # m/s^2
+MAX_LAT_JERK_UP = 2.5 # m/s^3
+MAX_LAT_JERK_DOWN = 5.0 # m/s^3
+MAX_LAT_JERK_UP_TOLERANCE = 0.5 # m/s^3
+
+# jerk is measured over half a second
+JERK_MEAS_T = 0.5
+
+
+@parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)])
+class TestLateralLimits:
+ car_model: str
+
+ @classmethod
+ def setup_class(cls):
+ CarInterface, _, _, _ = interfaces[cls.car_model]
+ CP = CarInterface.get_non_essential_params(cls.car_model)
+
+ if CP.dashcamOnly:
+ pytest.skip("Platform is behind dashcamOnly")
+
+ # TODO: test all platforms
+ if CP.lateralTuning.which() != 'torque':
+ pytest.skip()
+
+ if CP.notCar:
+ pytest.skip()
+
+ CarControllerParams = importlib.import_module(f'opendbc.car.{CP.carName}.values').CarControllerParams
+ cls.control_params = CarControllerParams(CP)
+ cls.torque_params = get_torque_params()[cls.car_model]
+
+ @staticmethod
+ def calculate_0_5s_jerk(control_params, torque_params):
+ steer_step = control_params.STEER_STEP
+ max_lat_accel = torque_params['MAX_LAT_ACCEL_MEASURED']
+
+ # Steer up/down delta per 10ms frame, in percentage of max torque
+ steer_up_per_frame = control_params.STEER_DELTA_UP / control_params.STEER_MAX / steer_step
+ steer_down_per_frame = control_params.STEER_DELTA_DOWN / control_params.STEER_MAX / steer_step
+
+ # Lateral acceleration reached in 0.5 seconds, clipping to max torque
+ accel_up_0_5_sec = min(steer_up_per_frame * JERK_MEAS_T / DT_CTRL, 1.0) * max_lat_accel
+ accel_down_0_5_sec = min(steer_down_per_frame * JERK_MEAS_T / DT_CTRL, 1.0) * max_lat_accel
+
+ # Convert to m/s^3
+ return accel_up_0_5_sec / JERK_MEAS_T, accel_down_0_5_sec / JERK_MEAS_T
+
+ def test_jerk_limits(self):
+ up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params)
+ assert up_jerk <= MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE
+ assert down_jerk <= MAX_LAT_JERK_DOWN
+
+ def test_max_lateral_accel(self):
+ assert self.torque_params["MAX_LAT_ACCEL_MEASURED"] <= MAX_LAT_ACCEL
+
+
+class LatAccelReport:
+ car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict)
+
+ def pytest_sessionfinish(self):
+ print(f"\n\n---- Lateral limit report ({len(CAR_MODELS)} cars) ----\n")
+
+ max_car_model_len = max([len(car_model) for car_model in self.car_model_jerks])
+ for car_model, _jerks in sorted(self.car_model_jerks.items(), key=lambda i: i[1]['up_jerk'], reverse=True):
+ violation = _jerks["up_jerk"] > MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE or \
+ _jerks["down_jerk"] > MAX_LAT_JERK_DOWN
+ violation_str = " - VIOLATION" if violation else ""
+
+ print(f"{car_model:{max_car_model_len}} - up jerk: {round(_jerks['up_jerk'], 2):5} " +
+ f"m/s^3, down jerk: {round(_jerks['down_jerk'], 2):5} m/s^3{violation_str}")
+
+ @pytest.fixture(scope="class", autouse=True)
+ def class_setup(self, request):
+ yield
+ cls = request.cls
+ if hasattr(cls, "control_params"):
+ up_jerk, down_jerk = TestLateralLimits.calculate_0_5s_jerk(cls.control_params, cls.torque_params)
+ self.car_model_jerks[cls.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk}
+
+
+if __name__ == '__main__':
+ sys.exit(pytest.main([__file__, '-n0', '--no-summary'], plugins=[LatAccelReport()])) # noqa: TID251
diff --git a/opendbc/car/tests/test_routes.py b/opendbc/car/tests/test_routes.py
new file mode 100644
index 0000000000..5c7ab12e83
--- /dev/null
+++ b/opendbc/car/tests/test_routes.py
@@ -0,0 +1,11 @@
+from parameterized import parameterized
+
+from opendbc.car.values import PLATFORMS
+from opendbc.car.tests.routes import non_tested_cars, routes
+
+
+@parameterized.expand(PLATFORMS.keys())
+def test_test_route_present(platform):
+ tested_platforms = [r.car_model for r in routes]
+ assert platform in set(tested_platforms) | set(non_tested_cars), \
+ f"Missing test route for {platform}. Add a route to opendbc/car/tests/routes.py"
diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml
index a4fc2a479f..3f881cac34 100644
--- a/opendbc/car/torque_data/override.toml
+++ b/opendbc/car/torque_data/override.toml
@@ -36,10 +36,12 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"SUBARU_OUTBACK" = [2.0, 1.5, 0.2]
"CADILLAC_ESCALADE" = [1.899999976158142, 1.842270016670227, 0.1120000034570694]
"CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2]
+"CADILLAC_XT4" = [1.45, 1.6, 0.2]
"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.05]
"CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
"CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16]
"CHEVROLET_EQUINOX" = [2.5, 2.5, 0.05]
+"CHEVROLET_VOLT_2019" = [1.4, 1.4, 0.16]
"VOLKSWAGEN_CADDY_MK3" = [1.2, 1.2, 0.1]
"VOLKSWAGEN_PASSAT_NMS" = [2.5, 2.5, 0.1]
"VOLKSWAGEN_SHARAN_MK2" = [2.5, 2.5, 0.1]
diff --git a/opendbc/car/torque_data/substitute.toml b/opendbc/car/torque_data/substitute.toml
index 8724a08010..6ffebbeec6 100644
--- a/opendbc/car/torque_data/substitute.toml
+++ b/opendbc/car/torque_data/substitute.toml
@@ -70,6 +70,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"VOLKSWAGEN_TAOS_MK1" = "VOLKSWAGEN_TIGUAN_MK2"
"VOLKSWAGEN_POLO_MK6" = "VOLKSWAGEN_GOLF_MK7"
"SEAT_ATECA_MK1" = "VOLKSWAGEN_GOLF_MK7"
+"VOLKSWAGEN_JETTA_MK6" = "VOLKSWAGEN_PASSAT_NMS"
"SUBARU_CROSSTREK_HYBRID" = "SUBARU_IMPREZA_2020"
"SUBARU_FORESTER_HYBRID" = "SUBARU_IMPREZA_2020"
diff --git a/opendbc/car/volkswagen/fingerprints.py b/opendbc/car/volkswagen/fingerprints.py
index 83756830a6..4711beaf3c 100644
--- a/opendbc/car/volkswagen/fingerprints.py
+++ b/opendbc/car/volkswagen/fingerprints.py
@@ -335,6 +335,14 @@
b'\xf1\x875Q0907572S \xf1\x890780',
],
},
+ CAR.VOLKSWAGEN_JETTA_MK6: {
+ (Ecu.srs, 0x715, None): [
+ b'\xf1\x875C0959655M \xf1\x890726\xf1\x82\t00NB1108--------24',
+ ],
+ (Ecu.fwdRadar, 0x757, None): [
+ b'\xf1\x877N0907572C \xf1\x890211\xf1\x82\x0151',
+ ],
+ },
CAR.VOLKSWAGEN_JETTA_MK7: {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8704E906024AK\xf1\x899937',
diff --git a/opendbc/car/volkswagen/values.py b/opendbc/car/volkswagen/values.py
index ca13f37ad2..67bfdb3bd8 100644
--- a/opendbc/car/volkswagen/values.py
+++ b/opendbc/car/volkswagen/values.py
@@ -269,6 +269,12 @@ class CAR(Platforms):
chassis_codes={"5G", "AU", "BA", "BE"},
wmis={WMI.VOLKSWAGEN_MEXICO_CAR, WMI.VOLKSWAGEN_EUROPE_CAR},
)
+ VOLKSWAGEN_JETTA_MK6 = VolkswagenPQPlatformConfig(
+ [VWCarDocs("Volkswagen Jetta 2015-2018")],
+ VolkswagenCarSpecs(mass=1518, wheelbase=2.65, minSteerSpeed=50 * CV.KPH_TO_MS, minEnableSpeed=20 * CV.KPH_TO_MS),
+ chassis_codes={"5K", "AJ"},
+ wmis={WMI.VOLKSWAGEN_MEXICO_CAR},
+ )
VOLKSWAGEN_JETTA_MK7 = VolkswagenMQBPlatformConfig(
[
VWCarDocs("Volkswagen Jetta 2018-24"),
diff --git a/opendbc/dbc/generator/toyota/_toyota_2017.dbc b/opendbc/dbc/generator/toyota/_toyota_2017.dbc
index e21f7426b5..10ed74fd08 100644
--- a/opendbc/dbc/generator/toyota/_toyota_2017.dbc
+++ b/opendbc/dbc/generator/toyota/_toyota_2017.dbc
@@ -45,6 +45,13 @@ BO_ 37 STEER_ANGLE_SENSOR: 8 XXX
SG_ STEER_FRACTION : 39|4@0- (0.1,0) [-0.7|0.7] "deg" XXX
SG_ STEER_RATE : 35|12@0- (1,0) [-2000|2000] "deg/s" XXX
+BO_ 120 ENG2F42: 4 CGW
+ SG_ FAVLMCHH : 7|16@0- (2,0) [0|0] "N" Vector__XX228X
+ SG_ CCRNG : 23|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ FDRVTYPD : 22|3@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GEARHD : 18|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ ENG2F42S : 31|8@0+ (1,0) [0|0] "" Vector__XXX
+
BO_ 166 BRAKE: 8 XXX
SG_ BRAKE_AMOUNT : 7|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PEDAL : 23|8@0+ (1,0) [0|255] "" XXX
@@ -71,6 +78,7 @@ BO_ 353 DSU_SPEED: 7 XXX
BO_ 452 ENGINE_RPM: 8 CGW
SG_ RPM : 7|16@0- (0.78125,0) [0|0] "rpm" SCS
+ SG_ ENGINE_RUNNING : 27|1@0+ (1,0) [0|1] "" XXX
BO_ 466 PCM_CRUISE: 8 XXX
SG_ GAS_RELEASED : 4|1@0+ (1,0) [0|1] "" XXX
@@ -91,9 +99,10 @@ BO_ 467 PCM_CRUISE_2: 8 XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
-BO_ 552 ACCELEROMETER: 8 XXX
- SG_ ACCEL_Z : 22|15@0- (1,0) [0|32767] "m/s^2" XXX
- SG_ ACCEL_X : 6|15@0- (0.001,0) [-20|20] "m/s^2" XXX
+BO_ 552 VSC1S29: 4 CGW
+ SG_ ICBACT : 7|1@0+ (1,0) [0|0] "" DS1
+ SG_ DVS0PCS : 6|15@0- (0.001,0) [0|0] "m/s^2" DS1
+ SG_ SM228 : 31|8@0+ (1,0) [0|0] "" DS1
BO_ 560 BRAKE_2: 7 XXX
SG_ BRAKE_PRESSED : 26|1@0+ (1,0) [0|1] "" XXX
@@ -147,6 +156,31 @@ BO_ 742 LEAD_INFO: 8 DSU
SG_ LEAD_REL_SPEED : 23|12@0- (0.025,0) [-100|100] "m/s" HCU
SG_ LEAD_LONG_DIST : 7|13@0+ (0.05,0) [0|300] "m" HCU
+BO_ 800 VSC1S07: 8 CGW
+ SG_ FBKRLY : 6|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCM : 4|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCSFT : 3|1@0+ (1,0) [0|0] "" DS1
+ SG_ FABS : 2|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ TSVSC : 1|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCL : 0|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQCSTBKB : 15|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PSBSTBY : 14|1@0+ (1,0) [0|0] "" DS1
+ SG_ P2BRXMK : 13|1@0+ (1,0) [0|0] "" DS1
+ SG_ MCC : 11|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQBKB : 10|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRSTOP : 9|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ BRKON : 8|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ ASLP : 23|8@0- (1,0) [0|0] "deg" DS1
+ SG_ BRTYPACC : 31|2@0+ (1,0) [0|0] "" DS1
+ SG_ BRKABT3 : 26|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT2 : 25|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT1 : 24|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GVC : 39|8@0- (0.04,0) [0|0] "m/s^2" DS1
+ SG_ XGVCINV : 43|1@0+ (1,0) [0|0] "" DS1
+ SG_ S07CNT : 52|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PCSBRSTA : 50|2@0+ (1,0) [0|0] "" DS1
+ SG_ VSC07SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM
+
BO_ 835 ACC_CONTROL: 8 DSU
SG_ ACCEL_CMD : 7|16@0- (0.001,0) [-20|20] "m/s^2" HCU
SG_ ALLOW_LONG_PRESS : 17|2@0+ (1,0) [0|2] "" XXX
@@ -272,6 +306,18 @@ BO_ 1044 AUTO_HIGH_BEAM: 8 FCM
SG_ F_AHB : 55|4@0+ (1,0) [0|0] "" Vector__XXX
SG_ C_AHB : 51|4@0+ (1,0) [0|0] "" Vector__XXX
+BO_ 1056 VSC1S08: 8 CGW
+ SG_ YR1Z : 7|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ YR2Z : 23|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ GL1Z : 39|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ GL2Z : 47|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ YRGSDIR : 55|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,SCS
+ SG_ GLZS : 51|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,MAV,SCS
+ SG_ YRZF : 50|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZS : 49|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZKS : 48|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ VSC08SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM,MAV
+
BO_ 1083 AUTOPARK_STATUS: 8 IPAS
SG_ STATE : 7|4@0+ (1,0) [0|15] "" XXX
@@ -350,9 +396,11 @@ BO_ 1552 BODY_CONTROL_STATE_2: 8 XXX
BO_ 1553 UI_SETTING: 8 XXX
SG_ UNITS : 26|2@0+ (1,0) [0|3] "" XXX
SG_ ODOMETER : 39|32@0+ (1,0) [0|1048575] "" XXX
+
BO_ 1556 BLINKERS_STATE: 8 XXX
- SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
+ SG_ BLINKER_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" XXX
SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX
+ SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
BO_ 1568 BODY_CONTROL_STATE: 8 XXX
SG_ METER_DIMMED : 38|1@0+ (1,0) [0|1] "" XXX
@@ -381,6 +429,20 @@ BO_ 1592 DOOR_LOCKS: 8 XXX
SG_ LOCK_STATUS : 20|1@0+ (1,0) [0|1] "" XXX
SG_ LOCKED_VIA_KEYFOB : 23|1@0+ (1,0) [0|1] "" XXX
+BO_ 1779 ADAS_TOGGLE_STATE: 8 XXX
+ SG_ OK_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" BCM
+ SG_ SWS_TOGGLE_CMD : 24|1@0+ (1,0) [0|1] "" XXX
+ SG_ SWS_SENSITIVITY_CMD : 26|2@0+ (1,0) [0|3] "" XXX
+ SG_ LKAS_ON_CMD : 28|1@0+ (1,0) [0|1] "" XXX
+ SG_ LKAS_OFF_CMD : 29|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_HI_CMD : 30|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_STD_CMD : 31|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_TOGGLE : 34|1@0+ (1,0) [0|1] "" XXX
+ SG_ BSM_TOGGLE_CMD : 37|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_SONAR_TOGGLE : 38|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_TOGGLE_CMD : 40|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_SENSITIVITY_CMD : 41|1@0+ (1,0) [0|1] "" XXX
+
CM_ SG_ 36 YAW_RATE "verify";
CM_ SG_ 36 ACCEL_X "x-axis accel";
CM_ SG_ 37 STEER_FRACTION "1/15th of the signal STEER_ANGLE, which is 1.5 deg; note that 0x8 is never set";
@@ -400,6 +462,8 @@ CM_ SG_ 614 ANGLE "set to measured angle when ipas control isn't active";
CM_ SG_ 643 _COUNTER "only used on cars that use this msg for cruise control";
CM_ SG_ 643 BRAKE_STATUS "only used on cars that use this msg for cruise control";
CM_ SG_ 643 PRECOLLISION_ACTIVE "set 0.5s before any braking";
+CM_ SG_ 800 SLOPE_ANGLE "potentially used by the PCM to compensate for road pitch";
+CM_ SG_ 800 ACCEL "filtered ego acceleration";
CM_ SG_ 835 ACC_TYPE "if 2, car is likely to have a permanent low speed lockout. 1 is ok";
CM_ SG_ 835 RADAR_DIRTY "Display Clean Radar Sensor message on HUD";
CM_ SG_ 835 ACC_MALFUNCTION "display ACC fault on dash if set to 1";
@@ -512,4 +576,5 @@ VAL_ 1552 METER_SLIDER_DIMMED 1 "Dimmed" 0 "Not Dimmed";
VAL_ 1552 UNITS 1 "km (km/L)" 2 "km (L/100km)" 3 "miles (MPG US)" 4 "miles (MPG Imperial)";
VAL_ 1553 UNITS 1 "km" 2 "miles";
VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left";
+VAL_ 1556 BLINKER_BUTTON_PRESSED 1 "button pressed" 0 "not pressed";
VAL_ 1592 LOCK_STATUS 0 "locked" 1 "unlocked";
diff --git a/opendbc/dbc/hongqi_hs5.dbc b/opendbc/dbc/hongqi_hs5.dbc
new file mode 100644
index 0000000000..76b41d873c
--- /dev/null
+++ b/opendbc/dbc/hongqi_hs5.dbc
@@ -0,0 +1,160 @@
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX
+
+
+BO_ 146 ECM_1: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ THROTTLE_1 : 8|12@1+ (1,0) [0|255] "" XXX
+ SG_ THROTTLE_2 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ THROTTLE_3 : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ DRIVER_THROTTLE : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 192 ABS_1: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|15] "" XXX
+ SG_ FRONT_LEFT : 8|16@1+ (0.01,0) [0|65535] "km/h" XXX
+ SG_ FRONT_RIGHT : 24|16@1+ (0.01,0) [0|65535] "km/h" XXX
+ SG_ VEHICLE_SPEED : 40|16@1+ (0.01,0) [0|65535] "km/h" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 194 ABS_2: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|15] "" XXX
+ SG_ REAR_LEFT : 8|16@1+ (0.01,0) [0|65535] "km/h" XXX
+ SG_ REAR_RIGHT : 24|16@1+ (0.01,0) [0|65535] "km/h" XXX
+ SG_ BRAKE_PRESSURE : 40|8@1+ (1,0) [0|255] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 208 EPS_1: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|15] "" XXX
+ SG_ STEER_ANGLE : 8|15@1+ (0.0225,0) [0|65535] "" XXX
+ SG_ STEER_ANGLE_DIRECTION : 23|1@1+ (1,0) [0|1] "direction" XXX
+ SG_ STEER_RATE : 24|15@1+ (0.0225,0) [0|65535] "" XXX
+ SG_ STEER_RATE_DIRECTION : 39|1@1+ (1,0) [0|1] "direction" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 336 EPS_2: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ EPS_TORQUE : 8|10@1- (1,0) [0|255] "" XXX
+ SG_ EPS_TORQUE_DIRECTION : 18|1@1+ (1,0) [0|1] "direction" XXX
+ SG_ UNKNOWN : 22|2@1+ (1,0) [0|3] "" XXX
+ SG_ LKAS_STATUS : 24|4@1+ (1,0) [0|15] "" XXX
+ SG_ DRIVER_INPUT_TORQUE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ LKAS_TORQUE : 40|10@1+ (1,0) [0|1023] "" XXX
+ SG_ LKAS_TORQUE_DIRECTION : 50|1@1+ (1,0) [0|1] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 272 ACC: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ UNKNOWN_1 : 8|12@1+ (1,0) [0|4095] "" XXX
+ SG_ UNKNOWN_2 : 20|4@1+ (1,0) [0|15] "" XXX
+ SG_ ACCELERATION : 24|12@1+ (1,-300) [0|255] "" XXX
+ SG_ STATUS : 36|4@1+ (1,0) [0|31] "x" XXX
+ SG_ UNKNOWN_3 : 46|1@1+ (1,0) [0|1] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 274 LKAS: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ LKAS_TORQUE : 8|10@1+ (1,0) [0|2047] "x" XXX
+ SG_ LKAS_TORQUE_DIRECTION : 18|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKAS_TORQUE_ACTIVE : 19|1@1+ (1,0) [0|1] "" XXX
+ SG_ UNKNOWN_ACTIVE_STATE : 26|1@1+ (1,0) [0|1] "" XXX
+ SG_ MAYBE_HUD_LANE_STATES : 28|2@1+ (1,0) [0|3] "" XXX
+ SG_ LKAS_ACTIVE : 32|1@1+ (1,0) [0|255] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 148 MAYBE_ABS: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ UNKNOWN_1 : 8|16@1+ (1,0) [0|15] "x" XXX
+ SG_ UNKNOWN_2 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ BRAKE_PRESSED : 35|1@1+ (1,0) [0|1] "x" XXX
+ SG_ UNKNOWN_3 : 46|2@1+ (1,0) [0|3] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 304 ABS_3: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_1 : 15|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 23|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_3 : 31|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_4 : 39|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_5 : 47|8@1+ (1,0) [0|255] "" XXX
+ SG_ DRIVER_BRAKE_PRESSURE : 48|12@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 144 MAYBE_ENGINE: 8 XXX
+ SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_4 : 8|12@1+ (1,0) [0|255] "" XXX
+ SG_ MAYBE_RPM : 20|12@1+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_1 : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 46|14@1+ (1,0) [0|4095] "" XXX
+ SG_ COUNTER : 60|4@1+ (1,0) [0|15] "" XXX
+
+BO_ 422 MAYBE_ACC_BUTTONS: 8 XXX
+ SG_ NEW_SIGNAL_1 : 18|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 560 TURN_SIGNALS: 8 XXX
+ SG_ RIGHT_TURN_SIGNALING : 45|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_TURN_SIGNALING : 44|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_TURN_BULB_3 : 21|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_TURN_BULB_3 : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_TURN_BULB_2 : 19|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_TURN_BULB_2 : 18|1@1+ (1,0) [0|1] "" XXX
+ SG_ LEFT_TURN_BULB_1 : 16|1@1+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_TURN_BULB_1 : 17|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 586 DOOR_FL: 8 XXX
+ SG_ OPEN : 2|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 588 DOOR_FR: 8 XXX
+ SG_ OPEN : 2|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 590 DOOR_RL: 8 XXX
+ SG_ OPEN : 2|1@1+ (1,0) [0|1] "" XXX
+
+BO_ 591 DOOR_RR: 8 XXX
+ SG_ OPEN : 2|1@1+ (1,0) [0|1] "" XXX
+
+
+
+
+CM_ SG_ 274 UNKNOWN_ACTIVE_STATE "Triggers changes from 8 to 9 in EPS_2.LKAS_STATUS";
+CM_ SG_ 560 RIGHT_TURN_SIGNALING "Includes 2.5 second convenience lane change interval";
+CM_ SG_ 560 LEFT_TURN_SIGNALING "Includes 2.5 second convenience lane change interval";
+VAL_ 336 LKAS_STATUS 1 "INITIALIZING" 5 "READY" 8 "ACTIVE_1" 9 "ACTIVE_2" 13 "FAULT" ;
+VAL_ 586 OPEN 0 "CLOSED" 1 "OPEN" ;
+VAL_ 588 OPEN 0 "CLOSED" 1 "OPEN" ;
+VAL_ 590 OPEN 0 "CLOSED" 1 "OPEN" ;
+VAL_ 591 OPEN 0 "CLOSED" 1 "OPEN" ;
diff --git a/opendbc/dbc/toyota_new_mc_pt_generated.dbc b/opendbc/dbc/toyota_new_mc_pt_generated.dbc
index 4126560fcc..c29df54853 100644
--- a/opendbc/dbc/toyota_new_mc_pt_generated.dbc
+++ b/opendbc/dbc/toyota_new_mc_pt_generated.dbc
@@ -49,6 +49,13 @@ BO_ 37 STEER_ANGLE_SENSOR: 8 XXX
SG_ STEER_FRACTION : 39|4@0- (0.1,0) [-0.7|0.7] "deg" XXX
SG_ STEER_RATE : 35|12@0- (1,0) [-2000|2000] "deg/s" XXX
+BO_ 120 ENG2F42: 4 CGW
+ SG_ FAVLMCHH : 7|16@0- (2,0) [0|0] "N" Vector__XX228X
+ SG_ CCRNG : 23|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ FDRVTYPD : 22|3@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GEARHD : 18|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ ENG2F42S : 31|8@0+ (1,0) [0|0] "" Vector__XXX
+
BO_ 166 BRAKE: 8 XXX
SG_ BRAKE_AMOUNT : 7|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PEDAL : 23|8@0+ (1,0) [0|255] "" XXX
@@ -75,6 +82,7 @@ BO_ 353 DSU_SPEED: 7 XXX
BO_ 452 ENGINE_RPM: 8 CGW
SG_ RPM : 7|16@0- (0.78125,0) [0|0] "rpm" SCS
+ SG_ ENGINE_RUNNING : 27|1@0+ (1,0) [0|1] "" XXX
BO_ 466 PCM_CRUISE: 8 XXX
SG_ GAS_RELEASED : 4|1@0+ (1,0) [0|1] "" XXX
@@ -95,9 +103,10 @@ BO_ 467 PCM_CRUISE_2: 8 XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
-BO_ 552 ACCELEROMETER: 8 XXX
- SG_ ACCEL_Z : 22|15@0- (1,0) [0|32767] "m/s^2" XXX
- SG_ ACCEL_X : 6|15@0- (0.001,0) [-20|20] "m/s^2" XXX
+BO_ 552 VSC1S29: 4 CGW
+ SG_ ICBACT : 7|1@0+ (1,0) [0|0] "" DS1
+ SG_ DVS0PCS : 6|15@0- (0.001,0) [0|0] "m/s^2" DS1
+ SG_ SM228 : 31|8@0+ (1,0) [0|0] "" DS1
BO_ 560 BRAKE_2: 7 XXX
SG_ BRAKE_PRESSED : 26|1@0+ (1,0) [0|1] "" XXX
@@ -151,6 +160,31 @@ BO_ 742 LEAD_INFO: 8 DSU
SG_ LEAD_REL_SPEED : 23|12@0- (0.025,0) [-100|100] "m/s" HCU
SG_ LEAD_LONG_DIST : 7|13@0+ (0.05,0) [0|300] "m" HCU
+BO_ 800 VSC1S07: 8 CGW
+ SG_ FBKRLY : 6|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCM : 4|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCSFT : 3|1@0+ (1,0) [0|0] "" DS1
+ SG_ FABS : 2|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ TSVSC : 1|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCL : 0|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQCSTBKB : 15|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PSBSTBY : 14|1@0+ (1,0) [0|0] "" DS1
+ SG_ P2BRXMK : 13|1@0+ (1,0) [0|0] "" DS1
+ SG_ MCC : 11|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQBKB : 10|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRSTOP : 9|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ BRKON : 8|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ ASLP : 23|8@0- (1,0) [0|0] "deg" DS1
+ SG_ BRTYPACC : 31|2@0+ (1,0) [0|0] "" DS1
+ SG_ BRKABT3 : 26|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT2 : 25|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT1 : 24|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GVC : 39|8@0- (0.04,0) [0|0] "m/s^2" DS1
+ SG_ XGVCINV : 43|1@0+ (1,0) [0|0] "" DS1
+ SG_ S07CNT : 52|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PCSBRSTA : 50|2@0+ (1,0) [0|0] "" DS1
+ SG_ VSC07SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM
+
BO_ 835 ACC_CONTROL: 8 DSU
SG_ ACCEL_CMD : 7|16@0- (0.001,0) [-20|20] "m/s^2" HCU
SG_ ALLOW_LONG_PRESS : 17|2@0+ (1,0) [0|2] "" XXX
@@ -276,6 +310,18 @@ BO_ 1044 AUTO_HIGH_BEAM: 8 FCM
SG_ F_AHB : 55|4@0+ (1,0) [0|0] "" Vector__XXX
SG_ C_AHB : 51|4@0+ (1,0) [0|0] "" Vector__XXX
+BO_ 1056 VSC1S08: 8 CGW
+ SG_ YR1Z : 7|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ YR2Z : 23|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ GL1Z : 39|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ GL2Z : 47|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ YRGSDIR : 55|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,SCS
+ SG_ GLZS : 51|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,MAV,SCS
+ SG_ YRZF : 50|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZS : 49|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZKS : 48|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ VSC08SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM,MAV
+
BO_ 1083 AUTOPARK_STATUS: 8 IPAS
SG_ STATE : 7|4@0+ (1,0) [0|15] "" XXX
@@ -354,9 +400,11 @@ BO_ 1552 BODY_CONTROL_STATE_2: 8 XXX
BO_ 1553 UI_SETTING: 8 XXX
SG_ UNITS : 26|2@0+ (1,0) [0|3] "" XXX
SG_ ODOMETER : 39|32@0+ (1,0) [0|1048575] "" XXX
+
BO_ 1556 BLINKERS_STATE: 8 XXX
- SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
+ SG_ BLINKER_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" XXX
SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX
+ SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
BO_ 1568 BODY_CONTROL_STATE: 8 XXX
SG_ METER_DIMMED : 38|1@0+ (1,0) [0|1] "" XXX
@@ -385,6 +433,20 @@ BO_ 1592 DOOR_LOCKS: 8 XXX
SG_ LOCK_STATUS : 20|1@0+ (1,0) [0|1] "" XXX
SG_ LOCKED_VIA_KEYFOB : 23|1@0+ (1,0) [0|1] "" XXX
+BO_ 1779 ADAS_TOGGLE_STATE: 8 XXX
+ SG_ OK_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" BCM
+ SG_ SWS_TOGGLE_CMD : 24|1@0+ (1,0) [0|1] "" XXX
+ SG_ SWS_SENSITIVITY_CMD : 26|2@0+ (1,0) [0|3] "" XXX
+ SG_ LKAS_ON_CMD : 28|1@0+ (1,0) [0|1] "" XXX
+ SG_ LKAS_OFF_CMD : 29|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_HI_CMD : 30|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_STD_CMD : 31|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_TOGGLE : 34|1@0+ (1,0) [0|1] "" XXX
+ SG_ BSM_TOGGLE_CMD : 37|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_SONAR_TOGGLE : 38|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_TOGGLE_CMD : 40|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_SENSITIVITY_CMD : 41|1@0+ (1,0) [0|1] "" XXX
+
CM_ SG_ 36 YAW_RATE "verify";
CM_ SG_ 36 ACCEL_X "x-axis accel";
CM_ SG_ 37 STEER_FRACTION "1/15th of the signal STEER_ANGLE, which is 1.5 deg; note that 0x8 is never set";
@@ -404,6 +466,8 @@ CM_ SG_ 614 ANGLE "set to measured angle when ipas control isn't active";
CM_ SG_ 643 _COUNTER "only used on cars that use this msg for cruise control";
CM_ SG_ 643 BRAKE_STATUS "only used on cars that use this msg for cruise control";
CM_ SG_ 643 PRECOLLISION_ACTIVE "set 0.5s before any braking";
+CM_ SG_ 800 SLOPE_ANGLE "potentially used by the PCM to compensate for road pitch";
+CM_ SG_ 800 ACCEL "filtered ego acceleration";
CM_ SG_ 835 ACC_TYPE "if 2, car is likely to have a permanent low speed lockout. 1 is ok";
CM_ SG_ 835 RADAR_DIRTY "Display Clean Radar Sensor message on HUD";
CM_ SG_ 835 ACC_MALFUNCTION "display ACC fault on dash if set to 1";
@@ -516,6 +580,7 @@ VAL_ 1552 METER_SLIDER_DIMMED 1 "Dimmed" 0 "Not Dimmed";
VAL_ 1552 UNITS 1 "km (km/L)" 2 "km (L/100km)" 3 "miles (MPG US)" 4 "miles (MPG Imperial)";
VAL_ 1553 UNITS 1 "km" 2 "miles";
VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left";
+VAL_ 1556 BLINKER_BUTTON_PRESSED 1 "button pressed" 0 "not pressed";
VAL_ 1592 LOCK_STATUS 0 "locked" 1 "unlocked";
CM_ "toyota_new_mc_pt.dbc starts here";
diff --git a/opendbc/dbc/toyota_nodsu_pt_generated.dbc b/opendbc/dbc/toyota_nodsu_pt_generated.dbc
index 549f667087..cd351a3967 100644
--- a/opendbc/dbc/toyota_nodsu_pt_generated.dbc
+++ b/opendbc/dbc/toyota_nodsu_pt_generated.dbc
@@ -49,6 +49,13 @@ BO_ 37 STEER_ANGLE_SENSOR: 8 XXX
SG_ STEER_FRACTION : 39|4@0- (0.1,0) [-0.7|0.7] "deg" XXX
SG_ STEER_RATE : 35|12@0- (1,0) [-2000|2000] "deg/s" XXX
+BO_ 120 ENG2F42: 4 CGW
+ SG_ FAVLMCHH : 7|16@0- (2,0) [0|0] "N" Vector__XX228X
+ SG_ CCRNG : 23|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ FDRVTYPD : 22|3@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GEARHD : 18|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ ENG2F42S : 31|8@0+ (1,0) [0|0] "" Vector__XXX
+
BO_ 166 BRAKE: 8 XXX
SG_ BRAKE_AMOUNT : 7|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PEDAL : 23|8@0+ (1,0) [0|255] "" XXX
@@ -75,6 +82,7 @@ BO_ 353 DSU_SPEED: 7 XXX
BO_ 452 ENGINE_RPM: 8 CGW
SG_ RPM : 7|16@0- (0.78125,0) [0|0] "rpm" SCS
+ SG_ ENGINE_RUNNING : 27|1@0+ (1,0) [0|1] "" XXX
BO_ 466 PCM_CRUISE: 8 XXX
SG_ GAS_RELEASED : 4|1@0+ (1,0) [0|1] "" XXX
@@ -95,9 +103,10 @@ BO_ 467 PCM_CRUISE_2: 8 XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
-BO_ 552 ACCELEROMETER: 8 XXX
- SG_ ACCEL_Z : 22|15@0- (1,0) [0|32767] "m/s^2" XXX
- SG_ ACCEL_X : 6|15@0- (0.001,0) [-20|20] "m/s^2" XXX
+BO_ 552 VSC1S29: 4 CGW
+ SG_ ICBACT : 7|1@0+ (1,0) [0|0] "" DS1
+ SG_ DVS0PCS : 6|15@0- (0.001,0) [0|0] "m/s^2" DS1
+ SG_ SM228 : 31|8@0+ (1,0) [0|0] "" DS1
BO_ 560 BRAKE_2: 7 XXX
SG_ BRAKE_PRESSED : 26|1@0+ (1,0) [0|1] "" XXX
@@ -151,6 +160,31 @@ BO_ 742 LEAD_INFO: 8 DSU
SG_ LEAD_REL_SPEED : 23|12@0- (0.025,0) [-100|100] "m/s" HCU
SG_ LEAD_LONG_DIST : 7|13@0+ (0.05,0) [0|300] "m" HCU
+BO_ 800 VSC1S07: 8 CGW
+ SG_ FBKRLY : 6|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCM : 4|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCSFT : 3|1@0+ (1,0) [0|0] "" DS1
+ SG_ FABS : 2|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ TSVSC : 1|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCL : 0|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQCSTBKB : 15|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PSBSTBY : 14|1@0+ (1,0) [0|0] "" DS1
+ SG_ P2BRXMK : 13|1@0+ (1,0) [0|0] "" DS1
+ SG_ MCC : 11|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQBKB : 10|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRSTOP : 9|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ BRKON : 8|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ ASLP : 23|8@0- (1,0) [0|0] "deg" DS1
+ SG_ BRTYPACC : 31|2@0+ (1,0) [0|0] "" DS1
+ SG_ BRKABT3 : 26|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT2 : 25|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT1 : 24|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GVC : 39|8@0- (0.04,0) [0|0] "m/s^2" DS1
+ SG_ XGVCINV : 43|1@0+ (1,0) [0|0] "" DS1
+ SG_ S07CNT : 52|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PCSBRSTA : 50|2@0+ (1,0) [0|0] "" DS1
+ SG_ VSC07SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM
+
BO_ 835 ACC_CONTROL: 8 DSU
SG_ ACCEL_CMD : 7|16@0- (0.001,0) [-20|20] "m/s^2" HCU
SG_ ALLOW_LONG_PRESS : 17|2@0+ (1,0) [0|2] "" XXX
@@ -276,6 +310,18 @@ BO_ 1044 AUTO_HIGH_BEAM: 8 FCM
SG_ F_AHB : 55|4@0+ (1,0) [0|0] "" Vector__XXX
SG_ C_AHB : 51|4@0+ (1,0) [0|0] "" Vector__XXX
+BO_ 1056 VSC1S08: 8 CGW
+ SG_ YR1Z : 7|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ YR2Z : 23|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ GL1Z : 39|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ GL2Z : 47|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ YRGSDIR : 55|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,SCS
+ SG_ GLZS : 51|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,MAV,SCS
+ SG_ YRZF : 50|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZS : 49|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZKS : 48|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ VSC08SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM,MAV
+
BO_ 1083 AUTOPARK_STATUS: 8 IPAS
SG_ STATE : 7|4@0+ (1,0) [0|15] "" XXX
@@ -354,9 +400,11 @@ BO_ 1552 BODY_CONTROL_STATE_2: 8 XXX
BO_ 1553 UI_SETTING: 8 XXX
SG_ UNITS : 26|2@0+ (1,0) [0|3] "" XXX
SG_ ODOMETER : 39|32@0+ (1,0) [0|1048575] "" XXX
+
BO_ 1556 BLINKERS_STATE: 8 XXX
- SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
+ SG_ BLINKER_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" XXX
SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX
+ SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
BO_ 1568 BODY_CONTROL_STATE: 8 XXX
SG_ METER_DIMMED : 38|1@0+ (1,0) [0|1] "" XXX
@@ -385,6 +433,20 @@ BO_ 1592 DOOR_LOCKS: 8 XXX
SG_ LOCK_STATUS : 20|1@0+ (1,0) [0|1] "" XXX
SG_ LOCKED_VIA_KEYFOB : 23|1@0+ (1,0) [0|1] "" XXX
+BO_ 1779 ADAS_TOGGLE_STATE: 8 XXX
+ SG_ OK_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" BCM
+ SG_ SWS_TOGGLE_CMD : 24|1@0+ (1,0) [0|1] "" XXX
+ SG_ SWS_SENSITIVITY_CMD : 26|2@0+ (1,0) [0|3] "" XXX
+ SG_ LKAS_ON_CMD : 28|1@0+ (1,0) [0|1] "" XXX
+ SG_ LKAS_OFF_CMD : 29|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_HI_CMD : 30|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_STD_CMD : 31|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_TOGGLE : 34|1@0+ (1,0) [0|1] "" XXX
+ SG_ BSM_TOGGLE_CMD : 37|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_SONAR_TOGGLE : 38|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_TOGGLE_CMD : 40|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_SENSITIVITY_CMD : 41|1@0+ (1,0) [0|1] "" XXX
+
CM_ SG_ 36 YAW_RATE "verify";
CM_ SG_ 36 ACCEL_X "x-axis accel";
CM_ SG_ 37 STEER_FRACTION "1/15th of the signal STEER_ANGLE, which is 1.5 deg; note that 0x8 is never set";
@@ -404,6 +466,8 @@ CM_ SG_ 614 ANGLE "set to measured angle when ipas control isn't active";
CM_ SG_ 643 _COUNTER "only used on cars that use this msg for cruise control";
CM_ SG_ 643 BRAKE_STATUS "only used on cars that use this msg for cruise control";
CM_ SG_ 643 PRECOLLISION_ACTIVE "set 0.5s before any braking";
+CM_ SG_ 800 SLOPE_ANGLE "potentially used by the PCM to compensate for road pitch";
+CM_ SG_ 800 ACCEL "filtered ego acceleration";
CM_ SG_ 835 ACC_TYPE "if 2, car is likely to have a permanent low speed lockout. 1 is ok";
CM_ SG_ 835 RADAR_DIRTY "Display Clean Radar Sensor message on HUD";
CM_ SG_ 835 ACC_MALFUNCTION "display ACC fault on dash if set to 1";
@@ -516,6 +580,7 @@ VAL_ 1552 METER_SLIDER_DIMMED 1 "Dimmed" 0 "Not Dimmed";
VAL_ 1552 UNITS 1 "km (km/L)" 2 "km (L/100km)" 3 "miles (MPG US)" 4 "miles (MPG Imperial)";
VAL_ 1553 UNITS 1 "km" 2 "miles";
VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left";
+VAL_ 1556 BLINKER_BUTTON_PRESSED 1 "button pressed" 0 "not pressed";
VAL_ 1592 LOCK_STATUS 0 "locked" 1 "unlocked";
CM_ "toyota_nodsu_pt.dbc starts here";
diff --git a/opendbc/dbc/toyota_tnga_k_pt_generated.dbc b/opendbc/dbc/toyota_tnga_k_pt_generated.dbc
index 1a21ab81b6..99a1e59055 100644
--- a/opendbc/dbc/toyota_tnga_k_pt_generated.dbc
+++ b/opendbc/dbc/toyota_tnga_k_pt_generated.dbc
@@ -49,6 +49,13 @@ BO_ 37 STEER_ANGLE_SENSOR: 8 XXX
SG_ STEER_FRACTION : 39|4@0- (0.1,0) [-0.7|0.7] "deg" XXX
SG_ STEER_RATE : 35|12@0- (1,0) [-2000|2000] "deg/s" XXX
+BO_ 120 ENG2F42: 4 CGW
+ SG_ FAVLMCHH : 7|16@0- (2,0) [0|0] "N" Vector__XX228X
+ SG_ CCRNG : 23|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ FDRVTYPD : 22|3@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GEARHD : 18|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ ENG2F42S : 31|8@0+ (1,0) [0|0] "" Vector__XXX
+
BO_ 166 BRAKE: 8 XXX
SG_ BRAKE_AMOUNT : 7|8@0+ (1,0) [0|255] "" XXX
SG_ BRAKE_PEDAL : 23|8@0+ (1,0) [0|255] "" XXX
@@ -75,6 +82,7 @@ BO_ 353 DSU_SPEED: 7 XXX
BO_ 452 ENGINE_RPM: 8 CGW
SG_ RPM : 7|16@0- (0.78125,0) [0|0] "rpm" SCS
+ SG_ ENGINE_RUNNING : 27|1@0+ (1,0) [0|1] "" XXX
BO_ 466 PCM_CRUISE: 8 XXX
SG_ GAS_RELEASED : 4|1@0+ (1,0) [0|1] "" XXX
@@ -95,9 +103,10 @@ BO_ 467 PCM_CRUISE_2: 8 XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
-BO_ 552 ACCELEROMETER: 8 XXX
- SG_ ACCEL_Z : 22|15@0- (1,0) [0|32767] "m/s^2" XXX
- SG_ ACCEL_X : 6|15@0- (0.001,0) [-20|20] "m/s^2" XXX
+BO_ 552 VSC1S29: 4 CGW
+ SG_ ICBACT : 7|1@0+ (1,0) [0|0] "" DS1
+ SG_ DVS0PCS : 6|15@0- (0.001,0) [0|0] "m/s^2" DS1
+ SG_ SM228 : 31|8@0+ (1,0) [0|0] "" DS1
BO_ 560 BRAKE_2: 7 XXX
SG_ BRAKE_PRESSED : 26|1@0+ (1,0) [0|1] "" XXX
@@ -151,6 +160,31 @@ BO_ 742 LEAD_INFO: 8 DSU
SG_ LEAD_REL_SPEED : 23|12@0- (0.025,0) [-100|100] "m/s" HCU
SG_ LEAD_LONG_DIST : 7|13@0+ (0.05,0) [0|300] "m" HCU
+BO_ 800 VSC1S07: 8 CGW
+ SG_ FBKRLY : 6|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCM : 4|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCSFT : 3|1@0+ (1,0) [0|0] "" DS1
+ SG_ FABS : 2|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ TSVSC : 1|1@0+ (1,0) [0|0] "" DS1
+ SG_ FVSCL : 0|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQCSTBKB : 15|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PSBSTBY : 14|1@0+ (1,0) [0|0] "" DS1
+ SG_ P2BRXMK : 13|1@0+ (1,0) [0|0] "" DS1
+ SG_ MCC : 11|1@0+ (1,0) [0|0] "" DS1
+ SG_ RQBKB : 10|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRSTOP : 9|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ BRKON : 8|1@0+ (1,0) [0|0] "" DS1,FCM
+ SG_ ASLP : 23|8@0- (1,0) [0|0] "deg" DS1
+ SG_ BRTYPACC : 31|2@0+ (1,0) [0|0] "" DS1
+ SG_ BRKABT3 : 26|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT2 : 25|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ BRKABT1 : 24|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ GVC : 39|8@0- (0.04,0) [0|0] "m/s^2" DS1
+ SG_ XGVCINV : 43|1@0+ (1,0) [0|0] "" DS1
+ SG_ S07CNT : 52|1@0+ (1,0) [0|0] "" Vector__XXX
+ SG_ PCSBRSTA : 50|2@0+ (1,0) [0|0] "" DS1
+ SG_ VSC07SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM
+
BO_ 835 ACC_CONTROL: 8 DSU
SG_ ACCEL_CMD : 7|16@0- (0.001,0) [-20|20] "m/s^2" HCU
SG_ ALLOW_LONG_PRESS : 17|2@0+ (1,0) [0|2] "" XXX
@@ -276,6 +310,18 @@ BO_ 1044 AUTO_HIGH_BEAM: 8 FCM
SG_ F_AHB : 55|4@0+ (1,0) [0|0] "" Vector__XXX
SG_ C_AHB : 51|4@0+ (1,0) [0|0] "" Vector__XXX
+BO_ 1056 VSC1S08: 8 CGW
+ SG_ YR1Z : 7|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ YR2Z : 23|16@0- (1,0) [0|0] "rad/s" DS1,FCM,MAV
+ SG_ GL1Z : 39|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ GL2Z : 47|8@0- (0.0359,0) [0|0] "m/s^2" DS1,FCM,KSS,MAV,SCS
+ SG_ YRGSDIR : 55|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,SCS
+ SG_ GLZS : 51|1@0+ (1,0) [0|0] "" DS1,FCM,KSS,MAV,SCS
+ SG_ YRZF : 50|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZS : 49|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ YRZKS : 48|1@0+ (1,0) [0|0] "" DS1,FCM,MAV
+ SG_ VSC08SUM : 63|8@0+ (1,0) [0|0] "" DS1,FCM,MAV
+
BO_ 1083 AUTOPARK_STATUS: 8 IPAS
SG_ STATE : 7|4@0+ (1,0) [0|15] "" XXX
@@ -354,9 +400,11 @@ BO_ 1552 BODY_CONTROL_STATE_2: 8 XXX
BO_ 1553 UI_SETTING: 8 XXX
SG_ UNITS : 26|2@0+ (1,0) [0|3] "" XXX
SG_ ODOMETER : 39|32@0+ (1,0) [0|1048575] "" XXX
+
BO_ 1556 BLINKERS_STATE: 8 XXX
- SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
+ SG_ BLINKER_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" XXX
SG_ HAZARD_LIGHT : 27|1@0+ (1,0) [0|1] "" XXX
+ SG_ TURN_SIGNALS : 29|2@0+ (1,0) [0|3] "" XXX
BO_ 1568 BODY_CONTROL_STATE: 8 XXX
SG_ METER_DIMMED : 38|1@0+ (1,0) [0|1] "" XXX
@@ -385,6 +433,20 @@ BO_ 1592 DOOR_LOCKS: 8 XXX
SG_ LOCK_STATUS : 20|1@0+ (1,0) [0|1] "" XXX
SG_ LOCKED_VIA_KEYFOB : 23|1@0+ (1,0) [0|1] "" XXX
+BO_ 1779 ADAS_TOGGLE_STATE: 8 XXX
+ SG_ OK_BUTTON_PRESSED : 15|1@0+ (1,0) [0|1] "" BCM
+ SG_ SWS_TOGGLE_CMD : 24|1@0+ (1,0) [0|1] "" XXX
+ SG_ SWS_SENSITIVITY_CMD : 26|2@0+ (1,0) [0|3] "" XXX
+ SG_ LKAS_ON_CMD : 28|1@0+ (1,0) [0|1] "" XXX
+ SG_ LKAS_OFF_CMD : 29|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_HI_CMD : 30|1@0+ (1,0) [0|1] "" XXX
+ SG_ LDA_SENSITIVITY_STD_CMD : 31|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_TOGGLE : 34|1@0+ (1,0) [0|1] "" XXX
+ SG_ BSM_TOGGLE_CMD : 37|1@0+ (1,0) [0|1] "" XXX
+ SG_ IPAS_SONAR_TOGGLE : 38|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_TOGGLE_CMD : 40|1@0+ (1,0) [0|1] "" XXX
+ SG_ PCS_SENSITIVITY_CMD : 41|1@0+ (1,0) [0|1] "" XXX
+
CM_ SG_ 36 YAW_RATE "verify";
CM_ SG_ 36 ACCEL_X "x-axis accel";
CM_ SG_ 37 STEER_FRACTION "1/15th of the signal STEER_ANGLE, which is 1.5 deg; note that 0x8 is never set";
@@ -404,6 +466,8 @@ CM_ SG_ 614 ANGLE "set to measured angle when ipas control isn't active";
CM_ SG_ 643 _COUNTER "only used on cars that use this msg for cruise control";
CM_ SG_ 643 BRAKE_STATUS "only used on cars that use this msg for cruise control";
CM_ SG_ 643 PRECOLLISION_ACTIVE "set 0.5s before any braking";
+CM_ SG_ 800 SLOPE_ANGLE "potentially used by the PCM to compensate for road pitch";
+CM_ SG_ 800 ACCEL "filtered ego acceleration";
CM_ SG_ 835 ACC_TYPE "if 2, car is likely to have a permanent low speed lockout. 1 is ok";
CM_ SG_ 835 RADAR_DIRTY "Display Clean Radar Sensor message on HUD";
CM_ SG_ 835 ACC_MALFUNCTION "display ACC fault on dash if set to 1";
@@ -516,6 +580,7 @@ VAL_ 1552 METER_SLIDER_DIMMED 1 "Dimmed" 0 "Not Dimmed";
VAL_ 1552 UNITS 1 "km (km/L)" 2 "km (L/100km)" 3 "miles (MPG US)" 4 "miles (MPG Imperial)";
VAL_ 1553 UNITS 1 "km" 2 "miles";
VAL_ 1556 TURN_SIGNALS 3 "none" 2 "right" 1 "left";
+VAL_ 1556 BLINKER_BUTTON_PRESSED 1 "button pressed" 0 "not pressed";
VAL_ 1592 LOCK_STATUS 0 "locked" 1 "unlocked";
CM_ "toyota_tnga_k_pt.dbc starts here";
diff --git a/pyproject.toml b/pyproject.toml
index c6496e287c..3eb94d8b22 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -16,6 +16,8 @@ dependencies = [
"crcmod",
"tqdm",
"pandacan@git+https://github.com/commaai/panda.git@master",
+ "setuptools", # setuptools includes distutils which is needed by Cython and pre-commit.
+ # distutils was removed in python3.12 from the standard library.
]
[project.optional-dependencies]
@@ -33,6 +35,10 @@ docs = [
"Jinja2",
"natsort",
]
+examples = [
+ "inputs",
+ "matplotlib",
+]
[tool.pytest.ini_options]
addopts = "--ignore=panda/ -Werror --strict-config --strict-markers --durations=10 -n auto"
@@ -92,3 +98,7 @@ ignore = [
"NPY002", # new numpy random syntax is worse
]
flake8-implicit-str-concat.allow-multiline=false
+
+[tool.ruff.lint.flake8-tidy-imports.banned-api]
+"pytest.main".msg = "pytest.main requires special handling that is easy to mess up!"
+"unittest".msg = "Use pytest"