diff --git a/selfdrive/car/body/values.py b/selfdrive/car/body/values.py index a1195f7cb539c3..946f4f6be62617 100644 --- a/selfdrive/car/body/values.py +++ b/selfdrive/car/body/values.py @@ -1,9 +1,9 @@ -from cereal import car from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarDocs from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu SPEED_FROM_RPM = 0.008587 diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index c44c647fd4f667..f8fdddb2783e8e 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -1,13 +1,13 @@ from enum import IntFlag from dataclasses import dataclass, field -from cereal import car from panda.python import uds from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class ChryslerFlags(IntFlag): diff --git a/selfdrive/car/data_structures.py b/selfdrive/car/data_structures.py index 47bd135224f9a4..65f1014ffeb229 100644 --- a/selfdrive/car/data_structures.py +++ b/selfdrive/car/data_structures.py @@ -74,6 +74,8 @@ class CarParams: carFw: list['CarParams.CarFw'] = auto_field() + carVin: str = auto_field() + class SteerControlType(StrEnum): torque = auto() angle = auto() @@ -122,3 +124,14 @@ class Ecu(StrEnum): programmedFuelInjection = auto() debug = auto() + + @auto_dataclass + class LateralTorqueTuning: + useSteeringAngle: bool = auto_field() + kp: float = auto_field() + ki: float = auto_field() + friction: float = auto_field() + kf: float = auto_field() + steeringAngleDeadzoneDeg: float = auto_field() + latAccelFactor: float = auto_field() + latAccelOffset: float = auto_field() diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index 336d0d55429329..e08f58255884aa 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -1,14 +1,13 @@ #!/usr/bin/env python3 -import capnp import time from panda.python.uds import SERVICE_TYPE from openpilot.selfdrive.car import make_tester_present_msg, carlog -from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable +from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from openpilot.selfdrive.car.fw_query_definitions import EcuAddrBusType -def _is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subaddr: int = None) -> bool: +def _is_tester_present_response(msg: CanData, subaddr: int = None) -> bool: # ISO-TP messages are always padded to 8 bytes # tester present response is always a single frame dat_offset = 1 if subaddr is not None else 0 diff --git a/selfdrive/car/ford/tests/test_ford.py b/selfdrive/car/ford/tests/test_ford.py index b1a19017d401b0..5a57d0c40d9e07 100644 --- a/selfdrive/car/ford/tests/test_ford.py +++ b/selfdrive/car/ford/tests/test_ford.py @@ -1,16 +1,15 @@ import random from collections.abc import Iterable -import capnp from hypothesis import settings, given, strategies as st from parameterized import parameterized -from cereal import car +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.fw_versions import build_fw_dict from openpilot.selfdrive.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, get_platform_codes from openpilot.selfdrive.car.ford.fingerprints import FW_VERSIONS -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu ECU_ADDRESSES = { @@ -49,7 +48,7 @@ def test_fw_query_config(self): assert subaddr is None, "Unexpected ECU subaddress" @parameterized.expand(FW_VERSIONS.items()) - def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[capnp.lib.capnp._EnumModule, int, int | None], Iterable[bytes]]): + def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[CarParams.Ecu, int, int | None], Iterable[bytes]]): for (ecu, addr, subaddr), fws in fw_versions.items(): assert ecu in ECU_PART_NUMBER, "Unexpected ECU" assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch" @@ -96,7 +95,7 @@ def test_fuzzy_match(self): car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) - CP = car.CarParams.new_message(carFw=car_fw) + CP = CarParams(carFw=car_fw) matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS) assert matches == {platform} diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index b1868bfa9bb97d..38da1dbfc7829d 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -6,11 +6,12 @@ import panda.python.uds as uds from cereal import car from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, dbc_dict, DbcDict, PlatformConfig, Platforms +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ Device from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index bb2827571cd771..dd2d407a7ba178 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import capnp import copy from dataclasses import dataclass, field import struct @@ -7,9 +6,11 @@ import panda.python.uds as uds +from openpilot.selfdrive.car.data_structures import CarParams + AddrType = tuple[int, int | None] EcuAddrBusType = tuple[int, int | None, int] -EcuAddrSubAddr = tuple[int, int, int | None] +EcuAddrSubAddr = tuple[CarParams.Ecu, int, int | None] LiveFwVersions = dict[AddrType, set[bytes]] OfflineFwVersions = dict[str, dict[EcuAddrSubAddr, list[bytes]]] @@ -78,7 +79,7 @@ class StdQueries: class Request: request: list[bytes] response: list[bytes] - whitelist_ecus: list[int] = field(default_factory=list) + whitelist_ecus: list[CarParams.Ecu] = field(default_factory=list) rx_offset: int = 0x8 bus: int = 1 # Whether this query should be run on the first auxiliary panda (CAN FD cars for example) @@ -94,9 +95,9 @@ class FwQueryConfig: requests: list[Request] # TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus # Overrides and removes from essential ecus for specific models and ecus (exact matching) - non_essential_ecus: dict[capnp.lib.capnp._EnumModule, list[str]] = field(default_factory=dict) + non_essential_ecus: dict[CarParams.Ecu, list[str]] = field(default_factory=dict) # Ecus added for data collection, not to be fingerprinted on - extra_ecus: list[tuple[capnp.lib.capnp._EnumModule, int, int | None]] = field(default_factory=list) + extra_ecus: list[tuple[CarParams.Ecu, int, int | None]] = field(default_factory=list) # Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN, # returns set of candidates. Only will match if one candidate is returned match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index fee375b937e9ff..4f6d874ffb276d 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -4,7 +4,6 @@ from typing import Any, Protocol, TypeVar from tqdm import tqdm -import capnp import panda.python.uds as uds from openpilot.selfdrive.car import carlog @@ -40,7 +39,7 @@ def is_brand(brand: str, filter_brand: str | None) -> bool: return filter_brand is None or brand == filter_brand -def build_fw_dict(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder], filter_brand: str = None) -> dict[AddrType, set[bytes]]: +def build_fw_dict(fw_versions: list[CarParams.CarFw], filter_brand: str = None) -> dict[AddrType, set[bytes]]: fw_versions_dict: defaultdict[AddrType, set[bytes]] = defaultdict(set) for fw in fw_versions: if is_brand(fw.brand, filter_brand) and not fw.logging: @@ -145,8 +144,8 @@ def match_fw_to_car_exact(live_fw_versions: LiveFwVersions, match_brand: str = N return set(candidates.keys()) - invalid -def match_fw_to_car(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder], vin: str, - allow_exact: bool = True, allow_fuzzy: bool = True, log: bool = True) -> tuple[bool, set[str]]: +def match_fw_to_car(fw_versions: list[CarParams.CarFw], vin: str, allow_exact: bool = True, + allow_fuzzy: bool = True, log: bool = True) -> tuple[bool, set[str]]: # Try exact matching first exact_matches: list[tuple[bool, MatchFwToCar]] = [] if allow_exact: @@ -230,7 +229,7 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, set[Ad def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, vin: str, ecu_rx_addrs: set[EcuAddrBusType], timeout: float = 0.1, num_pandas: int = 1, debug: bool = False, - progress: bool = False) -> list[capnp.lib.capnp._DynamicStructBuilder]: + progress: bool = False) -> list[CarParams.CarFw]: """Queries for FW versions ordering brands by likelihood, breaks when exact match is found""" all_car_fw = [] @@ -255,7 +254,7 @@ def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, query_brand: str = None, extra: OfflineFwVersions = None, timeout: float = 0.1, num_pandas: int = 1, debug: bool = False, - progress: bool = False) -> list[capnp.lib.capnp._DynamicStructBuilder]: + progress: bool = False) -> list[CarParams.CarFw]: versions = VERSIONS.copy() if query_brand is not None: @@ -307,7 +306,7 @@ def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_ob if query_addrs: query = IsoTpParallelQuery(can_send, can_recv, r.bus, query_addrs, r.request, r.response, r.rx_offset, debug=debug) for (tx_addr, sub_addr), version in query.get_data(timeout).items(): - f = CarParams.CarFw.new_message() + f = CarParams.CarFw() f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown) f.fwVersion = version @@ -386,7 +385,7 @@ def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_ob for version in fw_vers: subaddr = None if version.subAddress == 0 else hex(version.subAddress) print(f" Brand: {version.brand:{padding}}, bus: {version.bus}, OBD: {version.obdMultiplexing} - " + - f"(Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion}]") + f"(Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion!r}]") print("}") print() diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 53a4621d27fe89..80ae67146a8107 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -2,10 +2,11 @@ from cereal import car from openpilot.selfdrive.car import dbc_dict, PlatformConfig, DbcDict, Platforms, CarSpecs +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 53e5435f294c45..793fd9687f3d62 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -5,10 +5,11 @@ from panda.python import uds from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu VisualAlert = car.CarControl.HUDControl.VisualAlert diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 0db82a7577f69c..c25b6a82df8244 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -6,10 +6,11 @@ from panda.python import uds from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 4e434ec386d805..6660aa57296568 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -12,6 +12,7 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.simple_kalman import KF1D, get_kalman_gain from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, get_friction, STD_CARGO_KG +from openpilot.selfdrive.car.data_structures import CarParams, RadarData from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.helpers import clip @@ -52,7 +53,7 @@ class LatControlInputs(NamedTuple): aego: float -TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float] +TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, CarParams.LateralTorqueTuning, float, float, bool, bool], float] @cache @@ -123,7 +124,7 @@ def get_non_essential_params(cls, candidate: str): return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False) @classmethod - def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool): + def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[CarParams.CarFw], experimental_long: bool, docs: bool): ret = CarInterfaceBase.get_std_params(candidate) platform = PLATFORMS[candidate] @@ -150,12 +151,12 @@ def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_ @staticmethod @abstractmethod - def _get_params(ret: car.CarParams, candidate, fingerprint: dict[int, dict[int, int]], - car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool): + def _get_params(ret: CarParams, candidate, fingerprint: dict[int, dict[int, int]], + car_fw: list[CarParams.CarFw], experimental_long: bool, docs: bool): raise NotImplementedError @staticmethod - def init(CP: car.CarParams, can_recv: CanRecvCallable, can_send: CanSendCallable): + def init(CP: CarParams, can_recv: CanRecvCallable, can_send: CanSendCallable): pass @staticmethod @@ -166,7 +167,7 @@ def get_steer_feedforward_default(desired_angle, v_ego): def get_steer_feedforward_function(self): return self.get_steer_feedforward_default - def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, + def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: CarParams.LateralTorqueTuning, lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float: # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation) @@ -187,7 +188,7 @@ def get_std_params(candidate): # standard ALC params ret.tireStiffnessFactor = 1.0 - ret.steerControlType = car.CarParams.SteerControlType.torque + ret.steerControlType = CarParams.SteerControlType.torque ret.minSteerSpeed = 0. ret.wheelSpeedFactor = 1.0 @@ -350,10 +351,10 @@ def __init__(self, CP): self.radar_ts = CP.radarTimeStep self.frame = 0 - def update(self, can_strings): + def update(self, can_strings) -> RadarData | None: self.frame += 1 if (self.frame % int(100 * self.radar_ts)) == 0: - return car.RadarData.new_message() + return RadarData() return None diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index cfd7067db60841..ef85186ba8e532 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -1,13 +1,13 @@ from dataclasses import dataclass, field from enum import IntFlag -from cereal import car from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu # Steer torque limits diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index eecffb21bcc0d1..e61ac5518b0967 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -1,12 +1,12 @@ from dataclasses import dataclass, field -from cereal import car from panda.python import uds from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarDocs, CarHarness, CarParts from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index dcbea1979fd227..c2ddbc2a1614d6 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -4,10 +4,11 @@ from cereal import car from panda.python import uds from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Tool, Column from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu class CarControllerParams: diff --git a/selfdrive/car/tesla/values.py b/selfdrive/car/tesla/values.py index 0f9cd00f63edeb..a0736934b4b0cf 100644 --- a/selfdrive/car/tesla/values.py +++ b/selfdrive/car/tesla/values.py @@ -2,10 +2,11 @@ from cereal import car from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, PlatformConfig, Platforms, dbc_dict +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarDocs from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index 2eb2fdab727a86..929a8e70fb1e02 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -1,4 +1,4 @@ -from selfdrive.car.data_structures import CarParams +from openpilot.selfdrive.car.data_structures import CarParams SteerControlType = CarParams.SteerControlType diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 39532092bcc2b8..b6d4eefcfc4789 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -4,8 +4,8 @@ from enum import Enum, IntFlag from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, AngleRateLimit, dbc_dict -from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarDocs, Column, CarParts, CarHarness from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 27816712f6da26..24cf9623601370 100644 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -7,11 +7,12 @@ from opendbc.can.can_define import CANDefine from openpilot.selfdrive.car import dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms from openpilot.selfdrive.car.conversions import Conversions as CV +from openpilot.selfdrive.car.data_structures import CarParams from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \ Device from openpilot.selfdrive.car.fw_query_definitions import EcuAddrSubAddr, FwQueryConfig, Request, p16 -Ecu = car.CarParams.Ecu +Ecu = CarParams.Ecu NetworkLocation = car.CarParams.NetworkLocation TransmissionType = car.CarParams.TransmissionType GearShifter = car.CarState.GearShifter