From 6a308b9cefe543a08160d4dbdfc62b0c5eb5a368 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:40:50 -0400 Subject: [PATCH 01/17] move CARS_template.md --- opendbc/car/docs/CARS_template.md | 74 +++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 opendbc/car/docs/CARS_template.md diff --git a/opendbc/car/docs/CARS_template.md b/opendbc/car/docs/CARS_template.md new file mode 100644 index 0000000000..2f49e79b81 --- /dev/null +++ b/opendbc/car/docs/CARS_template.md @@ -0,0 +1,74 @@ +{% set footnote_tag = '[{}](#footnotes)' %} +{% set star_icon = '[![star](assets/icon-star-{}.svg)](##)' %} +{% set video_icon = '' %} +{# Force hardware column wider by using a blank image with max width. #} +{% set width_tag = '%s
 ' %} +{% set hardware_col_name = 'Hardware Needed' %} +{% set wide_hardware_col_name = width_tag|format(hardware_col_name) -%} + + + +# Supported Cars + +A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. + +# {{all_car_docs | length}} Supported Cars + +|{{Column | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}| +|---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%} +{% for car_docs in all_car_docs %} +|{% for column in Column %}{{car_docs.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %} + +{% endfor %} + +### Footnotes +{% for footnote in footnotes %} +{{loop.index}}{{footnote}}
+{% endfor %} + +## Community Maintained Cars +Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). + +# Don't see your car here? + +**openpilot can support many more cars than it currently does.** There are a few reasons your car may not be supported. +If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported! We're adding support for new cars all the time. **We don't have a roadmap for car support**, and in fact, most car support comes from users like you! + +### Which cars are able to be supported? + +openpilot uses the existing steering, gas, and brake interfaces in your car. If your car lacks any one of these interfaces, openpilot will not be able to control the car. If your car has [ACC](https://en.wikipedia.org/wiki/Adaptive_cruise_control) and any form of [LKAS](https://en.wikipedia.org/wiki/Automated_Lane_Keeping_Systems)/[LCA](https://en.wikipedia.org/wiki/Lane_centering), then it almost certainly has these interfaces. These features generally started shipping on cars around 2016. Note that manufacturers will often make their own [marketing terms](https://en.wikipedia.org/wiki/Adaptive_cruise_control#Vehicle_models_supporting_adaptive_cruise_control) for these features, such as Hyundai's "Smart Cruise Control" branding of Adaptive Cruise Control. + +If your car has the following packages or features, then it's a good candidate for support. + +| Make | Required Package/Features | +| ---- | ------------------------- | +| Acura | Any car with AcuraWatch Plus will work. AcuraWatch Plus comes standard on many newer models. | +| Ford | Any car with Lane Centering will likely work. | +| Honda | Any car with Honda Sensing will work. Honda Sensing comes standard on many newer models. | +| Subaru | Any car with EyeSight will work. EyeSight comes standard on many newer models. | +| Nissan | Any car with ProPILOT will likely work. | +| Toyota & Lexus | Any car that has Toyota/Lexus Safety Sense with "Lane Departure Alert with Steering Assist (LDA w/SA)" and/or "Lane Tracing Assist (LTA)" will work. Note that LDA without Steering Assist will not work. These features come standard on most newer models. | +| Hyundai, Kia, & Genesis | Any car with Smart Cruise Control (SCC) and Lane Following Assist (LFA) or Lane Keeping Assist (LKAS) will work. LKAS/LFA comes standard on most newer models. Any form of SCC will work, such as NSCC. | +| Chrysler, Jeep, & Ram | Any car with LaneSense and Adaptive Cruise Control will likely work. These come standard on many newer models. | + +### FlexRay + +All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay. + +### Toyota Security + +openpilot does not yet support these Toyota models due to a new message authentication method. +[Vote](https://comma.ai/shop#toyota-security) if you'd like to see openpilot support on these models. + +* Toyota RAV4 Prime 2021+ +* Toyota Sienna 2021+ +* Toyota Venza 2021+ +* Toyota Sequoia 2023+ +* Toyota Tundra 2022+ +* Toyota Highlander 2024+ +* Toyota Corolla Cross 2022+ (only US model) +* Toyota Camry 2025+ +* Lexus NX 2022+ +* Toyota bZ4x 2023+ +* Subaru Solterra 2023+ + From f2c3163682e83bf846ed7aa6d3b61bd552fbf728 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:41:36 -0400 Subject: [PATCH 02/17] move docs.py, rename to generate_docs.py --- opendbc/car/docs/generate_docs.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 opendbc/car/docs/generate_docs.py diff --git a/opendbc/car/docs/generate_docs.py b/opendbc/car/docs/generate_docs.py new file mode 100755 index 0000000000..f807fc320e --- /dev/null +++ b/opendbc/car/docs/generate_docs.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +import argparse +import os + +from openpilot.common.basedir import BASEDIR +from opendbc.car.docs import get_all_car_docs, generate_cars_md + +CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md") +CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Auto generates supported cars documentation", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + parser.add_argument("--template", default=CARS_MD_TEMPLATE, help="Override default template filename") + parser.add_argument("--out", default=CARS_MD_OUT, help="Override default generated filename") + args = parser.parse_args() + + with open(args.out, 'w') as f: + f.write(generate_cars_md(get_all_car_docs(), args.template)) + print(f"Generated and written to {args.out}") From a34e354f17c98178999b15657c1a8e28a0378489 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:42:35 -0400 Subject: [PATCH 03/17] move docs_definitions.py --- opendbc/car/{ => docs}/docs_definitions.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opendbc/car/{ => docs}/docs_definitions.py (100%) diff --git a/opendbc/car/docs_definitions.py b/opendbc/car/docs/docs_definitions.py similarity index 100% rename from opendbc/car/docs_definitions.py rename to opendbc/car/docs/docs_definitions.py From bb463f827e64c621996a8a5002195f9a5b90e992 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:43:56 -0400 Subject: [PATCH 04/17] move test_platform_configs.py --- opendbc/car/{tests => docs}/test_platform_configs.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opendbc/car/{tests => docs}/test_platform_configs.py (100%) diff --git a/opendbc/car/tests/test_platform_configs.py b/opendbc/car/docs/test_platform_configs.py similarity index 100% rename from opendbc/car/tests/test_platform_configs.py rename to opendbc/car/docs/test_platform_configs.py From 16df0a21d12d2a260393d554e33bd8723f7a3dd2 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:44:55 -0400 Subject: [PATCH 05/17] move test_docs.py --- opendbc/car/{tests => docs}/test_docs.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opendbc/car/{tests => docs}/test_docs.py (100%) diff --git a/opendbc/car/tests/test_docs.py b/opendbc/car/docs/test_docs.py similarity index 100% rename from opendbc/car/tests/test_docs.py rename to opendbc/car/docs/test_docs.py From 8961b570c1533721351dcb95e52a94abcd27b95f Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:45:45 -0400 Subject: [PATCH 06/17] rename docs_definitions -> definitions --- opendbc/car/docs/{docs_definitions.py => definitions.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opendbc/car/docs/{docs_definitions.py => definitions.py} (100%) diff --git a/opendbc/car/docs/docs_definitions.py b/opendbc/car/docs/definitions.py similarity index 100% rename from opendbc/car/docs/docs_definitions.py rename to opendbc/car/docs/definitions.py From b7a4a3ba34746455bc962d766554b4bac7c4c648 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:49:55 -0400 Subject: [PATCH 07/17] rename test_docs -> test_docs_format --- opendbc/car/docs/{test_docs.py => test_docs_format.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opendbc/car/docs/{test_docs.py => test_docs_format.py} (100%) diff --git a/opendbc/car/docs/test_docs.py b/opendbc/car/docs/test_docs_format.py similarity index 100% rename from opendbc/car/docs/test_docs.py rename to opendbc/car/docs/test_docs_format.py From 9d6f65ad411b3d025ec58bb83f53aa1eab97f36a Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 16:50:52 -0400 Subject: [PATCH 08/17] move openpilot test_docs, rename test_docs_diff --- opendbc/car/docs/test_docs_diff.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 opendbc/car/docs/test_docs_diff.py diff --git a/opendbc/car/docs/test_docs_diff.py b/opendbc/car/docs/test_docs_diff.py new file mode 100644 index 0000000000..a203b2feff --- /dev/null +++ b/opendbc/car/docs/test_docs_diff.py @@ -0,0 +1,26 @@ +import os + +from openpilot.common.basedir import BASEDIR +from opendbc.car.docs import generate_cars_md, get_all_car_docs +from openpilot.selfdrive.debug.dump_car_docs import dump_car_docs +from openpilot.selfdrive.debug.print_docs_diff import print_car_docs_diff +from openpilot.selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE + + +class TestCarDocs: + @classmethod + def setup_class(cls): + cls.all_cars = get_all_car_docs() + + def test_generator(self): + generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE) + with open(CARS_MD_OUT) as f: + current_cars_md = f.read() + + assert generated_cars_md == current_cars_md, "Run selfdrive/opcar/docs.py to update the compatibility documentation" + + def test_docs_diff(self): + dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump") + dump_car_docs(dump_path) + print_car_docs_diff(dump_path) + os.remove(dump_path) From cf00a084c780fad74908467405a2b18d4729b313 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 17:13:13 -0400 Subject: [PATCH 09/17] Revert "move openpilot test_docs, rename test_docs_diff" This reverts commit 9d6f65ad411b3d025ec58bb83f53aa1eab97f36a. --- opendbc/car/docs/test_docs_diff.py | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 opendbc/car/docs/test_docs_diff.py diff --git a/opendbc/car/docs/test_docs_diff.py b/opendbc/car/docs/test_docs_diff.py deleted file mode 100644 index a203b2feff..0000000000 --- a/opendbc/car/docs/test_docs_diff.py +++ /dev/null @@ -1,26 +0,0 @@ -import os - -from openpilot.common.basedir import BASEDIR -from opendbc.car.docs import generate_cars_md, get_all_car_docs -from openpilot.selfdrive.debug.dump_car_docs import dump_car_docs -from openpilot.selfdrive.debug.print_docs_diff import print_car_docs_diff -from openpilot.selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE - - -class TestCarDocs: - @classmethod - def setup_class(cls): - cls.all_cars = get_all_car_docs() - - def test_generator(self): - generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE) - with open(CARS_MD_OUT) as f: - current_cars_md = f.read() - - assert generated_cars_md == current_cars_md, "Run selfdrive/opcar/docs.py to update the compatibility documentation" - - def test_docs_diff(self): - dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump") - dump_car_docs(dump_path) - print_car_docs_diff(dump_path) - os.remove(dump_path) From ad50d7a92105f83379f2b67cf896374841148f51 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 17:24:06 -0400 Subject: [PATCH 10/17] reintegrate generate_docs.py into one file --- opendbc/car/__init__.py | 2 +- opendbc/car/body/values.py | 2 +- opendbc/car/chrysler/values.py | 2 +- opendbc/car/docs.py | 59 ----------------------- opendbc/car/docs/generate_docs.py | 71 ++++++++++++++++++++++++++-- opendbc/car/docs/test_docs_format.py | 2 +- opendbc/car/ford/values.py | 2 +- opendbc/car/gm/values.py | 2 +- opendbc/car/honda/values.py | 2 +- opendbc/car/hyundai/values.py | 2 +- opendbc/car/mazda/values.py | 2 +- opendbc/car/nissan/values.py | 2 +- opendbc/car/subaru/values.py | 2 +- opendbc/car/tesla/values.py | 2 +- opendbc/car/toyota/values.py | 2 +- opendbc/car/volkswagen/values.py | 2 +- 16 files changed, 82 insertions(+), 76 deletions(-) delete mode 100644 opendbc/car/docs.py diff --git a/opendbc/car/__init__.py b/opendbc/car/__init__.py index 455d8c3803..49e92c30ea 100644 --- a/opendbc/car/__init__.py +++ b/opendbc/car/__init__.py @@ -8,7 +8,7 @@ from panda import uds from opendbc.car import structs from opendbc.car.can_definitions import CanData -from opendbc.car.docs_definitions import CarDocs +from opendbc.car.docs.definitions import CarDocs from opendbc.car.common.numpy_fast import clip, interp # set up logging diff --git a/opendbc/car/body/values.py b/opendbc/car/body/values.py index 3c221548c3..dfe1e8d479 100644 --- a/opendbc/car/body/values.py +++ b/opendbc/car/body/values.py @@ -1,6 +1,6 @@ from opendbc.car import CarSpecs, PlatformConfig, Platforms, dbc_dict from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarDocs +from opendbc.car.docs.definitions import CarDocs from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = CarParams.Ecu diff --git a/opendbc/car/chrysler/values.py b/opendbc/car/chrysler/values.py index 472b707f9d..cb6d130638 100644 --- a/opendbc/car/chrysler/values.py +++ b/opendbc/car/chrysler/values.py @@ -4,7 +4,7 @@ from panda import uds from opendbc.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts +from opendbc.car.docs.definitions import CarHarness, CarDocs, CarParts from opendbc.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = CarParams.Ecu diff --git a/opendbc/car/docs.py b/opendbc/car/docs.py deleted file mode 100644 index b44c873c3c..0000000000 --- a/opendbc/car/docs.py +++ /dev/null @@ -1,59 +0,0 @@ -from collections import defaultdict -import jinja2 -from enum import Enum -from natsort import natsorted - -from opendbc.car import gen_empty_fingerprint -from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarDocs, Column, CommonFootnote, PartType -from opendbc.car.car_helpers import interfaces, get_interface_attr -from opendbc.car.values import PLATFORMS - - -def get_all_footnotes() -> dict[Enum, int]: - all_footnotes = list(CommonFootnote) - for footnotes in get_interface_attr("Footnote", ignore_none=True).values(): - all_footnotes.extend(footnotes) - return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)} - - -def get_all_car_docs() -> list[CarDocs]: - all_car_docs: list[CarDocs] = [] - footnotes = get_all_footnotes() - for model, platform in PLATFORMS.items(): - car_docs = platform.config.car_docs - # If available, uses experimental longitudinal limits for the docs - CP = interfaces[model][0].get_params(platform, fingerprint=gen_empty_fingerprint(), - car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)], experimental_long=True, docs=True) - - if CP.dashcamOnly or not len(car_docs): - continue - - # A platform can include multiple car models - for _car_docs in car_docs: - if not hasattr(_car_docs, "row"): - _car_docs.init_make(CP) - _car_docs.init(CP, footnotes) - all_car_docs.append(_car_docs) - - # Sort cars by make and model + year - sorted_cars: list[CarDocs] = natsorted(all_car_docs, key=lambda car: car.name.lower()) - return sorted_cars - - -def group_by_make(all_car_docs: list[CarDocs]) -> dict[str, list[CarDocs]]: - sorted_car_docs = defaultdict(list) - for car_docs in all_car_docs: - sorted_car_docs[car_docs.make].append(car_docs) - return dict(sorted_car_docs) - - -def generate_cars_md(all_car_docs: list[CarDocs], template_fn: str) -> str: - with open(template_fn) as f: - template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) - - footnotes = [fn.value.text for fn in get_all_footnotes()] - cars_md: str = template.render(all_car_docs=all_car_docs, PartType=PartType, - group_by_make=group_by_make, footnotes=footnotes, - Column=Column) - return cars_md diff --git a/opendbc/car/docs/generate_docs.py b/opendbc/car/docs/generate_docs.py index f807fc320e..493f7af19a 100755 --- a/opendbc/car/docs/generate_docs.py +++ b/opendbc/car/docs/generate_docs.py @@ -1,12 +1,77 @@ #!/usr/bin/env python3 import argparse +from collections import defaultdict +import jinja2 import os +from enum import Enum +from natsort import natsorted + +from opendbc.car import gen_empty_fingerprint +from opendbc.car.structs import CarParams +from opendbc.car.docs.definitions import CarDocs, Column, CommonFootnote, PartType +from opendbc.car.car_helpers import interfaces, get_interface_attr +from opendbc.car.values import PLATFORMS + +try: + from openpilot.common.basedir import BASEDIR +except: + # TODO: make sure we run in a sensible way if not checked out as a submodule + # FIXME: no bare except + BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) -from openpilot.common.basedir import BASEDIR -from opendbc.car.docs import get_all_car_docs, generate_cars_md CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md") -CARS_MD_TEMPLATE = os.path.join(BASEDIR, "selfdrive", "car", "CARS_template.md") +CARS_MD_TEMPLATE = os.path.join(BASEDIR, "opendbc", "car", "docs", "CARS_template.md") + + +def get_all_footnotes() -> dict[Enum, int]: + all_footnotes = list(CommonFootnote) + for footnotes in get_interface_attr("Footnote", ignore_none=True).values(): + all_footnotes.extend(footnotes) + return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)} + + +def get_all_car_docs() -> list[CarDocs]: + all_car_docs: list[CarDocs] = [] + footnotes = get_all_footnotes() + for model, platform in PLATFORMS.items(): + car_docs = platform.config.car_docs + # If available, uses experimental longitudinal limits for the docs + CP = interfaces[model][0].get_params(platform, fingerprint=gen_empty_fingerprint(), + car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)], experimental_long=True, docs=True) + + if CP.dashcamOnly or not len(car_docs): + continue + + # A platform can include multiple car models + for _car_docs in car_docs: + if not hasattr(_car_docs, "row"): + _car_docs.init_make(CP) + _car_docs.init(CP, footnotes) + all_car_docs.append(_car_docs) + + # Sort cars by make and model + year + sorted_cars: list[CarDocs] = natsorted(all_car_docs, key=lambda car: car.name.lower()) + return sorted_cars + + +def group_by_make(all_car_docs: list[CarDocs]) -> dict[str, list[CarDocs]]: + sorted_car_docs = defaultdict(list) + for car_docs in all_car_docs: + sorted_car_docs[car_docs.make].append(car_docs) + return dict(sorted_car_docs) + + +def generate_cars_md(all_car_docs: list[CarDocs], template_fn: str) -> str: + with open(template_fn) as f: + template = jinja2.Template(f.read(), trim_blocks=True, lstrip_blocks=True) + + footnotes = [fn.value.text for fn in get_all_footnotes()] + cars_md: str = template.render(all_car_docs=all_car_docs, PartType=PartType, + group_by_make=group_by_make, footnotes=footnotes, + Column=Column) + return cars_md + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Auto generates supported cars documentation", diff --git a/opendbc/car/docs/test_docs_format.py b/opendbc/car/docs/test_docs_format.py index 9e6e7b632d..8d9cb6f65a 100644 --- a/opendbc/car/docs/test_docs_format.py +++ b/opendbc/car/docs/test_docs_format.py @@ -4,7 +4,7 @@ from opendbc.car.car_helpers import interfaces from opendbc.car.docs import get_all_car_docs -from opendbc.car.docs_definitions import Cable, Column, PartType, Star +from opendbc.car.docs.definitions import Cable, Column, PartType, Star from opendbc.car.honda.values import CAR as HONDA from opendbc.car.values import PLATFORMS diff --git a/opendbc/car/ford/values.py b/opendbc/car/ford/values.py index c3cc9b5641..513c7ee86b 100644 --- a/opendbc/car/ford/values.py +++ b/opendbc/car/ford/values.py @@ -6,7 +6,7 @@ from panda import uds from opendbc.car import AngleRateLimit, CarSpecs, dbc_dict, DbcDict, PlatformConfig, Platforms from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ +from opendbc.car.docs.definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ Device from opendbc.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16 diff --git a/opendbc/car/gm/values.py b/opendbc/car/gm/values.py index 852a6fbf85..59de8ffd50 100644 --- a/opendbc/car/gm/values.py +++ b/opendbc/car/gm/values.py @@ -2,7 +2,7 @@ from opendbc.car import dbc_dict, PlatformConfig, DbcDict, Platforms, CarSpecs from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts +from opendbc.car.docs.definitions import CarHarness, CarDocs, CarParts from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = CarParams.Ecu diff --git a/opendbc/car/honda/values.py b/opendbc/car/honda/values.py index 1200f69cca..a7e157d46b 100644 --- a/opendbc/car/honda/values.py +++ b/opendbc/car/honda/values.py @@ -4,7 +4,7 @@ from panda import uds from opendbc.car import CarSpecs, PlatformConfig, Platforms, dbc_dict, structs from opendbc.car.common.conversions import Conversions as CV -from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column +from opendbc.car.docs.definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = structs.CarParams.Ecu diff --git a/opendbc/car/hyundai/values.py b/opendbc/car/hyundai/values.py index 2eeb337636..3a43c5aeee 100644 --- a/opendbc/car/hyundai/values.py +++ b/opendbc/car/hyundai/values.py @@ -6,7 +6,7 @@ from opendbc.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from opendbc.car.common.conversions import Conversions as CV from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column +from opendbc.car.docs.definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from opendbc.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = CarParams.Ecu diff --git a/opendbc/car/mazda/values.py b/opendbc/car/mazda/values.py index 47cf43ca06..0402a1cc44 100644 --- a/opendbc/car/mazda/values.py +++ b/opendbc/car/mazda/values.py @@ -4,7 +4,7 @@ from opendbc.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from opendbc.car.common.conversions import Conversions as CV from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts +from opendbc.car.docs.definitions import CarHarness, CarDocs, CarParts from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = CarParams.Ecu diff --git a/opendbc/car/nissan/values.py b/opendbc/car/nissan/values.py index a8755e52cf..bcba1958a2 100644 --- a/opendbc/car/nissan/values.py +++ b/opendbc/car/nissan/values.py @@ -3,7 +3,7 @@ from panda import uds from opendbc.car import AngleRateLimit, CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarDocs, CarHarness, CarParts +from opendbc.car.docs.definitions import CarDocs, CarHarness, CarParts from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = CarParams.Ecu diff --git a/opendbc/car/subaru/values.py b/opendbc/car/subaru/values.py index c7f93f9fae..542d4e1c29 100644 --- a/opendbc/car/subaru/values.py +++ b/opendbc/car/subaru/values.py @@ -4,7 +4,7 @@ from panda import uds from opendbc.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Tool, Column +from opendbc.car.docs.definitions import CarFootnote, CarHarness, CarDocs, CarParts, Tool, Column from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = CarParams.Ecu diff --git a/opendbc/car/tesla/values.py b/opendbc/car/tesla/values.py index 10c8fcd066..a924b5a977 100644 --- a/opendbc/car/tesla/values.py +++ b/opendbc/car/tesla/values.py @@ -2,7 +2,7 @@ from opendbc.car.structs import CarParams from opendbc.car import structs from opendbc.car import AngleRateLimit, CarSpecs, PlatformConfig, Platforms, dbc_dict -from opendbc.car.docs_definitions import CarDocs +from opendbc.car.docs.definitions import CarDocs from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = CarParams.Ecu diff --git a/opendbc/car/toyota/values.py b/opendbc/car/toyota/values.py index a218cac0b6..f59af0c9a9 100644 --- a/opendbc/car/toyota/values.py +++ b/opendbc/car/toyota/values.py @@ -6,7 +6,7 @@ from opendbc.car import CarSpecs, PlatformConfig, Platforms, AngleRateLimit, dbc_dict from opendbc.car.common.conversions import Conversions as CV from opendbc.car.structs import CarParams -from opendbc.car.docs_definitions import CarFootnote, CarDocs, Column, CarParts, CarHarness +from opendbc.car.docs.definitions import CarFootnote, CarDocs, Column, CarParts, CarHarness from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = CarParams.Ecu diff --git a/opendbc/car/volkswagen/values.py b/opendbc/car/volkswagen/values.py index c095b7767f..5f3eaf721b 100644 --- a/opendbc/car/volkswagen/values.py +++ b/opendbc/car/volkswagen/values.py @@ -7,7 +7,7 @@ from opendbc.car import dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms from opendbc.car.common.conversions import Conversions as CV from opendbc.car import structs -from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ +from opendbc.car.docs.definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ Device from opendbc.car.fw_query_definitions import EcuAddrSubAddr, FwQueryConfig, Request, p16 From cb6f975466b3d74aa5adb41ecaaee798cb4e5f58 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 17:26:38 -0400 Subject: [PATCH 11/17] move dump_car_docs and print_docs_diff --- opendbc/car/docs/dump_car_docs.py | 18 +++++ opendbc/car/docs/print_docs_diff.py | 120 ++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100755 opendbc/car/docs/dump_car_docs.py create mode 100755 opendbc/car/docs/print_docs_diff.py diff --git a/opendbc/car/docs/dump_car_docs.py b/opendbc/car/docs/dump_car_docs.py new file mode 100755 index 0000000000..f0e99cda24 --- /dev/null +++ b/opendbc/car/docs/dump_car_docs.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +import argparse +import pickle + +from opendbc.car.docs import get_all_car_docs + + +def dump_car_docs(path): + with open(path, 'wb') as f: + pickle.dump(get_all_car_docs(), f) + print(f'Dumping car info to {path}') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--path", required=True) + args = parser.parse_args() + dump_car_docs(args.path) diff --git a/opendbc/car/docs/print_docs_diff.py b/opendbc/car/docs/print_docs_diff.py new file mode 100755 index 0000000000..388acf3af5 --- /dev/null +++ b/opendbc/car/docs/print_docs_diff.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +import argparse +from collections import defaultdict +import difflib +import pickle + +from opendbc.car.docs import get_all_car_docs +from opendbc.car.docs_definitions import Column + +FOOTNOTE_TAG = "{}" +STAR_ICON = '' +VIDEO_ICON = '' + \ + '' +COLUMNS = "|" + "|".join([column.value for column in Column]) + "|" +COLUMN_HEADER = "|---|---|---|{}|".format("|".join([":---:"] * (len(Column) - 3))) +ARROW_SYMBOL = "➡️" + + +def load_base_car_docs(path): + with open(path, "rb") as f: + return pickle.load(f) + + +def match_cars(base_cars, new_cars): + changes = [] + additions = [] + for new in new_cars: + # Addition if no close matches or close match already used + # Change if close match and not already used + matches = difflib.get_close_matches(new.name, [b.name for b in base_cars], cutoff=0.) + if not len(matches) or matches[0] in [c[1].name for c in changes]: + additions.append(new) + else: + changes.append((new, next(car for car in base_cars if car.name == matches[0]))) + + # Removal if base car not in changes + removals = [b for b in base_cars if b.name not in [c[1].name for c in changes]] + return changes, additions, removals + + +def build_column_diff(base_car, new_car): + row_builder = [] + for column in Column: + base_column = base_car.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) + new_column = new_car.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) + + if base_column != new_column: + row_builder.append(f"{base_column} {ARROW_SYMBOL} {new_column}") + else: + row_builder.append(new_column) + + return format_row(row_builder) + + +def format_row(builder): + return "|" + "|".join(builder) + "|" + + +def print_car_docs_diff(path): + base_car_docs = defaultdict(list) + new_car_docs = defaultdict(list) + + for car in load_base_car_docs(path): + base_car_docs[car.car_fingerprint].append(car) + for car in get_all_car_docs(): + new_car_docs[car.car_fingerprint].append(car) + + # Add new platforms to base cars so we can detect additions and removals in one pass + base_car_docs.update({car: [] for car in new_car_docs if car not in base_car_docs}) + + changes = defaultdict(list) + for base_car_model, base_cars in base_car_docs.items(): + # Match car info changes, and get additions and removals + new_cars = new_car_docs[base_car_model] + car_changes, car_additions, car_removals = match_cars(base_cars, new_cars) + + # Removals + for car_docs in car_removals: + changes["removals"].append(format_row([car_docs.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column])) + + # Additions + for car_docs in car_additions: + changes["additions"].append(format_row([car_docs.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column])) + + for new_car, base_car in car_changes: + # Column changes + row_diff = build_column_diff(base_car, new_car) + if ARROW_SYMBOL in row_diff: + changes["column"].append(row_diff) + + # Detail sentence changes + if base_car.detail_sentence != new_car.detail_sentence: + changes["detail"].append(f"- Sentence for {base_car.name} changed!\n" + + " ```diff\n" + + f" - {base_car.detail_sentence}\n" + + f" + {new_car.detail_sentence}\n" + + " ```") + + # Print diff + if any(len(c) for c in changes.values()): + markdown_builder = ["### ⚠️ This PR makes changes to [CARS.md](../blob/master/docs/CARS.md) ⚠️"] + + for title, category in (("## 🔀 Column Changes", "column"), ("## ❌ Removed", "removals"), + ("## ➕ Added", "additions"), ("## 📖 Detail Sentence Changes", "detail")): + if len(changes[category]): + markdown_builder.append(title) + if category not in ("detail",): + markdown_builder.append(COLUMNS) + markdown_builder.append(COLUMN_HEADER) + markdown_builder.extend(changes[category]) + + print("\n".join(markdown_builder)) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--path", required=True) + args = parser.parse_args() + print_car_docs_diff(args.path) From 7dbcbdaa1ca70d7c6a87cfb0f6441eec4c71b56a Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 17:34:26 -0400 Subject: [PATCH 12/17] fixup imports --- opendbc/car/docs/dump_car_docs.py | 2 +- opendbc/car/docs/print_docs_diff.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/opendbc/car/docs/dump_car_docs.py b/opendbc/car/docs/dump_car_docs.py index f0e99cda24..bfcc0330ae 100755 --- a/opendbc/car/docs/dump_car_docs.py +++ b/opendbc/car/docs/dump_car_docs.py @@ -2,7 +2,7 @@ import argparse import pickle -from opendbc.car.docs import get_all_car_docs +from opendbc.car.docs.generate_docs import get_all_car_docs def dump_car_docs(path): diff --git a/opendbc/car/docs/print_docs_diff.py b/opendbc/car/docs/print_docs_diff.py index 388acf3af5..5c60a5e0c2 100755 --- a/opendbc/car/docs/print_docs_diff.py +++ b/opendbc/car/docs/print_docs_diff.py @@ -4,8 +4,8 @@ import difflib import pickle -from opendbc.car.docs import get_all_car_docs -from opendbc.car.docs_definitions import Column +from opendbc.car.docs.generate_docs import get_all_car_docs +from opendbc.car.docs.definitions import Column FOOTNOTE_TAG = "{}" STAR_ICON = ' Date: Wed, 2 Oct 2024 17:36:26 -0400 Subject: [PATCH 13/17] fixup imports --- opendbc/car/docs/test_docs_format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc/car/docs/test_docs_format.py b/opendbc/car/docs/test_docs_format.py index 8d9cb6f65a..0a012a14cc 100644 --- a/opendbc/car/docs/test_docs_format.py +++ b/opendbc/car/docs/test_docs_format.py @@ -3,7 +3,7 @@ import re from opendbc.car.car_helpers import interfaces -from opendbc.car.docs import get_all_car_docs +from opendbc.car.docs.generate_docs import get_all_car_docs from opendbc.car.docs.definitions import Cable, Column, PartType, Star from opendbc.car.honda.values import CAR as HONDA from opendbc.car.values import PLATFORMS From 12784e0a561977ef895ca13e3a9f8a821981c4ce Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 17:42:24 -0400 Subject: [PATCH 14/17] deal with BASEDIR later --- opendbc/car/docs/generate_docs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/opendbc/car/docs/generate_docs.py b/opendbc/car/docs/generate_docs.py index 493f7af19a..91e910591c 100755 --- a/opendbc/car/docs/generate_docs.py +++ b/opendbc/car/docs/generate_docs.py @@ -12,12 +12,13 @@ from opendbc.car.car_helpers import interfaces, get_interface_attr from opendbc.car.values import PLATFORMS -try: - from openpilot.common.basedir import BASEDIR -except: - # TODO: make sure we run in a sensible way if not checked out as a submodule - # FIXME: no bare except - BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) +from openpilot.common.basedir import BASEDIR +#try: +# from openpilot.common.basedir import BASEDIR +#except: +# # TODO: make sure we run in a sensible way if not checked out as a submodule +# # FIXME: no bare except +# BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md") From c1bef2671407aaa37617995a1286576370460a2f Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 17:52:52 -0400 Subject: [PATCH 15/17] we will, in fact, be dealing with BASEDIR now --- opendbc/car/docs/generate_docs.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/opendbc/car/docs/generate_docs.py b/opendbc/car/docs/generate_docs.py index 91e910591c..14a1d4279a 100755 --- a/opendbc/car/docs/generate_docs.py +++ b/opendbc/car/docs/generate_docs.py @@ -12,13 +12,11 @@ from opendbc.car.car_helpers import interfaces, get_interface_attr from opendbc.car.values import PLATFORMS -from openpilot.common.basedir import BASEDIR -#try: -# from openpilot.common.basedir import BASEDIR -#except: -# # TODO: make sure we run in a sensible way if not checked out as a submodule -# # FIXME: no bare except -# BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) +try: + from openpilot.common.basedir import BASEDIR +except ModuleNotFoundError: + # TODO: make sure we run in a sensible way if not checked out as a submodule + BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md") From d3bb3d382106beeb0acbf37f57c166647f836197 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 18:05:17 -0400 Subject: [PATCH 16/17] better BASEDIR --- opendbc/car/docs/generate_docs.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/opendbc/car/docs/generate_docs.py b/opendbc/car/docs/generate_docs.py index 14a1d4279a..7415bbe365 100755 --- a/opendbc/car/docs/generate_docs.py +++ b/opendbc/car/docs/generate_docs.py @@ -7,20 +7,16 @@ from natsort import natsorted from opendbc.car import gen_empty_fingerprint +from opendbc.car.common.basedir import BASEDIR from opendbc.car.structs import CarParams from opendbc.car.docs.definitions import CarDocs, Column, CommonFootnote, PartType from opendbc.car.car_helpers import interfaces, get_interface_attr from opendbc.car.values import PLATFORMS -try: - from openpilot.common.basedir import BASEDIR -except ModuleNotFoundError: - # TODO: make sure we run in a sensible way if not checked out as a submodule - BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../")) - -CARS_MD_OUT = os.path.join(BASEDIR, "docs", "CARS.md") -CARS_MD_TEMPLATE = os.path.join(BASEDIR, "opendbc", "car", "docs", "CARS_template.md") +# FIXME: make sure we run in a sensible way if not checked out as a submodule, try-except for writing to CARS.md +CARS_MD_OUT = os.path.join(BASEDIR, "../", "../", "../", "docs", "CARS.md") +CARS_MD_TEMPLATE = os.path.join(BASEDIR, "docs", "CARS_template.md") def get_all_footnotes() -> dict[Enum, int]: From 1d5f0c5dc51f856a083bf162df80b647af979964 Mon Sep 17 00:00:00 2001 From: Jason Young Date: Wed, 2 Oct 2024 18:10:48 -0400 Subject: [PATCH 17/17] these go away soon, leave in openpilot --- opendbc/car/docs/dump_car_docs.py | 18 ----- opendbc/car/docs/print_docs_diff.py | 120 ---------------------------- 2 files changed, 138 deletions(-) delete mode 100755 opendbc/car/docs/dump_car_docs.py delete mode 100755 opendbc/car/docs/print_docs_diff.py diff --git a/opendbc/car/docs/dump_car_docs.py b/opendbc/car/docs/dump_car_docs.py deleted file mode 100755 index bfcc0330ae..0000000000 --- a/opendbc/car/docs/dump_car_docs.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import pickle - -from opendbc.car.docs.generate_docs import get_all_car_docs - - -def dump_car_docs(path): - with open(path, 'wb') as f: - pickle.dump(get_all_car_docs(), f) - print(f'Dumping car info to {path}') - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--path", required=True) - args = parser.parse_args() - dump_car_docs(args.path) diff --git a/opendbc/car/docs/print_docs_diff.py b/opendbc/car/docs/print_docs_diff.py deleted file mode 100755 index 5c60a5e0c2..0000000000 --- a/opendbc/car/docs/print_docs_diff.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -import argparse -from collections import defaultdict -import difflib -import pickle - -from opendbc.car.docs.generate_docs import get_all_car_docs -from opendbc.car.docs.definitions import Column - -FOOTNOTE_TAG = "{}" -STAR_ICON = '' -VIDEO_ICON = '' + \ - '' -COLUMNS = "|" + "|".join([column.value for column in Column]) + "|" -COLUMN_HEADER = "|---|---|---|{}|".format("|".join([":---:"] * (len(Column) - 3))) -ARROW_SYMBOL = "➡️" - - -def load_base_car_docs(path): - with open(path, "rb") as f: - return pickle.load(f) - - -def match_cars(base_cars, new_cars): - changes = [] - additions = [] - for new in new_cars: - # Addition if no close matches or close match already used - # Change if close match and not already used - matches = difflib.get_close_matches(new.name, [b.name for b in base_cars], cutoff=0.) - if not len(matches) or matches[0] in [c[1].name for c in changes]: - additions.append(new) - else: - changes.append((new, next(car for car in base_cars if car.name == matches[0]))) - - # Removal if base car not in changes - removals = [b for b in base_cars if b.name not in [c[1].name for c in changes]] - return changes, additions, removals - - -def build_column_diff(base_car, new_car): - row_builder = [] - for column in Column: - base_column = base_car.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) - new_column = new_car.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) - - if base_column != new_column: - row_builder.append(f"{base_column} {ARROW_SYMBOL} {new_column}") - else: - row_builder.append(new_column) - - return format_row(row_builder) - - -def format_row(builder): - return "|" + "|".join(builder) + "|" - - -def print_car_docs_diff(path): - base_car_docs = defaultdict(list) - new_car_docs = defaultdict(list) - - for car in load_base_car_docs(path): - base_car_docs[car.car_fingerprint].append(car) - for car in get_all_car_docs(): - new_car_docs[car.car_fingerprint].append(car) - - # Add new platforms to base cars so we can detect additions and removals in one pass - base_car_docs.update({car: [] for car in new_car_docs if car not in base_car_docs}) - - changes = defaultdict(list) - for base_car_model, base_cars in base_car_docs.items(): - # Match car info changes, and get additions and removals - new_cars = new_car_docs[base_car_model] - car_changes, car_additions, car_removals = match_cars(base_cars, new_cars) - - # Removals - for car_docs in car_removals: - changes["removals"].append(format_row([car_docs.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column])) - - # Additions - for car_docs in car_additions: - changes["additions"].append(format_row([car_docs.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column])) - - for new_car, base_car in car_changes: - # Column changes - row_diff = build_column_diff(base_car, new_car) - if ARROW_SYMBOL in row_diff: - changes["column"].append(row_diff) - - # Detail sentence changes - if base_car.detail_sentence != new_car.detail_sentence: - changes["detail"].append(f"- Sentence for {base_car.name} changed!\n" + - " ```diff\n" + - f" - {base_car.detail_sentence}\n" + - f" + {new_car.detail_sentence}\n" + - " ```") - - # Print diff - if any(len(c) for c in changes.values()): - markdown_builder = ["### ⚠️ This PR makes changes to [CARS.md](../blob/master/docs/CARS.md) ⚠️"] - - for title, category in (("## 🔀 Column Changes", "column"), ("## ❌ Removed", "removals"), - ("## ➕ Added", "additions"), ("## 📖 Detail Sentence Changes", "detail")): - if len(changes[category]): - markdown_builder.append(title) - if category not in ("detail",): - markdown_builder.append(COLUMNS) - markdown_builder.append(COLUMN_HEADER) - markdown_builder.extend(changes[category]) - - print("\n".join(markdown_builder)) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--path", required=True) - args = parser.parse_args() - print_car_docs_diff(args.path)