openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
4.2 KiB

#!/usr/bin/env python3
import argparse
import os
from typing import get_args
from collections import defaultdict
import jinja2
from enum import Enum
from natsort import natsorted
from opendbc.car.common.basedir import BASEDIR
from opendbc.car import gen_empty_fingerprint
from opendbc.car.structs import CarParams
from opendbc.car.docs_definitions import BaseCarHarness, CarDocs, Device, ExtraCarDocs, Column, ExtraCarsColumn, CommonFootnote, PartType, SupportType
from opendbc.car.car_helpers import interfaces
from opendbc.car.interfaces import get_interface_attr
from opendbc.car.values import Platform
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.extra_cars import CAR as EXTRA
EXTRA_CARS_MD_OUT = os.path.join(BASEDIR, "../", "../", "docs", "CARS.md")
EXTRA_CARS_MD_TEMPLATE = os.path.join(BASEDIR, "CARS_template.md")
# TODO: merge these platforms into normal car ports with SupportType flag
ExtraPlatform = Platform | EXTRA
EXTRA_BRANDS = get_args(ExtraPlatform)
EXTRA_PLATFORMS: dict[str, ExtraPlatform] = {str(platform): platform for brand in EXTRA_BRANDS for platform in brand}
def get_params_for_docs(platform) -> CarParams:
cp_platform = platform if platform in interfaces else MOCK.MOCK
CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
alpha_long=True, docs=True)
return CP
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 build_sorted_car_docs_list(platforms, footnotes=None):
collected_car_docs: list[CarDocs | ExtraCarDocs] = []
for platform in platforms.values():
car_docs = platform.config.car_docs
CP = get_params_for_docs(platform)
if 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)
collected_car_docs.append(_car_docs)
# Sort cars by make and model + year
sorted_cars = natsorted(collected_car_docs, key=lambda car: car.name.lower())
return sorted_cars
# CAUTION: This function is imported by shop.comma.ai and comma.ai/vehicles, test changes carefully
def get_all_car_docs() -> list[CarDocs]:
collected_footnotes = get_all_footnotes()
sorted_list: list[CarDocs] = build_sorted_car_docs_list(EXTRA_PLATFORMS, footnotes=collected_footnotes)
return sorted_list
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)
# CAUTION: This function is imported by shop.comma.ai and comma.ai/vehicles, test changes carefully
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,
Device=Device, Column=Column, ExtraCarsColumn=ExtraCarsColumn,
BaseCarHarness=BaseCarHarness, SupportType=SupportType)
return cars_md
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Auto generates supportability info docs for all known cars",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--template", default=EXTRA_CARS_MD_TEMPLATE, help="Override default template filename")
parser.add_argument("--out", default=EXTRA_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}")